Stripe: Customer, Destination Charge
Stripe: Customer, Destination Charge
Creates the Charge object with Transfer Amount to charge the Customer ID for any amount in any currency. Any Connected Account are available. If the primary payment method (Customer object) fails, the backup payment method will be charged. If all method fails, no Charge object will be created and an Abended Error log will be output.
Configs
  • U: Select HTTP_Authz Setting *
  • B: Set Customer ID on each line (first line is primary) *#{EL}
  • C1: Set Charge Amount in positive integer *#{EL}
  • C2: Set Currency Code (e.g. “USD” “JPY” “EUR” etc) *#{EL}
  • C3: Set Charge Description (Registration Num, Corp Name, etc) *#{EL}
  • C4: Set Transfer Destination (e.g. “acct_1234567890abcdef”) *#{EL}
  • C5: Set Transfer Amount in positive integer *#{EL}
  • D1: Select STRING DATA for Stripe Charge ID (update)
  • D2: Select STRING DATA for Card Brand (update)
  • D3: Select STRING DATA for Card Last4 (update)
  • D4: Select STRING/YMDATE for Card Exp (update)
Script (click to open)
// 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連結プロセス(オンボーディングプロセス)が完了します。
*/

Download

The Addon-import feature is available with Professional edition.

Notes

  • Can include the automated step “charging process” into the workflow. (No code)
  • The Stripe API key “secret key” is required for HTTP_Authz Setting.
  • 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.
  • 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.

Capture

Creates the Charge object with Transfer Amount to charge the Customer ID for any amount in any currency. Any Connected Account are available. If all method fails, no Charge object will be created and an Abended Error log will be output.
Creates the Charge object with Transfer Amount to charge the Customer ID for any amount in any currency. Any Connected Account are available. If all method fails, no Charge object will be created and an Abended Error log will be output.

Appendix

See also

1 thought on “Stripe: Customer, Destination Charge”

  1. Pingback: Stripe: Customer, Destination Charge – Questetra Support

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: