第528話:自動工程で PayPal ステータスの自動確認

2017年3月27日

請求の自動化

ワークフローシステム『Questetra』から、請求システムとしての『PayPal』をコントロールできれば、とても便利です。

たとえば『商品納入フロー』が完了した直後に「納入内容に合わせた PayPal 請求書」が自動発行されるような仕組みを作れば、「請求ミス」や「請求モレ」の発生を防ぐことができます。もし、現状が「紙の請求書」を郵送する請求業務なのであれば、切手代・印刷費・事務人件費を全てゼロにすることも可能です。

前回までの記事では、「PayPal 内に請求書を生成させる」や「PayPal 内に生成させた請求書を更にお客様にメール送信させる」といった指示が、PayPal に対して自動的に行われる仕組みを紹介しました。

更なる自動化

  • PayPal に「PayPal請求書」を生成させる
  • PayPal に「PayPal請求書」をメール送信させる
が自動化できたのなら、更に
  • PayPal に対して、入金があったか確認する
についても自動化したいものです。(債権回収業務の効率化)

今回の記事では、自動工程を上手に組み立てて『入金確認フロー』を無人化することを考察してみます。

※ここでは自動工程の一種である「スクリプト工程」を使うため、プログラミング知識が必要となります

[エントリ受付システム-ペイパル請求~入金確認]



[エントリ受付システム-ペイパル請求~入金確認:「2.PayPal決済確認」画面]

決済ステータスの自動確認

この例で配置されているスクリプト工程『入金チェック』では、案件が到達する度に、「Show invoice details」がリクエストされます。
  •  GET "https://api.paypal.com/v1/invoicing/invoices/" + paypalId

その際に得られる「PayPal からのレスポンス」が自動的に参照され、すでに支払いが行われているかどうか(PayPal請求書のステータス)を検知できる仕組みとなっています。

もし支払いが行われていると判明した場合には「領収書発行日セット」「領収書PDF生成」「領収書PDFメール送信」の工程に自動的に流れていきます。

また、もし支払いが行われていない場合には、人間工程「2.PayPal決済確認」に戻ってきますが、この工程は「24時間放置されると改めて下流に流れる」という設定になっているため、更に24時間後に改めて「PayPal請求書」のステータス確認が行われることになります。(この例では手動で流すこともルートも用意されています)

※ 他にも「支払完了通知メール」や「Webhook」によるステータス確認方法も考えられます。

サンプル・コード

スクリプト工程『入金チェック』にセットすべきスクリプトのサンプルを、以下に掲示します。

※ 上流にあるスクリプト工程『請求書生成』と『請求書送信』については、前回までの記事を参照してください。

ポイントは、レスポンスされた JSON オブジェクトのステータス「ResponseObj.status」が『PAID』になっている場合に、『ResponseObj.payments[0].date』の値を案件データとして取り込んでいるところです。分岐ポイントでは、「入金日」のデータが取り込まれた案件について「すでに支払いが行われている」と認識するように設定されています。

更に他のデータを取り込む必要がある場合には、もう少し実装項目を増やす必要があります。その場合、以下に「レスポンスされた JSON オブジェクト」の SAMPLE RESPONCE をあわせて掲示しておきますので、必要に応じて参照して、適宜スクリプトを加筆してください。

<スクリプト工程「入金チェック」の設定例>
// PayPal Invoicing API SEND (ver. 20170322)
// (c) 2017, Questetra, Inc. (the MIT License)

var sandboxmode = false; // true or false

//// == コンフィグ&参照 / Config & Retrieving ==
// Your "REST API app" on PayPal Dashboard
// https://developer.paypal.com/developer/applications/
var clientId = "Your-Client-Id-Your-Client-Id-Your-Client-Id-Your-Client-Id-Your-Client-Id-Your-";
var secret   = "Your-Secret-Your-Secret-Your-Secret-Your-Secret-Your-Secret-Your-Secret-Your-Sec";
var clientIdSandbox = "Your-Client-Id-Your-Client-Id-Your-Client-Id-Your-Client-Id-Your-Client-Id-Your-";
var secretSandbox   = "Your-Secret-Your-Secret-Your-Secret-Your-Secret-Your-Secret-Your-Secret-Your-Sec";
if( sandboxmode ){ clientId = clientIdSandbox; secret = secretSandbox; }

var paypalId = data.get( "q_paypalId" ) + "";


//// == 演算 / Calculating ==
var accessLog = "";

// Getting OAuth2 Token via client_credentials grant
var uriToken = "https://api.paypal.com/v1/oauth2/token";
var uriTokenSandbox = "https://api.sandbox.paypal.com/v1/oauth2/token";
if( sandboxmode ){ uriToken = uriTokenSandbox; }
var response = httpClient.begin()
  .basic( clientId, secret )
  .formParam( "grant_type", "client_credentials" )
  .post( uriToken );
accessLog += "---POST request--- " + response.getStatusCode() + "\n";
accessLog += response.getResponseAsString() + "\n";
accessLog += "\n";
var oauthTokenObj = JSON.parse( response.getResponseAsString() );
var oauthToken = oauthTokenObj.access_token;
accessLog += "oauthToken: " + oauthToken + "\n";
accessLog += "\n";

// invoice Detail
var uriDetail = "https://api.paypal.com/v1/invoicing/invoices/" + paypalId;
var uriDetailSandbox = "https://api.sandbox.paypal.com/v1/invoicing/invoices/" + paypalId;
if( sandboxmode ){ uriDetail = uriDetailSandbox; }
var responseDetail = httpClient.begin()
  .bearer( oauthToken )
  .get( uriDetail );

accessLog += "---GET request--- " + responseDetail.getStatusCode() + "\n";
accessLog += responseDetail.getResponseAsString() + "\n";
accessLog += "\n";
var paypalInvoiceObj = JSON.parse( responseDetail.getResponseAsString() );
var paypalInvoiceStatus = paypalInvoiceObj.status;
var paypalInvoicePaidDate = "";
var paypalInvoicePaidAmount = 0;
if ( paypalInvoiceStatus == "PAID" ){
  paypalInvoicePaidDate = paypalInvoiceObj.payments[0].date;
  // e.g.: "2017-03-21 22:10:51 PDT"
  paypalInvoicePaidDate = paypalInvoicePaidDate.slice(0,10);
  paypalInvoicePaidAmount = parseInt( paypalInvoiceObj.payments[0].amount.value );
}
accessLog += "paypalInvoiceStatus: " + paypalInvoiceStatus + "\n";
accessLog += "paypalInvoicePaidDate: " + paypalInvoicePaidDate + "\n";
accessLog += "\n";


//// == ワークフローデータへの代入 / Data Updating ==
retVal.put( "q_accessLog3", accessLog );
retVal.put( "q_paypalInvoicePaidDate",  java.sql.Date.valueOf( paypalInvoicePaidDate ) );
retVal.put( "q_paypalInvoicePaidAmount", java.math.BigDecimal( paypalInvoicePaidAmount ) );

<SAMPLE RESPONCE> (※部分的に編集されています)
※ GET "https://api.paypal.com/v1/invoicing/invoices/" + paypalId

{
  "id":"INV2-XXXX-YYYY-ZZZZ-FXC6",
  "number":"3410",
  "template_id":"TEMP-52B5XXXXSA83YYYY3",
  "status":"PAID",
  "merchant_info":{
    "email":"account+paypal@example.com",
    "business_name":"京大情報学同窓会",
    "website":"http://www.example.com/",
    "address":{
      "line1":"左京区吉田本町",
      "line2":"京都大学",
      "city":"京都市",
      "state":"京都府",
      "postal_code":"606-8501",
      "country_code":"JP"
    }
  },
  "billing_info":[
    {
      "email":"jy@yambal.net",
      "first_name":"テスト 一郎 様",
      "business_name":"テスト部",
      "language":"ja_JP"
    }
  ],
  "items":[
    {
      "name":"一般社会人(3000円)",
      "quantity":1.0,
      "unit_price":{
        "currency":"JPY",
        "value":"3000.00"
      }
    }
  ],
  "invoice_date":"2017-03-21 PDT",
  "payment_term":{
    "term_type":"NET_10",
    "due_date":"2017-03-31 PDT"
  },
  "tax_calculated_after_discount":false,
  "tax_inclusive":false,
  "merchant_memo":"https://YourWorkflowPlatformId.questetra.net/PE/Workitem/list?processInstanceId=3410",
  "total_amount":{
    "currency":"JPY",
    "value":"3000.00"
  },
  "payments":[
    {
      "type":"PAYPAL",
      "transaction_id":"0335XXXX9112YYYYL",
      "transaction_type":"SALE",
      "method":"PAYPAL",
      "date":"2017-03-21 22:10:51 PDT",
      "amount":{
        "currency":"JPY",
        "value":"3000.00"
      }
    }
  ],
  "metadata":{
    "created_date":"2017-03-21 22:02:49 PDT",
    "last_updated_date":"2017-03-21 22:10:51 PDT",
    "first_sent_date":"2017-03-21 22:08:04 PDT",
    "last_sent_date":"2017-03-21 22:08:04 PDT"
  },
  "paid_amount":{
    "paypal":{
      "currency":"JPY",
      "value":"3000.00"
    }
  },
  "allow_tip":false,
  "links":[
    {
      "rel":"self",
      "href":"https://api.paypal.com/v1/invoicing/invoices/INV2-XXXX-YYYY-ZZZZ-FXC6",
      "method":"GET"
    }
  ]
}

<データ項目一覧画面>


[雛形ダウンロード (無料)]
<類似プロセス>
≪関連記事≫

[英文記事 (English Entry) ]

1 件のコメント :

  1. ヒューマン工程の締切タイムアウトは、処理時刻として保存されない?

    返信削除