PayPal: Invoice, Check Detail
PayPal: Invoice, Check Detail
Checks the status of Invoice on the payment platform PayPal. If in PAID status, payment date is retrievable.
Configs
  • A1: Select HTTP_Authz (BasicAuthn User:ClientID Passwd:SECRET) *
  • B1: Set PayPal Invoice Id *#{EL}
  • C1: Select STRING DATA for PayPal Invoice Status (update)
  • D1: Select STRING/DATE DATA for Payment Date (update)
  • D2: Select NUMBER DATA for Payment Amount (update)
  • D3: Select STRING DATA for Currency Code (update)
  • E1: Select STRING DATA for JSON Response (update)
Script (click to open)
// 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 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

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 に自動送信されます
*/

/*
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 "Show invoice details" /v2/invoicing/invoices
    - https://developer.paypal.com/docs/invoicing/full-integration/show-invoice-details/
    - https://developer.paypal.com/docs/api/invoicing/v2/#invoices_get
- status
    - DRAFT. The invoice is in draft state. It is not yet sent to the payer.
    - SENT. The invoice has been sent to the payer. The payment is awaited from the payer.
    - SCHEDULED. The invoice is scheduled on a future date. It is not yet sent to the payer.
    - PAID. The payer has paid for the invoice.
    - MARKED_AS_PAID. The invoice is marked as paid by the invoicer.
    - CANCELLED. The invoice has been cancelled by the invoicer.
    - REFUNDED. The invoice has been refunded by the invoicer.
    - PARTIALLY_PAID. The payer has partially paid for the invoice.
    - PARTIALLY_REFUNDED. The invoice has been partially refunded by the invoicer.
    - MARKED_AS_REFUNDED. The invoice is marked as refunded by the invoicer.
    - UNPAID. The invoicer is yet to receive the payment from the payer for the invoice.
    - PAYMENT_PENDING. The invoicer is yet to receive the payment for the invoice. It is under pending review.

APPENDIX-ja
- テストのために(Live モードではなく)Sandbox モードで API 通信させたい場合
    - Sandbox 用の CLIENT-ID と SECRET をセット
    - スクリプト内のアクセスURLを "api.sandbox.paypal.com" に ('postUri1' と 'postUri2')
- PayPal API Reference "Show invoice details" /v2/invoicing/invoices
    - https://developer.paypal.com/docs/invoicing/full-integration/show-invoice-details/
    - https://developer.paypal.com/docs/api/invoicing/v2/#invoices_get
- status
    - DRAFT. The invoice is in draft state. It is not yet sent to the payer.
    - SENT. The invoice has been sent to the payer. The payment is awaited from the payer.
    - SCHEDULED. The invoice is scheduled on a future date. It is not yet sent to the payer.
    - PAID. The payer has paid for the invoice.
    - MARKED_AS_PAID. The invoice is marked as paid by the invoicer.
    - CANCELLED. The invoice has been cancelled by the invoicer.
    - REFUNDED. The invoice has been refunded by the invoicer.
    - PARTIALLY_PAID. The payer has partially paid for the invoice.
    - PARTIALLY_REFUNDED. The invoice has been partially refunded by the invoicer.
    - MARKED_AS_REFUNDED. The invoice is marked as refunded by the invoicer.
    - UNPAID. The invoicer is yet to receive the payment from the payer for the invoice.
    - PAYMENT_PENDING. The invoicer is yet to receive the payment for the invoice. It is under pending review.
*/


//////// 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 strInvoiceid       = configs.get( "StrConfB1" ) + ""; // required
  if( strInvoiceid     === "" ){
    throw new Error( "\n AutomatedTask ConfigError:" +
                     " Config {B1 Invoice Id} not specified \n" );
  }
const strPocketInvoiceStatus   = configs.getObject( "SelectConfC1" );
const multiPocketPaymentDate   = configs.getObject( "SelectConfD1" );
const numPocketPaymentAmount   = configs.getObject( "SelectConfD2" );
const strPocketPaymentCurrency = configs.getObject( "SelectConfD3" );
const strPocketJson            = configs.getObject( "SelectConfE1" );


//// == 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: Show Invoice Detail
let getUri2  = "https://api.paypal.com/v2/invoicing/invoices/" + strInvoiceid;
let request2 = httpClient.begin(); // HttpRequestWrapper
    request2 = request2.bearer( strBearerToken );
engine.log( " AutomatedTask ApiRequest2 Prepared" );

// try request2
const response2 = request2.get( getUri2 ); // HttpResponseWrapper
engine.log( " AutomatedTask ApiRequest2 Start: " + getUri2 );
const response2Code = response2.getStatusCode() + ""; // (primitive string)
const response2Body = response2.getResponseAsString() + "";
engine.log( " AutomatedTask ApiResponse2 Status: " + response2Code );
if( response2Code !== "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
{
  "id":"INV2-XXXX-5MHS-XXXX-MXJH",
  "status":"PAID",
  "detail":{
    "currency_code":"JPY",
    "note":"ご決済完了後、24時間程度でワークフロー基盤の更新が完了します。",
    "terms_and_conditions":"利用規約 https://questetra.com/ja/license-agreement/",
    "memo":"BPMS Process ID: 1100005",
    "category_code":"SHIPPABLE",
    "invoice_number":"20200629-1100005",
    "invoice_date":"2020-06-28",
    "payment_term":{
      "term_type":"DUE_ON_DATE_SPECIFIED",
      "due_date":"2020-06-30"
    },
    "viewed_by_recipient":false,
    "group_draft":false,
    "metadata":{
      "create_time":"2020-06-29T01:33:54Z",
      "last_update_time":"2020-07-01T07:05:01Z",
      "first_sent_time":"2020-06-29T10:01:35Z",
      "last_sent_time":"2020-06-29T10:01:35Z",
      "created_by_flow":"REGULAR_SINGLE",
      "recipient_view_url":"https://www.paypal.com/invoice/p/#WUFZXXXXGGFLXXXX",
      "invoicer_view_url":"https://www.paypal.com/invoice/details/INV2-XXXX-5MHS-XXXX-MXJH",
      "caller_type":"UNKNOWN"
    },
    "archived":false
  },
  "invoicer":{
    "business_name":"株式会社クエステトラ",
    "address":{
      "address_line_1":"中京区御池通間之町東入",
      "address_line_2":"高宮町206 御池ビル4階",
      "admin_area_2":"京都市",
      "admin_area_1":"京都府",
      "postal_code":"604-0835",
      "country_code":"JP"
    },
    "email_address":"support@questetra.com",
    "phones":[{
      "country_code":"81",
      "national_number":"0752055007",
      "phone_type":"MOBILE"
    }],
    "website":"www.questetra.com",
    "logo_url":"https://questetra.com/wp-content/uploads/2018/11/Corporate-logo-100x100.png"
  },
  "primary_recipients":[{
    "billing_info":{
      "business_name":"京都大学大学院情報学研究科同窓会",
      "name":{
        "given_name":"スズキ イチロー",
        "surname":"会長",
        "full_name":"スズキ イチロー 会長"
      },
      "email_address":"example@example.net",
      "language":"ja-JP"
    }
  }],
  "items":[{
    "id":"ITEM-9HP85000J5100010H",
    "name":"Yoga Mat",
    "description":"Elastic mat to practice yoga.",
    "quantity":"24",
    "unit_amount":{
      "currency_code":"JPY",
      "value":"4032"
    },
    "tax":{
      "id":"TAX-58K20007V50000009",
      "name":"TAX",
      "percent":"10",
      "amount":{
        "currency_code":"JPY",
        "value":"9677"
      }
    }
  }],
  "configuration":{
    "tax_calculated_after_discount":false,
    "tax_inclusive":false,
    "allow_tip":false,
    "template_id":"TEMP-130000003M300003N"},
    "amount":{
      "breakdown":{
        "item_total":{
          "currency_code":"JPY",
          "value":"96768"
        },
      "discount":{
        "invoice_discount":{
          "amount":{
            "currency_code":"JPY",
            "value":"0"
          }
        },
        "item_discount":{"
          currency_code":"JPY",
          "value":"0"
        }
      },
      "tax_total":{
        "currency_code":"JPY",
        "value":"9677"
      }
    },
    "currency_code":"JPY",
    "value":"106445"
  },
  "due_amount":{
    "currency_code":"JPY",
    "value":"0"
  },
  "payments":{
    "paid_amount":{
      "currency_code":"JPY",
      "value":"106445"
    },
    "transactions":[{
      "type":"PAYPAL",
      "payment_id":"9EA40005PY8100033",
      "transaction_type":"SALE",
      "payment_date":"2020-07-01",
      "method":"PAYPAL",
      "amount":{
        "currency_code":"JPY",
        "value":"106445"
      }
    }
  ]},
  "links":[{ ◆ }]
}
***/
const response2Obj     = JSON.parse( response2Body );
let strInvoiceStatus   = response2Obj.status;
let strPaymentDate     = "2099-12-31";
let strPaymentAmount   = "0";
let strPaymentCurrency = "";
if( strInvoiceStatus === "PAID" ){
  strPaymentDate     = response2Obj.payments.transactions[0].payment_date;
  strPaymentAmount   = response2Obj.payments.transactions[0].amount.value;
  strPaymentCurrency = response2Obj.payments.transactions[0].amount.currency_code;
}


//// == Data Updating / ワークフローデータへの代入 ==
if( strPocketInvoiceStatus !== null ){
  engine.setData( strPocketInvoiceStatus, strInvoiceStatus );
}
if( multiPocketPaymentDate !== null ){ // STRING or DATE
  if( multiPocketPaymentDate.matchDataType( "STRING" ) ){
    engine.setData( multiPocketPaymentDate, strPaymentDate );
  }else{
    engine.setData( multiPocketPaymentDate,
         java.sql.Date.valueOf( strPaymentDate )
    );
  }
}
if( numPocketPaymentAmount !== null ){
  let numPaymentValue = parseFloat( strPaymentAmount );
  engine.setData( numPocketPaymentAmount, new java.math.BigDecimal( numPaymentValue ) );
}
if( strPocketPaymentCurrency !== null ){
  engine.setData( strPocketPaymentCurrency, strPaymentCurrency );
}
if( strPocketJson !== null ){
  engine.setData( strPocketJson, response2Body );
}

} //////// END "main()" /////////////////////////////////////////////////////////////////

Download

2021-01-18 (C) Questetra, Inc. (MIT License)
https://support.questetra.com/addons/paypal-invoice-ckeck-detail/
The Addon-import feature is available with Professional or Enterprise edition.

Notes

  • Invoicer can automate billing operations using the PayPal Invoicing via Invoices API.
  • This addon requires the CLIENT-ID and SECRET. (Get on the dashboard)
  • Terminology 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.

Capture

Checks the status of Invoice on the payment platform PayPal. If in PAID status, payment date is retrievable.

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 “Show invoice details” /v2/invoicing/invoices
  • status
    • DRAFT. The invoice is in draft state. It is not yet sent to the payer.
    • SENT. The invoice has been sent to the payer. The payment is awaited from the payer.
    • SCHEDULED. The invoice is scheduled on a future date. It is not yet sent to the payer.
    • PAID. The payer has paid for the invoice.
    • MARKED_AS_PAID. The invoice is marked as paid by the invoicer.
    • CANCELLED. The invoice has been cancelled by the invoicer.
    • REFUNDED. The invoice has been refunded by the invoicer.
    • PARTIALLY_PAID. The payer has partially paid for the invoice.
    • PARTIALLY_REFUNDED. The invoice has been partially refunded by the invoicer.
    • MARKED_AS_REFUNDED. The invoice is marked as refunded by the invoicer.
    • UNPAID. The invoicer is yet to receive the payment from the payer for the invoice.
    • PAYMENT_PENDING. The invoicer is yet to receive the payment for the invoice. It is under pending review.

See also

Leave a Reply

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

%d bloggers like this: