第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 をあわせて掲示しておきますので、必要に応じて参照して、適宜スクリプトを加筆してください。

<スクリプト工程「入金チェック」の設定例>
  1. // PayPal Invoicing API SEND (ver. 20170322)
  2. // (c) 2017, Questetra, Inc. (the MIT License)
  3.  
  4. var sandboxmode = false; // true or false
  5.  
  6. //// == コンフィグ&参照 / Config & Retrieving ==
  7. // Your "REST API app" on PayPal Dashboard
  8. // https://developer.paypal.com/developer/applications/
  9. var clientId = "Your-Client-Id-Your-Client-Id-Your-Client-Id-Your-Client-Id-Your-Client-Id-Your-";
  10. var secret = "Your-Secret-Your-Secret-Your-Secret-Your-Secret-Your-Secret-Your-Secret-Your-Sec";
  11. var clientIdSandbox = "Your-Client-Id-Your-Client-Id-Your-Client-Id-Your-Client-Id-Your-Client-Id-Your-";
  12. var secretSandbox = "Your-Secret-Your-Secret-Your-Secret-Your-Secret-Your-Secret-Your-Secret-Your-Sec";
  13. if( sandboxmode ){ clientId = clientIdSandbox; secret = secretSandbox; }
  14.  
  15. var paypalId = data.get( "q_paypalId" ) + "";
  16.  
  17.  
  18. //// == 演算 / Calculating ==
  19. var accessLog = "";
  20.  
  21. // Getting OAuth2 Token via client_credentials grant
  22. var uriToken = "https://api.paypal.com/v1/oauth2/token";
  23. var uriTokenSandbox = "https://api.sandbox.paypal.com/v1/oauth2/token";
  24. if( sandboxmode ){ uriToken = uriTokenSandbox; }
  25. var response = httpClient.begin()
  26. .basic( clientId, secret )
  27. .formParam( "grant_type", "client_credentials" )
  28. .post( uriToken );
  29. accessLog += "---POST request--- " + response.getStatusCode() + "\n";
  30. accessLog += response.getResponseAsString() + "\n";
  31. accessLog += "\n";
  32. var oauthTokenObj = JSON.parse( response.getResponseAsString() );
  33. var oauthToken = oauthTokenObj.access_token;
  34. accessLog += "oauthToken: " + oauthToken + "\n";
  35. accessLog += "\n";
  36.  
  37. // invoice Detail
  38. var uriDetail = "https://api.paypal.com/v1/invoicing/invoices/" + paypalId;
  39. var uriDetailSandbox = "https://api.sandbox.paypal.com/v1/invoicing/invoices/" + paypalId;
  40. if( sandboxmode ){ uriDetail = uriDetailSandbox; }
  41. var responseDetail = httpClient.begin()
  42. .bearer( oauthToken )
  43. .get( uriDetail );
  44.  
  45. accessLog += "---GET request--- " + responseDetail.getStatusCode() + "\n";
  46. accessLog += responseDetail.getResponseAsString() + "\n";
  47. accessLog += "\n";
  48. var paypalInvoiceObj = JSON.parse( responseDetail.getResponseAsString() );
  49. var paypalInvoiceStatus = paypalInvoiceObj.status;
  50. var paypalInvoicePaidDate = "";
  51. var paypalInvoicePaidAmount = 0;
  52. if ( paypalInvoiceStatus == "PAID" ){
  53. paypalInvoicePaidDate = paypalInvoiceObj.payments[0].date;
  54. // e.g.: "2017-03-21 22:10:51 PDT"
  55. paypalInvoicePaidDate = paypalInvoicePaidDate.slice(0,10);
  56. paypalInvoicePaidAmount = parseInt( paypalInvoiceObj.payments[0].amount.value );
  57. }
  58. accessLog += "paypalInvoiceStatus: " + paypalInvoiceStatus + "\n";
  59. accessLog += "paypalInvoicePaidDate: " + paypalInvoicePaidDate + "\n";
  60. accessLog += "\n";
  61.  
  62.  
  63. //// == ワークフローデータへの代入 / Data Updating ==
  64. retVal.put( "q_accessLog3", accessLog );
  65. retVal.put( "q_paypalInvoicePaidDate", java.sql.Date.valueOf( paypalInvoicePaidDate ) );
  66. retVal.put( "q_paypalInvoicePaidAmount", java.math.BigDecimal( paypalInvoicePaidAmount ) );

<SAMPLE RESPONCE> (※部分的に編集されています)
  1. GET "https://api.paypal.com/v1/invoicing/invoices/" + paypalId
  2.  
  3. {
  4. "id":"INV2-XXXX-YYYY-ZZZZ-FXC6",
  5. "number":"3410",
  6. "template_id":"TEMP-52B5XXXXSA83YYYY3",
  7. "status":"PAID",
  8. "merchant_info":{
  9. "email":"account+paypal@example.com",
  10. "business_name":"京大情報学同窓会",
  11. "website":"http://www.example.com/",
  12. "address":{
  13. "line1":"左京区吉田本町",
  14. "line2":"京都大学",
  15. "city":"京都市",
  16. "state":"京都府",
  17. "postal_code":"606-8501",
  18. "country_code":"JP"
  19. }
  20. },
  21. "billing_info":[
  22. {
  23. "email":"jy@yambal.net",
  24. "first_name":"テスト 一郎 様",
  25. "business_name":"テスト部",
  26. "language":"ja_JP"
  27. }
  28. ],
  29. "items":[
  30. {
  31. "name":"一般社会人(3000円)",
  32. "quantity":1.0,
  33. "unit_price":{
  34. "currency":"JPY",
  35. "value":"3000.00"
  36. }
  37. }
  38. ],
  39. "invoice_date":"2017-03-21 PDT",
  40. "payment_term":{
  41. "term_type":"NET_10",
  42. "due_date":"2017-03-31 PDT"
  43. },
  44. "tax_calculated_after_discount":false,
  45. "tax_inclusive":false,
  46. "merchant_memo":"https://YourWorkflowPlatformId.questetra.net/PE/Workitem/list?processInstanceId=3410",
  47. "total_amount":{
  48. "currency":"JPY",
  49. "value":"3000.00"
  50. },
  51. "payments":[
  52. {
  53. "type":"PAYPAL",
  54. "transaction_id":"0335XXXX9112YYYYL",
  55. "transaction_type":"SALE",
  56. "method":"PAYPAL",
  57. "date":"2017-03-21 22:10:51 PDT",
  58. "amount":{
  59. "currency":"JPY",
  60. "value":"3000.00"
  61. }
  62. }
  63. ],
  64. "metadata":{
  65. "created_date":"2017-03-21 22:02:49 PDT",
  66. "last_updated_date":"2017-03-21 22:10:51 PDT",
  67. "first_sent_date":"2017-03-21 22:08:04 PDT",
  68. "last_sent_date":"2017-03-21 22:08:04 PDT"
  69. },
  70. "paid_amount":{
  71. "paypal":{
  72. "currency":"JPY",
  73. "value":"3000.00"
  74. }
  75. },
  76. "allow_tip":false,
  77. "links":[
  78. {
  79. "rel":"self",
  80. "href":"https://api.paypal.com/v1/invoicing/invoices/INV2-XXXX-YYYY-ZZZZ-FXC6",
  81. "method":"GET"
  82. }
  83. ]
  84. }

<データ項目一覧画面>


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

[英文記事 (English Entry) ]

1 件のコメント :

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

    返信削除