タグアーカイブ 支払いステータス

WooCommerce処理中注文を未払いのまま請求書プラグインに連携する方法

WooCommerce処理中注文を未払いのまま請求書プラグインに連携する方法

WooCommerceで銀行振込(BACS)や後払い決済を使う場合、注文を「処理中」にした途端に、外部の請求書発行プラグインがその注文を「支払い済み」と認識してしまうことがある。この原因は、WooCommerceが処理中ステータスに遷移する際に支払い日(_date_paid)を自動で記録し、多くのプラグインがそのメタデータを支払い完了の合図として読み取るからだ。ここではこの仕組みを詳しく解説し、後払い注文を未払いのまま連携させる確実な修正方法を紹介する。

なぜ処理中になった注文が「支払い済み」扱いになるのか

なぜ処理中になった注文が「支払い済み」扱いになるのか

WooCommerceの内部動作として、注文が「処理中(processing)」または「完了(completed)」に切り替わると、maybe_set_date_paid()というメソッドが呼ばれ、現在の日時を_postmetaテーブルの_date_paidに保存する。この動作は、クレジットカード決済など即時払いが完了した瞬間を記録するためにある。ところが銀行振込(BACS)は標準で「保留中(on-hold)」になるが、運用上「処理中」に手動変更したり、コードで処理中に固定すると、実際には入金前でも支払い日が書き込まれてしまう。

請求書発行プラグイン(WooCommerce PDF Invoicesや会計連携プラグインなど)は、通常この_date_paidをもとに「支払い済み」かどうかを判断する。さらに、WC_Orderクラスのis_paid()メソッドは内部的に「処理中」「完了」といったステータスを見てtrueを返す設計のため、_date_paidが空でも「支払い済み」と扱われるケースも多い。結果として、入金前の後払い注文が会計ソフト上で「支払い済み請求書」として取り込まれてしまうのだ。

修正前
注文ステータス:処理中 WooCommerceが_date_paidを自動記録 請求書プラグインが「支払い済み」と判定
修正後
注文ステータス:処理中 _date_paidは記録されない(未払いのまま) 請求書プラグインは「未払い」として連携

上図のように、_date_paidの書き込みを止めるか、支払い済み判定のロジック自体を書き換えることで、請求書が正しく「未払い」で連携されるようになる。次に、具体的にどう対処すればよいかを方法別に紹介する。

支払い済み判定のメカニズムを特定する

支払い済み判定のメカニズムを特定する

修正に入る前に、自分が使っている請求書発行プラグインがどのタイミングで「支払い済み」と判断しているかを知っておくと無駄な試行錯誤が減る。大きく分けると以下の3パターンがあり、フィルターの効き方が変わる。

  • _date_paidのメタデータを直接 get_post_meta() や$order->get_meta(‘_date_paid’) で読み取っている
  • WC_Order::get_date_paid() メソッドを呼び出している(フィルターフック posible)
  • WC_Order::is_paid() メソッドで判定している(ステータスベース)

多くのプラグインは最後のis_paid()や、直接メタデータを読む形をとる。get_date_paid()フィルターだけでは直らなかった場合、is_paid()の返り値を書き換えるか、そもそも_date_paid自体を保存させないアプローチが有効だ。

強制的に未払いにする3つの方法

強制的に未払いにする3つの方法

方法1. _date_paidが記録されるのを根本から防ぐ

WooCommerceが処理中ステータスに変わったときに_date_paidをセットするのは、maybe_set_date_paid()の中で「このステータスは支払い完了とみなす」という配列に「processing」が含まれているからだ。この配列はwoocommerce_payment_complete_order_statusフィルターで変更できる。以下のコードをテーマのfunctions.phpまたはCode Snippetsプラグインで追加すれば、BACS(bank transfer)決済の注文でのみ「processing」を支払い完了ステータスから外せる。

add_filter('woocommerce_payment_complete_order_status', function($statuses, $order) {
    if ($order instanceof WC_Order && 'bacs' === $order->get_payment_method()) {
        $statuses = array_filter($statuses, function($s) {
            return $s !== 'processing';
        });
    }
    return $statuses;
}, 10, 2);

これにより、BACSの注文が「処理中」に移行しても、WooCommerceは「これは支払い完了ステータスではない」と認識し、_date_paidを一切書き込まない。注文メモなどに残る変わったログも出ず、動作は非常にクリーンだ。結果として、請求書プラグインが_date_paidを見ている限り、未払いのままとなる。

方法2. is_paid()の返り値を上書きする

もし日付メタデータを消してもなお請求書が「支払い済み」になってしまう場合は、プラグインがWC_Order::is_paid()メソッドを使っている可能性が高い。このメソッドは内部的にwc_get_is_paid_statuses()が返すステータス配列(デフォルトでは’processing’と’completed’)と照合し、trueを返す。こちらもフィルターでBACSだけ処理中を除外できる。

add_filter('woocommerce_order_is_paid_statuses', function($statuses, $order) {
    if ($order instanceof WC_Order && 'bacs' === $order->get_payment_method()) {
        $statuses = array_diff($statuses, array('processing'));
    }
    return $statuses;
}, 10, 2);

このコードを追加すると、is_paid()は見かけ上「処理中」でもfalseを返すため、請求書プラグインは「未払い」と判断する。方法1と併用すれば、_date_paidの直接読み取りもis_paid()経由の判定も両方ブロックできる。

方法3. プラグイン側のエクスポートフィルターを利用する

どうしても上記のフィルターで直らない、あるいは他プラグインとの兼ね合いで処理中ステータスを支払い完了扱いのままにしたい場合は、請求書発行プラグインが用意しているデータ書き換え用のフックを使う。たとえば、WooCommerce PDF Invoices & Packing Slips であれば wpo_wcpdf_document_data や wpo_wcpdf_invoice_data といったフィルターがある。請求書に含める「支払い済み」フラグや日付を、注文の支払い方法がBACSのときだけ空にすることで解決できる。

プラグインのフィルター一覧は開発元のドキュメントで確認する必要があるが、一般に「Paid = 1」や「paid_date」といったキーを書き換えることが多い。次のサンプルは、WooCommerce PDF Invoicesで支払い状況を未払いに戻す例だ。

add_filter('wpo_wcpdf_invoice_data', function($data, $document) {
    if ($document->order instanceof WC_Order && 'bacs' === $document->order->get_payment_method()) {
        $data['paid'] = 0;
        $data['date_paid'] = '';
    }
    return $data;
}, 10, 2);

なお、プラグインが読み取るフィールド名は製品によって異なるため、実際のソースコードや開発元への問い合わせで正確なキー名を調べるのが確実だ。

カスタム注文ステータスで処理中と区別する方法

カスタム注文ステータスで処理中と区別する方法

根本的に「後払い専用の処理中ステータス」をWooCommerceに追加するという手もある。標準の処理中ステータスは、支払い完了後の発送準備として使われる場面が多い。これに対し、後払いは「入金確認前だが、すでに注文を受け付け、請求書を発行したい」という微妙な状態だ。そこで「後払い処理中」のようなカスタムステータスを作れば、WooCommerceの支払いロジックに干渉せず、かつ請求書プラグインも処理中ではないため誤って支払い済み扱いしなくなる。

function register_custom_order_status_invoice_processing() {
    register_post_status('wc-invoice-processing', array(
        'label'                     => '後払い処理中',
        'public'                    => true,
        'show_in_admin_status_list' => true,
        'show_in_admin_all_list'    => true,
        'exclude_from_search'       => false,
        'label_count'               => _n_noop('後払い処理中 (%s)', '後払い処理中 (%s)')
    ));
}
add_action('init', 'register_custom_order_status_invoice_processing');

add_filter('wc_order_statuses', function($order_statuses) {
    $order_statuses['wc-invoice-processing'] = '後払い処理中';
    return $order_statuses;
});

このステータスをBACSの注文に割り当てれば、標準の処理中ルートを通らずに済む。ただし、配送プラグインや在庫連動がこのカスタムステータスを「処理中」同様に扱うよう追加のフックが必要になるケースもある。その場合は、woocommerce_order_is_paid_statusesフィルターなどで「wc-invoice-processing」も支払い完了とみなしたい処理にだけ含めると調整できる。

よくある質問

この修正を適用すると、クレジットカードの処理中注文まで未払いになりませんか

紹介したコードはいずれも if 文で’ bacs ‘決済に限定しているため、クレジットカードや他の即時決済には影響しない。条件を厳密に書けば、安全に導入できる。

後払い注文のステータスをカスタムステータスにしたら、WooCommerceの標準メールは飛びますか

新規ステータスを追加しただけでは自動的にメールは送信されない。woocommerce_order_status_invoice-processing のようなアクションフックを利用して、独自のメールテンプレートをトリガーするか、処理中と同じメールを送るように設定する必要がある。

どの方法を選ぶべきかの判断基準は

まずは方法1と方法2を組み合わせて適用してみるのが最も手軽で汎用性が高い。それで解決しない場合はプラグイン固有のフィルターを探す。長期的に後払いワークフローを整理したいならカスタムステータスがおすすめだ。

この記事のポイント

  • 処理中へのステータス変更で_date_paidが自動保存される仕様が原因
  • woocommerce_payment_complete_order_statusフィルターで_date_paid書き込みをBACSだけ無効化できる
  • is_paid()の返り値を上書きすれば、日付以外の「支払い済み」判定もブロック可能
  • 請求書プラグイン固有のフィルターがあれば、そこからも支払い情報を空にできる
  • 後払い専用のカスタム注文ステータスを導入すれば、処理中と混同せずに管理できる