Safari の Export as PDF と Print からの Save as PDF

大ハマりです。

輸出のためのインボイスをまとめているんですが、結構枚数があるので、半自動処理をしています。

これがかなり曲者というか、トリッキーというかなんですが、流れとしては、

  • 倉庫にある品物のうち、積み込むもののインボイス番号をピックアップする
  • インボイス番号から、Amazon 等での注文だと判明したもの(日用品, 例えば洗剤など)の invoice を Safari で表示, 一旦 HTML としてローカルに保存する
  • ローカルに保存した HTML のうち不要なものを CSS を細工して取り除く(ヘッダやふった、ロゴなど)
  • Export as PDF を使い PDF に変換して保存する
  • 各インボイス番号に基づきソートし、連番を振った上で、FPDF を使い 1 ファイルにまとめる

って感じなんです。

Amazon とか、まあその辺での小物の買い物は、次のような理由でものすごく数が多いので、いちいち人力でやっていたら、大変だし、ミスが起こります。
なので、自動化しているんですが。。。

  • 洗剤やケミカル類, おにゃー様のグッズなどは、Subscribe & Save という定期注文で、1 アイテムごとにインボイスができるため、10 アイテムを定期注文しているなら、10 件のインボイスが発生する
  • Subscribe & Save は、同じアイテムを 2 個買うと、1 件の定期注文とカウントされるけど、1 アイテムづつを 2 件定期注文すると、注文件数に下駄をはかせることができ、割引率がアップ
  • また、数が多いときは、数量変更だと、いちいち変更作業が必要だけど、全部ならスキップをワンクリックするだけで良いので楽

ぱっと見はうまく動いていたんです、ぱっと見は。

問題は、表題の通りなんですが、Export as PDF と Print からの Save as PDF の違いです。

本当は、Print からの Save as PDF で PDF に変換したかったんですが、プリントダイアログの操作をしないといけなくて、この部分が不安定だったんで、それを省略できる Export as PDF で処理していました。

このところずっとこれで問題なく動いていたんですが、出来上がった PDF の用紙サイズがおかしなことになっているのです。
インスペクタで見ると、Paper size: 40.19 x 23.32cm となっています。
これを A4 サイズにすると、横 210mm x縦 297mm なので、右半分が欠落してしまいます。

当たり前ですが、Print からの Save as PDF の場合、用紙サイズの設定ができるので、このような問題は起こりません。

で、なんで一旦 HTML で保存をするのか、というと、Amazon の側が当然セキュリティのため、暗号通信になっているので、wget だとかそこらへんでゴニョゴニョできそうになかったため、です。

次に HTML から PDF の変換を、それこそ FPDF でやれよ、って話ですが、JavaScript やら CSS でゴニョゴニョしているため、レイアウトが崩れすぎて使い物にならなかったため、です。
Acrobat を使ったらできるんだろうか。。。持ってないけど。

しかしまあ、個人事業者の方で、こういう税金を払う時に提出しないといけないインボイス類って、どうやってるんでしょうかね。

というわけで、丸一日かかっても解決できませんでしたので、今回は人力で Print からの Save as PDF での変換作業で凌ぎたいと思います。

それはそうと、次の Lodge 製品の仕入れの件なんですが、今まではバラバラというか、一個一個の荷物として倉庫に搬入してもらい、それをこちらで輸出用の梱包にまとめていたんです。
ただ、この方法だと輸送コストが嵩む上、紛失や破損、あとそれらの管理のコストもかなりかかるし、Lodge 製品もある程度売れるようになってきたので、量をまとめて注文をしようかなと思うわけです。

それで、担当者が知らない単語がでてきたのですが、

ということのようです。

  • MOQ Minimum Order Quantity 最低注文数
  • SPQ Standard Packing Quantity 最小発注単位
  • SNP Standard Number of Package 標準の梱包の数=「出荷梱包単位」

さて、SNP ですが、例えば Lodge の製品で言えば、L8SK3 などは複数枚, たしか 3 枚で 1 つの箱に入っているんです。
その場合、SNP = 3 なのかなと思うわけです。
ただ、その箱が本当に最終の箱か、とも思うんですが、基本的にある程度の大きさがあり、当然に、鉄なので重たいので、3 枚入りの箱を、さらに大きな箱で梱包するのかという疑問なんですが、以前紹介した Lodge の工場での生産風景で、出荷時にパレットにはい付けして、ストレッチフィルムで梱包している様子が見て取れますが、このパレット 1 枚、これも SNP といえば、SNP じゃないの、って話です。
さらに言えば、パレットにきれいに積みつけられる数、1 段のですよ、これも SNP といえば SNP ではないかと。

うちの標準の梱包サイズで言えば、L8SK3 は LCC3 と共通の箱を使い、1 箱 5 枚で再梱包しています。
再梱包する理由は、L8SK3 には外箱がないため、Amazon で保管されている際に、

  • 1 アイテムがどこまでか範囲をはっきりさせるため
  • 商品を保護するため

1 アイテムごとに箱に入れるか、ビニール袋等で個別に梱包し、FBA ラベルを貼り付けることを求められるためです。

厳密に言えば、この作業はメーカーバーコードで納品すれば省略できますが、手間暇かけて丁寧に検品して、丁寧に梱包してこそ差別化できる わけでし、値段とその部分でしか差別化はできませんから、ここが自分の唯一の仕事と言っても過言ではありません。

で、箱の寸法ですが、B4-80 と同じくらいなんですが、長さ 375 × 幅 265mm(内寸)なので、400 x 300 といったところです。

写真は、保管のために倉庫内で積んである様子で、棒積みになっています。
この後、輸送のために、交互の煉瓦積みに積みなおししましたが。

要するに保管時には、ダンボールの強度を優先して、劣化を避けるために低く積んでおくわけです。
輸送の際には、特にこの箱は輸送専用で、Amazon に到着したら破棄されて、お客様にお届けするものではないので、到着まで持てば良いので、荷崩れせず、かつ、スペース効率の良い積み方に切り替える、というわけです。
写真の量で 3 x 3 で 9 箱、入り数が 5 ですから、一箱 15 キロはないですが、一つ 5 pounds なので、10kg ちょっとですね。なので、1 段で 100kg くらいです。
4 段積めば、一番下の段には 30kg 以上乗っているのですから、小学生くらいの子供が踏み台に使っているようなものです。
なので、ちゃんと考えないと、すぐに箱がダメになってしまうんです。
箱は 100 円近くしますので、パレット一つあたり、梱包の材料代だけで何千円もかかっているんです。

もちろん、LCC3 のように積み上げても、製品全体で重量を受け止めることができ、ダンボールが痛まない場合、また、LCC3 の場合、普通の茶色の箱と、カラー印刷の化粧箱とバリエーションがあるんですが、カラー印刷はコートされているのか、とてもとても滑りやすいため、そもそも棒積みで何段か積んだら、リフトが止まっただけで前方に滑り落ちかねないので、こういうものはシュリンクフィルムを軽く巻きつけておくと、フィルム同士が接すると滑り止めにもなるので、輸送ラベルからの保護も兼ねて、シュリンクフィルムを巻くようにしています。

えらく話が脱線しましたが、アメリカのパレットは、40″ x 48″ なので、1,000 x 1,200mm といったところなので、LCC 3 の箱なら、煉瓦積みで 300 x 400 が 4 個 x 1 列、400 x 300 が 3 個 x 2 列で、10 個/段, ということになるんじゃないかなと思うわけです。

ただ、最初から色々と細かくいいすぎるのもアレかと思うわけで、向こうも素人ではないというよりも、こちらよりも経験も知識もあるだろうから、まずはやってみて、問題が出たら煮詰めていけばいいんじゃないかなと思います。
まあ、結構、自分のやり方に固執して、それ以外はできない、という人もいるというか、そういう人の方が多いんで、問題が出ても解決できないってのは往々にしてあるパターンだったりもするんですが。

案ずるより産むが易しともいうし、とにかくやってみようと思います。

AmazonFBA の納品データ作りがものすごく大変になった件

つい最近のことなんですが、AmazonFBA の納品時のミスが多いためか、納品の際に輸送箱の三辺のサイズや重量等のデータ登録が義務付けられました。

とりあえず、輸送箱に連番のシールを貼って、サイズ等を測り、それをいちいち Numbers に入力して、その後、xlsx ファイルをダウンロードして、そこに転記していますが、かなり面倒くさいのです。

出力される FBA ラベルは、tcpdf を使って、連番、例えば、輸送箱が 50 箱ならば、1/50 — 50/50 という風に表示を追加して、貼り間違いや、箱のロストがわかるように工夫しています。

それでふと思ったのが、箱詰めの指示自体を同じようにラベルシールで出力して、そのシールに情報登録用 URL を出力しておき、iPhone でアクセス、ラベルに箱サイズ等を手書きして OCR 処理して入力すればミスが減るのではと思いました。

で、Google Cloud Vision API を使い、PHP で手書き文字の認識を試してみました。
使ってみた画像はこちら。

<?php
    
    $apiKey = 'your key';

    $content = base64_encode(file_get_contents('./text.jpg'));
    
    $requests = ['requests' =>
        ['image'    => ['content' => $content],
         'features' => ['type' => 'TEXT_DETECTION', 'maxResults' => 10]
        ]];

    $json = json_encode($requests);

    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, 'https://vision.googleapis.com/v1/images:annotate?key=' . $apiKey);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
    curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
    curl_setopt($curl, CURLOPT_TIMEOUT, 15);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $json);

    $res = curl_exec($curl);
    $data = json_decode($res, true);
    curl_close($curl);

    var_dump($data);

?>

結果ですが。。。

6 0f: LCC3
W 50 636H21 4KG

という感じ。
流石に字が汚いので、微妙なところですが、数字だけならそこそこかもしれません。

ただまあ、いちいち写真を撮影したりする手間を掛けるのなら、普通に打ち込んだ方が早いかもしれません。

今のところ、どうするのがいいのか考えあぐねている状態なので、おいおい煮詰めていこうと思います。

積み込みはしたものの出発を延期

昨日、薪(のようなもの)の積み込みしはしたのですが、出発は延期にしました。
というのも、今回初めての CFS に搬入になるのですが、そこを管轄する検疫所・税関がどこかわからないためです。
FAX の調子が悪かったようで、ずっと A/N が届かないので、再度電話をして、メールで送ってもらったものを確認したのが 17 時を回っていたため、検疫所・税関に確認が取れなかったのです。

神戸のあたりは、いつもの六甲出張所、ポートアイランド出張所の他に、本関というところがあるようですが、ここは一度も行ったことがなく、記憶が確かなら、石造りのレトロな庁舎で、とても 40ft コンテナトレーラの駐車場があるようなところではないのです。

検疫所も、六甲であれば、神戸検疫所食品監視第二課なので、六甲の税関出張所の 5F に入っている(去年の浸水被害で引っ越した)ので、楽なのですが、そうでないなら、和田岬の方になります。
ここは行ったことがないのですが、庁舎内への駐車は難しそうです。

もし、六甲でなくなるのであれば、すでにドラフトを提出してるものからやり直しになるし、駐車場の問題等もあり、1 日で終われないと 16 日の神社祭日に戻れないリスクが高いので、延期にしました。

でも、17 日に出発するとしても、この日は、午前中に配達と出張祭典(お祓い)があるので、早くても午後からなので、18 日早朝までに和歌山着、荷下ろしをして神戸に向かって、だいたい 4 時間は見ておかないといけないので、早くても午後スタート、そうなると引き取りのタイムリミットの 16 時に間に合う可能性はかなり低く、この日は、書類関連を提出して審査をしてもらうところで終わりそうです。
翌日の 19 日に通関、検査がなくてすんなり引き取れたとして、休憩も含めると 10 時間以上はかかるので、20 日にギリギリ間に合うか、間に合わないか、といったところです。
20 日には、分会の大麻頒布始祭があって、祭員を頼まれているのですが、どうしたものか。。。
後で電話して相談してみようと思います。

それと、引き上げてきた雑貨類も、荷下ろしを終え、パレットからバラして、あらかた検品をしましたが。。。
NO STACK と書いてあるんですが、その上に他の貨物が積み上げられていて、下の方の箱がずれてしまっています。
困ったものです。
これでは品質が保てないので、倉庫を変更することにしたわけです。

なんだかんだで、昨日、100kg ほど、特に急ぐ商品を納品しました。
今日、明日と延期にしたので、検品・梱包・納品(出荷)を進めていきたいと思います。

後、備忘録。

fpdf で申告等の書類を出力しているわけですが、既存の書類の中に文字を流し込みたい、というニーズがあるわけですが、今までは IPA の等幅明朝体を使って、いちいち行に分割して出力していました。
でも、プロポーショナルフォントを使うこともあるだろうし、そういう場合に、幅を取得したり、あるいは指定した矩形の中に描画したいこともあるわけで、ちょっとやり方を調べてみました。

まず、文字列の幅の取得方法については、そのままズバリですが、

矩形の中に描画するには、MultiCell という機能を使うようです。

<?php
require('fpdf/mbfpdf.php');

$pdf=new MBFPDF('P', 'mm', 'A4');
$pdf->AddMBFont(GOTHIC ,'SJIS');
$pdf->AddPage();
$pdf->SetFont(GOTHIC,'',20);

$pdf->Cell(80, 15, '非常に長い文章を入力した場合の挙動', 1, 1);
$pdf->MultiCell(80, 15, '非常に長い文章を入力した場合の挙動', 1);
$pdf->MultiCell(80, 15, "非常に長い文章を\n入力した場合\nの挙動", 1);

$pdf->Output();
?>

上記のようなコードで、出力は以下のようになるそうです。

PDF ファイルのページ数を知る方法

PDF ファイルのページ数を知る方法ですが、どうやるんだろうな、と思っていて、ざっくり調べたんですが、ずっと分からずにいたんですが、ひょんなことから、わかりました。

<?php

require_once('tcpdf.php');
require_once('fpdi.php');

$tcpdf = new \FPDI();

// PDFファイル指定
$file = 'test.pdf';

// テンプレートファイルの読み込み・ページ数を取得
$pagenum = $tcpdf->setSourceFile($file);

var_dump($pagenum);

そのままズバリ。
今まで捨てていた、setSourceFile の戻り値がページ数でした。
これで、複数ページあるインボイスにページ番号を振ることができるようになります。
実に素晴らしい。

それと、ふと思ったこととして、クリックポストの宛名のラベル印刷ですが、Safari から直接やると、中央で crop されて、左上ではないので、一旦保存して、Preview.app を使って切り抜いているんです。
まあ、紙をいちいちハサミで切るような間抜けなことをするよりはマシなんですが、とても美しくない。

それで、

<?php
require_once('tcpdf/tcpdf.php');
require_once('FPDI-2/src/autoload.php');
use setasign\Fpdi\TcpdfFpdi; 
$pdf = new TcpdfFpdi();
$pdf->SetMargins(0, 0, 0);
$pdf->SetCellPadding(0);
$pdf->SetAutoPageBreak(false);
$pdf->setPrintHeader(false);    
$pdf->setPrintFooter(false);

$pageCount = $pdf->setSourceFile('foo/bar/baz.pdf');

for ($i = 1; $i <= $pageCount; ++$i) {
    $pdf->AddPage('P', 'A6');
    $pdf->useTemplate($pdf->importPage($i));
}

$pdf->Output(sprintf("%s.pdf", time()), 'I');

とやってみたんですが、そのままだと、Encrypted とか抜かしてエラーになるんですよ。
この時の PDF は出力されたものをそのまま command + S で保存したもの。

一旦 Preview.app で開いて、Export to PDF… をすると、暗号化が外れて問題なし。
あるいは、command + P で印刷出力したものも問題なし。

ただ、手間は大して変わらないので、なら初めから Preview.app で crop したのでいい気がしてきました。

そんなこんなで、さらに正確に輸出入の申告用の書類を作成することができそうです。

で、今日は、昨日頑張って通関してきた荷物をデバンして、代わりに乾燥させていた薪を製品に加工するため、太陽電池小屋から運び出して、コンテナに積み込みました。

まあ、それにしても高く積んでくれたものです。
パレットが 2 枚重ねてあって、意味がわからなかったんですが、重すぎてパレットが折れて、2 枚重ねにしてあったようです。
1 枚抜こうとしたら、もっと折れて、全部バラして積み直す羽目になりました。
何度も、何度も、高く積むなと言っているんですが。。。

途中、グリ石を道端にストックしてあったものが邪魔になるので片付けたり、そのついでに去年の豪雨で市道が崩れて流れ込んでいるものが放置されているのも片付けたりしてたもんだから、積み終えたら 16 時を回ってしまいました。
それから、回送したので、第 2 ヤードに着いたら真っ暗で、誰もいなくて、煙突の打ち合わせとか、いろいろしようと思ったんですが、間に合いませんでした。

明日は、加工前の薪は下ろして、和歌山に納品する薪を積み込み、その帰りに神戸に寄って、遅れた荷物を通関・引き取りを済ませたいところです。

ただ、昨日 A/N を発行すると電話があったものの、その後なしのつぶてなので、とっても危険な匂いがプンプンしています。
流石に 2 度空ぶるのはキツすぎるので、18, 19 日で出向いた方がいいのかな、と思ったりもしないでもないですが、20 日は午後から分会の大麻頒布始祭があって、祭員をやらないといけないということなので、遅れるわけにもいかず、それ以上後ろにずらすと、予約の方々にものすごく迷惑がかかるので、タイミングが難しいところです。

やることはたまる一方なのですが、まあ、頑張れない性分なので、ゆっくりとマイペースで、それなりに片付けられるように頑張ります。

Brave(ブレイブ)横型往復式薪割り機を安く送るには

今日は午前中は、食品等輸入届出書を半自動で作成するスクリプトを書きました。

とにかくガリガリ、ゴリゴリ書いて、サクッと出来上がりましたので、今後は B/L 番号や、本船、あと、何がいくつ入ってくるかを指定するだけで、食品等輸入届出書が PDF で出来上がるという寸法です。
あとは添付資料等も自動作成すれば完璧です。

ただ、現状、輸入申告については、人力でゴリゴリ Numbers で packing list を作ったりという前時代的なことをしているので、これも invoice から自動的に税番ごとに分類するとかの下準備をスクリプトで自動化したいように思う所です。
こちらが自動されれば、当然、食品等輸入届出書を用意しなけばいけない品物ピックアップも合わせて自動化されるわけですから。

まあ、いつまで紙ベースでやるんだよ、と言われそうですけど、NACCS はタダではないし、コスト的に見合わないので、今後も導入することはないと思います。
そういう意味では、当然に、食品等輸入届出書も FAINS を使うことはない、ということになりますかね。

とまあ、そんな具合で、昼からは雑貨の出荷作業をやりました。

出荷が終わって、そろそろ薪の準備を始める人も増えてくるだろうということで、薪割り機が売れ始めるんではないかと思うわけですが、現状、大型の重量物は個人宅には配送してもらえない制約があり、とても不便なので、なんとかならないかと思っているわけです。

ヤマト運輸は、ヤマト便の場合 30kg まで、らくらく家財宅急便は 100kg まで(厳密には、150kg までだけど、料金が非現実的)、佐川は 50kg までドアツードアで運んでもらえます。

それで大きな部品の重量を測ってみました。

まず、エンジンなどと、作動油タンクなどを含むフレーム部分が 34kg です。
この時点で 30kg を超えるのですが、エンジンはボルト 2 本で留まっているだけなので、分解すれば簡単に 30kg 以下になります。
エンジンには油圧ポンプが組み付けてあるのですが、ここはバラす必要はないでしょう。

問題は、メインのフレームで、重量はほぼ 100kg, 96.9kg ありました。

この部分は、27 番の Beam Assembly, これの内側にスライドするウエッジを含む 28 番の Beam Slide があり、Beam Slide の内部に Beam Slide と Beam Assembly を連結する形で 34 番の 4”x24” Hydraulic Cylinder が組み付けられ、底面を 36 番の Bottom Plate で蓋をされている状態です。

まだバラしていないので各部分の重量は定かではないのですが、100kg を超えないよう梱包できるのであれば、バラす = 再度組み立てる必要があるわけで、そのまま運べるらくらく家財宅急便で運んでもらえないものかと思います。

かなり大雑把な外寸ですが、W 104cm, D 突起部を含まず 15cm でログテーブル取り付け部などの突起が左右あるのですが、それが +3cm 弱、H が 39cm といったところですので、3 辺の和は 165cm くらいということになります。
サイズ的には、160cm にはギリギリ収まらないのではないか、と思います。
らくらく家財宅急便は重量が 100kg を超えない範囲では、重さは料金には関係ありませんので、重たい荷物の場合、ヤマト便よりも割安になることがあります。

これ以上は、バラして重さを計ってみるしかないかなというところです。

見積もりが大変なのでなんとかしたい件

寒くなってきて、薪ストーブの見積もりがちらほら。

そういえば、自動見積り計算機を作ってみよう、なんてほざいたはいいけど、すっかり忘れていたことを今しがた思い出しましたが、早速壁にぶち当たりました。

為替レートってどうやって取得しようかしら、ということです。

ちょっと検索したら、Google の JSON API がヒットしたんですが、404 だったんです。

代わりに見つけたのがこれ。

yql を使う方法が回答されていました。

必要なのは、CADJPY なので、以下のように書き換えました。

http://query.yahooapis.com/v1/public/yql?q=select * from yahoo.finance.xchange where pair in ("CADJPY")&env=store://datatables.org/alltableswithkeys

答えは、XML で戻してくれて、

<?xml version="1.0" encoding="UTF-8"?>
<query xmlns:yahoo="http://www.yahooapis.com/v1/base.rng" yahoo:count="1" yahoo:created="2015-11-10T16:31:22Z" yahoo:lang="en-us"><results><rate id="CADJPY"><Name>CAD/JPY</Name><Rate>92.9053</Rate><Date>11/10/2015</Date><Time>4:31pm</Time><Ask>92.9156</Ask><Bid>92.8950</Bid></rate></results></query><!-- total: 938 -->
<!-- pprd1-node250-lh1.manhattan.sg3.yahoo.com -->

ってな具合なわけです。

というわけで、早速実装しましょう。

<?php
if ($xml = simplexml_load_file('http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.xchange%20where%20pair%20in%20(%22CADJPY%22)&env=store://datatables.org/alltableswithkeys')) {
    print (string)($xml->xpath('//rate[@id="CADJPY"]/Rate')[0]);
}
?>

都度都度 yql に問い合わせが発生するので、結果をキャッシュするようにするなどは必要でしょうし、エラー処理も一切省いてますが、為替レートに基づいた見積もりを作れるようになるわけで、多少は正確になりそうです。

ていうか、xpath 式とか、久しぶりすぎてすっかり忘れてましたが、最近の若い人だったら、生まれてませんとか言われそうですね。

まあ、今日は眠いんで、ここまで。