// GraalJS Script (engine type: 2)
/*
NOTES
- Invoicer can automate billing operations using the PayPal Invoicing via Invoices API.
- https://www.paypal.com/merchantapps/appcenter/acceptpayments/invoicing
- The invoices are controlled by a 24-character ID (e.g. "INV2-Z56S-5LLA-Q52L-CPZ5")
- This addon requires the CLIENT-ID and SECRET. (Get on the dashboard)
- Developer Dashboard -> My apps & credentials -> REST API Apps (Live mode)
- https://developer.paypal.com/developer/applications/
- Terminology in this addon is based on Invoices API v2 (2019-04).
- Be careful when migrating from implementations prior to April 2019.
- e.g. "merchant" to "invoicer"
- e.g. "billing info" to "recipient"
- When PayPal emails the recipient, the invoice moves from draft to payable state.
- To move from a draft to payable state, the SEND INVOICE action is required.
- Invoice Status: DRAFT, SCHEDULED, SENT, PAID, MARKED_AS_PAID, CANCELLED, REFUNDED,,
- https://developer.paypal.com/docs/api/invoicing/v2/#invoices_create
- However, if "invoice_date" is set, automatically sent at 7:00 of Invoicer time zone
- The URL for viewing the invoice differs between the recipient and the invoicer.
- recipient_view_url: https://www.paypal.com/invoice/p/#XXXX5MHSXXXXMXJH
- invoicer_view_url: https://www.paypal.com/invoice/details/INV2-XXXX-5MHS-XXXX-MXJH
NOTE-ja
- 請求人は、請求書ツール(Invoicing)による請求業務を自動化できます(Invoices API経由)
- https://www.paypal.com/jp/webapps/mpp/merchant/solutions/invoicing
- 請求書は24文字のIDでコントロールされます(e.g. "INV2-Z56S-5LLA-Q52L-CPZ5")
- このアドオンの利用には CLIENT-ID と SECRET が必要です。(ダッシュボードで取得)
- Developer Dashboard -> My apps & credentials -> REST API Apps (Live mode)
- https://developer.paypal.com/developer/applications/
- このアドオンの表記は Invoices API v2 〔2019-04〕ベースの用語にて記載されています。
- 2019-04 以前の実装から移行する場合は、特にご注意ください。
- "merchant"(販売人) ではなく "invoicer"(請求人)
- "billing info"(請求先) ではなく "recipient"(受取人)
- "請求書ドラフト" は原則、PayPalから受取人に対しメールされた際に決済可能な状態になります
- すなわち請求書ドラフトを有効化するには、別途「送信」アクションが必要です。
- Invoice Status: DRAFT, SCHEDULED, SENT, PAID, MARKED_AS_PAID, CANCELLED, REFUNDED,,
- https://developer.paypal.com/docs/api/invoicing/v2/#invoices_create
- ただし "請求日" がセットされた場合は、請求人タイムゾーンの 7:00 に自動送信されます
- 請求書表示用のURLは、受取人〔請求先〕用と請求人用で異なります。
- recipient_view_url: https://www.paypal.com/invoice/p/#XXXX5MHSXXXXMXJH
- invoicer_view_url: https://www.paypal.com/invoice/details/INV2-XXXX-5MHS-XXXX-MXJH
*/
/*
APPENDIX
- To request API in Sandbox mode (instead of Live mode)
- Set CLIENT-ID and SECRET for Sandbox
- Edit Access URLs to "api.sandbox.paypal.com" ('postUri1' and 'postUri2')
- PayPal API Reference "Send invoice" /v2/invoicing/invoices
- https://developer.paypal.com/docs/invoicing/basic-integration/#3-send-invoice
- https://developer.paypal.com/docs/api/invoicing/v2/#invoices_send
APPENDIX-ja
- テストのために(Live モードではなく)Sandbox モードで API 通信させたい場合
- Sandbox 用の CLIENT-ID と SECRET をセット
- スクリプト内のアクセスURLを "api.sandbox.paypal.com" に ('postUri1' と 'postUri2')
- PayPal API Reference "Send invoice" /v2/invoicing/invoices
- https://developer.paypal.com/docs/invoicing/basic-integration/#3-send-invoice
- https://developer.paypal.com/docs/api/invoicing/v2/#invoices_send
*/
//////// START "main()" /////////////////////////////////////////////////////////////////
main();
function main(){
//// == Config Retrieving / 工程コンフィグの参照 ==
const strAuthzSetting = configs.get( "AuthzConfA1" ); // required (Authz by Basic_AuthN)
engine.log( " AutomatedTask Config: Authz Setting: " + strAuthzSetting );
const strNoticesetting = configs.get( "StrConfA2" ) + "";
let boolNoticesetting = true;
if( strNoticesetting === "false" ){
boolNoticesetting = false;
}
engine.log( " AutomatedTask Config: Notification to Invoicer: " + boolNoticesetting );
const strInvoiceid = configs.get( "StrConfB1" ) + ""; // required
if( strInvoiceid === "" ){
throw new Error( "\n AutomatedTask ConfigError:" +
" Config {B1 Invoice Id} not specified \n" );
}
//// == Data Retrieving / ワークフローデータの参照 ==
// (Nothing. Retrieved via Expression Language in Config Retrieving)
//// == Calculating / 演算 ==
// prepare request1: Get an Access Token
// (PayPal OAuth 2.0 credentials / Client Credentials)
// https://developer.paypal.com/docs/api/overview#get-credentials
// https://developer.paypal.com/docs/api/get-an-access-token-curl/
let postUri1 = "https://api.paypal.com/v1/oauth2/token";
let request1 = httpClient.begin(); // HttpRequestWrapper
request1 = request1.authSetting( strAuthzSetting );
request1 = request1.formParam( "grant_type", "client_credentials" );
engine.log( " AutomatedTask ApiRequest1 Prepared" );
// try request1
const response1 = request1.post( postUri1 ); // HttpResponseWrapper
engine.log( " AutomatedTask ApiRequest1 Start: " + postUri1 );
const response1Code = response1.getStatusCode() + ""; // (primitive string)
const response1Body = response1.getResponseAsString() + "";
engine.log( " AutomatedTask ApiResponse1 Status: " + response1Code );
if( response1Code !== "200"){
throw new Error( "\n AutomatedTask UnexpectedResponseError: " +
response1Code + "\n" + response1Body + "\n" );
}
// parse response1
/*** engine.log( response1Body ); // debug
response sample
{
"scope":"https://api.paypal.com/v1/payments/.※ https://uri.paypal.com/services/invoicing
openid https://uri.paypal.com/payments/payouts ....",
"access_token":"A21AAO9wpfXXXXXXXXXXL1P96HvZkRXXXXXXXXXXDlSVGSvUjlXXXXX...XXXXX",
"token_type":"Bearer",
"app_id":"APP-6BKXXX232XXX3090N",
"expires_in":32400,
"nonce":"2021-01-14T06:13:03Z1dgXXXCnnXXXgLKXXXgn0XXXcrJXXXoALXXXXBUXXXs"
}
***/
const response1Obj = JSON.parse( response1Body );
const strBearerToken = response1Obj.access_token;
// prepare request2: Send Invoice
let request2Obj = {};
request2Obj.send_to_invoicer = boolNoticesetting;
let postUri2 = "https://api.paypal.com/v2/invoicing/invoices/" + strInvoiceid + "/send";
let request2 = httpClient.begin(); // HttpRequestWrapper
request2 = request2.bearer( strBearerToken );
request2 = request2.body( JSON.stringify( request2Obj ), "application/json" );
engine.log( " AutomatedTask ApiRequest2 Prepared" );
// try request2
const response2 = request2.post( postUri2 ); // HttpResponseWrapper
engine.log( " AutomatedTask ApiRequest2 Start: " + postUri2 );
const response2Code = response2.getStatusCode() + ""; // (primitive string)
const response2Body = response2.getResponseAsString() + "";
engine.log( " AutomatedTask ApiResponse2 Status: " + response2Code );
if( response2Code !== "200"){ // Reference wrong "202", Overview right "200"
throw new Error( "\n AutomatedTask UnexpectedResponseError: " +
response2Code + "\n" + response2Body + "\n" );
}
// https://developer.paypal.com/docs/api-basics/HTMLStatusCodes/
// parse response2
/*** engine.log( response2Body ); // debug
response sample
{
"href":"https://www.paypal.com/invoice/p/#INV2-XXXX-DQHU-XXXX-UKG5",
"rel":"payer-view",
"method":"GET"
}
***/
//// == Data Updating / ワークフローデータへの代入 ==
// (No Output except Console Log)
} //////// END "main()" /////////////////////////////////////////////////////////////////