第527話:自動工程で PayPal Invoicing API を呼ぶ

2017年3月21日

請求システムとしての PayPal

「PayPal 請求書」は、とても便利です。

PayPal にログインして「相手のメールアドレス」と「販売した商品明細」をセットするだけで、誰でも簡単に請求書を送ることができます。「ちょっとした受託作業」や「特別な値引き」にも柔軟に対応できる数少ない決済手段と言えるでしょう。その簡単さは「むしろECサイトで買い物をする手続きの方が難しい」と思えてしまうくらいです。しかも、買い手から売り手に「クレジットカード番号」を渡す必要もありません。

しかし、何十枚も発行しなければならない、となれば流石に面倒です。(その「柔軟さ」がアダとなってしまいます)

全く同じ請求内容であれば一括して処理する機能もあるのですが、それぞれに微妙に内容が異なるのであれば一つ一つ請求情報をセットせざるをえません。ただ、手作業の繰り返しは、どうしてもミスを招きます。

請求書生成と送信の自動化

以前の記事(※)で『PayPal システムに対して「PayPal 請求書を生成せよ」というリクエストが自動送信される仕組み』を紹介しました。

第525話:自動工程から OAuth2 リクエストを送出させる方法

今回の記事では、更に『「生成した PayPal 請求書を先方に送信せよ」というリクエストが自動送信される仕組み』について考えてみたいと思います。(プログラミング知識が必要となります)

[エントリ受付システム]

手作業を極力排除した業務プロセス

ここで紹介している業務プロセス定義は『セミナー』や『勉強会』などの「イベント参加受付業務」です。

業務フロー図を見れば一目瞭然ですが、「Webフォームへの入力」が行われるたびに案件が流れ始め、「請求が必要なエントリ」の場合にのみ、「請求書生成のフロー」に分流する仕組みとなっています。(OR分岐)

業務フロー図内に配置されている工程の多くは「自動工程」(背景グレー)となっており、「人間工程」(背景水色)は『1.請求チェック』と『2.入金チェック』しかありません。しかも『1.請求チェック』については、5分経過で自動完了するように設定された人間工程であり、平時において何か具体的な作業が規定されている訳ではありません。(不正アクセスが増えた際に締切時間を長くしてチェックを強化するなど)

サンプルコード

「件名セット」「敬称セット」「領収書発行日セット」および「参加証PDF生成」「領収書PDF生成」の5つの自動工程はいずれも Questetra 標準の【サービス工程】です。

「請求書生成」「請求書送信」の2つの自動工程は【スクリプト工程】であり、サーバサイド JavaScript をセットする必要があります。スクリプトの中で、PayPal Invoicing API との通信が規定されます。

<スクリプト工程「請求書生成」の設定例>
// PayPal Invoicing API CREATE (ver. 20170314)
// (c) 2017, Questetra, Inc. (the MIT License)

var sandboxmode = false; // true or false

//// == コンフィグ&参照 / Config & Retrieving ==
// Get Your "REST API app" via 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; }

// Your Info
var merchantEmail = "support@questetra.com";
var merchantEmailSandbox = "qstore-paypal-facilitator@questetra.com";
if( sandboxmode ){ merchantEmail = merchantEmailSandbox; }
//var merchantBusinessName = "Questetra, Inc.";
var merchantBusinessName = "株式会社クエステトラ";
//var merchantAddress2 = "Nakagyo-ku Oike-dori-Ainomachi"; // first line
var merchantAddress1 = "中京区御池通間之町東入"; // second line
//var merchantAddress1 = "Takamiya-cho 206 Oike Bldg 4th";
var merchantAddress2 = "高宮町206 御池ビル4階";
//var merchantAddressCity = "Kyoto";
var merchantAddressCity = "京都市";
//var merchantAddressState = "KYOTO";
var merchantAddressState = "京都府";
var merchantAddressPC = "604-0835";
var merchantAddressCC = "JP";
var merchantWebsite = "https://www.questetra.com/corp/";
// for Link to BPMS on PayPal
var merchantMemo = "https://YourPlatformID.questetra.net/PE/Workitem/list?processInstanceId=";
merchantMemo += processInstance.getProcessInstanceId();

// Customer Info
//var billingLanguage = "en_US";
var billingLanguage = "ja_JP";
var billingEmail = data.get( "q_billingEmail" ) + "";
var billingName1 = data.get( "q_billingName1" ) + "";
var billingBusinessName = data.get( "q_billingBusinessName" ) + "";

// Items Info
//var itemUnitPriceCurrency = "USD";
var itemUnitPriceCurrency = "JPY";
//var itemTaxName = "JCT";
var itemTaxName = "消費税";
var itemTaxPercent = 8;
var itemName = data.get( "q_item" ).get(0).getDisplay() + "";
var itemQuantity = 1; // number
var itemUnitPrice = data.get( "q_item" ).get(0).getValue() + ""; // string

// Invoice Info
var invoiceNumber = processInstance.getProcessInstanceId() + ""; // string
var invoiceDate = data.get( "q_invoiceDate" ) + " JST"; // yyyy-MM-dd z
var termType = "NET_10"; //"DUE_ON_RECEIPT";
var logoUrl = "https://www.questetra.com/wp-content/uploads/2017/03/Corporate-logo-100x100.png";

//// == 演算 / 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";

// Create invoice
var invoiceObj = {};
invoiceObj.number = invoiceNumber;
invoiceObj.invoice_date = invoiceDate;
invoiceObj.payment_term = {};
invoiceObj.payment_term.term_type = termType;
invoiceObj.logo_url = logoUrl;
invoiceObj.merchant_memo = merchantMemo;

invoiceObj.merchant_info = {};
invoiceObj.merchant_info.email = merchantEmail;
invoiceObj.merchant_info.business_name = merchantBusinessName;
invoiceObj.merchant_info.address = {};
invoiceObj.merchant_info.address.line1 = merchantAddress1;
invoiceObj.merchant_info.address.line2 = merchantAddress2;
invoiceObj.merchant_info.address.city = merchantAddressCity;
invoiceObj.merchant_info.address.state = merchantAddressState;
invoiceObj.merchant_info.address.postal_code = merchantAddressPC;
invoiceObj.merchant_info.address.country_code = merchantAddressCC;
invoiceObj.merchant_info.website = merchantWebsite;
invoiceObj.billing_info = [];
invoiceObj.billing_info[0] = {};
invoiceObj.billing_info[0].email = billingEmail;
invoiceObj.billing_info[0].first_name = billingName1;
// invoiceObj.billing_info[0].last_name = billingName2;
invoiceObj.billing_info[0].business_name = billingBusinessName;
invoiceObj.billing_info[0].language = billingLanguage;
invoiceObj.items = [];
invoiceObj.items[0] = {};
invoiceObj.items[0].name = itemName;
// invoiceObj.items[0].description =itemDescription;
invoiceObj.items[0].quantity = itemQuantity;
invoiceObj.items[0].unit_price = {};
invoiceObj.items[0].unit_price.currency = itemUnitPriceCurrency;
invoiceObj.items[0].unit_price.value = itemUnitPrice;
invoiceObj.items[0].tax = {};
invoiceObj.items[0].tax.name = itemTaxName;
invoiceObj.items[0].tax.percent = itemTaxPercent;
var uriCreate = "https://api.paypal.com/v1/invoicing/invoices/";
var uriCreateSandbox = "https://api.sandbox.paypal.com/v1/invoicing/invoices/";
if( sandboxmode ){ uriCreate = uriCreateSandbox; }
var responseCreate = httpClient.begin()
.bearer( oauthToken )
.body( JSON.stringify( invoiceObj ), "application/json" )
.post( uriCreate );

accessLog += "---POST request--- " + responseCreate.getStatusCode() + "\n";
accessLog += JSON.stringify( invoiceObj ) + "\n";
accessLog += "\n";
accessLog += responseCreate.getResponseAsString() + "\n";
accessLog += "\n";
var paypalIdObj = JSON.parse( responseCreate.getResponseAsString() );
var paypalId = paypalIdObj.id;
accessLog += "paypalId: " + paypalId + "\n";
accessLog += "\n";

//// == ワークフローデータへの代入 / Data Updating ==
retVal.put( "q_accessLog", accessLog );
retVal.put( "q_paypalId", paypalId );

<スクリプト工程「請求書送付」の設定例>
// PayPal Invoicing API SEND (ver. 20170303)
// (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";

// Send invoice
var uriSend = "https://api.paypal.com/v1/invoicing/invoices/" + paypalId + "/send";
var uriSendSandbox = "https://api.sandbox.paypal.com/v1/invoicing/invoices/" + paypalId + "/send";
if( sandboxmode ){ uriSend = uriSendSandbox; }
var responseSend = httpClient.begin()
.bearer( oauthToken )
.post( uriSend );

accessLog += "---POST request--- " + responseSend.getStatusCode() + "\n";
accessLog += responseSend.getResponseAsString() + "\n";
accessLog += "\n";

//// == ワークフローデータへの代入 / Data Updating ==
retVal.put( "q_accessLog2", accessLog );


<Webフォーム画面>

<完成したPayPal請求書の例>

<データ項目一覧画面>



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

[英文記事 (English Entry) ]

0 件のコメント :

コメントを投稿