ITで遊ぶ

WooCommerceからB2Webへ(2)

以前、WooCommerceの注文データをREST APIを使って取り出す方法をやってみました。
しかしこのサンプルプログラムではPandasを使っており、B2Webへの入力とするCSVを作るにはまるで向かないこと、よくよく調べるとエクセルでは難しいので、全部、Pythonで処理することにして、プログラムを全面的に書き直しました。

この記事が有用な人は次のような人です。

  • WooCommerceってよさそうじゃないか。ECサイトを運用したい。
  • 出荷を外部業者に頼っていてクロネコヤマトのB2Webを使って情報をやり取りしている。
  • クロネコヤマト B2 CSV Exporter for WooCommerceのようなブラックボックスを使いたくない。カネ払いたくない。
  • pythonは少しはわかるけど、自分でプログラムを書く力はない。

ということで対象読者を明らかにしてから、進みます。

ここではCSVモジュールを使いまわします。
なぜならば、CSVモジュールこそが次のような課題を解決してくれる強力な武器だからです。

CSVファイルをカラムの順番を気にせずに作りたい。

CSVファイルとは最初の行にフィールド名を書くこともありますが、基本的に左からのデータの順番によってフィールドが決まります。
しかしプログラムを開発している人間にとってはフィールド名を指定したら、その場にデータを書き込んでほしいものです。

Python CSVモジュール

CSVモジュールにはDictWriterという辞書型データを入力すると、そのキーの場所にデータを置いてくれる機能があります。

例をあげます。
今、カラン名がcol1,col2,col3というCSVファイルを作りたいとします。
columns = [“col1”, “col2”, “col3”]
というリストを作り、
writer = csv.DictWriter(“xxx.csv”, fieldnames=columns)
とオブジェクトを作ります。

writer.writeheader()
とすると一行目にカラン名を書き出します。

outdic[“col3”] = 3; outdic[“col2”] = 2 ; outdic[“col1”] = 1
と辞書型変数を作り、

writer.writerow(outdic)
とすれば、

めでたく

col1, col2, col3
1,2,3

というCSVが出力されます。

こういうことがPandasでは、私が調べた限りでは、できません。

Woocommerce REST APIのデータについて

結果は以下の方法でJSONで得ることができます。APIの使い方は前回の記事を見てください。
内容によっては明細データを含んでいるので単純ではありません。


wcapi = API(
url = "https://your url",
consumer_key = "ck_yourkey",
consumer_secret = "cs_yourkey",
version="wc/v3",
timeout=50
)

jsonlist = wcapi.get("orders?status=processing").json()

得られるフィールド名

以下のようになっています。
この中でbilling.nameのようなドット付きフィールドはbillingというくくりで明細データとして出力されています。

in_cols = ["id","parent_id","status","currency","version", \
           "prices_include_tax","date_created","date_modified", \
           "discount_total","discount_tax","shipping_total", \
           "shipping_tax","cart_tax","total","total_tax", \
           "customer_id","order_key","payment_method", \
           "payment_method_title","transaction_id", \
           "customer_ip_address","customer_user_agent", \
           "created_via","customer_note","date_completed", \
           "date_paid","cart_hash","number","meta_data", \
           "line_items","tax_lines","shipping_lines", \
           "fee_lines","coupon_lines","refunds","payment_url", \
           "is_editable","needs_payment","needs_processing", \
           "date_created_gmt","date_modified_gmt", \
           "date_completed_gmt","date_paid_gmt","currency_symbol", \
           "billing.first_name","billing.last_name", \
           "billing.company","billing.address_1","billing.address_2", \
           "billing.city","billing.state","billing.postcode", \
           "billing.country","billing.email","billing.phone", \
           "shipping.first_name","shipping.last_name", \
           "shipping.company","shipping.address_1","shipping.address_2", \
           "shipping.city","shipping.state","shipping.postcode", \
           "shipping.country","shipping.phone","_links.self", \
           "_links.collection"]

この中でbilling.とshipping.というデータがあります。
このふたつはさらにJSONとなっています。

また、shipping.はとくに指定されていない限り、ブランクです。
billing.を届け先にしないといけないということになります。

billing.stateやshipping.satateはJP02などのようなコードが入っており、都道府県名ではありません。これはISO3166-2でコード化された県名のようです。
調べたところ以下のとおり

iso3166["JP01"] = "北海道"; iso3166["JP02"] = "青森県"; iso3166["JP04"] = "宮城県"
iso3166["JP05"] = "秋田県"; iso3166["JP06"] = "山形県"; iso3166["JP07"] = "福島県"
iso3166["JP08"] = "茨城県"; iso3166["JP09"] = "栃木県"; iso3166["JP10"] = "群馬県"
iso3166["JP11"] = "埼玉県"; iso3166["JP12"] = "千葉県"; iso3166["JP13"] = "東京都"
iso3166["JP14"] = "神奈川県"; iso3166["JP15"] = "新潟県";iso3166["JP16"] = "富山県"
iso3166["JP17"] = "石川県"; iso3166["JP18"] = "福井県";iso3166["JP19"] = "山梨県"
iso3166["JP20"] = "長野県"; iso3166["JP21"] = "岐阜県"; iso3166["JP22"] = "静岡県"
iso3166["JP23"] = "愛知県"; iso3166["JP24"] = "三重県"; iso3166["JP25"] = "滋賀県"
iso3166["JP26"] = "京都府"; iso3166["JP27"] = "大阪府"; iso3166["JP28"] = "兵庫県"
iso3166["JP29"] = "奈良県"; iso3166["JP30"] = "和歌山県"; iso3166["JP31"] = "鳥取県"
iso3166["JP32"] = "島根県"; iso3166["JP33"] = "岡山県"; iso3166["JP34"] = "広島県"
iso3166["JP35"] = "山口県"; iso3166["JP36"] = "徳島県"; iso3166["JP37"] = "香川県"
iso3166["JP38"] = "愛媛県"; iso3166["JP39"] = "高知県"; iso3166["JP40"] = "福岡県"
iso3166["JP41"] = "佐賀県"; iso3166["JP42"] = "長崎県"; iso3166["JP43"] = "熊本県"
iso3166["JP44"] = "大分県"; iso3166["JP45"] = "宮崎県"; iso3166["JP46"] = "鹿児島県"
iso3166["JP47"] = "沖縄県"

B2Webの宅急便用フィールド

ここに準拠して作りました。

out_cols = ["お客様管理番号","送り状種類","クール区分","伝票番号","出荷予定日", \
            "お届け予定日","配達時間帯","お届け先コード","お届け先電話番号", \
            "お届け先電話番号枝","お届け先郵便番号","お届け先住所", \
            "お届け先建物名","お届け先会社・部門1","お届け先会社・部門2", \
            "お届け先名","お届け先名略称カナ","敬称","ご依頼主コード", \
            "ご依頼主電話番号","ご依頼主電話番号枝","ご依頼主郵便番号", \
            "ご依頼主住所","ご依頼主建物名","ご依頼主名","ご依頼主名略称カナ", \
            "品名コード1","品名1","品名コード2","品名2","荷扱い1", \
            "荷扱い2","記事","コレクト代金引換額","コレクト内消費税", \
            "営業所止置き","営業所コード","発行枚数","個数口枠の印字", \
            "ご請求先顧客コード","ご請求先分類コード","運賃管理番号"]

ここまでの情報で以下のプログラム本体を読むことはできると思います。

今回のプログラムの全体像

絶対に変更しなきゃいけないところは、色をつけてあります。¥マークはすべてバックスラッシュです。pythonで継続行を意味します。


'''
This program convert Woocommerce REST API data into Kuroneko Yamato B2 file.

How to use:
1. Get woocommerce API key and fill in this program.
2. fill in my_ data.
3. run as 'python woob2.py' 
(If your Python environment does not have woocommerce library, use 'pip install woocommerce')
4. You can get 'b2.csv'
Detail things are written on https://playing-engineer.com/

This program is FREE but not Public domain. All rights are reserved by Tsukasa Takao 2024.
'''

import datetime
from woocommerce import API
import csv
import json

my_csvfilename = "b2.csv"
my_phone = "あなたの電話番号"
my_postcode = "あなたの郵便番号"
my_address = "あなたの住所"
my_name = "あなたの社名か名前"

in_cols = ["id","parent_id","status","currency","version", \
           "prices_include_tax","date_created","date_modified", \
           "discount_total","discount_tax","shipping_total", \
           "shipping_tax","cart_tax","total","total_tax", \
           "customer_id","order_key","payment_method", \
           "payment_method_title","transaction_id", \
           "customer_ip_address","customer_user_agent", \
           "created_via","customer_note","date_completed", \
           "date_paid","cart_hash","number","meta_data", \
           "line_items","tax_lines","shipping_lines", \
           "fee_lines","coupon_lines","refunds","payment_url", \
           "is_editable","needs_payment","needs_processing", \
           "date_created_gmt","date_modified_gmt", \
           "date_completed_gmt","date_paid_gmt","currency_symbol", \
           "billing.first_name","billing.last_name", \
           "billing.company","billing.address_1","billing.address_2", \
           "billing.city","billing.state","billing.postcode", \
           "billing.country","billing.email","billing.phone", \
           "shipping.first_name","shipping.last_name", \
           "shipping.company","shipping.address_1","shipping.address_2", \
           "shipping.city","shipping.state","shipping.postcode", \
           "shipping.country","shipping.phone","_links.self", \
           "_links.collection"]

out_cols = ["お客様管理番号","送り状種類","クール区分","伝票番号","出荷予定日", \
            "お届け予定日","配達時間帯","お届け先コード","お届け先電話番号", \
            "お届け先電話番号枝","お届け先郵便番号","お届け先住所", \
            "お届け先建物名","お届け先会社・部門1","お届け先会社・部門2", \
            "お届け先名","お届け先名略称カナ","敬称","ご依頼主コード", \
            "ご依頼主電話番号","ご依頼主電話番号枝","ご依頼主郵便番号", \
            "ご依頼主住所","ご依頼主建物名","ご依頼主名","ご依頼主名略称カナ", \
            "品名コード1","品名1","品名コード2","品名2","荷扱い1", \
            "荷扱い2","記事","コレクト代金引換額","コレクト内消費税", \
            "営業所止置き","営業所コード","発行枚数","個数口枠の印字", \
            "ご請求先顧客コード","ご請求先分類コード","運賃管理番号"]
iso3166 = {}
iso3166["JP01"] = "北海道"; iso3166["JP02"] = "青森県"; iso3166["JP04"] = "宮城県"
iso3166["JP05"] = "秋田県"; iso3166["JP06"] = "山形県"; iso3166["JP07"] = "福島県"
iso3166["JP08"] = "茨城県"; iso3166["JP09"] = "栃木県"; iso3166["JP10"] = "群馬県"
iso3166["JP11"] = "埼玉県"; iso3166["JP12"] = "千葉県"; iso3166["JP13"] = "東京都"
iso3166["JP14"] = "神奈川県"; iso3166["JP15"] = "新潟県";iso3166["JP16"] = "富山県"
iso3166["JP17"] = "石川県"; iso3166["JP18"] = "福井県";iso3166["JP19"] = "山梨県"
iso3166["JP20"] = "長野県"; iso3166["JP21"] = "岐阜県"; iso3166["JP22"] = "静岡県"
iso3166["JP23"] = "愛知県"; iso3166["JP24"] = "三重県"; iso3166["JP25"] = "滋賀県"
iso3166["JP26"] = "京都府"; iso3166["JP27"] = "大阪府"; iso3166["JP28"] = "兵庫県"
iso3166["JP29"] = "奈良県"; iso3166["JP30"] = "和歌山県"; iso3166["JP31"] = "鳥取県"
iso3166["JP32"] = "島根県"; iso3166["JP33"] = "岡山県"; iso3166["JP34"] = "広島県"
iso3166["JP35"] = "山口県"; iso3166["JP36"] = "徳島県"; iso3166["JP37"] = "香川県"
iso3166["JP38"] = "愛媛県"; iso3166["JP39"] = "高知県"; iso3166["JP40"] = "福岡県"
iso3166["JP41"] = "佐賀県"; iso3166["JP42"] = "長崎県"; iso3166["JP43"] = "熊本県"
iso3166["JP44"] = "大分県"; iso3166["JP45"] = "宮崎県"; iso3166["JP46"] = "鹿児島県"
iso3166["JP47"] = "沖縄県"

dt = datetime.datetime.today() 
today = "{0:%Y/%m/%d}".format(dt)

wcapi = API(
url = "あなたのAPIのURL",
consumer_key = "ck_あなたのキー",
consumer_secret = "cs_あなたのキー",
version="wc/v3",
timeout=50
)

jsonlist = wcapi.get("orders?status=processing").json()

# print(json.dumps(jsonlist)) # for first level debug

with open(my_csvfilename, 'w', encoding='shift-jis', newline="") as csvfile:
    writer = csv.DictWriter(csvfile, fieldnames=out_cols)
    writer.writeheader()
    for jsonitem in jsonlist:
    
        # build list
        outdic = {}
        outdic["送り状種類"] = "0"
        outdic["伝票番号"] = jsonitem["id"]
        outdic["出荷予定日"] = today

        shipping = jsonitem["shipping"]
        billing = jsonitem["billing"]

        if (shipping["phone"] == ""):
            outdic["お届け先郵便番号"] = billing["postcode"]    
            outdic["お届け先電話番号"] = billing["phone"]
            outdic["お届け先住所"] = iso3166[billing["state"]] \
            + billing["city"] \
            + billing["address_1"] 
            outdic["お届け先建物名"] = billing["address_2"] 
            outdic["お届け先会社・部門1"] = billing["company"]
            outdic["お届け先名"] = billing["last_name"] + " " \
            + billing["first_name"]
        else:
            outdic["お届け先電話番号"] = shipping["phone"]
            outdic["お届け先郵便番号"] = shipping["postcode"]
            outdic["お届け先住所"] = iso3166[shipping["state"]] \
            + shipping["city"] \
            + shipping["address_1"]
            outdic["お届け先建物名"] = shipping["address_2"] 
            outdic["お届け先会社・部門1"] = shipping["company"]
            outdic["お届け先名"] = shipping["last_name"] + " " \
            + shipping["first_name"]
            
        outdic["ご依頼主電話番号"] = my_phone
        outdic["ご依頼主郵便番号"] = my_postcode
        outdic["ご依頼主住所"] = my_address
        outdic["ご依頼主名"] = my_name

        items = jsonitem["line_items"]
        outdic["品名1"] = items[0]["name"]
        if (len(items)>1):
            outdic["品名2"] = items[1]["name"]

        writer.writerow(outdic)

csvfile.close()
print("________Process End!")

時間帯の指定とか、営業所止めとかいった特殊要件はCSV出力後にエクセルで編集です。

ソースをダウンロードしたい方はこちらからどうぞ

Hope your help.(Woocommerce使うなら絶対に役にたつと思うんだけど。弱小ブログなので、気づいてすらもらえないのが残念。。。)

関連記事

  1. ソフトウェアは進歩し続けなけりゃならんのか?

  2. 簡単なCSSフレームワーク milligram

  3. Raspberry Piに本当の乱数発生器が追加されていた

  4. 会員サイトのちょっとしたプラグインの日本語化

  5. Visual BasicとAccessDBを配布パッケージにする

  6. 新世代コンピューターシンセサイザー

  7. JavaScriptでオブジェクト指向をするには

  8. PHPのクラスの継承

記事をプリント