請求の自動化
ワークフローシステム『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"
- }
- ]
- }
<データ項目一覧画面>
[雛形ダウンロード (無料)]
- 業務テンプレート:エントリ受付システム-ペイパル請求~入金確認
- 第504話:監査書類を Dropbox に自動保存! (2016-10-11)
- 第503話:ユラギを無くすには「マスター参照」でしょ!(kintone編) (2016-10-03)
- 第498話:自動工程におけるデータ加工、アレコレ(その5) (2016-08-29)
- M230 自動工程: 業務データの複雑なデータ加工が自動実行されるように設定する(ECMAスクリプト) (使い方)
- M415 自動工程: 業務プロセス定義で利用可能な自動工程を追加する (使い方)
- M416 自動工程: 業務プロセス定義で利用可能な自動工程を自作する (使い方)
- M202 業務の流れ: 処理フローを定義し、各工程の締切時刻を設定する (使い方)
[英文記事 (English Entry) ]
ヒューマン工程の締切タイムアウトは、処理時刻として保存されない?
返信削除