// GraalJS Script (engine type: 2)
//////// START "main()" /////////////////////////////////////////////////////////////////
main();
function main(){
//// == Config Retrieving / 工程コンフィグの参照 ==
const strAuthzSetting = configs.get( "AuthzConfU" ); /// REQUIRED
engine.log( " AutomatedTask Config: Authz Setting: " + strAuthzSetting );
const strCustomerIds = configs.get( "strSetConfB" ); /// REQUIRED
let strChargeAmount = configs.get( "strSetConfC1" ); /// REQUIRED
const strCurrencyCode = configs.get( "strSetConfC2" ); /// REQUIRED
const strChargeDescr = configs.get( "strSetConfC3" ); /// REQUIRED
const strTransferDest = configs.get( "strSetConfC4" ); /// REQUIRED
let strTransferAmount = configs.get( "strSetConfC5" ); /// REQUIRED
const pocketChargeId = configs.getObject( "SelectConfD1" ); // NotRequired
const pocketCardBrand = configs.getObject( "SelectConfD2" ); // NotRequired
const pocketCardLast4 = configs.getObject( "SelectConfD3" ); // NotRequired
const pocketCardExp = configs.getObject( "SelectConfD4" ); // NotRequired *STRING/YMDATE
if( strCustomerIds.replace(/\n/g, '') === "" ){
throw new Error( "\n AutomatedTask ConfigError:" +
" Config {Customer ID B} is empty \n" );
}
if( strChargeAmount === "" ){
throw new Error( "\n AutomatedTask ConfigError:" +
" Config {ChargeAmount C1} is empty \n" );
}
if( strCurrencyCode === "" ){
throw new Error( "\n AutomatedTask ConfigError:" +
" Config {CurrencyCode C2} is empty \n" );
}
if( strChargeDescr === "" ){
throw new Error( "\n AutomatedTask ConfigError:" +
" Config {ChargeDescription C3} is empty \n" );
}
if( strTransferDest === "" ){
throw new Error( "\n AutomatedTask ConfigError:" +
" Config {TransferDestination C4} is empty \n" );
}
if( strTransferAmount === "" ){
throw new Error( "\n AutomatedTask ConfigError:" +
" Config {TransferAmount C5} is empty \n" );
}
strChargeAmount = strChargeAmount.replace(/,/g, '').replace(/\./g, '');
let numChargeAmount = parseInt( strChargeAmount, 10 );
if( numChargeAmount <= 0 ){
throw new Error( "\n AutomatedTask ConfigError:" +
" Config {ChargeAmount C1} must be positive \n" );
}
strChargeAmount = numChargeAmount + "";
strTransferAmount = strTransferAmount.replace(/,/g, '').replace(/\./g, '');
let numTransferAmount = parseInt( strTransferAmount, 10 );
if( numTransferAmount <= 0 ){
throw new Error( "\n AutomatedTask ConfigError:" +
" Config {TransferAmount C5} must be positive \n" );
}
strTransferAmount = numTransferAmount + "";
//// == Data Retrieving / ワークフローデータの参照 ==
// (nothing, except Expression Language config)
//// == Calculating / 演算 ==
/// Create Charge Object
/// POST /v1/charges
// https://stripe.com/docs/api/charges/create
// https://stripe.com/docs/api/authentication
// If you need to authenticate via bearer auth (e.g., for a cross-origin request),
// use -H "Authorization: Bearer sk_xxx" instead of -u sk_test_xxx.
let arrCustomerIds = strCustomerIds.split('\n');
let apiUri = "https://api.stripe.com/v1/charges";
let apiLog = "";
let responseStr = "";
let responseObj;
for( let i = 0; i < arrCustomerIds.length; i++ ){
let strCustomerId = arrCustomerIds[i];
if( strCustomerId === "" ){ continue; }
// preparing for API Request
let apiRequest = httpClient.begin(); // HttpRequestWrapper
apiRequest = apiRequest.authSetting( strAuthzSetting ); // with "Authorization: Bearer XX"
// https://questetra.zendesk.com/hc/en-us/articles/360024574471-R2300#HttpRequestWrapper
apiRequest = apiRequest.formParam( "customer", strCustomerId );
apiRequest = apiRequest.formParam( "amount", strChargeAmount );
apiRequest = apiRequest.formParam( "currency", strCurrencyCode );
apiRequest = apiRequest.formParam( "description", strChargeDescr );
apiRequest = apiRequest.formParam( "transfer_data[amount]", strTransferAmount );
apiRequest = apiRequest.formParam( "transfer_data[destination]", strTransferDest );
// throwing Request to the API (POST, GET, PUT, etc)
engine.log( " AutomatedTask Trying: POST " + apiUri );
const response = apiRequest.post( apiUri );
const responseCode = response.getStatusCode() + "";
engine.log( " AutomatedTask ApiResponse: Status " + responseCode );
if( responseCode !== "200"){
let apiLogTmp = " AutomatedTask RuntimeWarning:" +
" ChargeError: " + strCustomerId + "\n" +
response.getResponseAsString() ;
engine.log( apiLogTmp );
apiLog += apiLogTmp + "\n";
// C.F. https://stripe.com/docs/api/errors
}else{
// parsing Response Json
responseStr = response.getResponseAsString() + "";
responseObj = JSON.parse( responseStr );
let apiLogTmp = " AutomatedTask ApiResponse:" +
" New ChargeObject ID: " + responseObj.id + "\n" +
" AutomatedTask ApiResponse:" +
" Card Brand: " + responseObj.source.brand;
engine.log( apiLogTmp );
apiLog += apiLogTmp + "\n";
break;
}
}
if( responseStr === "" ){
throw new Error( "\n AutomatedTask UnexpectedResponseError: all response is not 200" +
"\n" + apiLog + "\n" );
}
//// == Data Updating / ワークフローデータへの代入 ==
if( pocketChargeId !== null ){ // STRING
engine.setData( pocketChargeId, responseObj.id );
}
if( pocketCardBrand !== null ){ // STRING
engine.setData( pocketCardBrand, responseObj.source.brand );
}
if( pocketCardLast4 !== null ){ // STRING
engine.setData( pocketCardLast4, responseObj.source.last4 );
}
if( pocketCardExp !== null ){ // STRING or YMDATE
if( pocketCardExp.matchDataType( "STRING" ) ){
engine.setData( pocketCardExp,
("0" + responseObj.source.exp_month).slice(-2) + "/" +
responseObj.source.exp_year );
}else{
engine.setData( pocketCardExp,
java.sql.Date.valueOf(
responseObj.source.exp_year + "-" +
("0" + responseObj.source.exp_month).slice(-2) + "-01"
)
);
}
}
} //////// END "main()" /////////////////////////////////////////////////////////////////
/*
Notes-en:
- Can include the automated step "charging process" into the workflow. (No code)
- When the matter reaches, a charging request is automatically sent to the Stripe API.
- https://stripe.com/docs/api/charges
- The Stripe API key "secret key" is required for HTTP_Authz Setting.
- https://dashboard.stripe.com/apikeys
- https://dashboard.stripe.com/test/apikeys
- If you want to test-operate the workflow app, use the "test key" of the Stripe API key.
- Set the secret key starting with `sk_text_` to "HTTP Authorization Aetting > Token Fixed Value".
- Name: `StripeSecretKeyForXYZ`
- Token: `sk_test_123456789012345678901234`
- For actual operation, set a secret key starting with `sk_live_`.
- A positive integer representing how much to charge in the smallest currency unit
- e.g., "100" cents to charge $1.00
- e.g., "100" to charge \100 (a zero-decimal currency) (JPY)
- "#{#q_numUsdWithoutCent}00" is also possible if numerical data without auxiliary info
- If present, commas "," and periods "." are removed in advance
- When using numeric data, be careful of the number of digits after the decimal point
- If the Charging is successful, the Transfer Amount will be sent to the Connected Account.
- https://stripe.com/docs/connect/destination-charges
- If Connect account config (acct_1234567890abcdef) is incorrect, the entire Charge request will be invalid.
- invalid_request_error: `No such account: 'acct_1234567890abcdef'`
- Multiple Customer IDs. can be listed. __Enhanced 202107__
- The Customer IDs (payment methods) on the second and subsequent lines are for backup.
- The maximum number of Customer IDs that can be set is 10.
APPENDIX-en:
- Numeric parsing depends on JavaScript `parseInt(x,10)`. (The prefix gives an error)
- See below for more information on available currency codes (JPY, USD, EUR, ...).
- https://stripe.com/docs/currencies
- In case of USD, the minimum amount is $0.50 or equivalent.
- The amount value supports up to eight digits (e.g., for a USD charge of $999,999.99)
- Refer to the following for the error codes (ResponseCode other than 200)
- https://stripe.com/docs/api/errors
- The error details can also be viewed from the dashboard. (Direct URL with the Customer ID)
- https://dashboard.stripe.com/customers/cus_12345678901234
- https://dashboard.stripe.com/test/customers/cus_12345678901234
- Charging details can be found in the "Payment" menu on the dashboard. (Direct URL with the Child ID)
- https://dashboard.stripe.com/payments/ch_123456789012345678901234
- https://dashboard.stripe.com/test/payments/ch_123456789012345678901234
- Transfer details in the "Connected accounts" menu on the dashboard. (with Connected Account ID)
- https://dashboard.stripe.com/connect/accounts/acct_1234567890123456
- https://dashboard.stripe.com/test/connect/accounts/acct_1234567890123456
- Transfer Amount is also expressed in the smallest currency unit (Positive integer).
- Exceeding the Charge amount will result in an error
- `destination[amount]` must be less than or equal to the charge amount
- Charges by the Connect Destination method (for Express/Custom type).
- https://stripe.com/docs/connect/destination-charges#transfer-amount
- Connected Account (child account) must be registered in advance on Stripe.
- You can get the link for Express account registration from the Stripe admini page.
- Give the link to the recipient of the Transfer Amount. (Link expiration date 7 days)
- Once the deposit account etc is registered, the Connect (onboarding) process will be completed.
Notes-ja:
- ワークフロー内に自動工程『課金処理』を組み込むことができるようになります。(ノーコード実装)
- 案件が到達すると Stripe API に対して課金リクエストが送信されます。(カード課金フローの自動化)
- https://stripe.com/docs/api/charges
- 通信設定には、Stripe APIキーの "シークレットキー" が必要です。
- https://dashboard.stripe.com/apikeys
- https://dashboard.stripe.com/test/apikeys
- ワークフローアプリをテスト運用したい場合は、テスト用のシークレットキー "テストキー" を利用します。
- `sk_text_` で始まるテストキーを『HTTP認証設定 > トークン直接指定』に設定します。
- Name: `StripeSecretKeyForXYZ`
- Token: `sk_test_123456789012345678901234`
- 本運用する場合は `sk_live_` で始まるシークレットキーを設定します。
- 課金額の設定は、最小の通貨単位で表現します。(正の整数)
- "1.00ドル" の場合は "100" セント (USD)
- 小数のない円通貨の場合は "100円" は "100" 円 (JPY)
- "1(ドル)" といったデータの場合 "#{#q_numUsdWithoutCent}00" のように設定します。
- もしカンマ "`,`" やピリオド "`.`" が存在する場合は課金処理前に除去されます。
- 小数の数値型データを使う場合、小数点以下の桁数設定に注意が必要です。
- "100.00円" は「1万円」の課金になります。
- 課金が成功すれば、分配金が Connected Account(子アカウント)に仕向送金されます。
- https://stripe.com/docs/connect/destination-charges
- 子アカウント設定(acct_1234567890abcdef)に誤りがある場合、課金リクエスト自体がエラーとなります。
- invalid_request_error: `No such account: 'acct_1234567890abcdef'`
- 複数の顧客IDを列挙することが可能です。 __Enhanced 202107__
- 2行目以降の顧客ID(支払方法)はバックアップ用です。
- 顧客IDの設定可能最大数は10件です。
APPENDIX-ja:
- 数値判定は JavaScript `parseInt(x,10)` に依存します (接頭辞はエラーになります)
- 利用できる通貨コードの詳細は以下を参照してください (JPY, USD, EUR, ...)
- https://stripe.com/docs/currencies
- 最小課金金額は、日本円の場合、50円です。
- 課金額の最大桁数は8桁です。(日本円の場合、99,999,999円)
- エラーコード(200以外のResponseCode)の内容については以下を参照してください。
- https://stripe.com/docs/api/errors
- エラー内容はダッシュボードからも参照可能です。(顧客IDを付与したURLでダイレクトアクセスも可)
- https://dashboard.stripe.com/customers/cus_12345678901234
- https://dashboard.stripe.com/test/customers/cus_12345678901234
- 課金詳細はダッシュボードの「支払い」メニューでも確認可能です。(課金IDを付与したURLが便利)
- https://dashboard.stripe.com/payments/ch_123456789012345678901234
- https://dashboard.stripe.com/test/payments/ch_123456789012345678901234
- 分配金詳細(送金詳細)は「子アカウント」(Connected accounts)メニューでも確認可能です。
- https://dashboard.stripe.com/connect/accounts/acct_1234567890123456
- https://dashboard.stripe.com/test/connect/accounts/acct_1234567890123456
- 分配金額の設定も、最小の通貨単位で表現します。(正の整数)
- 課金額を超える設定はエラーとなります
- `destination[amount]` must be less than or equal to the charge amount
- Connect Destination 方式(Express/Customタイプ向け)で課金されます。
- https://stripe.com/docs/connect/destination-charges#transfer-amount
- Connected Account(子アカウント)は、予め Stripe 上で登録されている必要があります。
- Express アカウント登録用のリンクは、Stripe 管理画面から取得できます。
- 分配金を受け取る方(子アカウントのユーザ)にリンクを伝えます。(リンク有効期限7日)
- 入金用口座等が登録されれば、Connect連結プロセス(オンボーディングプロセス)が完了します。
*/