# オフラインでカード支払いを回収する インターネット接続の問題が生じているときにカード支払いを回収します。 # iOS > This is a iOS for when terminal-card-present-integration is terminal and terminal-sdk-platform is ios and reader-type is bluetooth. View the full page at https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments?terminal-card-present-integration=terminal&terminal-sdk-platform=ios&reader-type=bluetooth. Terminal SDK を使用すると、アプリケーションではネットワーク接続なしで、モバイルリーダーを使用して支払いの回収を続行できます。 > オフラインで実行するときは、販売時に決済情報が収集されます。オーソリは接続の回復後にのみ試行され、支払いが転送されます。ユーザーであるお客様が、オフライン取引に関連する支払い拒否や改ざんに関するすべてのリスクを負います。改ざんされたリーダーが支払いを Stripe に転送できない場合、またはカード発行会社が取引を拒否した場合、売上を回収する方法はなく、すでに提供した商品やサービスへの顧客の支払いを受け取れなくなることがあります。 > > カード発行会社による拒否を減らすため、以下のことが推奨されます。 > > - できる限り早急にインターネット接続を再確立して、支払いを Stripe に記録します。 - 所定の金額を超える場合は取引を制限します。 - 合計すると所定の金額を超える複数の取引を SDK が保存した場合、[すべてのオフライン決済を失敗させます](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#managing-risk)。 ## オフライン中に決済を回収する オフライン決済の手順は、オンライン決済と同じで、決済の作成、回収、処理、およびキャプチャーが含まれます。このプロセスのどの段階でも、デバイスをオンラインからオフラインにできます。 1. [オフラインモードを有効にする](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#enable-offline-mode) 1. [オフライン中にリーダーに接続する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#connect-while-offline) 1. [オフラインイベントを処理する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#handle-offline-events) 1. [オフライン中に PaymentIntent を作成する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#create-payment-intent) 1. [支払い方法を収集する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#collect-payment-method) 1. [支払いを確定する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#confirm-payment) 1. [支払いが転送されるまで待つ](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#wait-for-forward) 1. (オプション) [支払いをキャプチャーする](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#capture-payment) 1. (オプション) [オフラインで回収した支払いを調べる](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#examine-offline) ## オフラインモードを有効にする オフラインモードを使用するには、アプリケーションが Terminal iOS SDK のバージョン `3.3.0` 以降を使用している必要があります。 [Configuration](https://docs.stripe.com/api/terminal/configuration.md) オブジェクトまたは[ダッシュボード](https://docs.stripe.com/terminal/fleet/configurations-overview.md?dashboard-or-api=dashboard#update-the-default-configuration-for-the-account)を使用して、`Location` で[サポートされている](https://docs.stripe.com/terminal/features/operate-offline/overview.md?reader-type=bluetooth#availability)デバイスのオフラインモードを有効にします。 ```curl curl https://api.stripe.com/v1/terminal/configurations \ -u "<>:" \ -d "offline[enabled]=true" ``` `Configuration` オブジェクトでオフラインモードを有効にすると、`Location` に[割り当てる](https://docs.stripe.com/terminal/fleet/configurations-overview.md?dashboard-or-api=api#create-a-configuration-for-an-individual-location)ことができます。また、アカウントの[デフォルト](https://docs.stripe.com/terminal/fleet/configurations-overview.md?dashboard-or-api=api#retrieve-the-account-default-configuration)の `Configuration` オブジェクトを更新すると、すべての `Locations` でオフラインモードをデフォルトで有効にすることもできます。Configuration API の変更が SDK とリーダーに反映されるまで数分かかる場合があり、反映するには、リーダーの接続をいったん切断してから再接続する必要があります。 ## オフライン中にリーダーに接続する SDK はオンラインに接続した後、必要な `Location` 情報をローカルに保存します。後続のオフライン接続では、その `Location` に保存されている設定情報が使用されます。 オフライン時にスマートリーダーで支払いを回収するには、直前の 30 日以内のオンライン時に、あらかじめ同じ `Location` の同じタイプのモバイルリーダーに接続し、また期間内にリーダーのソフトウェアを更新する必要があります。 オフライン時にこれらの要件を満たさずリーダーに接続しようとすると、リクエストはエラーで失敗します。 | エラー | 解決策 | | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **SDK がインターネットに接続されていません** | 使用している `Location` がオフラインモード用に[設定されている](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#enable-offline-mode)ことを確認します。それ以外の場合は、オンライン時に任意のリーダーに接続してから、オフライン時に同じタイプのリーダーに接続します。 | | **選択したリーダーをオフラインでの支払い回収に使用するには、ソフトウェアの更新が必要です。** | リーダーのソフトウェアが 30 日以上更新されていません。オンライン時にリーダーに接続して更新してください。 | | **選択したリーダーをオフラインでの支払い回収に使用するには、この場所でオンラインのペアリングを行う必要があります。** | POS がこれまでオンライン中に接続していないタイプのリーダーに接続しようとしています。まずオンライン中に、このリーダーまたは同じタイプのリーダーに接続する必要があります。または、オフライン中に接続する場合は、以前オンライン中に POS が接続していたタイプのリーダーに接続できます。 | アプリケーションを再インストールしたり、SDK のディスクストレージを消去する操作 (POS デバイス設定での POS アプリのキャッシュの消去など) を実行すると、SDK が保存している未転送の支払いがすべて失われます。破壊的なアクションを実行する前に、保存された決済がないことを確認してください。 ## オフラインイベントを処理する [クライアント側] - [OfflineDelegate (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Protocols/SCPOfflineDelegate.html) - [NetworkStatus (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Enums/SCPNetworkStatus.html) アプリケーションが SDK のネットワークステータスと転送された支払いの状態に関する更新を受信できるようにするには、`OfflineDelegate` プロトコルを実装して Terminal SDK に渡します。オフラインで支払いを回収する前に、`OfflineDelegate` を設定する必要があります。 #### Swift ```swift import StripeTerminal class CustomOfflineDelegate: OfflineDelegate { func terminal(_ terminal: Terminal, didChangeOfflineStatus offlineStatus: OfflineStatus) { // Check the value of `offlineStatus` and update your UI accordingly. For instance, // you can check the SDK's network status at `offlineStatus.sdk.networkStatus`. // // You can also check the SDK's current offline status using // `Terminal.shared.offlineStatus.sdk.networkStatus`. } func terminal(_ terminal: Terminal, didForwardPaymentIntent intent: PaymentIntent, error: Error?) { // The PaymentIntent was successfully forwarded, or an error occurred. // Reconcile any local state using the backend-generated `PaymentIntent.stripeId` // and the metadata you supplied when creating the PaymentIntent. // // Note that the `PaymentIntent.stripeId` may still be nil if creating the // PaymentIntent in the backend failed. } func terminal(_ terminal: Terminal, didReportForwardingError error: Error) { // A non-specific error occurred while forwarding a PaymentIntent. // Check the error message and your integration implementation to // troubleshoot. } } ``` #### Swift ```swift import UIKit import StripeTerminal @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { Terminal.initWithTokenProvider(APIClient.shared) Terminal.shared.offlineDelegate = CustomOfflineDelegate() // ... return true } // ... } ``` ## オフライン中に PaymentIntent を作成する [クライアント側] - [createPaymentIntent (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPTerminal.html#/c:objc\(cs\)SCPTerminal\(im\)createPaymentIntent:completion:) - [CreateConfiguration (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPCreateConfiguration.html) - [OfflineDetails (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPOfflineDetails.html) オフラインでの操作に対応するには、SDK の `createPaymentIntent` を使用して PaymentIntent オブジェクトを作成します。これにより、SDK はオフライン時に PaymentIntents を作成し、接続が再確立された後で Stripe に転送できます。 オフラインでの実行中、`PaymentIntent` オブジェクトは null の `stripeId` を保持します。PaymentIntent の[メタデータ](https://docs.stripe.com/payments/payment-intents.md#storing-information-in-metadata)にカスタム識別子を追加して、オフラインで作成された `PaymentIntent` オブジェクトをデータベースで照合できるようにすることをお勧めします。 [ステップ 7](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#wait-for-forward) で `PaymentIntent` が正常に Stripe に転送されたら、カスタム識別子を使用して `OfflineDelegate.didForwardPaymentIntent` コールバックで調整します。 #### Swift ```swift import UIKit import StripeTerminal class PaymentViewController: UIViewController { // Action for a "Checkout" button func checkoutAction() throws { // Populate the correct transaction amount from your application. let amount = UInt(10_00) // Build up parameters for creating a `PaymentIntent` let params = try PaymentIntentParametersBuilder( amount: amount, currency: "usd" ).setMetadata(["offlineId": UUID().uuidString]) .build() Terminal.shared.createPaymentIntent(params) { createResult, createError in if let error = createError { // Handle errors in your application. print("createPaymentIntent failed: \(error)") } else if let paymentIntent = createResult { print("createPaymentIntent succeeded")// If the `PaymentIntent` was created offline, its `stripeId` field will be nil. if let onlineCreatedId = paymentIntent.stripeId { print("created online"); } else { print("created offline") } } } } } ``` `Terminal.createPaymentIntent` は `CreateConfiguration` パラメーターを受け付けます。デフォルトでは、オフラインで実行している場合、Terminal SDK はすべてのオフライン決済を保存し、接続が回復したときに Stripe のバックエンドに転送します。 この動作をカスタマイズするには、`offlineBehavior` 属性を `REQUIRE_ONLINE`、`PREFER_ONLINE` または `FORCE_OFFLINE` に設定して `CreateConfiguration` オブジェクトを渡すことができます。 #### リスクの管理 `offlineBehavior` を `REQUIRE_ONLINE` に設定すると、現在の取引はオフラインでの操作時に失敗します。たとえば、一定の金額を越える取引を拒否したり、SDK に合計額が一定の金額を超える複数の取引が保存されている場合に、すべてのオフライン取引を拒否したりすることができます。 SDK では、リスクを管理しやすいように、次の 2 つのプロパティーを公開しています。 1. `Terminal.offlineStatus.sdk.offlinePaymentsCount` 1. `Terminal.offlineStatus.sdk.offlinePaymentAmountsByCurrency` #### オフライン時の遅延管理 ネットワーク接続に基づいて、Terminal SDK が支払いをオンラインとオフラインのどちらで回収するかを自動的に判断します。ただし、ネットワーク接続がアクティブであっても (取引を迅速に回収する必要があり、ネットワーク接続が遅い場合など)、オフラインでの操作が必要になる場合があります。 `CreateConfiguration` オブジェクトを `offlineBehavior` を `FORCE_OFFLINE` に設定して渡すと、接続に関係なくオフラインで支払いを回収できます。 Terminal SDK のネットワーク接続がアクティブな状態にあるときにオフラインで回収された支払いは、バックグラウンドで転送されます。 #### Swift ```swift import UIKit import StripeTerminal class PaymentViewController: UIViewController { // Action for a "Checkout" button func checkoutAction() throws { // ...build up parameters and callback for creating a `PaymentIntent` // Your app might want to prevent offline payments for too large an amount. // Here, we block the payment if the amount is over 1000 usd. // Otherwise, we allow collecting offline if the network connection is unavailable.let offlineBehavior: SCPOfflineBehavior = { if amount > UInt(1_000_00) { return .requireOnline } else { return .preferOnline } }() let createConfiguration = try CreateConfigurationBuilder().setOfflineBehavior(offlineBehavior).build() Terminal.shared.createPaymentIntent(params, createConfig: createConfiguration) { createResult, createError in // handle success or failure } } } ``` ## 支払い方法を収集する [クライアント側] - [didRequestReaderInput (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Protocols/SCPReaderDisplayDelegate.html#/c:objc\(pl\)SCPReaderDisplayDelegate\(im\)terminal:didRequestReaderInput:) - [CollectPaymentIntentConfiguration (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPCollectPaymentIntentConfiguration.html) > オフラインでリーダーを実行する間は、決済の責任をお客様が負うことになります。磁気ストライプデータはなりすましが簡単なため、Stripe はオフラインでの実行中はこのオプションを許可していません。*強力な顧客認証* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase) (SCA) が要求される市場では、カードのタップもサポートされていません。 オフラインでの支払いの回収は、[オンラインでの支払いの回収](https://docs.stripe.com/terminal/payments/collect-card-payment.md#collect-payment)と似ています。`didRequestReaderInput` メソッドを使用して、有効なカード提示オプションを顧客に表示します。 > Readers don’t support [inspecting payment method details before authorization](https://docs.stripe.com/terminal/payments/collect-card-payment.md?terminal-sdk-platform=ios#collect-inspect-payment-method) while offline. Although you can still use the `initWithUpdatePaymentIntent` parameter in `CollectPaymentIntentConfiguration`, the `paymentMethod` field on the PaymentIntent is absent if the SDK is operating offline. #### Swift ```swift import UIKit import StripeTerminal class PaymentViewController: UIViewController { // Action for a "Checkout" button func checkoutAction() { Terminal.shared.collectPaymentMethod(paymentIntent) { collectResult, collectError in if let error = collectError { print("collectPaymentMethod failed: \(error)") } else if let paymentIntent = collectResult { print("collectPaymentMethod succeeded") // ... Confirm the payment } } } } ``` ## 支払いを確定する [クライアント側] オフラインでの支払いの確定は、[オンラインでの支払いの確定](https://docs.stripe.com/terminal/payments/collect-card-payment.md#confirm-payment)と似ています。主な違いは、Stripe が適用するオフライン取引の上限額である 1 万 USD、または運用通貨で相当する額を超えた場合などは、オフライン固有のエラーケースを自社のシステムで処理する必要がある点です。 場合によっては、SDK がオンラインで `PaymentIntent` を作成し、オフラインで確定することがあります。これが発生すると、`PaymentIntent` に null 以外の `stripeId` が含まれる可能性があります。オフラインで確定された場合は、`offlineDetails` が定義され、入力されます。 #### Swift ```swift import UIKit import StripeTerminal class PaymentViewController: UIViewController { // Action for a "Checkout" button func checkoutAction() { Terminal.shared.confirmPaymentIntent(paymentIntent) { confirmResult, confirmError in if let error = confirmError { // Handle offline-specific errors in your application (for example, // unsupported payment method). print("confirmPaymentIntent failed: \(error)") } else if let confirmedPaymentIntent= confirmResult {print("confirmPaymentIntent succeeded") if let offlineDetails = paymentIntent.offlineDetails { print("confirmed offline"); } else { print("confirmed online") } } } } } ``` #### 領収書の提供 オフライン時に支払いの完了に使用されたカードの情報が必要になることがあります。たとえば、購入時の領収書を求める顧客に領収書を生成する必要がある場合などです。 PaymentIntent がオフラインで確定された場合、その [OfflineCardPresentDetails](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPOfflineCardPresentDetails.html)、 を `paymentIntent.offlineDetails.offlineCardPresentDetails` から取得できます。 このハッシュには、領収書の生成に使用される [ReceiptDetails](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPReceiptDetails.html)、 プロパティのほか、カード保有者の名前やカードブランドなどのカード情報が含まれます。 オフラインで処理された PaymentIntents では、`account_type` および `authorization_response_code` の領収書フィールドを使用できません。[構築済みのメール領収書](https://docs.stripe.com/terminal/features/receipts.md#prebuilt)は接続が回復し、支払いのキャプチャーが成功するまで送信されません。 ## 支払いが転送されるまで待つ [クライアント側] インターネットアクセスが復旧すると、SDK は保存されていたオフラインの支払いの転送を自動的に開始します。 SDK は、ネットワークステータスがオフラインであっても支払いの転送を試みます。つまり、デバイスがオフラインの場合でも、接続トークンプロバイダーは、接続トークンの提供を求めるリクエストを受け取る可能性があります。 POS デバイスの電源オフのタイミングが早すぎると、支払いが転送されない可能性があります。`Terminal.offlineStatus.sdk.networkStatus` をクエリすると、POS がオンライン状態にあり、支払いを転送できるか確認することができます。また、`Terminal.offlineStatus.sdk.offlinePaymentsCount` をクエリすると、Terminal SDK の転送が必要な支払いの件数を確認できます。 ## 決済をキャプチャーする オフライン時には、`captureMethod` を `automatic` に設定して、PaymentIntents を作成できます。 これらの PaymentIntent を確定すると、ステータスは `RequiresCapture` ではなく、`Succeeded` になります。Stripe は転送後の支払いを自動的にキャプチャーします。 手動キャプチャーを選択した場合、正常に転送されオーソリされた支払いは、バックエンドまたはアプリケーションからキャプチャーする必要があります。 - バックエンドから支払いをキャプチャーするには、[Webhook](https://docs.stripe.com/webhooks.md) を使用して、`requires_capture` ステータスの PaymentIntents をリッスンします。 - アプリケーションから支払いをキャプチャーするには、 SDK が各 PaymentIntent を転送するたびに、`OfflineDelegate.didForwardPayment` のコールをアプリケーションが受け取るのを待ちます。PaymentIntent のステータスが `RequiresCapture` であり、さらに `offlineDetails` が null、あるいは `requiresUpload` value of `NO` の場合、キャプチャーする準備ができています。 #### Swift ```swift Terminal.shared.confirmPaymentIntent(paymentIntent) { confirmResult, confirmError in if let error = confirmError { // Handle offline-specific errors in your application (for example, // unsupported payment method). print("confirmPaymentIntent failed: \(error)") } else if let confirmedPaymentIntent = confirmResult { if intent.status == .requiresCapture {if let offlineDetails = confirmedPaymentIntent.offlineDetails(), offlineDetails.requiresUpload { // Offline payment, wait for `didForwardPaymentIntent` (see snippet below) } else { // Online payment, can be captured now } } // else, handle other intent.status results here } } ``` オフライン決済は、 SDK によって OfflineDelegate の `didForwardPaymentIntent` で転送された後にキャプチャーします。 #### Swift ```swift import StripeTerminal class CustomOfflineDelegate: OfflineDelegate { // ... func terminal(_ terminal: Terminal, didForwardPaymentIntent intent: PaymentIntent, error: Error?) { if let error = error { // Handle the error appropriate for your application return } if intent.status == .requiresCapture { // The intent is ready to be captured. } else { // Handle the intent.status as appropriate. } } // ... } ``` ## オフラインで回収した支払いを調べる オーソリ後は、[PaymentIntents](https://docs.stripe.com/payments/payment-intents.md) API を使用して支払いのオフライン情報を調べることができます。`PaymentIntent` の[最新の Charge](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-latest_charge) オブジェクトの [payment method details](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-offline) にアクセスすると、オフラインで回収されたものであるかどうかを判定できます。 # Android > This is a Android for when terminal-card-present-integration is terminal and terminal-sdk-platform is android and reader-type is bluetooth. View the full page at https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments?terminal-card-present-integration=terminal&terminal-sdk-platform=android&reader-type=bluetooth. Terminal SDK を使用すると、アプリケーションではネットワーク接続なしで、モバイルリーダーを使用して支払いの回収を続行できます。 > オフラインで実行するときは、販売時に決済情報が収集されます。オーソリは接続の回復後にのみ試行され、支払いが転送されます。ユーザーであるお客様が、オフライン取引に関連する支払い拒否や改ざんに関するすべてのリスクを負います。改ざんされたリーダーが支払いを Stripe に転送できない場合、またはカード発行会社が取引を拒否した場合、売上を回収する方法はなく、すでに提供した商品やサービスへの顧客の支払いを受け取れなくなることがあります。 > > カード発行会社による拒否を減らすため、以下のことが推奨されます。 > > - できる限り早急にインターネット接続を再確立して、支払いを Stripe に記録します。 - 所定の金額を超える場合は取引を制限します。 - 合計すると所定の金額を超える複数の取引を SDK が保存した場合、[すべてのオフライン決済を失敗させます](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#managing-risk)。 ## オフライン中に決済を回収する オフライン決済の手順は、オンライン決済と同じで、決済の作成、回収、処理、およびキャプチャーが含まれます。このプロセスのどの段階でも、デバイスをオンラインからオフラインにできます。 1. [オフラインモードを有効にする](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#enable-offline-mode) 1. [オフライン中にリーダーに接続する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#connect-while-offline) 1. [オフラインイベントを処理する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#handle-offline-events) 1. [オフライン中に PaymentIntent を作成する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#create-payment-intent) 1. [支払い方法を収集する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#collect-payment-method) 1. [支払いを確定する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#confirm-payment) 1. [支払いが転送されるまで待つ](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#wait-for-forward) 1. (オプション) [支払いをキャプチャーする](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#capture-payment) 1. (オプション) [オフラインで回収した支払いを調べる](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#examine-offline) ## オフラインモードを有効にする オフラインモードを使用するには、アプリケーションが Terminal Android SDK のバージョン `3.2.0` 以降を使用している必要があります。 [Configuration](https://docs.stripe.com/api/terminal/configuration.md) オブジェクトまたは[ダッシュボード](https://docs.stripe.com/terminal/fleet/configurations-overview.md?dashboard-or-api=dashboard#update-the-default-configuration-for-the-account)を使用して、`Location` で[サポートされている](https://docs.stripe.com/terminal/features/operate-offline/overview.md?reader-type=bluetooth#availability)デバイスのオフラインモードを有効にします。 ```curl curl https://api.stripe.com/v1/terminal/configurations \ -u "<>:" \ -d "offline[enabled]=true" ``` `Configuration` オブジェクトでオフラインモードを有効にすると、`Location` に[割り当てる](https://docs.stripe.com/terminal/fleet/configurations-overview.md?dashboard-or-api=api#create-a-configuration-for-an-individual-location)ことができます。また、アカウントの[デフォルト](https://docs.stripe.com/terminal/fleet/configurations-overview.md?dashboard-or-api=api#retrieve-the-account-default-configuration)の `Configuration` オブジェクトを更新すると、すべての `Locations` でオフラインモードをデフォルトで有効にすることもできます。Configuration API の変更が SDK とリーダーに反映されるまで数分かかる場合があり、反映するには、リーダーの接続をいったん切断してから再接続する必要があります。 ## オフライン中にリーダーに接続する SDK はオンラインに接続した後、必要な `Location` 情報をローカルに保存します。後続のオフライン接続では、その `Location` に保存されている設定情報が使用されます。 オフライン時にスマートリーダーで支払いを回収するには、直前の 30 日以内のオンライン時に、あらかじめ同じ `Location` の同じタイプのモバイルリーダーに接続し、また期間内にリーダーのソフトウェアを更新する必要があります。 オフライン時にこれらの要件を満たさずリーダーに接続しようとすると、リクエストはエラーで失敗します。 | エラー | 解決策 | | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **SDK がインターネットに接続されていません** | 使用している `Location` がオフラインモード用に[設定されている](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#enable-offline-mode)ことを確認します。それ以外の場合は、オンライン時に任意のリーダーに接続してから、オフライン時に同じタイプのリーダーに接続します。 | | **選択したリーダーをオフラインでの支払い回収に使用するには、ソフトウェアの更新が必要です。** | リーダーのソフトウェアが 30 日以上更新されていません。オンライン時にリーダーに接続して更新してください。 | | **選択したリーダーをオフラインでの支払い回収に使用するには、この場所でオンラインのペアリングを行う必要があります。** | POS がこれまでオンライン中に接続していないタイプのリーダーに接続しようとしています。まずオンライン中に、このリーダーまたは同じタイプのリーダーに接続する必要があります。または、オフライン中に接続する場合は、以前オンライン中に POS が接続していたタイプのリーダーに接続できます。 | アプリケーションを再インストールしたり、SDK のディスクストレージを消去する操作 (POS デバイス設定での POS アプリのキャッシュの消去など) を実行すると、SDK が保存している未転送の支払いがすべて失われます。破壊的なアクションを実行する前に、保存された決済がないことを確認してください。 ## オフラインイベントを処理する [クライアント側] - [OfflineListener (Android)](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.callable/-offline-listener/index.html) - [NetworkStatus (Android)](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-network-status/index.html) アプリケーションが SDK のネットワークステータスと転送された支払いの状態に関する更新を受信できるようにするには、`OfflineListener` インターフェイスを実装して Terminal SDK に渡します。オフラインで支払いを回収する前に、`OfflineListener` を設定する必要があります。 #### Kotlin ```kotlin class CustomOfflineListener : OfflineListener { override fun onOfflineStatusChange(offlineStatus: OfflineStatus) { // Check the value of `offlineStatus` and update your UI accordingly. For instance, // you can check the SDK's network status at `offlineStatus.sdk.networkStatus`. // // You can also check the SDK's current offline status using // `Terminal::offlineStatus`. } override fun onPaymentIntentForwarded(paymentIntent: PaymentIntent, e: TerminalException?) { // The PaymentIntent was successfully forwarded, or an error occurred. // Reconcile any local state using the backend-generated `PaymentIntent::id` // and the metadata you supplied when creating the PaymentIntent. // // Note that the `PaymentIntent::id` may still be null if creating the // PaymentIntent in the backend failed. } override fun onForwardingFailure(e: TerminalException) { // A non-specific error occurred while forwarding a PaymentIntent. // Check the error message and your integration implementation to // troubleshoot. } } ``` #### Kotlin ```kotlin Terminal.init( context = applicationContext, logLevel = LogLevel.VERBOSE, tokenProvider = CustomConnectionTokenProvider(), listener = CustomTerminalListener(), offlineListener = CustomOfflineListener(), ) ``` ## オフライン中に PaymentIntent を作成する [クライアント側] - [createPaymentIntent (Android)](https://stripe.dev/stripe-terminal-android/core/com.stripe.stripeterminal/-terminal/create-payment-intent.html) - [CreateConfiguration (Android)](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-create-configuration/index.html) - [OfflineDetails (Android)](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-offline-details/index.html) オフラインでの操作に対応するには、SDK の `createPaymentIntent` を使用して PaymentIntent オブジェクトを作成します。これにより、SDK はオフライン時に PaymentIntents を作成し、接続が再確立された後で Stripe に転送できます。 オフラインでの実行中、`PaymentIntent` オブジェクトは null の `id` を保持します。PaymentIntent の[メタデータ](https://docs.stripe.com/payments/payment-intents.md#storing-information-in-metadata)にカスタム識別子を追加して、オフラインで作成された `PaymentIntent` オブジェクトをデータベースで照合できるようにすることをお勧めします。 [ステップ 7](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#wait-for-forward) で `PaymentIntent` が正常に Stripe に転送されたら、カスタム識別子を使用して `OfflineListener::onPaymentIntentForwarded` コールバックで調整します。 #### Kotlin ```kotlin private const val TAG = "PaymentActivity" class PaymentActivity : AppCompatActivity() { // Action for a "Checkout" button private fun onCheckout(cart: Cart) { // Build up parameters for creating a `PaymentIntent` val params = PaymentIntentParameters.Builder() .setAmount(cart.total) .setCurrency(cart.currency).setMetadata(mapOf("unique-id" to UUID.randomUUID().toString())) .build() val createPaymentCallback: PaymentIntentCallback = object : PaymentIntentCallback { override fun onSuccess(paymentIntent: PaymentIntent) { Log.d(TAG, "createPaymentIntent succeeded")// If the `PaymentIntent` was created offline, its `id` field will be null. if (paymentIntent.id != null) { Log.d(TAG, "created online") } else { Log.d(TAG, "created offline") } // ... Collect a PaymentMethod } override fun onFailure(e: TerminalException) { Log.e(TAG, "createPaymentIntent failed", e) // Handle errors in your application. } } Terminal.getInstance().createPaymentIntent(params, createPaymentCallback) } } ``` `Terminal.createPaymentIntent` は `CreateConfiguration` パラメーターを受け付けます。デフォルトでは、オフラインで実行している場合、Terminal SDK はすべてのオフライン決済を保存し、接続が回復したときに Stripe のバックエンドに転送します。 この動作をカスタマイズするには、`offlineBehavior` 属性を `REQUIRE_ONLINE`、`PREFER_ONLINE` または `FORCE_OFFLINE` に設定して `CreateConfiguration` オブジェクトを渡すことができます。 #### リスクの管理 `offlineBehavior` を `REQUIRE_ONLINE` に設定すると、現在の取引はオフラインでの操作時に失敗します。たとえば、一定の金額を越える取引を拒否したり、SDK に合計額が一定の金額を超える複数の取引が保存されている場合に、すべてのオフライン取引を拒否したりすることができます。 SDK では、リスクを管理しやすいように、次の 2 つのプロパティーを公開しています。 1. `Terminal.offlineStatus.sdk.offlinePaymentsCount` 1. `Terminal.offlineStatus.sdk.offlinePaymentAmountsByCurrency` #### オフライン時の遅延管理 ネットワーク接続に基づいて、Terminal SDK が支払いをオンラインとオフラインのどちらで回収するかを自動的に判断します。ただし、ネットワーク接続がアクティブであっても (取引を迅速に回収する必要があり、ネットワーク接続が遅い場合など)、オフラインでの操作が必要になる場合があります。 `CreateConfiguration` オブジェクトを `offlineBehavior` を `FORCE_OFFLINE` に設定して渡すと、接続に関係なくオフラインで支払いを回収できます。 Terminal SDK のネットワーク接続がアクティブな状態にあるときにオフラインで回収された支払いは、バックグラウンドで転送されます。 #### Kotlin ```kotlin private const val TAG = "PaymentActivity" class PaymentActivity : AppCompatActivity() { // Action for a "Checkout" button private fun onCheckout(cart: Cart) { // ...build up parameters and callback for creating a `PaymentIntent` // Your app might want to prevent offline payments for too large an amount. // Here, we require a network connection if the payment if the amount is over 1000 usd. // Otherwise, we allow collecting offline if the network connection is unavailable.val offlineBehavior = if (cart.total > 1000000) { OfflineBehavior.REQUIRE_ONLINE } else { OfflineBehavior.PREFER_ONLINE } val createConfig = CreateConfiguration(offlineBehavior) Terminal.getInstance().createPaymentIntent(params, createPaymentCallback, createConfig) } } ``` ## 支払い方法を収集する [クライアント側] - [onRequestReaderInput (Android)](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.callable/-reader-listener/on-request-reader-input.html) - [CollectPaymentIntentConfiguration (Android)](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-collect-payment-intent-configuration/index.html) > オフラインでリーダーを実行する間は、決済の責任をお客様が負うことになります。磁気ストライプデータはなりすましが簡単なため、Stripe はオフラインでの実行中はこのオプションを許可していません。*強力な顧客認証* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase) (SCA) が要求される市場では、カードのタップもサポートされていません。 オフラインでの支払いの回収は、[オンラインでの支払いの回収](https://docs.stripe.com/terminal/payments/collect-card-payment.md#collect-payment)と似ています。`onRequestReaderInput` メソッドを使用して、有効なカード提示オプションを顧客に表示します。 > Readers don’t support [inspecting payment method details before authorization](https://docs.stripe.com/terminal/payments/collect-card-payment.md?terminal-sdk-platform=android#collect-inspect-payment-method) while offline. Although you can still set the `updatePaymentIntent` parameter in `CollectPaymentIntentConfiguration`, the `paymentMethod` field on the PaymentIntent is absent if the SDK is operating offline. #### Kotlin ```kotlin private const val TAG = "PaymentActivity" class PaymentActivity : AppCompatActivity() { // Action for a "Checkout" button private fun onCheckout(cart: Cart) { val collectPaymentCallback: PaymentIntentCallback = object : PaymentIntentCallback { override fun onSuccess(paymentIntent: PaymentIntent) { Log.d(TAG, "collectPaymentMethod succeeded") // ... Confirm the payment } override fun onFailure(e: TerminalException) { Log.d(TAG, "collectPaymentMethod failed:", e) } } val collectConfig = CollectPaymentIntentConfiguration.Builder().build() Terminal.getInstance().collectPaymentMethod(paymentIntent, collectPaymentCallback, collectConfig) } } ``` ## 支払いを確定する [クライアント側] オフラインでの支払いの確定は、[オンラインでの支払いの確定](https://docs.stripe.com/terminal/payments/collect-card-payment.md#confirm-payment)と似ています。主な違いは、Stripe が適用するオフライン取引の上限額である 1 万 USD、または運用通貨で相当する額を超えた場合などは、オフライン固有のエラーケースを自社のシステムで処理する必要がある点です。 場合によっては、SDK がオンラインで `PaymentIntent` を作成し、オフラインで確定することがあります。これが発生すると、`PaymentIntent` に null 以外の `id` が含まれる可能性があります。オフラインで確定された場合は、`offlineDetails` が定義され、入力されます。 #### Kotlin ```kotlin private const val TAG = "PaymentActivity" class PaymentActivity : AppCompatActivity() { // Action for a "Checkout" button private fun onCheckout(cart: Cart) { val confirmPaymentIntentCallback: PaymentIntentCallback = object : PaymentIntentCallback { override fun onSuccess(paymentIntent: PaymentIntent) { Log.d(TAG, "confirmPaymentIntent succeeded")// If the `PaymentIntent` was confirmed offline, `paymentIntent.offlineDetails` will be defined if (paymentIntent.offlineDetails != null) { Log.d(TAG, "confirmed offline") } else { Log.d(TAG, "confirmed online") } } override fun onFailure(e: TerminalException) { // Handle offline-specific errors in your application (for example, // unsupported payment method). Log.e(TAG, "confirmPaymentIntent failed:", e) } } Terminal.getInstance().confirmPaymentIntent(paymentIntent, confirmPaymentIntentCallback) } } ``` #### 領収書の提供 オフライン時に支払いの完了に使用されたカードの情報が必要になることがあります。たとえば、購入時の領収書を求める顧客に領収書を生成する必要がある場合などです。 PaymentIntent がオフラインで確定された場合、その [OfflineCardPresentDetails](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-offline-card-present-details/index.html)、 を `paymentIntent.offlineDetails.offlineCardPresentDetails` から取得できます。 このハッシュには、領収書の生成に使用される [ReceiptDetails](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-receipt-details/index.html)、 プロパティのほか、カード保有者の名前やカードブランドなどのカード情報が含まれます。 オフラインで処理された PaymentIntents では、`account_type` および `authorization_response_code` の領収書フィールドを使用できません。[構築済みのメール領収書](https://docs.stripe.com/terminal/features/receipts.md#prebuilt)は接続が回復し、支払いのキャプチャーが成功するまで送信されません。 ## 支払いが転送されるまで待つ [クライアント側] インターネットアクセスが復旧すると、SDK は保存されていたオフラインの支払いの転送を自動的に開始します。 SDK は、ネットワークステータスがオフラインであっても支払いの転送を試みます。つまり、デバイスがオフラインの場合でも、接続トークンプロバイダーは、接続トークンの提供を求めるリクエストを受け取る可能性があります。 POS デバイスの電源オフのタイミングが早すぎると、支払いが転送されない可能性があります。`Terminal.offlineStatus.sdk.networkStatus` をクエリすると、POS がオンライン状態にあり、支払いを転送できるか確認することができます。また、`Terminal.offlineStatus.sdk.offlinePaymentsCount` をクエリすると、Terminal SDK の転送が必要な支払いの件数を確認できます。 ## 決済をキャプチャーする オフライン時には、`captureMethod` を `automatic` に設定して、PaymentIntents を作成できます。 これらの PaymentIntent を確定すると、ステータスは `REQUIRES_CAPTURE` ではなく、`SUCCEEDED` になります。Stripe は転送後の支払いを自動的にキャプチャーします。 手動キャプチャーを選択した場合、正常に転送されオーソリされた支払いは、バックエンドまたはアプリケーションからキャプチャーする必要があります。 - バックエンドから支払いをキャプチャーするには、[Webhook](https://docs.stripe.com/webhooks.md) を使用して、`requires_capture` ステータスの PaymentIntents をリッスンします。 - アプリケーションから支払いをキャプチャーするには、 SDK が各 PaymentIntent を転送するたびに、`OfflineListener::onPaymentIntentForwarded` のコールをアプリケーションが受け取るのを待ちます。PaymentIntent のステータスが `REQUIRES_CAPTURE` であり、さらに `offlineDetails` が null、あるいは `requiresUpload` value of `false` の場合、キャプチャーする準備ができています。 #### Kotlin ```kotlin private const val TAG = "PaymentActivity" class PaymentActivity : AppCompatActivity() { // Action for a "Checkout" button private fun onCheckout(cart: Cart) { val callback: PaymentIntentCallback = object : PaymentIntentCallback { override fun onSuccess(paymentIntent: PaymentIntent) { Log.d(TAG, "confirmPaymentIntent succeeded") if (paymentIntent.status == PaymentIntentStatus.REQUIRES_CAPTURE) {val offlineDetails = paymentIntent.offlineDetails if (offlineDetails?.requiresUpload == true) { // Offline payment, wait for `onPaymentIntentForwarded` (see snippet below) } else { // Online payment, can be captured now } } else { // Handle other status results here } } override fun onFailure(e: TerminalException) { // Handle offline-specific errors in your application (for example, // unsupported payment method). Log.e(TAG, "confirmPaymentIntent failed:", e) } } Terminal.getInstance().confirmPaymentIntent(paymentIntent, callback) } } ``` オフライン決済は、 SDK によって `OfflineListener::onPaymentIntentForwarded` で転送された後にキャプチャーします。 #### Kotlin ```kotlin class CustomOfflineListener : OfflineListener { // ... override fun onPaymentIntentForwarded(paymentIntent: PaymentIntent, e: TerminalException?) { if (e != null) { // Handle the error appropriate for your application } else if (paymentIntent.status == PaymentIntentStatus.REQUIRES_CAPTURE) { // The paymentIntent is ready to be captured } else { // Handle other status results here } } // ... } ``` ## オフラインで回収した支払いを調べる オーソリ後は、[PaymentIntents](https://docs.stripe.com/payments/payment-intents.md) API を使用して支払いのオフライン情報を調べることができます。`PaymentIntent` の[最新の Charge](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-latest_charge) オブジェクトの [payment method details](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-offline) にアクセスすると、オフラインで回収されたものであるかどうかを判定できます。 # React Native > This is a React Native for when terminal-card-present-integration is terminal and terminal-sdk-platform is react-native and reader-type is bluetooth. View the full page at https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments?terminal-card-present-integration=terminal&terminal-sdk-platform=react-native&reader-type=bluetooth. Terminal SDK を使用すると、アプリケーションではネットワーク接続なしで、モバイルリーダーを使用して支払いの回収を続行できます。 > オフラインで実行するときは、販売時に決済情報が収集されます。オーソリは接続の回復後にのみ試行され、支払いが転送されます。ユーザーであるお客様が、オフライン取引に関連する支払い拒否や改ざんに関するすべてのリスクを負います。改ざんされたリーダーが支払いを Stripe に転送できない場合、またはカード発行会社が取引を拒否した場合、売上を回収する方法はなく、すでに提供した商品やサービスへの顧客の支払いを受け取れなくなることがあります。 > > カード発行会社による拒否を減らすため、以下のことが推奨されます。 > > - できる限り早急にインターネット接続を再確立して、支払いを Stripe に記録します。 - 所定の金額を超える場合は取引を制限します。 - 合計すると所定の金額を超える複数の取引を SDK が保存した場合、[すべてのオフライン決済を失敗させます](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#managing-risk)。 ## オフライン中に決済を回収する オフライン決済の手順は、オンライン決済と同じで、決済の作成、回収、処理、およびキャプチャーが含まれます。このプロセスのどの段階でも、デバイスをオンラインからオフラインにできます。 1. [オフラインモードを有効にする](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#enable-offline-mode) 1. [オフライン中にリーダーに接続する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#connect-while-offline) 1. [オフラインイベントを処理する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#handle-offline-events) 1. [オフライン中に PaymentIntent を作成する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#create-payment-intent) 1. [支払い方法を収集する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#collect-payment-method) 1. [支払いを確定する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#confirm-payment) 1. [支払いが転送されるまで待つ](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#wait-for-forward) 1. (オプション) [支払いをキャプチャーする](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#capture-payment) 1. (オプション) [オフラインで回収した支払いを調べる](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#examine-offline) ## オフラインモードを有効にする [Configuration](https://docs.stripe.com/api/terminal/configuration.md) オブジェクトまたは[ダッシュボード](https://docs.stripe.com/terminal/fleet/configurations-overview.md?dashboard-or-api=dashboard#update-the-default-configuration-for-the-account)を使用して、`Location` で[サポートされている](https://docs.stripe.com/terminal/features/operate-offline/overview.md?reader-type=bluetooth#availability)デバイスのオフラインモードを有効にします。 ```curl curl https://api.stripe.com/v1/terminal/configurations \ -u "<>:" \ -d "offline[enabled]=true" ``` `Configuration` オブジェクトでオフラインモードを有効にすると、`Location` に[割り当てる](https://docs.stripe.com/terminal/fleet/configurations-overview.md?dashboard-or-api=api#create-a-configuration-for-an-individual-location)ことができます。また、アカウントの[デフォルト](https://docs.stripe.com/terminal/fleet/configurations-overview.md?dashboard-or-api=api#retrieve-the-account-default-configuration)の `Configuration` オブジェクトを更新すると、すべての `Locations` でオフラインモードをデフォルトで有効にすることもできます。Configuration API の変更が SDK とリーダーに反映されるまで数分かかる場合があり、反映するには、リーダーの接続をいったん切断してから再接続する必要があります。 ## オフライン中にリーダーに接続する SDK はオンラインに接続した後、必要な `Location` 情報をローカルに保存します。後続のオフライン接続では、その `Location` に保存されている設定情報が使用されます。 オフライン時にスマートリーダーで支払いを回収するには、直前の 30 日以内のオンライン時に、あらかじめ同じ `Location` の同じタイプのモバイルリーダーに接続し、また期間内にリーダーのソフトウェアを更新する必要があります。 オフライン時にこれらの要件を満たさずリーダーに接続しようとすると、リクエストはエラーで失敗します。 | エラー | 解決策 | | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **SDK がインターネットに接続されていません** | 使用している `Location` がオフラインモード用に[設定されている](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#enable-offline-mode)ことを確認します。それ以外の場合は、オンライン時に任意のリーダーに接続してから、オフライン時に同じタイプのリーダーに接続します。 | | **選択したリーダーをオフラインでの支払い回収に使用するには、ソフトウェアの更新が必要です。** | リーダーのソフトウェアが 30 日以上更新されていません。オンライン時にリーダーに接続して更新してください。 | | **選択したリーダーをオフラインでの支払い回収に使用するには、この場所でオンラインのペアリングを行う必要があります。** | POS がこれまでオンライン中に接続していないタイプのリーダーに接続しようとしています。まずオンライン中に、このリーダーまたは同じタイプのリーダーに接続する必要があります。または、オフライン中に接続する場合は、以前オンライン中に POS が接続していたタイプのリーダーに接続できます。 | アプリケーションを再インストールしたり、SDK のディスクストレージを消去する操作 (POS デバイス設定での POS アプリのキャッシュの消去など) を実行すると、SDK が保存している未転送の支払いがすべて失われます。破壊的なアクションを実行する前に、保存された決済がないことを確認してください。 ## オフラインイベントを処理する [クライアント側] - [UserCallbacks (React Native)](https://stripe.dev/stripe-terminal-react-native/api-reference/index.html#UserCallbacks) - [OfflineStatus (React Native)](https://stripe.dev/stripe-terminal-react-native/api-reference/index.html#OfflineStatus) アプリケーションが SDK のネットワークステータスと転送された支払いの状態に関する更新を受信できるようにするには、`useStripeTerminal` フックにオフラインコールバックを実装します。 ```js const { connectReader, disconnectReader, connectedReader } = useStripeTerminal({ onDidChangeOfflineStatus(status: OfflineStatus) { // Check the value of `offlineStatus` and update your UI accordingly. // // You can also check the SDK's current offline status calling // `getOfflineStatus`. }, onDidForwardingFailure(error) { // A non-specific error occurred while forwarding a PaymentIntent. // Check the error message and your integration implementation to // troubleshoot. }, onDidForwardPaymentIntent(paymentIntent, error) { // The PaymentIntent was successfully forwarded, or an error occurred. // Reconcile any local state using the backend-generated `paymentIntent.id` // and the metadata you supplied when creating the PaymentIntent. // // Note that the `paymentIntent.id` may still be null if creating the // PaymentIntent in the backend failed. }, }); ``` ## オフライン中に PaymentIntent を作成する [クライアント側] - [createPaymentIntent (React Native)](https://stripe.dev/stripe-terminal-react-native/api-reference/interfaces/StripeTerminalSdkType.html#createPaymentIntent) - [CreatePaymentIntentParams (React Native)](https://stripe.dev/stripe-terminal-react-native/api-reference/index.html#CreatePaymentIntentParams) - [OfflineStatus (React Native)](https://stripe.dev/stripe-terminal-react-native/api-reference/index.html#OfflineStatus) - [OfflineStatusDetails (React Native)](https://stripe.dev/stripe-terminal-react-native/api-reference/index.html#OfflineStatusDetails) オフラインでの操作に対応するには、SDK の `createPaymentIntent` を使用して PaymentIntent オブジェクトを作成します。これにより、SDK はオフライン時に PaymentIntents を作成し、接続が再確立された後で Stripe に転送できます。 オフラインでの実行中、`PaymentIntent` オブジェクトは null の `id` を保持します。PaymentIntent の[メタデータ](https://docs.stripe.com/payments/payment-intents.md#storing-information-in-metadata)にカスタム識別子を追加して、オフラインで作成された `PaymentIntent` オブジェクトをデータベースで照合できるようにすることをお勧めします。 [ステップ 7](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#wait-for-forward) で `PaymentIntent` が正常に Stripe に転送されたら、カスタム識別子を使用して `onDidForwardPaymentIntent` コールバックで調整します。 ```js const _createPaymentIntent = async (cart) => { const {error, paymentIntent} = await createPaymentIntent({ amount: cart.total, currency: cart.currency,metadata: { "unique-id": UUID().uuidString } }); } ``` `Terminal.createPaymentIntent` は `CreateConfiguration` パラメーターを受け付けます。デフォルトでは、オフラインで実行している場合、Terminal SDK はすべてのオフライン決済を保存し、接続が回復したときに Stripe のバックエンドに転送します。 この動作をカスタマイズするには、`offlineBehavior` 属性を `REQUIRE_ONLINE`、`PREFER_ONLINE` または `FORCE_OFFLINE` に設定して `CreateConfiguration` オブジェクトを渡すことができます。 #### リスクの管理 `offlineBehavior` を `REQUIRE_ONLINE` に設定すると、現在の取引はオフラインでの操作時に失敗します。たとえば、一定の金額を越える取引を拒否したり、SDK に合計額が一定の金額を超える複数の取引が保存されている場合に、すべてのオフライン取引を拒否したりすることができます。 SDK では、リスクを管理しやすいように、次の 2 つのプロパティーを公開しています。 1. `OfflineStatus.sdk.offlinePaymentsCount` 1. `OfflineStatus.sdk.offlinePaymentAmountsByCurrency` #### オフライン時の遅延管理 ネットワーク接続に基づいて、Terminal SDK が支払いをオンラインとオフラインのどちらで回収するかを自動的に判断します。ただし、ネットワーク接続がアクティブであっても (取引を迅速に回収する必要があり、ネットワーク接続が遅い場合など)、オフラインでの操作が必要になる場合があります。 `offlineBehavior` を `force_offline` に設定して、接続に関係なく支払いをオフラインで回収できます。 Terminal SDK のネットワーク接続がアクティブな状態にあるときにオフラインで回収された支払いは、バックグラウンドで転送されます。 ```js const _createPaymentIntent = async (cart) => { // Your app might want to prevent offline payments for too large an amount. // Here, we require a network connection if the payment if the amount is over 1000 usd. // Otherwise, we allow collecting offline if the network connection is unavailable.let offlineBehavior: if (cart.total > 1000000) { offlineBehavior = 'require_online' } else { offlineBehavior = 'prefer_online' } const {error, paymentIntent} = await createPaymentIntent({ amount: cart.total, currency: cart.currency,offlineBehavior, }); } ``` ## 支払い方法を収集する [クライアント側] - [UserCallbacks (React Native)](https://stripe.dev/stripe-terminal-react-native/api-reference/index.html#UserCallbacks) - [CollectPaymentMethodParams (React Native)](https://stripe.dev/stripe-terminal-react-native/api-reference/index.html#CollectPaymentMethodParams) > オフラインでリーダーを実行する間は、決済の責任をお客様が負うことになります。磁気ストライプデータはなりすましが簡単なため、Stripe はオフラインでの実行中はこのオプションを許可していません。*強力な顧客認証* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase) (SCA) が要求される市場では、カードのタップもサポートされていません。 オフラインでの支払いの回収は、[オンラインでの支払いの回収](https://docs.stripe.com/terminal/payments/collect-card-payment.md#collect-payment)と似ています。 メソッドを使用して、有効なカード提示オプションを顧客に表示します。 > [承認前に決済手段の詳細を調査する](https://docs.stripe.com/terminal/payments/collect-card-payment.md?terminal-sdk-platform=react-native#collect-inspect-payment-method)機能は、オフラインではサポートされていません。`CollectConfiguration` で `updatePaymentIntent` パラメーターを引き続き設定できますが、SDK がオフラインで実行されている場合、PaymentIntent の `paymentMethod` フィールドは表示されません。 ```js const _collectPaymentMethod_ = async () => { const { paymentIntent, error } = await collectPaymentMethod({ paymentIntent: paymentIntent }); if (error) { // Handle errors in your application. } // ... Confirm the payment } ``` ## 支払いを確定する [クライアント側] オフラインでの支払いの確定は、[オンラインでの支払いの確定](https://docs.stripe.com/terminal/payments/collect-card-payment.md#confirm-payment)と似ています。主な違いは、Stripe が適用するオフライン取引の上限額である 1 万 USD、または運用通貨で相当する額を超えた場合などは、オフライン固有のエラーケースを自社のシステムで処理する必要がある点です。 場合によっては、SDK がオンラインで `PaymentIntent` を作成し、オフラインで確定することがあります。これが発生すると、`PaymentIntent` に null 以外の `id` が含まれる可能性があります。オフラインで確定された場合は、`offlineDetails` が定義され、入力されます。 ```js const _confirmPaymentIntent = async () => { const { paymentIntent, error } = await confirmPaymentIntent({ paymentIntent: paymentIntent }); if (error) { // Handle offline-specific errors in your application (for example, // unsupported payment method). } if (paymentIntent.offlineDetails) { console.log('confirmed offline'); } else { console.log('confirmed online'); } } ``` #### 領収書の提供 オフライン時に支払いの完了に使用されたカードの情報が必要になることがあります。たとえば、購入時の領収書を求める顧客に領収書を生成する必要がある場合などです。 PaymentIntent がオフラインで確定された場合、その [OfflineCardPresentDetails](https://stripe.dev/stripe-terminal-react-native/api-reference/index.html#OfflineCardPresentDetails)、 を `paymentIntent.offlineDetails.offlineCardPresentDetails` から取得できます。 このハッシュには、領収書の生成に使用される [ReceiptDetails](https://stripe.dev/stripe-terminal-react-native/api-reference/index.html#ReceiptDetails)、 プロパティのほか、カード保有者の名前やカードブランドなどのカード情報が含まれます。 オフラインで処理された PaymentIntents では、`account_type` および `authorization_response_code` の領収書フィールドを使用できません。[構築済みのメール領収書](https://docs.stripe.com/terminal/features/receipts.md#prebuilt)は接続が回復し、支払いのキャプチャーが成功するまで送信されません。 ## 支払いが転送されるまで待つ [クライアント側] インターネットアクセスが復旧すると、SDK は保存されていたオフラインの支払いの転送を自動的に開始します。 SDK は、ネットワークステータスがオフラインであっても支払いの転送を試みます。つまり、デバイスがオフラインの場合でも、接続トークンプロバイダーは、接続トークンの提供を求めるリクエストを受け取る可能性があります。 POS デバイスの電源オフのタイミングが早すぎると、支払いが転送されない可能性があります。`OfflineStatus.sdk.networkStatus` をクエリすると、POS がオンライン状態にあり、支払いを転送できるか確認することができます。また、`OfflineStatus.sdk.offlinePaymentsCount` をクエリすると、Terminal SDK の転送が必要な支払いの件数を確認できます。 ## 決済をキャプチャーする オフライン時には、`captureMethod` を `automatic` に設定して、PaymentIntents を作成できます。 これらの PaymentIntent を確定すると、ステータスは `requiresCapture` ではなく、`succeeded` になります。Stripe は転送後の支払いを自動的にキャプチャーします。 手動キャプチャーを選択した場合、正常に転送されオーソリされた支払いは、バックエンドまたはアプリケーションからキャプチャーする必要があります。 - バックエンドから支払いをキャプチャーするには、[Webhook](https://docs.stripe.com/webhooks.md) を使用して、`requires_capture` ステータスの PaymentIntents をリッスンします。 - アプリケーションから支払いをキャプチャーするには、 SDK が各 PaymentIntent を転送するたびに、`useStripeTerminal` フックの `onDidForwardPaymentIntent` のコールをアプリケーションが受け取るのを待ちます。PaymentIntent のステータスが `requiresCapture` であり、さらに `OfflineDetails` が null、あるいは `requiresUpload` value of `false` の場合、キャプチャーする準備ができています。 ```js const _confirmPaymentIntent = async () => { const { paymentIntent, error } = await confirmPaymentIntent({ paymentIntent: paymentIntent }); if (error) { // Handle offline-specific errors in your application (for example, // unsupported payment method). } if (paymentIntent.status == 'requiresCapture') {const offlineDetails = paymentIntent.offlineDetails; if (offlineDetails.requiresUpload === true) { // Offline payment, wait for `onDidForwardPaymentIntent` (see snippet below) } else { // Online payment, can be captured now } } else { // handle other paymentIntent.status results here } } ``` オフライン決済は、 SDK によって `onDidForwardPaymentIntent` で転送された後にキャプチャーします。 ```js const { connectReader, disconnectReader, connectedReader } = useStripeTerminal({ onDidForwardPaymentIntent(paymentIntent, error) { if (error) { // Handle the error appropriate for your application } else if (paymentIntent.status == 'requires_capture') { // The paymentIntent is ready to be captured } else { // Handle the paymentIntent.status as appropriate. } }, }); ``` ## オフラインで回収した支払いを調べる オーソリ後は、[PaymentIntents](https://docs.stripe.com/payments/payment-intents.md) API を使用して支払いのオフライン情報を調べることができます。`PaymentIntent` の[最新の Charge](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-latest_charge) オブジェクトの [payment method details](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-offline) にアクセスすると、オフラインで回収されたものであるかどうかを判定できます。 # iOS > This is a iOS for when terminal-card-present-integration is terminal and terminal-sdk-platform is ios and reader-type is internet. View the full page at https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments?terminal-card-present-integration=terminal&terminal-sdk-platform=ios&reader-type=internet. Terminal SDK を使用すると、アプリケーションではインターネット接続がなくてもスマートリーダーを使用して支払いの回収を続行できます。 Stripe のスマートリーダー以外の POS デバイスを使用している場合でも、POS デバイスがスマートリーダーと通信できるようにするには、有効なローカルネットワークが必要になります。スマートリーダーのオフラインでの操作は、ISP の障害時など、POS とリーダーが Stripe と通信できない状況で行われます。ローカルネットワークなしでオフライン操作を行いたい場合は、Stripe Terminal の[モバイルリーダー](https://docs.stripe.com/terminal/mobile-readers.md)をご検討ください。 また、Apps on Devices を導入してオフラインで操作することもできます。POS アプリケーションはスマートリーダー上で直接実行されるため、支払いの回収にローカルネットワークを必要としません。ただし、ネットワークがインターネットにアクセスできない場合でも、リーダーを初めて起動するときにはローカルネットワークを使用する必要があります。 > オフラインで実行するときは、販売時に決済情報が収集されます。オーソリは接続の回復後にのみ試行され、支払いが転送されます。インターネットリーダーを使用してオフラインで実行する場合、リーダーは収集した決済情報を保存します。ユーザーであるお客様が、オフライン取引に関連する支払い拒否や改ざんに関するすべてのリスクを負います。改ざんされたリーダーが支払いを Stripe に転送できない場合、またはカード発行会社が取引を拒否した場合、売上を回収する方法はなく、すでに提供した商品やサービスへの顧客の支払いを受け取れなくなることがあります。 > > カード発行会社による拒否を減らすため、以下のことが推奨されます。 > > - できる限り早急にインターネット接続を再確立して、支払いを Stripe に記録します。 - 所定の金額を超える場合は取引を制限します。 - 合計すると所定の金額を超える複数の取引を SDK が保存した場合、[すべてのオフライン決済を失敗させます](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#managing-risk)。 ## オフライン中に決済を回収する オフライン決済の手順は、オンライン決済と同じで、決済の作成、回収、処理、およびキャプチャーが含まれます。このプロセスのどの段階でも、デバイスをオンラインからオフラインにできます。 1. [オフラインモードを有効にする](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#enable-offline-mode) 1. [オフライン中にリーダーに接続する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#connect-while-offline) 1. [オフラインイベントを処理する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#handle-offline-events) 1. [オフライン中に PaymentIntent を作成する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#create-payment-intent) 1. [支払い方法を収集する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#collect-payment-method) 1. [支払いを確定する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#confirm-payment) 1. [支払いが転送されるまで待つ](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#wait-for-forward) 1. (オプション) [支払いをキャプチャーする](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#capture-payment) 1. (オプション) [オフラインで回収した支払いを調べる](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#examine-offline) ## オフラインモードを有効にする オフラインモードを使用するには、アプリケーションが Terminal iOS SDK のバージョン `3.3.0` 以降を使用している必要があります。 [Configuration](https://docs.stripe.com/api/terminal/configuration.md) オブジェクトまたは[ダッシュボード](https://docs.stripe.com/terminal/fleet/configurations-overview.md?dashboard-or-api=dashboard#update-the-default-configuration-for-the-account)を使用して、`Location` で[サポートされている](https://docs.stripe.com/terminal/features/operate-offline/overview.md?reader-type=internet#availability)デバイスのオフラインモードを有効にします。 ```curl curl https://api.stripe.com/v1/terminal/configurations \ -u "<>:" \ -d "offline[enabled]=true" ``` `Configuration` オブジェクトでオフラインモードを有効にすると、`Location` に[割り当てる](https://docs.stripe.com/terminal/fleet/configurations-overview.md?dashboard-or-api=api#create-a-configuration-for-an-individual-location)ことができます。また、アカウントの[デフォルト](https://docs.stripe.com/terminal/fleet/configurations-overview.md?dashboard-or-api=api#retrieve-the-account-default-configuration)の `Configuration` オブジェクトを更新すると、すべての `Locations` でオフラインモードをデフォルトで有効にすることもできます。Configuration API の変更が SDK とリーダーに反映されるまで数分かかる場合があり、反映するには、リーダーの接続をいったん切断してから再接続する必要があります。 ## オフライン中にリーダーに接続する リーダーはオンラインに接続した後、必要な `Location` 情報をローカルに保存します。後続のオフライン接続では、その `Location` に保存されている設定情報が使用されます。 オフライン時にスマートリーダーで支払いを回収するには、直前の 30 日以内のオンライン時に、あらかじめ同じ `Location` の同じタイプのモバイルリーダー (同じローカルネットワーク上にある) に接続しておく必要があります。 オンラインで接続した後、リーダーは `Location` 情報をローカルに保存し、オフラインでの操作時にその `Location` から設定情報を導出します。リーダーと POS デバイスはオンライン接続に使用される同一のローカルネットワーク上に存在する必要があります。オフライン時にネットワークを切り替えることはできません。 オフライン時にこれらの要件を満たさずリーダーに接続しようとすると、リクエストはエラーで失敗します。 | エラー | 解決策 | | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **SDK がインターネットに接続されていません** | 使用している `Location` がオフラインモード用に[設定されている](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#enable-offline-mode)ことを確認します。それ以外の場合は、オンライン時に任意のリーダーに接続してから、オフライン時に同じタイプのリーダーに接続します。 | | **選択したリーダーをオフラインでの支払い回収に使用するには、ソフトウェアの更新が必要です。** | リーダーのソフトウェアが 30 日以上更新されていません。オンライン時にリーダーに接続して更新してください。 | | **選択したリーダーをオフラインでの支払い回収に使用するには、この場所でオンラインのペアリングを行う必要があります。** | POS がこれまでオンライン中に接続していないタイプのリーダーに接続しようとしています。まずオンライン中に、このリーダーまたは同じタイプのリーダーに接続する必要があります。または、オフライン中に接続する場合は、以前オンライン中に POS が接続していたタイプのリーダーに接続できます。 | ## オフラインイベントを処理する [クライアント側] - [OfflineDelegate (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Protocols/SCPOfflineDelegate.html) アプリケーションが SDK のネットワークステータスと転送された支払いの状態に関する更新を受信できるようにするには、`OfflineDelegate` プロトコルを実装して Terminal SDK に渡します。オフラインで支払いを回収する前に、`OfflineDelegate` を設定する必要があります。 #### Swift ```swift import StripeTerminal class CustomOfflineDelegate: OfflineDelegate { func terminal(_ terminal: Terminal, didChangeOfflineStatus offlineStatus: OfflineStatus) { // Check the value of `offlineStatus` and update your UI accordingly. For instance, // you can check the SDK's network status at `offlineStatus.sdk.networkStatus`. // // You can also check the SDK's current offline status using // `Terminal.shared.offlineStatus.sdk.networkStatus`. } func terminal(_ terminal: Terminal, didForwardPaymentIntent intent: PaymentIntent, error: Error?) { // The PaymentIntent was successfully forwarded, or an error occurred. // Reconcile any local state using the backend-generated `PaymentIntent.stripeId` // and the metadata you supplied when creating the PaymentIntent. // // Note that the `PaymentIntent.stripeId` may still be nil if creating the // PaymentIntent in the backend failed. } func terminal(_ terminal: Terminal, didReportForwardingError error: Error) { // A non-specific error occurred while forwarding a PaymentIntent. // Check the error message and your integration implementation to // troubleshoot. } } ``` #### Swift ```swift import UIKit import StripeTerminal @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { Terminal.initWithTokenProvider(APIClient.shared) Terminal.shared.offlineDelegate = CustomOfflineDelegate() // ... return true } // ... } ``` ## オフライン中に PaymentIntent を作成する [クライアント側] - [createPaymentIntent (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPTerminal.html#/c:objc\(cs\)SCPTerminal\(im\)createPaymentIntent:completion:) - [CreateConfiguration (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPCreateConfiguration.html) - [OfflineDetails (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPOfflineDetails.html) オフラインでの操作に対応するには、SDK の `createPaymentIntent` を使用して PaymentIntent オブジェクトを作成します。これにより、SDK はオフライン時に PaymentIntents を作成し、接続が再確立された後で Stripe に転送できます。 オフラインでの実行中、`PaymentIntent` オブジェクトは null の `stripeId` を保持します。PaymentIntent の[メタデータ](https://docs.stripe.com/payments/payment-intents.md#storing-information-in-metadata)にカスタム識別子を追加して、オフラインで作成された `PaymentIntent` オブジェクトをデータベースで照合できるようにすることをお勧めします。 オフライン支払いが Stripe に転送されたときに `PaymentIntent` イベントを受信するように [Webhook](https://docs.stripe.com/webhooks.md) エンドポイントを設定し、識別子を使用してそのイベントを `PaymentIntent` ID に関連付けることができます。 #### Swift ```swift import UIKit import StripeTerminal class PaymentViewController: UIViewController { // Action for a "Checkout" button func checkoutAction() throws { // Populate the correct transaction amount from your application. let amount = UInt(10_00) // Build up parameters for creating a `PaymentIntent` let params = try PaymentIntentParametersBuilder( amount: amount, currency: "usd" ).setMetadata(["offlineId": UUID().uuidString]) .build() Terminal.shared.createPaymentIntent(params) { createResult, createError in if let error = createError { // Handle errors in your application. print("createPaymentIntent failed: \(error)") } else if let paymentIntent = createResult { print("createPaymentIntent succeeded")// If the `PaymentIntent` was created offline, its `stripeId` field will be nil. if let onlineCreatedId = paymentIntent.stripeId { print("created online"); } else { print("created offline") } } } } } ``` `Terminal.createPaymentIntent` は `CreateConfiguration` パラメーターを受け付けます。デフォルトでは、オフラインで実行している場合、Terminal SDK はすべてのオフライン決済を保存し、接続が回復したときに Stripe のバックエンドに転送します。 この動作をカスタマイズするには、`offlineBehavior` 属性を `REQUIRE_ONLINE`、`PREFER_ONLINE` または `FORCE_OFFLINE` に設定して `CreateConfiguration` オブジェクトを渡すことができます。 #### リスクの管理 `offlineBehavior` を `REQUIRE_ONLINE` に設定すると、現在の取引はオフラインでの操作時に失敗します。たとえば、一定の金額を越える取引を拒否したり、リーダーに合計額が一定の金額を超える複数の取引が保存されている場合に、すべてのオフライン取引を拒否したりすることができます。 SDK では、リスクを管理しやすいように、次の 2 つのプロパティーを公開しています。 1. `Terminal.offlineStatus.reader.offlinePaymentsCount` 1. `Terminal.offlineStatus.reader.offlinePaymentAmountsByCurrency` #### オフライン時の遅延管理 ネットワーク接続に基づいて、Terminal SDK が支払いをオンラインとオフラインのどちらで回収するかを自動的に判断します。ただし、ネットワーク接続がアクティブであっても (取引を迅速に回収する必要があり、ネットワーク接続が遅い場合など)、オフラインでの操作が必要になる場合があります。 `CreateConfiguration` オブジェクトを `offlineBehavior` を `FORCE_OFFLINE` に設定して渡すと、接続に関係なくオフラインで支払いを回収できます。 Terminal リーダーのネットワーク接続がアクティブな状態にあるときにオフラインで回収された支払いは、バックグラウンドで転送されます。 #### Swift ```swift import UIKit import StripeTerminal class PaymentViewController: UIViewController { // Action for a "Checkout" button func checkoutAction() throws { // ...build up parameters and callback for creating a `PaymentIntent` // Your app might want to prevent offline payments for too large an amount. // Here, we block the payment if the amount is over 1000 usd. // Otherwise, we allow collecting offline if the network connection is unavailable.let offlineBehavior: SCPOfflineBehavior = { if amount > UInt(1_000_00) { return .requireOnline } else { return .preferOnline } }() let createConfiguration = try CreateConfigurationBuilder().setOfflineBehavior(offlineBehavior).build() Terminal.shared.createPaymentIntent(params, createConfig: createConfiguration) { createResult, createError in // handle success or failure } } } ``` ## 支払い方法を収集する [クライアント側] - [CollectPaymentIntentConfiguration (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPCollectPaymentIntentConfiguration.html) > オフラインでリーダーを実行する間は、決済の責任をお客様が負うことになります。磁気ストライプデータはなりすましが簡単なため、Stripe はオフラインでの実行中はこのオプションを許可していません。*強力な顧客認証* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase) (SCA) が要求される市場では、カードのタップもサポートされていません。 オフラインでの支払いの回収は、[オンラインでの支払いの回収](https://docs.stripe.com/terminal/payments/collect-card-payment.md#collect-payment)と似ています。スマートリーダーは、利用可能な決済オプションを顧客に自動的に表示します。 > Readers don’t support [inspecting payment method details before authorization](https://docs.stripe.com/terminal/payments/collect-card-payment.md?terminal-sdk-platform=ios#collect-inspect-payment-method) while offline. Although you can still use the `initWithUpdatePaymentIntent` parameter in `CollectPaymentIntentConfiguration`, the `paymentMethod` field on the PaymentIntent is absent if the SDK is operating offline. #### Swift ```swift import UIKit import StripeTerminal class PaymentViewController: UIViewController { // Action for a "Checkout" button func checkoutAction() { Terminal.shared.collectPaymentMethod(paymentIntent) { collectResult, collectError in if let error = collectError { print("collectPaymentMethod failed: \(error)") } else if let paymentIntent = collectResult { print("collectPaymentMethod succeeded") // ... Confirm the payment } } } } ``` ## 支払いを確定する [クライアント側] オフラインでの支払いの確定は、[オンラインでの支払いの確定](https://docs.stripe.com/terminal/payments/collect-card-payment.md#confirm-payment)と似ています。主な違いは、Stripe が適用するオフライン取引の上限額である 1 万 USD、または運用通貨で相当する額を超えた場合などは、オフライン固有のエラーケースを自社のシステムで処理する必要がある点です。 場合によっては、SDK がオンラインで `PaymentIntent` を作成し、オフラインで確定することがあります。これが発生すると、`PaymentIntent` に null 以外の `stripeId` が含まれる可能性があります。オフラインで確定された場合は、`offlineDetails` が定義され、入力されます。 #### Swift ```swift import UIKit import StripeTerminal class PaymentViewController: UIViewController { // Action for a "Checkout" button func checkoutAction() { Terminal.shared.confirmPaymentIntent(paymentIntent) { confirmResult, confirmError in if let error = confirmError { // Handle offline-specific errors in your application (for example, // unsupported payment method). print("confirmPaymentIntent failed: \(error)") } else if let confirmedPaymentIntent= confirmResult {print("confirmPaymentIntent succeeded") if let offlineDetails = paymentIntent.offlineDetails { print("confirmed offline"); } else { print("confirmed online") } } } } } ``` #### 領収書の提供 オフライン時に支払いの完了に使用されたカードの情報が必要になることがあります。たとえば、購入時の領収書を求める顧客に領収書を生成する必要がある場合などです。 PaymentIntent がオフラインで確定された場合、その [OfflineCardPresentDetails](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPOfflineCardPresentDetails.html)、 を `paymentIntent.offlineDetails.offlineCardPresentDetails` から取得できます。 このハッシュには、領収書の生成に使用される [ReceiptDetails](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPReceiptDetails.html)、 プロパティのほか、カード保有者の名前やカードブランドなどのカード情報が含まれます。 オフラインで処理された PaymentIntents では、`account_type` および `authorization_response_code` の領収書フィールドを使用できません。[構築済みのメール領収書](https://docs.stripe.com/terminal/features/receipts.md#prebuilt)は接続が回復し、支払いのキャプチャーが成功するまで送信されません。 ## 支払いが転送されるまで待つ [クライアント側] ネットワーク接続が復旧すると、リーダーは保存されていたオフラインの支払いの転送を自動的に開始します。 リーダーは、ネットワークステータスがオフラインであっても支払いの転送を試みます。つまり、デバイスがオフラインの場合でも、接続トークンプロバイダーは、接続トークンの提供を求めるリクエストを受け取る可能性があります。 スマートリーダーの接続解除や電源オフのタイミングが早すぎると、支払いが転送されない可能性があります。`Terminal.offlineStatus.reader.networkStatus` をクエリすると、スマートリーダーがオンライン状態にあり、支払いを転送できるか確認することができます。また、`Terminal.offlineStatus.reader.offlinePaymentsCount` をクエリすると、リーダー の転送が必要な支払いの件数を確認できます。 スマートリーダーが破損したり、支払い処理に使用できなくなった場合でも、多くの場合は保存された支払いを転送できます。Stripe への再接続を可能にするには、スマートリーダーと POS が接続されていることを確認し、インターネットへのアクセスを再確立してください。 ## 決済をキャプチャーする オフライン時には、`captureMethod` を `automatic` に設定して、PaymentIntents を作成できます。 これらの PaymentIntent を確定すると、ステータスは `RequiresCapture` ではなく、`Succeeded` になります。Stripe は転送後の支払いを自動的にキャプチャーします。 手動キャプチャーを選択した場合、正常に転送されオーソリされた支払いは、バックエンドまたはアプリケーションからキャプチャーする必要があります。 - バックエンドから支払いをキャプチャーするには、[Webhook](https://docs.stripe.com/webhooks.md) を使用して、`requires_capture` ステータスの PaymentIntents をリッスンします。 - アプリケーションから支払いをキャプチャーするには、リーダーが各 PaymentIntent を転送するたびに、`OfflineDelegate.didForwardPayment` のコールをアプリケーションが受け取るのを待ちます。PaymentIntent のステータスが `RequiresCapture` であり、さらに `offlineDetails` が null、あるいは `requiresUpload` value of `NO` の場合、キャプチャーする準備ができています。 #### Swift ```swift Terminal.shared.confirmPaymentIntent(paymentIntent) { confirmResult, confirmError in if let error = confirmError { // Handle offline-specific errors in your application (for example, // unsupported payment method). print("confirmPaymentIntent failed: \(error)") } else if let confirmedPaymentIntent = confirmResult { if intent.status == .requiresCapture {if let offlineDetails = confirmedPaymentIntent.offlineDetails(), offlineDetails.requiresUpload { // Offline payment, wait for `didForwardPaymentIntent` (see snippet below) } else { // Online payment, can be captured now } } // else, handle other intent.status results here } } ``` オフライン決済は、 リーダーによって OfflineDelegate の `didForwardPaymentIntent` で転送された後にキャプチャーします。 #### Swift ```swift import StripeTerminal class CustomOfflineDelegate: OfflineDelegate { // ... func terminal(_ terminal: Terminal, didForwardPaymentIntent intent: PaymentIntent, error: Error?) { if let error = error { // Handle the error appropriate for your application return } if intent.status == .requiresCapture { // The intent is ready to be captured. } else { // Handle the intent.status as appropriate. } } // ... } ``` ## オフラインで回収した支払いを調べる オーソリ後は、[PaymentIntents](https://docs.stripe.com/payments/payment-intents.md) API を使用して支払いのオフライン情報を調べることができます。`PaymentIntent` の[最新の Charge](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-latest_charge) オブジェクトの [payment method details](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-offline) にアクセスすると、オフラインで回収されたものであるかどうかを判定できます。 # Android > This is a Android for when terminal-card-present-integration is terminal and terminal-sdk-platform is android and reader-type is internet. View the full page at https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments?terminal-card-present-integration=terminal&terminal-sdk-platform=android&reader-type=internet. Terminal SDK を使用すると、アプリケーションではインターネット接続がなくてもスマートリーダーを使用して支払いの回収を続行できます。 Stripe のスマートリーダー以外の POS デバイスを使用している場合でも、POS デバイスがスマートリーダーと通信できるようにするには、有効なローカルネットワークが必要になります。スマートリーダーのオフラインでの操作は、ISP の障害時など、POS とリーダーが Stripe と通信できない状況で行われます。ローカルネットワークなしでオフライン操作を行いたい場合は、Stripe Terminal の[モバイルリーダー](https://docs.stripe.com/terminal/mobile-readers.md)をご検討ください。 また、Apps on Devices を導入してオフラインで操作することもできます。POS アプリケーションはスマートリーダー上で直接実行されるため、支払いの回収にローカルネットワークを必要としません。ただし、ネットワークがインターネットにアクセスできない場合でも、リーダーを初めて起動するときにはローカルネットワークを使用する必要があります。 > オフラインで実行するときは、販売時に決済情報が収集されます。オーソリは接続の回復後にのみ試行され、支払いが転送されます。インターネットリーダーを使用してオフラインで実行する場合、リーダーは収集した決済情報を保存します。ユーザーであるお客様が、オフライン取引に関連する支払い拒否や改ざんに関するすべてのリスクを負います。改ざんされたリーダーが支払いを Stripe に転送できない場合、またはカード発行会社が取引を拒否した場合、売上を回収する方法はなく、すでに提供した商品やサービスへの顧客の支払いを受け取れなくなることがあります。 > > カード発行会社による拒否を減らすため、以下のことが推奨されます。 > > - できる限り早急にインターネット接続を再確立して、支払いを Stripe に記録します。 - 所定の金額を超える場合は取引を制限します。 - 合計すると所定の金額を超える複数の取引を SDK が保存した場合、[すべてのオフライン決済を失敗させます](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#managing-risk)。 ## オフライン中に決済を回収する オフライン決済の手順は、オンライン決済と同じで、決済の作成、回収、処理、およびキャプチャーが含まれます。このプロセスのどの段階でも、デバイスをオンラインからオフラインにできます。 1. [オフラインモードを有効にする](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#enable-offline-mode) 1. [オフライン中にリーダーに接続する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#connect-while-offline) 1. [オフラインイベントを処理する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#handle-offline-events) 1. [オフライン中に PaymentIntent を作成する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#create-payment-intent) 1. [支払い方法を収集する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#collect-payment-method) 1. [支払いを確定する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#confirm-payment) 1. [支払いが転送されるまで待つ](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#wait-for-forward) 1. (オプション) [支払いをキャプチャーする](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#capture-payment) 1. (オプション) [オフラインで回収した支払いを調べる](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#examine-offline) ## オフラインモードを有効にする オフラインモードを使用するには、アプリケーションが Terminal Android SDK のバージョン `3.2.0` 以降を使用している必要があります。 [Configuration](https://docs.stripe.com/api/terminal/configuration.md) オブジェクトまたは[ダッシュボード](https://docs.stripe.com/terminal/fleet/configurations-overview.md?dashboard-or-api=dashboard#update-the-default-configuration-for-the-account)を使用して、`Location` で[サポートされている](https://docs.stripe.com/terminal/features/operate-offline/overview.md?reader-type=internet#availability)デバイスのオフラインモードを有効にします。 ```curl curl https://api.stripe.com/v1/terminal/configurations \ -u "<>:" \ -d "offline[enabled]=true" ``` `Configuration` オブジェクトでオフラインモードを有効にすると、`Location` に[割り当てる](https://docs.stripe.com/terminal/fleet/configurations-overview.md?dashboard-or-api=api#create-a-configuration-for-an-individual-location)ことができます。また、アカウントの[デフォルト](https://docs.stripe.com/terminal/fleet/configurations-overview.md?dashboard-or-api=api#retrieve-the-account-default-configuration)の `Configuration` オブジェクトを更新すると、すべての `Locations` でオフラインモードをデフォルトで有効にすることもできます。Configuration API の変更が SDK とリーダーに反映されるまで数分かかる場合があり、反映するには、リーダーの接続をいったん切断してから再接続する必要があります。 ## オフライン中にリーダーに接続する リーダーはオンラインに接続した後、必要な `Location` 情報をローカルに保存します。後続のオフライン接続では、その `Location` に保存されている設定情報が使用されます。 オフライン時にスマートリーダーで支払いを回収するには、直前の 30 日以内のオンライン時に、あらかじめ同じ `Location` の同じタイプのモバイルリーダー (同じローカルネットワーク上にある) に接続しておく必要があります。 オンラインで接続した後、リーダーは `Location` 情報をローカルに保存し、オフラインでの操作時にその `Location` から設定情報を導出します。リーダーと POS デバイスはオンライン接続に使用される同一のローカルネットワーク上に存在する必要があります。オフライン時にネットワークを切り替えることはできません。 オフライン時にこれらの要件を満たさずリーダーに接続しようとすると、リクエストはエラーで失敗します。 | エラー | 解決策 | | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **SDK がインターネットに接続されていません** | 使用している `Location` がオフラインモード用に[設定されている](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#enable-offline-mode)ことを確認します。それ以外の場合は、オンライン時に任意のリーダーに接続してから、オフライン時に同じタイプのリーダーに接続します。 | | **選択したリーダーをオフラインでの支払い回収に使用するには、ソフトウェアの更新が必要です。** | リーダーのソフトウェアが 30 日以上更新されていません。オンライン時にリーダーに接続して更新してください。 | | **選択したリーダーをオフラインでの支払い回収に使用するには、この場所でオンラインのペアリングを行う必要があります。** | POS がこれまでオンライン中に接続していないタイプのリーダーに接続しようとしています。まずオンライン中に、このリーダーまたは同じタイプのリーダーに接続する必要があります。または、オフライン中に接続する場合は、以前オンライン中に POS が接続していたタイプのリーダーに接続できます。 | ## オフラインイベントを処理する [クライアント側] - [OfflineListener (Android)](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.callable/-offline-listener/index.html) アプリケーションが SDK のネットワークステータスと転送された支払いの状態に関する更新を受信できるようにするには、`OfflineListener` インターフェイスを実装して Terminal SDK に渡します。オフラインで支払いを回収する前に、`OfflineListener` を設定する必要があります。 #### Kotlin ```kotlin class CustomOfflineListener : OfflineListener { override fun onOfflineStatusChange(offlineStatus: OfflineStatus) { // Check the value of `offlineStatus` and update your UI accordingly. For instance, // you can check the SDK's network status at `offlineStatus.sdk.networkStatus`. // // You can also check the SDK's current offline status using // `Terminal::offlineStatus`. } override fun onPaymentIntentForwarded(paymentIntent: PaymentIntent, e: TerminalException?) { // The PaymentIntent was successfully forwarded, or an error occurred. // Reconcile any local state using the backend-generated `PaymentIntent::id` // and the metadata you supplied when creating the PaymentIntent. // // Note that the `PaymentIntent::id` may still be null if creating the // PaymentIntent in the backend failed. } override fun onForwardingFailure(e: TerminalException) { // A non-specific error occurred while forwarding a PaymentIntent. // Check the error message and your integration implementation to // troubleshoot. } } ``` #### Kotlin ```kotlin Terminal.init( context = applicationContext, logLevel = LogLevel.VERBOSE, tokenProvider = CustomConnectionTokenProvider(), listener = CustomTerminalListener(), offlineListener = CustomOfflineListener(), ) ``` ## オフライン中に PaymentIntent を作成する [クライアント側] - [createPaymentIntent (Android)](https://stripe.dev/stripe-terminal-android/core/com.stripe.stripeterminal/-terminal/create-payment-intent.html) - [CreateConfiguration (Android)](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-create-configuration/index.html) - [OfflineDetails (Android)](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-offline-details/index.html) オフラインでの操作に対応するには、SDK の `createPaymentIntent` を使用して PaymentIntent オブジェクトを作成します。これにより、SDK はオフライン時に PaymentIntents を作成し、接続が再確立された後で Stripe に転送できます。 オフラインでの実行中、`PaymentIntent` オブジェクトは null の `id` を保持します。PaymentIntent の[メタデータ](https://docs.stripe.com/payments/payment-intents.md#storing-information-in-metadata)にカスタム識別子を追加して、オフラインで作成された `PaymentIntent` オブジェクトをデータベースで照合できるようにすることをお勧めします。 オフライン支払いが Stripe に転送されたときに `PaymentIntent` イベントを受信するように [Webhook](https://docs.stripe.com/webhooks.md) エンドポイントを設定し、識別子を使用してそのイベントを `PaymentIntent` ID に関連付けることができます。 #### Kotlin ```kotlin private const val TAG = "PaymentActivity" class PaymentActivity : AppCompatActivity() { // Action for a "Checkout" button private fun onCheckout(cart: Cart) { // Build up parameters for creating a `PaymentIntent` val params = PaymentIntentParameters.Builder() .setAmount(cart.total) .setCurrency(cart.currency).setMetadata(mapOf("unique-id" to UUID.randomUUID().toString())) .build() val createPaymentCallback: PaymentIntentCallback = object : PaymentIntentCallback { override fun onSuccess(paymentIntent: PaymentIntent) { Log.d(TAG, "createPaymentIntent succeeded")// If the `PaymentIntent` was created offline, its `id` field will be null. if (paymentIntent.id != null) { Log.d(TAG, "created online") } else { Log.d(TAG, "created offline") } // ... Collect a PaymentMethod } override fun onFailure(e: TerminalException) { Log.e(TAG, "createPaymentIntent failed", e) // Handle errors in your application. } } Terminal.getInstance().createPaymentIntent(params, createPaymentCallback) } } ``` `Terminal.createPaymentIntent` は `CreateConfiguration` パラメーターを受け付けます。デフォルトでは、オフラインで実行している場合、Terminal SDK はすべてのオフライン決済を保存し、接続が回復したときに Stripe のバックエンドに転送します。 この動作をカスタマイズするには、`offlineBehavior` 属性を `REQUIRE_ONLINE`、`PREFER_ONLINE` または `FORCE_OFFLINE` に設定して `CreateConfiguration` オブジェクトを渡すことができます。 #### リスクの管理 `offlineBehavior` を `REQUIRE_ONLINE` に設定すると、現在の取引はオフラインでの操作時に失敗します。たとえば、一定の金額を越える取引を拒否したり、リーダーに合計額が一定の金額を超える複数の取引が保存されている場合に、すべてのオフライン取引を拒否したりすることができます。 SDK では、リスクを管理しやすいように、次の 2 つのプロパティーを公開しています。 1. `Terminal.offlineStatus.reader.offlinePaymentsCount` 1. `Terminal.offlineStatus.reader.offlinePaymentAmountsByCurrency` #### オフライン時の遅延管理 ネットワーク接続に基づいて、Terminal SDK が支払いをオンラインとオフラインのどちらで回収するかを自動的に判断します。ただし、ネットワーク接続がアクティブであっても (取引を迅速に回収する必要があり、ネットワーク接続が遅い場合など)、オフラインでの操作が必要になる場合があります。 `CreateConfiguration` オブジェクトを `offlineBehavior` を `FORCE_OFFLINE` に設定して渡すと、接続に関係なくオフラインで支払いを回収できます。 Terminal リーダーのネットワーク接続がアクティブな状態にあるときにオフラインで回収された支払いは、バックグラウンドで転送されます。 #### Kotlin ```kotlin private const val TAG = "PaymentActivity" class PaymentActivity : AppCompatActivity() { // Action for a "Checkout" button private fun onCheckout(cart: Cart) { // ...build up parameters and callback for creating a `PaymentIntent` // Your app might want to prevent offline payments for too large an amount. // Here, we require a network connection if the payment if the amount is over 1000 usd. // Otherwise, we allow collecting offline if the network connection is unavailable.val offlineBehavior = if (cart.total > 1000000) { OfflineBehavior.REQUIRE_ONLINE } else { OfflineBehavior.PREFER_ONLINE } val createConfig = CreateConfiguration(offlineBehavior) Terminal.getInstance().createPaymentIntent(params, createPaymentCallback, createConfig) } } ``` ## 支払い方法を収集する [クライアント側] - [CollectPaymentIntentConfiguration (Android)](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-collect-payment-intent-configuration/index.html) > オフラインでリーダーを実行する間は、決済の責任をお客様が負うことになります。磁気ストライプデータはなりすましが簡単なため、Stripe はオフラインでの実行中はこのオプションを許可していません。*強力な顧客認証* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase) (SCA) が要求される市場では、カードのタップもサポートされていません。 オフラインでの支払いの回収は、[オンラインでの支払いの回収](https://docs.stripe.com/terminal/payments/collect-card-payment.md#collect-payment)と似ています。スマートリーダーは、利用可能な決済オプションを顧客に自動的に表示します。 > Readers don’t support [inspecting payment method details before authorization](https://docs.stripe.com/terminal/payments/collect-card-payment.md?terminal-sdk-platform=android#collect-inspect-payment-method) while offline. Although you can still set the `updatePaymentIntent` parameter in `CollectPaymentIntentConfiguration`, the `paymentMethod` field on the PaymentIntent is absent if the SDK is operating offline. #### Kotlin ```kotlin private const val TAG = "PaymentActivity" class PaymentActivity : AppCompatActivity() { // Action for a "Checkout" button private fun onCheckout(cart: Cart) { val collectPaymentCallback: PaymentIntentCallback = object : PaymentIntentCallback { override fun onSuccess(paymentIntent: PaymentIntent) { Log.d(TAG, "collectPaymentMethod succeeded") // ... Confirm the payment } override fun onFailure(e: TerminalException) { Log.d(TAG, "collectPaymentMethod failed:", e) } } val collectConfig = CollectPaymentIntentConfiguration.Builder().build() Terminal.getInstance().collectPaymentMethod(paymentIntent, collectPaymentCallback, collectConfig) } } ``` ## 支払いを確定する [クライアント側] オフラインでの支払いの確定は、[オンラインでの支払いの確定](https://docs.stripe.com/terminal/payments/collect-card-payment.md#confirm-payment)と似ています。主な違いは、Stripe が適用するオフライン取引の上限額である 1 万 USD、または運用通貨で相当する額を超えた場合などは、オフライン固有のエラーケースを自社のシステムで処理する必要がある点です。 場合によっては、SDK がオンラインで `PaymentIntent` を作成し、オフラインで確定することがあります。これが発生すると、`PaymentIntent` に null 以外の `id` が含まれる可能性があります。オフラインで確定された場合は、`offlineDetails` が定義され、入力されます。 #### Kotlin ```kotlin private const val TAG = "PaymentActivity" class PaymentActivity : AppCompatActivity() { // Action for a "Checkout" button private fun onCheckout(cart: Cart) { val confirmPaymentIntentCallback: PaymentIntentCallback = object : PaymentIntentCallback { override fun onSuccess(paymentIntent: PaymentIntent) { Log.d(TAG, "confirmPaymentIntent succeeded")// If the `PaymentIntent` was confirmed offline, `paymentIntent.offlineDetails` will be defined if (paymentIntent.offlineDetails != null) { Log.d(TAG, "confirmed offline") } else { Log.d(TAG, "confirmed online") } } override fun onFailure(e: TerminalException) { // Handle offline-specific errors in your application (for example, // unsupported payment method). Log.e(TAG, "confirmPaymentIntent failed:", e) } } Terminal.getInstance().confirmPaymentIntent(paymentIntent, confirmPaymentIntentCallback) } } ``` #### 領収書の提供 オフライン時に支払いの完了に使用されたカードの情報が必要になることがあります。たとえば、購入時の領収書を求める顧客に領収書を生成する必要がある場合などです。 PaymentIntent がオフラインで確定された場合、その [OfflineCardPresentDetails](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-offline-card-present-details/index.html)、 を `paymentIntent.offlineDetails.offlineCardPresentDetails` から取得できます。 このハッシュには、領収書の生成に使用される [ReceiptDetails](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-receipt-details/index.html)、 プロパティのほか、カード保有者の名前やカードブランドなどのカード情報が含まれます。 オフラインで処理された PaymentIntents では、`account_type` および `authorization_response_code` の領収書フィールドを使用できません。[構築済みのメール領収書](https://docs.stripe.com/terminal/features/receipts.md#prebuilt)は接続が回復し、支払いのキャプチャーが成功するまで送信されません。 ## 支払いが転送されるまで待つ [クライアント側] ネットワーク接続が復旧すると、リーダーは保存されていたオフラインの支払いの転送を自動的に開始します。 リーダーは、ネットワークステータスがオフラインであっても支払いの転送を試みます。つまり、デバイスがオフラインの場合でも、接続トークンプロバイダーは、接続トークンの提供を求めるリクエストを受け取る可能性があります。 スマートリーダーの接続解除や電源オフのタイミングが早すぎると、支払いが転送されない可能性があります。`Terminal.offlineStatus.reader.networkStatus` をクエリすると、スマートリーダーがオンライン状態にあり、支払いを転送できるか確認することができます。また、`Terminal.offlineStatus.reader.offlinePaymentsCount` をクエリすると、リーダー の転送が必要な支払いの件数を確認できます。 スマートリーダーが破損したり、支払い処理に使用できなくなった場合でも、多くの場合は保存された支払いを転送できます。Stripe への再接続を可能にするには、スマートリーダーと POS が接続されていることを確認し、インターネットへのアクセスを再確立してください。 ## 決済をキャプチャーする オフライン時には、`captureMethod` を `automatic` に設定して、PaymentIntents を作成できます。 これらの PaymentIntent を確定すると、ステータスは `REQUIRES_CAPTURE` ではなく、`SUCCEEDED` になります。Stripe は転送後の支払いを自動的にキャプチャーします。 手動キャプチャーを選択した場合、正常に転送されオーソリされた支払いは、バックエンドまたはアプリケーションからキャプチャーする必要があります。 - バックエンドから支払いをキャプチャーするには、[Webhook](https://docs.stripe.com/webhooks.md) を使用して、`requires_capture` ステータスの PaymentIntents をリッスンします。 - アプリケーションから支払いをキャプチャーするには、リーダーが各 PaymentIntent を転送するたびに、`OfflineListener::onPaymentIntentForwarded` のコールをアプリケーションが受け取るのを待ちます。PaymentIntent のステータスが `REQUIRES_CAPTURE` であり、さらに `offlineDetails` が null、あるいは `requiresUpload` value of `false` の場合、キャプチャーする準備ができています。 #### Kotlin ```kotlin private const val TAG = "PaymentActivity" class PaymentActivity : AppCompatActivity() { // Action for a "Checkout" button private fun onCheckout(cart: Cart) { val callback: PaymentIntentCallback = object : PaymentIntentCallback { override fun onSuccess(paymentIntent: PaymentIntent) { Log.d(TAG, "confirmPaymentIntent succeeded") if (paymentIntent.status == PaymentIntentStatus.REQUIRES_CAPTURE) {val offlineDetails = paymentIntent.offlineDetails if (offlineDetails?.requiresUpload == true) { // Offline payment, wait for `onPaymentIntentForwarded` (see snippet below) } else { // Online payment, can be captured now } } else { // Handle other status results here } } override fun onFailure(e: TerminalException) { // Handle offline-specific errors in your application (for example, // unsupported payment method). Log.e(TAG, "confirmPaymentIntent failed:", e) } } Terminal.getInstance().confirmPaymentIntent(paymentIntent, callback) } } ``` オフライン決済は、 リーダーによって `OfflineListener::onPaymentIntentForwarded` で転送された後にキャプチャーします。 #### Kotlin ```kotlin class CustomOfflineListener : OfflineListener { // ... override fun onPaymentIntentForwarded(paymentIntent: PaymentIntent, e: TerminalException?) { if (e != null) { // Handle the error appropriate for your application } else if (paymentIntent.status == PaymentIntentStatus.REQUIRES_CAPTURE) { // The paymentIntent is ready to be captured } else { // Handle other status results here } } // ... } ``` ## オフラインで回収した支払いを調べる オーソリ後は、[PaymentIntents](https://docs.stripe.com/payments/payment-intents.md) API を使用して支払いのオフライン情報を調べることができます。`PaymentIntent` の[最新の Charge](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-latest_charge) オブジェクトの [payment method details](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-offline) にアクセスすると、オフラインで回収されたものであるかどうかを判定できます。 # React Native > This is a React Native for when terminal-card-present-integration is terminal and terminal-sdk-platform is react-native and reader-type is internet. View the full page at https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments?terminal-card-present-integration=terminal&terminal-sdk-platform=react-native&reader-type=internet. Terminal SDK を使用すると、アプリケーションではインターネット接続がなくてもスマートリーダーを使用して支払いの回収を続行できます。 Stripe のスマートリーダー以外の POS デバイスを使用している場合でも、POS デバイスがスマートリーダーと通信できるようにするには、有効なローカルネットワークが必要になります。スマートリーダーのオフラインでの操作は、ISP の障害時など、POS とリーダーが Stripe と通信できない状況で行われます。ローカルネットワークなしでオフライン操作を行いたい場合は、Stripe Terminal の[モバイルリーダー](https://docs.stripe.com/terminal/mobile-readers.md)をご検討ください。 また、Apps on Devices を導入してオフラインで操作することもできます。POS アプリケーションはスマートリーダー上で直接実行されるため、支払いの回収にローカルネットワークを必要としません。ただし、ネットワークがインターネットにアクセスできない場合でも、リーダーを初めて起動するときにはローカルネットワークを使用する必要があります。 > オフラインで実行するときは、販売時に決済情報が収集されます。オーソリは接続の回復後にのみ試行され、支払いが転送されます。インターネットリーダーを使用してオフラインで実行する場合、リーダーは収集した決済情報を保存します。ユーザーであるお客様が、オフライン取引に関連する支払い拒否や改ざんに関するすべてのリスクを負います。改ざんされたリーダーが支払いを Stripe に転送できない場合、またはカード発行会社が取引を拒否した場合、売上を回収する方法はなく、すでに提供した商品やサービスへの顧客の支払いを受け取れなくなることがあります。 > > カード発行会社による拒否を減らすため、以下のことが推奨されます。 > > - できる限り早急にインターネット接続を再確立して、支払いを Stripe に記録します。 - 所定の金額を超える場合は取引を制限します。 - 合計すると所定の金額を超える複数の取引を SDK が保存した場合、[すべてのオフライン決済を失敗させます](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#managing-risk)。 ## オフライン中に決済を回収する オフライン決済の手順は、オンライン決済と同じで、決済の作成、回収、処理、およびキャプチャーが含まれます。このプロセスのどの段階でも、デバイスをオンラインからオフラインにできます。 1. [オフラインモードを有効にする](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#enable-offline-mode) 1. [オフライン中にリーダーに接続する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#connect-while-offline) 1. [オフラインイベントを処理する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#handle-offline-events) 1. [オフライン中に PaymentIntent を作成する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#create-payment-intent) 1. [支払い方法を収集する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#collect-payment-method) 1. [支払いを確定する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#confirm-payment) 1. [支払いが転送されるまで待つ](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#wait-for-forward) 1. (オプション) [支払いをキャプチャーする](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#capture-payment) 1. (オプション) [オフラインで回収した支払いを調べる](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#examine-offline) ## オフラインモードを有効にする [Configuration](https://docs.stripe.com/api/terminal/configuration.md) オブジェクトまたは[ダッシュボード](https://docs.stripe.com/terminal/fleet/configurations-overview.md?dashboard-or-api=dashboard#update-the-default-configuration-for-the-account)を使用して、`Location` で[サポートされている](https://docs.stripe.com/terminal/features/operate-offline/overview.md?reader-type=internet#availability)デバイスのオフラインモードを有効にします。 ```curl curl https://api.stripe.com/v1/terminal/configurations \ -u "<>:" \ -d "offline[enabled]=true" ``` `Configuration` オブジェクトでオフラインモードを有効にすると、`Location` に[割り当てる](https://docs.stripe.com/terminal/fleet/configurations-overview.md?dashboard-or-api=api#create-a-configuration-for-an-individual-location)ことができます。また、アカウントの[デフォルト](https://docs.stripe.com/terminal/fleet/configurations-overview.md?dashboard-or-api=api#retrieve-the-account-default-configuration)の `Configuration` オブジェクトを更新すると、すべての `Locations` でオフラインモードをデフォルトで有効にすることもできます。Configuration API の変更が SDK とリーダーに反映されるまで数分かかる場合があり、反映するには、リーダーの接続をいったん切断してから再接続する必要があります。 ## オフライン中にリーダーに接続する リーダーはオンラインに接続した後、必要な `Location` 情報をローカルに保存します。後続のオフライン接続では、その `Location` に保存されている設定情報が使用されます。 オフライン時にスマートリーダーで支払いを回収するには、直前の 30 日以内のオンライン時に、あらかじめ同じ `Location` の同じタイプのモバイルリーダー (同じローカルネットワーク上にある) に接続しておく必要があります。 オンラインで接続した後、リーダーは `Location` 情報をローカルに保存し、オフラインでの操作時にその `Location` から設定情報を導出します。リーダーと POS デバイスはオンライン接続に使用される同一のローカルネットワーク上に存在する必要があります。オフライン時にネットワークを切り替えることはできません。 オフライン時にこれらの要件を満たさずリーダーに接続しようとすると、リクエストはエラーで失敗します。 | エラー | 解決策 | | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **SDK がインターネットに接続されていません** | 使用している `Location` がオフラインモード用に[設定されている](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#enable-offline-mode)ことを確認します。それ以外の場合は、オンライン時に任意のリーダーに接続してから、オフライン時に同じタイプのリーダーに接続します。 | | **選択したリーダーをオフラインでの支払い回収に使用するには、ソフトウェアの更新が必要です。** | リーダーのソフトウェアが 30 日以上更新されていません。オンライン時にリーダーに接続して更新してください。 | | **選択したリーダーをオフラインでの支払い回収に使用するには、この場所でオンラインのペアリングを行う必要があります。** | POS がこれまでオンライン中に接続していないタイプのリーダーに接続しようとしています。まずオンライン中に、このリーダーまたは同じタイプのリーダーに接続する必要があります。または、オフライン中に接続する場合は、以前オンライン中に POS が接続していたタイプのリーダーに接続できます。 | ## オフラインイベントを処理する [クライアント側] - [UserCallbacks (React Native)](https://stripe.dev/stripe-terminal-react-native/api-reference/index.html#UserCallbacks) アプリケーションが SDK のネットワークステータスと転送された支払いの状態に関する更新を受信できるようにするには、`useStripeTerminal` フックにオフラインコールバックを実装します。 ```js const { connectReader, disconnectReader, connectedReader } = useStripeTerminal({ onDidChangeOfflineStatus(status: OfflineStatus) { // Check the value of `offlineStatus` and update your UI accordingly. // // You can also check the SDK's current offline status calling // `getOfflineStatus`. }, onDidForwardingFailure(error) { // A non-specific error occurred while forwarding a PaymentIntent. // Check the error message and your integration implementation to // troubleshoot. }, onDidForwardPaymentIntent(paymentIntent, error) { // The PaymentIntent was successfully forwarded, or an error occurred. // Reconcile any local state using the backend-generated `paymentIntent.id` // and the metadata you supplied when creating the PaymentIntent. // // Note that the `paymentIntent.id` may still be null if creating the // PaymentIntent in the backend failed. }, }); ``` ## オフライン中に PaymentIntent を作成する [クライアント側] - [createPaymentIntent (React Native)](https://stripe.dev/stripe-terminal-react-native/api-reference/interfaces/StripeTerminalSdkType.html#createPaymentIntent) - [CreatePaymentIntentParams (React Native)](https://stripe.dev/stripe-terminal-react-native/api-reference/index.html#CreatePaymentIntentParams) - [OfflineStatus (React Native)](https://stripe.dev/stripe-terminal-react-native/api-reference/index.html#OfflineStatus) - [OfflineStatusDetails (React Native)](https://stripe.dev/stripe-terminal-react-native/api-reference/index.html#OfflineStatusDetails) オフラインでの操作に対応するには、SDK の `createPaymentIntent` を使用して PaymentIntent オブジェクトを作成します。これにより、SDK はオフライン時に PaymentIntents を作成し、接続が再確立された後で Stripe に転送できます。 オフラインでの実行中、`PaymentIntent` オブジェクトは null の `id` を保持します。PaymentIntent の[メタデータ](https://docs.stripe.com/payments/payment-intents.md#storing-information-in-metadata)にカスタム識別子を追加して、オフラインで作成された `PaymentIntent` オブジェクトをデータベースで照合できるようにすることをお勧めします。 オフライン支払いが Stripe に転送されたときに `PaymentIntent` イベントを受信するように [Webhook](https://docs.stripe.com/webhooks.md) エンドポイントを設定し、識別子を使用してそのイベントを `PaymentIntent` ID に関連付けることができます。 ```js const _createPaymentIntent = async (cart) => { const {error, paymentIntent} = await createPaymentIntent({ amount: cart.total, currency: cart.currency,metadata: { "unique-id": UUID().uuidString } }); } ``` `Terminal.createPaymentIntent` は `CreateConfiguration` パラメーターを受け付けます。デフォルトでは、オフラインで実行している場合、Terminal SDK はすべてのオフライン決済を保存し、接続が回復したときに Stripe のバックエンドに転送します。 この動作をカスタマイズするには、`offlineBehavior` 属性を `REQUIRE_ONLINE`、`PREFER_ONLINE` または `FORCE_OFFLINE` に設定して `CreateConfiguration` オブジェクトを渡すことができます。 #### リスクの管理 `offlineBehavior` を `REQUIRE_ONLINE` に設定すると、現在の取引はオフラインでの操作時に失敗します。たとえば、一定の金額を越える取引を拒否したり、リーダーに合計額が一定の金額を超える複数の取引が保存されている場合に、すべてのオフライン取引を拒否したりすることができます。 SDK では、リスクを管理しやすいように、次の 2 つのプロパティーを公開しています。 1. `OfflineStatus.reader.offlinePaymentsCount` 1. `OfflineStatus.reader.offlinePaymentAmountsByCurrency` #### オフライン時の遅延管理 ネットワーク接続に基づいて、Terminal SDK が支払いをオンラインとオフラインのどちらで回収するかを自動的に判断します。ただし、ネットワーク接続がアクティブであっても (取引を迅速に回収する必要があり、ネットワーク接続が遅い場合など)、オフラインでの操作が必要になる場合があります。 `offlineBehavior` を `force_offline` に設定して、接続に関係なく支払いをオフラインで回収できます。 Terminal リーダーのネットワーク接続がアクティブな状態にあるときにオフラインで回収された支払いは、バックグラウンドで転送されます。 ```js const _createPaymentIntent = async (cart) => { // Your app might want to prevent offline payments for too large an amount. // Here, we require a network connection if the payment if the amount is over 1000 usd. // Otherwise, we allow collecting offline if the network connection is unavailable.let offlineBehavior: if (cart.total > 1000000) { offlineBehavior = 'require_online' } else { offlineBehavior = 'prefer_online' } const {error, paymentIntent} = await createPaymentIntent({ amount: cart.total, currency: cart.currency,offlineBehavior, }); } ``` ## 支払い方法を収集する [クライアント側] - [CollectPaymentMethodParams (React Native)](https://stripe.dev/stripe-terminal-react-native/api-reference/index.html#CollectPaymentMethodParams) > オフラインでリーダーを実行する間は、決済の責任をお客様が負うことになります。磁気ストライプデータはなりすましが簡単なため、Stripe はオフラインでの実行中はこのオプションを許可していません。*強力な顧客認証* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase) (SCA) が要求される市場では、カードのタップもサポートされていません。 オフラインでの支払いの回収は、[オンラインでの支払いの回収](https://docs.stripe.com/terminal/payments/collect-card-payment.md#collect-payment)と似ています。スマートリーダーは、利用可能な決済オプションを顧客に自動的に表示します。 > [承認前に決済手段の詳細を調査する](https://docs.stripe.com/terminal/payments/collect-card-payment.md?terminal-sdk-platform=react-native#collect-inspect-payment-method)機能は、オフラインではサポートされていません。`CollectConfiguration` で `updatePaymentIntent` パラメーターを引き続き設定できますが、SDK がオフラインで実行されている場合、PaymentIntent の `paymentMethod` フィールドは表示されません。 ```js const _collectPaymentMethod_ = async () => { const { paymentIntent, error } = await collectPaymentMethod({ paymentIntent: paymentIntent }); if (error) { // Handle errors in your application. } // ... Confirm the payment } ``` ## 支払いを確定する [クライアント側] オフラインでの支払いの確定は、[オンラインでの支払いの確定](https://docs.stripe.com/terminal/payments/collect-card-payment.md#confirm-payment)と似ています。主な違いは、Stripe が適用するオフライン取引の上限額である 1 万 USD、または運用通貨で相当する額を超えた場合などは、オフライン固有のエラーケースを自社のシステムで処理する必要がある点です。 場合によっては、SDK がオンラインで `PaymentIntent` を作成し、オフラインで確定することがあります。これが発生すると、`PaymentIntent` に null 以外の `id` が含まれる可能性があります。オフラインで確定された場合は、`offlineDetails` が定義され、入力されます。 ```js const _confirmPaymentIntent = async () => { const { paymentIntent, error } = await confirmPaymentIntent({ paymentIntent: paymentIntent }); if (error) { // Handle offline-specific errors in your application (for example, // unsupported payment method). } if (paymentIntent.offlineDetails) { console.log('confirmed offline'); } else { console.log('confirmed online'); } } ``` #### 領収書の提供 オフライン時に支払いの完了に使用されたカードの情報が必要になることがあります。たとえば、購入時の領収書を求める顧客に領収書を生成する必要がある場合などです。 PaymentIntent がオフラインで確定された場合、その [OfflineCardPresentDetails](https://stripe.dev/stripe-terminal-react-native/api-reference/index.html#OfflineCardPresentDetails)、 を `paymentIntent.offlineDetails.offlineCardPresentDetails` から取得できます。 このハッシュには、領収書の生成に使用される [ReceiptDetails](https://stripe.dev/stripe-terminal-react-native/api-reference/index.html#ReceiptDetails)、 プロパティのほか、カード保有者の名前やカードブランドなどのカード情報が含まれます。 オフラインで処理された PaymentIntents では、`account_type` および `authorization_response_code` の領収書フィールドを使用できません。[構築済みのメール領収書](https://docs.stripe.com/terminal/features/receipts.md#prebuilt)は接続が回復し、支払いのキャプチャーが成功するまで送信されません。 ## 支払いが転送されるまで待つ [クライアント側] ネットワーク接続が復旧すると、リーダーは保存されていたオフラインの支払いの転送を自動的に開始します。 リーダーは、ネットワークステータスがオフラインであっても支払いの転送を試みます。つまり、デバイスがオフラインの場合でも、接続トークンプロバイダーは、接続トークンの提供を求めるリクエストを受け取る可能性があります。 スマートリーダーの接続解除や電源オフのタイミングが早すぎると、支払いが転送されない可能性があります。`OfflineStatus.reader.networkStatus` をクエリすると、スマートリーダーがオンライン状態にあり、支払いを転送できるか確認することができます。また、`OfflineStatus.reader.offlinePaymentsCount` をクエリすると、リーダー の転送が必要な支払いの件数を確認できます。 スマートリーダーが破損したり、支払い処理に使用できなくなった場合でも、多くの場合は保存された支払いを転送できます。Stripe への再接続を可能にするには、スマートリーダーと POS が接続されていることを確認し、インターネットへのアクセスを再確立してください。 ## 決済をキャプチャーする オフライン時には、`captureMethod` を `automatic` に設定して、PaymentIntents を作成できます。 これらの PaymentIntent を確定すると、ステータスは `requiresCapture` ではなく、`succeeded` になります。Stripe は転送後の支払いを自動的にキャプチャーします。 手動キャプチャーを選択した場合、正常に転送されオーソリされた支払いは、バックエンドまたはアプリケーションからキャプチャーする必要があります。 - バックエンドから支払いをキャプチャーするには、[Webhook](https://docs.stripe.com/webhooks.md) を使用して、`requires_capture` ステータスの PaymentIntents をリッスンします。 - アプリケーションから支払いをキャプチャーするには、リーダーが各 PaymentIntent を転送するたびに、`useStripeTerminal` フックの `onDidForwardPaymentIntent` のコールをアプリケーションが受け取るのを待ちます。PaymentIntent のステータスが `requiresCapture` であり、さらに `OfflineDetails` が null、あるいは `requiresUpload` value of `false` の場合、キャプチャーする準備ができています。 ```js const _confirmPaymentIntent = async () => { const { paymentIntent, error } = await confirmPaymentIntent({ paymentIntent: paymentIntent }); if (error) { // Handle offline-specific errors in your application (for example, // unsupported payment method). } if (paymentIntent.status == 'requiresCapture') {const offlineDetails = paymentIntent.offlineDetails; if (offlineDetails.requiresUpload === true) { // Offline payment, wait for `onDidForwardPaymentIntent` (see snippet below) } else { // Online payment, can be captured now } } else { // handle other paymentIntent.status results here } } ``` オフライン決済は、 リーダーによって `onDidForwardPaymentIntent` で転送された後にキャプチャーします。 ```js const { connectReader, disconnectReader, connectedReader } = useStripeTerminal({ onDidForwardPaymentIntent(paymentIntent, error) { if (error) { // Handle the error appropriate for your application } else if (paymentIntent.status == 'requires_capture') { // The paymentIntent is ready to be captured } else { // Handle the paymentIntent.status as appropriate. } }, }); ``` ## オフラインで回収した支払いを調べる オーソリ後は、[PaymentIntents](https://docs.stripe.com/payments/payment-intents.md) API を使用して支払いのオフライン情報を調べることができます。`PaymentIntent` の[最新の Charge](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-latest_charge) オブジェクトの [payment method details](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-offline) にアクセスすると、オフラインで回収されたものであるかどうかを判定できます。 # Java > This is a Java for when terminal-card-present-integration is terminal and terminal-sdk-platform is java and reader-type is internet. View the full page at https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments?terminal-card-present-integration=terminal&terminal-sdk-platform=java&reader-type=internet. Terminal SDK を使用すると、アプリケーションではインターネット接続がなくてもスマートリーダーを使用して支払いの回収を続行できます。 Stripe のスマートリーダー以外の POS デバイスを使用している場合でも、POS デバイスがスマートリーダーと通信できるようにするには、有効なローカルネットワークが必要になります。スマートリーダーのオフラインでの操作は、ISP の障害時など、POS とリーダーが Stripe と通信できない状況で行われます。ローカルネットワークなしでオフライン操作を行いたい場合は、Stripe Terminal の[モバイルリーダー](https://docs.stripe.com/terminal/mobile-readers.md)をご検討ください。 また、Apps on Devices を導入してオフラインで操作することもできます。POS アプリケーションはスマートリーダー上で直接実行されるため、支払いの回収にローカルネットワークを必要としません。ただし、ネットワークがインターネットにアクセスできない場合でも、リーダーを初めて起動するときにはローカルネットワークを使用する必要があります。 > オフラインで実行するときは、販売時に決済情報が収集されます。オーソリは接続の回復後にのみ試行され、支払いが転送されます。インターネットリーダーを使用してオフラインで実行する場合、リーダーは収集した決済情報を保存します。ユーザーであるお客様が、オフライン取引に関連する支払い拒否や改ざんに関するすべてのリスクを負います。改ざんされたリーダーが支払いを Stripe に転送できない場合、またはカード発行会社が取引を拒否した場合、売上を回収する方法はなく、すでに提供した商品やサービスへの顧客の支払いを受け取れなくなることがあります。 > > カード発行会社による拒否を減らすため、以下のことが推奨されます。 > > - できる限り早急にインターネット接続を再確立して、支払いを Stripe に記録します。 - 所定の金額を超える場合は取引を制限します。 - 合計すると所定の金額を超える複数の取引を SDK が保存した場合、[すべてのオフライン決済を失敗させます](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#managing-risk)。 ## オフライン中に決済を回収する オフライン決済の手順は、オンライン決済と同じで、決済の作成、回収、処理、およびキャプチャーが含まれます。このプロセスのどの段階でも、デバイスをオンラインからオフラインにできます。 1. [オフラインモードを有効にする](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#enable-offline-mode) 1. [オフライン中にリーダーに接続する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#connect-while-offline) 1. [オフラインイベントを処理する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#handle-offline-events) 1. [オフライン中に PaymentIntent を作成する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#create-payment-intent) 1. [支払い方法を収集する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#collect-payment-method) 1. [支払いを確定する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#confirm-payment) 1. [支払いが転送されるまで待つ](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#wait-for-forward) 1. (オプション) [支払いをキャプチャーする](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#capture-payment) 1. (オプション) [オフラインで回収した支払いを調べる](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#examine-offline) ## オフラインモードを有効にする [Configuration](https://docs.stripe.com/api/terminal/configuration.md) オブジェクトまたは[ダッシュボード](https://docs.stripe.com/terminal/fleet/configurations-overview.md?dashboard-or-api=dashboard#update-the-default-configuration-for-the-account)を使用して、`Location` で[サポートされている](https://docs.stripe.com/terminal/features/operate-offline/overview.md?reader-type=internet#availability)デバイスのオフラインモードを有効にします。 ```curl curl https://api.stripe.com/v1/terminal/configurations \ -u "<>:" \ -d "offline[enabled]=true" ``` `Configuration` オブジェクトでオフラインモードを有効にすると、`Location` に[割り当てる](https://docs.stripe.com/terminal/fleet/configurations-overview.md?dashboard-or-api=api#create-a-configuration-for-an-individual-location)ことができます。また、アカウントの[デフォルト](https://docs.stripe.com/terminal/fleet/configurations-overview.md?dashboard-or-api=api#retrieve-the-account-default-configuration)の `Configuration` オブジェクトを更新すると、すべての `Locations` でオフラインモードをデフォルトで有効にすることもできます。Configuration API の変更が SDK とリーダーに反映されるまで数分かかる場合があり、反映するには、リーダーの接続をいったん切断してから再接続する必要があります。 ## オフライン中にリーダーに接続する リーダーはオンラインに接続した後、必要な `Location` 情報をローカルに保存します。後続のオフライン接続では、その `Location` に保存されている設定情報が使用されます。 オフライン時にスマートリーダーで支払いを回収するには、直前の 30 日以内のオンライン時に、あらかじめ同じ `Location` の同じタイプのモバイルリーダー (同じローカルネットワーク上にある) に接続しておく必要があります。 オンラインで接続した後、リーダーは `Location` 情報をローカルに保存し、オフラインでの操作時にその `Location` から設定情報を導出します。リーダーと POS デバイスはオンライン接続に使用される同一のローカルネットワーク上に存在する必要があります。オフライン時にネットワークを切り替えることはできません。 オフライン時にこれらの要件を満たさずリーダーに接続しようとすると、リクエストはエラーで失敗します。 | エラー | 解決策 | | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **SDK がインターネットに接続されていません** | 使用している `Location` がオフラインモード用に[設定されている](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#enable-offline-mode)ことを確認します。それ以外の場合は、オンライン時に任意のリーダーに接続してから、オフライン時に同じタイプのリーダーに接続します。 | | **選択したリーダーをオフラインでの支払い回収に使用するには、ソフトウェアの更新が必要です。** | リーダーのソフトウェアが 30 日以上更新されていません。オンライン時にリーダーに接続して更新してください。 | | **選択したリーダーをオフラインでの支払い回収に使用するには、この場所でオンラインのペアリングを行う必要があります。** | POS がこれまでオンライン中に接続していないタイプのリーダーに接続しようとしています。まずオンライン中に、このリーダーまたは同じタイプのリーダーに接続する必要があります。または、オフライン中に接続する場合は、以前オンライン中に POS が接続していたタイプのリーダーに接続できます。 | ## オフラインイベントを処理する [クライアント側] - [OfflineListener (Java)](https://stripe.dev/stripe-terminal-java/external/com.stripe.stripeterminal.external.callable/-offline-listener/index.html) アプリケーションが SDK のネットワークステータスと転送された支払いの状態に関する更新を受信できるようにするには、`OfflineListener` インターフェイスを実装して Terminal SDK に渡します。オフラインで支払いを回収する前に、`OfflineListener` を設定する必要があります。 ```java public class CustomOfflineListener implements OfflineListener { @Override public void onOfflineStatusChange(@NotNull OfflineStatus offlineStatus) { // Check the value of `offlineStatus` and update your UI accordingly. For instance, // you can check the SDK's network status at `offlineStatus.sdk.networkStatus`. // // You can also check the SDK's current offline status using // `Terminal::offlineStatus`. } @Override public void onPaymentIntentForwarded(@NotNull PaymentIntent paymentIntent, @Nullable TerminalException e) { // The PaymentIntent was successfully forwarded, or an error occurred. // Reconcile any local state using the backend-generated `PaymentIntent::getId` // and the metadata you supplied when creating the PaymentIntent. // // Note that the `PaymentIntent::getId` may still be null if creating the // PaymentIntent in the backend failed. } @Override public void onForwardingFailure(@NotNull TerminalException e) { // A non-specific error occurred while forwarding a PaymentIntent. // Check the error message and your integration implementation to // troubleshoot. } } ``` ```java Terminal.init( new CustomConnectionTokenProvider(), new CustomTerminalListener(), getApplicationInfo(), LogLevel.VERBOSE, new CustomOfflineListener() ); ``` ## オフライン中に PaymentIntent を作成する [クライアント側] - [createPaymentIntent (Java)](https://stripe.dev/stripe-terminal-java/core/com.stripe.stripeterminal/-terminal/create-payment-intent.html) - [CreateConfiguration (Java)](https://stripe.dev/stripe-terminal-java/external/com.stripe.stripeterminal.external.models/-create-configuration/index.html) - [OfflineDetails (Java)](https://stripe.dev/stripe-terminal-java/external/com.stripe.stripeterminal.external.models/-offline-details/index.html) オフラインでの操作に対応するには、SDK の `createPaymentIntent` を使用して PaymentIntent オブジェクトを作成します。これにより、SDK はオフライン時に PaymentIntents を作成し、接続が再確立された後で Stripe に転送できます。 オフラインでの実行中、`PaymentIntent` オブジェクトは null の `id` を保持します。PaymentIntent の[メタデータ](https://docs.stripe.com/payments/payment-intents.md#storing-information-in-metadata)にカスタム識別子を追加して、オフラインで作成された `PaymentIntent` オブジェクトをデータベースで照合できるようにすることをお勧めします。 オフライン支払いが Stripe に転送されたときに `PaymentIntent` イベントを受信するように [Webhook](https://docs.stripe.com/webhooks.md) エンドポイントを設定し、識別子を使用してそのイベントを `PaymentIntent` ID に関連付けることができます。 ```java HashMap metadata = new HashMap<> (); metadata.put("unique-id", UUID.randomUUID().toString()); final PaymentIntentParameters params = new PaymentIntentParameters.Builder() .setAmount(cart.getTotal()) .setCurrency(cart.getCurrency()).setMetadata(metadata) .build(); final PaymentIntentCallback createPaymentCallback = new PaymentIntentCallback() { @Override public void onSuccess(@NotNull PaymentIntent paymentIntent) { System.out.println("createPaymentIntent succeeded");// If the `PaymentIntent` was created offline, its `id` field will be null. if (paymentIntent.getId() != null) { System.out.println("created online"); } else { System.out.println("created offline"); } // ... Collect a PaymentMethod } @Override public void onFailure(@NotNull TerminalException e) { // Handle errors in your application. } }; Terminal.getInstance().createPaymentIntent(params, null, createPaymentCallback); ``` `Terminal.createPaymentIntent` は `CreateConfiguration` パラメーターを受け付けます。デフォルトでは、オフラインで実行している場合、Terminal SDK はすべてのオフライン決済を保存し、接続が回復したときに Stripe のバックエンドに転送します。 この動作をカスタマイズするには、`offlineBehavior` 属性を `REQUIRE_ONLINE`、`PREFER_ONLINE` または `FORCE_OFFLINE` に設定して `CreateConfiguration` オブジェクトを渡すことができます。 #### リスクの管理 `offlineBehavior` を `REQUIRE_ONLINE` に設定すると、現在の取引はオフラインでの操作時に失敗します。たとえば、一定の金額を越える取引を拒否したり、リーダーに合計額が一定の金額を超える複数の取引が保存されている場合に、すべてのオフライン取引を拒否したりすることができます。 SDK では、リスクを管理しやすいように、次の 2 つのプロパティーを公開しています。 1. `Terminal.offlineStatus.reader.offlinePaymentsCount` 1. `Terminal.offlineStatus.reader.offlinePaymentAmountsByCurrency` #### オフライン時の遅延管理 ネットワーク接続に基づいて、Terminal SDK が支払いをオンラインとオフラインのどちらで回収するかを自動的に判断します。ただし、ネットワーク接続がアクティブであっても (取引を迅速に回収する必要があり、ネットワーク接続が遅い場合など)、オフラインでの操作が必要になる場合があります。 `CreateConfiguration` オブジェクトを `offlineBehavior` を `FORCE_OFFLINE` に設定して渡すと、接続に関係なくオフラインで支払いを回収できます。 Terminal リーダーのネットワーク接続がアクティブな状態にあるときにオフラインで回収された支払いは、バックグラウンドで転送されます。 ```java // Your app might want to prevent offline payments for too large an amount. // Here, we block the payment if the amount is over 1000 usd. // Otherwise, we allow collecting offline if the network connection is unavailable. OfflineBehavior offlineBehavior = cart.getTotal() > 1000000 ? offlineBehavior = OfflineBehavior.REQUIRE_ONLINE : OfflineBehavior.PREFER_ONLINE; final CreateConfiguration createConfig = new CreateConfiguration(offlineBehavior); Terminal.getInstance().createPaymentIntent(params, createConfig, createPaymentCallback); ``` ## 支払い方法を収集する [クライアント側] - [CollectPaymentIntentConfiguration (Java)](https://stripe.dev/stripe-terminal-java/external/com.stripe.stripeterminal.external.models/-collect-payment-intent-configuration/index.html) > オフラインでリーダーを実行する間は、決済の責任をお客様が負うことになります。磁気ストライプデータはなりすましが簡単なため、Stripe はオフラインでの実行中はこのオプションを許可していません。*強力な顧客認証* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase) (SCA) が要求される市場では、カードのタップもサポートされていません。 オフラインでの支払いの回収は、[オンラインでの支払いの回収](https://docs.stripe.com/terminal/payments/collect-card-payment.md#collect-payment)と似ています。スマートリーダーは、利用可能な決済オプションを顧客に自動的に表示します。 > オフライン時は[オーソリ前に決済手段の詳細を確認すること](https://docs.stripe.com/terminal/payments/collect-card-payment.md?terminal-sdk-platform=java#collect-inspect-payment-method)はサポートされません。`CollectPaymentIntentConfiguration` で `updatePaymentIntent` メソッドを使用することはできますが、SDK がオフラインで動作している場合は、PaymentIntent の `paymentMethod` フィールドは存在しません。 ```java final PaymentIntentCallback collectPaymentCallback = new PaymentIntentCallback() { @Override public void onSuccess(@NotNull PaymentIntent paymentIntent) { System.out.println("collectPaymentMethod succeeded"); // ... Confirm the payment } @Override public void onFailure(@NotNull TerminalException e) { e.printStackTrace(); } }; final CollectPaymentIntentConfiguration collectConfig = new CollectPaymentIntentConfiguration.Builder().build(); Terminal.getInstance().collectPaymentMethod(paymentIntent, collectConfig, collectPaymentCallback); ``` ## 支払いを確定する [クライアント側] オフラインでの支払いの確定は、[オンラインでの支払いの確定](https://docs.stripe.com/terminal/payments/collect-card-payment.md#confirm-payment)と似ています。主な違いは、Stripe が適用するオフライン取引の上限額である 1 万 USD、または運用通貨で相当する額を超えた場合などは、オフライン固有のエラーケースを自社のシステムで処理する必要がある点です。 場合によっては、SDK がオンラインで `PaymentIntent` を作成し、オフラインで確定することがあります。これが発生すると、`PaymentIntent` に null 以外の `id` が含まれる可能性があります。オフラインで確定された場合は、`offlineDetails` が定義され、入力されます。 ```java final PaymentIntentCallback confirmPaymentIntentCallback = new PaymentIntentCallback() { @Override public void onSuccess(@NotNull PaymentIntent paymentIntent) { System.out.println("confirmPaymentIntent succeeded"); // If the `PaymentIntent` was confirmed offline, `paymentIntent.getOfflineDetails()` will be definedif (paymentIntent.getOfflineDetails() != null) { System.out.println("confirmed offline"); } else { System.out.println("confirmed online"); } } @Override public void onFailure(@NotNull TerminalException e) { // Handle offline-specific errors in your application (for example, // unsupported payment method). e.printStackTrace(); } }; Terminal.getInstance().confirmPaymentIntent(paymentIntent, confirmPaymentIntentCallback); ``` #### 領収書の提供 オフライン時に支払いの完了に使用されたカードの情報が必要になることがあります。たとえば、購入時の領収書を求める顧客に領収書を生成する必要がある場合などです。 PaymentIntent がオフラインで確定された場合、その [OfflineCardPresentDetails](https://stripe.dev/stripe-terminal-java/external/com.stripe.stripeterminal.external.models/-offline-card-present-details/index.html) を `paymentIntent.offlineDetails.offlineCardPresentDetails` から取得できます。 このハッシュには、領収書の生成に使用される [ReceiptDetails](https://stripe.dev/stripe-terminal-java/external/com.stripe.stripeterminal.external.models/-receipt-details/index.html) プロパティのほか、カード保有者の名前やカードブランドなどのカード情報が含まれます。 オフラインで処理された PaymentIntents では、`account_type` および `authorization_response_code` の領収書フィールドを使用できません。[構築済みのメール領収書](https://docs.stripe.com/terminal/features/receipts.md#prebuilt)は接続が回復し、支払いのキャプチャーが成功するまで送信されません。 ## 支払いが転送されるまで待つ [クライアント側] ネットワーク接続が復旧すると、リーダーは保存されていたオフラインの支払いの転送を自動的に開始します。 リーダーは、ネットワークステータスがオフラインであっても支払いの転送を試みます。つまり、デバイスがオフラインの場合でも、接続トークンプロバイダーは、接続トークンの提供を求めるリクエストを受け取る可能性があります。 スマートリーダーの接続解除や電源オフのタイミングが早すぎると、支払いが転送されない可能性があります。`Terminal.offlineStatus.reader.networkStatus` をクエリすると、スマートリーダーがオンライン状態にあり、支払いを転送できるか確認することができます。また、`Terminal.offlineStatus.reader.offlinePaymentsCount` をクエリすると、リーダー の転送が必要な支払いの件数を確認できます。 スマートリーダーが破損したり、支払い処理に使用できなくなった場合でも、多くの場合は保存された支払いを転送できます。Stripe への再接続を可能にするには、スマートリーダーと POS が接続されていることを確認し、インターネットへのアクセスを再確立してください。 ## 決済をキャプチャーする オフライン時には、`captureMethod` を `automatic` に設定して、PaymentIntents を作成できます。 これらの PaymentIntent を確定すると、ステータスは `REQUIRES_CAPTURE` ではなく、`SUCCEEDED` になります。Stripe は転送後の支払いを自動的にキャプチャーします。 手動キャプチャーを選択した場合、正常に転送されオーソリされた支払いは、バックエンドまたはアプリケーションからキャプチャーする必要があります。 - バックエンドから支払いをキャプチャーするには、[Webhook](https://docs.stripe.com/webhooks.md) を使用して、`requires_capture` ステータスの PaymentIntents をリッスンします。 - アプリケーションから支払いをキャプチャーするには、リーダーが各 PaymentIntent を転送するたびに、`OfflineListener.OnPaymentIntentForwarded` のコールをアプリケーションが受け取るのを待ちます。PaymentIntent のステータスが `REQUIRES_CAPTURE` であり、さらに `offlineDetails` が null、あるいは `requiresUpload` value of `false` の場合、キャプチャーする準備ができています。 ```java final PaymentIntentCallback confirmPaymentIntentCallback = new PaymentIntentCallback() { @Override public void onSuccess(@NotNull PaymentIntent paymentIntent) { System.out.println("confirmPaymentIntent succeeded"); if (paymentIntent.getStatus() == PaymentIntentStatus.REQUIRES_CAPTURE) {OfflineDetails offlineDetails = paymentIntent.getOfflineDetails(); if (offlineDetails != null && offlineDetails.getRequiresUpload()) { // Offline payment, wait for `onPaymentIntentForwarded` (see snippet below) } else { // Online payment, can be captured now } } else { // Handle other status results here } } @Override public void onFailure(@NotNull TerminalException e) { // Handle offline-specific errors in your application (for example, // unsupported payment method). } }; Terminal.getInstance().confirmPaymentIntent(paymentIntent, confirmPaymentIntentCallback); ``` オフライン決済は、 リーダーによって `OfflineListener::onPaymentIntentForwarded` で転送された後にキャプチャーします。 ```java public class CustomOfflineListener implements OfflineListener { // ... @Override public void onPaymentIntentForwarded(@NotNull PaymentIntent paymentIntent, @Nullable TerminalException e) { if (e != null) { // Handle the error appropriate for your application } else if (paymentIntent.getStatus() == PaymentIntentStatus.REQUIRES_CAPTURE) { // The paymentIntent is ready to be captured } else { // Handle other status results here } } // ... } ``` ## オフラインで回収した支払いを調べる オーソリ後は、[PaymentIntents](https://docs.stripe.com/payments/payment-intents.md) API を使用して支払いのオフライン情報を調べることができます。`PaymentIntent` の[最新の Charge](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-latest_charge) オブジェクトの [payment method details](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-offline) にアクセスすると、オフラインで回収されたものであるかどうかを判定できます。 # .NET > This is a .NET for when terminal-card-present-integration is terminal and terminal-sdk-platform is dotnet and reader-type is internet. View the full page at https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments?terminal-card-present-integration=terminal&terminal-sdk-platform=dotnet&reader-type=internet. Terminal SDK を使用すると、アプリケーションではインターネット接続がなくてもスマートリーダーを使用して支払いの回収を続行できます。 Stripe のスマートリーダー以外の POS デバイスを使用している場合でも、POS デバイスがスマートリーダーと通信できるようにするには、有効なローカルネットワークが必要になります。スマートリーダーのオフラインでの操作は、ISP の障害時など、POS とリーダーが Stripe と通信できない状況で行われます。ローカルネットワークなしでオフライン操作を行いたい場合は、Stripe Terminal の[モバイルリーダー](https://docs.stripe.com/terminal/mobile-readers.md)をご検討ください。 また、Apps on Devices を導入してオフラインで操作することもできます。POS アプリケーションはスマートリーダー上で直接実行されるため、支払いの回収にローカルネットワークを必要としません。ただし、ネットワークがインターネットにアクセスできない場合でも、リーダーを初めて起動するときにはローカルネットワークを使用する必要があります。 > オフラインで実行するときは、販売時に決済情報が収集されます。オーソリは接続の回復後にのみ試行され、支払いが転送されます。インターネットリーダーを使用してオフラインで実行する場合、リーダーは収集した決済情報を保存します。ユーザーであるお客様が、オフライン取引に関連する支払い拒否や改ざんに関するすべてのリスクを負います。改ざんされたリーダーが支払いを Stripe に転送できない場合、またはカード発行会社が取引を拒否した場合、売上を回収する方法はなく、すでに提供した商品やサービスへの顧客の支払いを受け取れなくなることがあります。 > > カード発行会社による拒否を減らすため、以下のことが推奨されます。 > > - できる限り早急にインターネット接続を再確立して、支払いを Stripe に記録します。 - 所定の金額を超える場合は取引を制限します。 - 合計すると所定の金額を超える複数の取引を SDK が保存した場合、[すべてのオフライン決済を失敗させます](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#managing-risk)。 ## オフライン中に決済を回収する オフライン決済の手順は、オンライン決済と同じで、決済の作成、回収、処理、およびキャプチャーが含まれます。このプロセスのどの段階でも、デバイスをオンラインからオフラインにできます。 1. [オフラインモードを有効にする](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#enable-offline-mode) 1. [オフライン中にリーダーに接続する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#connect-while-offline) 1. [オフラインイベントを処理する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#handle-offline-events) 1. [オフライン中に PaymentIntent を作成する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#create-payment-intent) 1. [支払い方法を収集する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#collect-payment-method) 1. [支払いを確定する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#confirm-payment) 1. [支払いが転送されるまで待つ](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#wait-for-forward) 1. (オプション) [支払いをキャプチャーする](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#capture-payment) 1. (オプション) [オフラインで回収した支払いを調べる](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#examine-offline) ## オフラインモードを有効にする [Configuration](https://docs.stripe.com/api/terminal/configuration.md) オブジェクトまたは[ダッシュボード](https://docs.stripe.com/terminal/fleet/configurations-overview.md?dashboard-or-api=dashboard#update-the-default-configuration-for-the-account)を使用して、`Location` で[サポートされている](https://docs.stripe.com/terminal/features/operate-offline/overview.md?reader-type=internet#availability)デバイスのオフラインモードを有効にします。 ```curl curl https://api.stripe.com/v1/terminal/configurations \ -u "<>:" \ -d "offline[enabled]=true" ``` `Configuration` オブジェクトでオフラインモードを有効にすると、`Location` に[割り当てる](https://docs.stripe.com/terminal/fleet/configurations-overview.md?dashboard-or-api=api#create-a-configuration-for-an-individual-location)ことができます。また、アカウントの[デフォルト](https://docs.stripe.com/terminal/fleet/configurations-overview.md?dashboard-or-api=api#retrieve-the-account-default-configuration)の `Configuration` オブジェクトを更新すると、すべての `Locations` でオフラインモードをデフォルトで有効にすることもできます。Configuration API の変更が SDK とリーダーに反映されるまで数分かかる場合があり、反映するには、リーダーの接続をいったん切断してから再接続する必要があります。 ## オフライン中にリーダーに接続する リーダーはオンラインに接続した後、必要な `Location` 情報をローカルに保存します。後続のオフライン接続では、その `Location` に保存されている設定情報が使用されます。 オフライン時にスマートリーダーで支払いを回収するには、直前の 30 日以内のオンライン時に、あらかじめ同じ `Location` の同じタイプのモバイルリーダー (同じローカルネットワーク上にある) に接続しておく必要があります。 オンラインで接続した後、リーダーは `Location` 情報をローカルに保存し、オフラインでの操作時にその `Location` から設定情報を導出します。リーダーと POS デバイスはオンライン接続に使用される同一のローカルネットワーク上に存在する必要があります。オフライン時にネットワークを切り替えることはできません。 オフライン時にこれらの要件を満たさずリーダーに接続しようとすると、リクエストはエラーで失敗します。 | エラー | 解決策 | | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **SDK がインターネットに接続されていません** | 使用している `Location` がオフラインモード用に[設定されている](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#enable-offline-mode)ことを確認します。それ以外の場合は、オンライン時に任意のリーダーに接続してから、オフライン時に同じタイプのリーダーに接続します。 | | **選択したリーダーをオフラインでの支払い回収に使用するには、ソフトウェアの更新が必要です。** | リーダーのソフトウェアが 30 日以上更新されていません。オンライン時にリーダーに接続して更新してください。 | | **選択したリーダーをオフラインでの支払い回収に使用するには、この場所でオンラインのペアリングを行う必要があります。** | POS がこれまでオンライン中に接続していないタイプのリーダーに接続しようとしています。まずオンライン中に、このリーダーまたは同じタイプのリーダーに接続する必要があります。または、オフライン中に接続する場合は、以前オンライン中に POS が接続していたタイプのリーダーに接続できます。 | ## オフラインイベントを処理する [クライアント側] アプリケーションが SDK のネットワークステータスと転送された支払いの状態に関する更新を受信できるようにするには、`IOfflineListener` インターフェイスを実装して、それを Terminal SDK に渡します。オフラインで支払いを回収する前に、`IOfflineListener` を設定する必要があります。 ```csharp using TerminalSdk.Api; namespace StripeExampleApi; public class CustomOfflineListener : IOfflineListener { public void OnOfflineStatusChange(OfflineStatus offlineStatus) { // Check the value of `offlineStatus` and update your UI accordingly. For instance, // you can check the reader's network status at `offlineStatus.Reader.NetworkStatus`. // // You can also check the reader's current offline status using // `Terminal.OfflineStatus`. } public void OnPaymentIntentForwarded(PaymentIntent paymentIntent, TerminalException? e) { // The PaymentIntent was successfully forwarded, or an error occurred. // Reconcile any local state using the backend-generated `paymentIntent.Id` // and the metadata you supplied when creating the PaymentIntent. // // Note that the `PaymentIntent.Id` may still be null if creating the // PaymentIntent in the backend failed. } public void OnForwardingFailure(TerminalException e) { // A non-specific error occurred while forwarding a PaymentIntent. // Check the error message and your integration implementation to // troubleshoot. } } ``` ```csharp Terminal.InitTerminal( new CustomConnectionTokenProvider(), new CustomTerminalListener(), new CustomOfflineListener(), new ApplicationInformation.Builder() .SetName("Terminal Test Console") .SetVersion("0.0.0.1") .SetDataDirectory(new DirectoryInfo("C:\\TerminalSDK")) .Build() ); ``` ## オフライン中に PaymentIntent を作成する [クライアント側] オフラインでの操作に対応するには、SDK の `CreatePaymentIntentAsync` を使用して PaymentIntent オブジェクトを作成します。これにより、SDK はオフライン時に PaymentIntents を作成し、接続が再確立された後で Stripe に転送できます。 オフラインでの実行中、`PaymentIntent` オブジェクトは null の `Id` を保持します。PaymentIntent の[メタデータ](https://docs.stripe.com/payments/payment-intents.md#storing-information-in-metadata)にカスタム識別子を追加して、オフラインで作成された `PaymentIntent` オブジェクトをデータベースで照合できるようにすることをお勧めします。 オフライン支払いが Stripe に転送されたときに `PaymentIntent` イベントを受信するように [Webhook](https://docs.stripe.com/webhooks.md) エンドポイントを設定し、識別子を使用してそのイベントを `PaymentIntent` ID に関連付けることができます。 ```csharp // Build up parameters for creating a `PaymentIntent` var paymentIntentParameters = new PaymentIntentParameters.Builder() .SetAmount(cart.Total) .SetCurrency(cart.Currency).SetMetadata(new Dictionary() { { "unique-id", Guid.NewGuid().ToString() } }) .Build(); try { var paymentIntent = await Terminal.Instance.CreatePaymentIntentAsync(paymentIntentParameters, null); _logger.LogDebug("CreatePaymentIntentAsync succeeded");// If the `PaymentIntent` was created offline, its `Id` field will be null. if (paymentIntent.Id != null) { _logger.LogDebug("created online"); } else { _logger.LogDebug("created offline"); } // ... Collect a PaymentMethod } catch (TerminalException ex) { _logger.LogError(ex, "CreatePaymentIntentAsync failed"); // Handle errors in your application. } ``` `Terminal.CreatePaymentIntentAsync` は `CreateConfiguration` パラメーターを受け付けます。デフォルトでは、オフラインで実行している場合、Terminal SDK はすべてのオフライン決済を保存し、接続が回復したときに Stripe のバックエンドに転送します。 この動作をカスタマイズするには、`OfflineBehavior` 属性を `RequireOnline`、`PreferOnline` または `ForceOffline` に設定して `CreateConfiguration` オブジェクトを渡すことができます。 #### リスクの管理 `OfflineBehavior` を `RequireOnline` に設定すると、現在の取引はオフラインでの操作時に失敗します。たとえば、一定の金額を越える取引を拒否したり、リーダーに合計額が一定の金額を超える複数の取引が保存されている場合に、すべてのオフライン取引を拒否したりすることができます。 SDK では、リスクを管理しやすいように、次の 2 つのプロパティーを公開しています。 1. `Terminal.OfflineStatus.Reader.OfflinePaymentsCount` 1. `Terminal.OfflineStatus.Reader.OfflinePaymentAmountsByCurrency` #### オフライン時の遅延管理 ネットワーク接続に基づいて、Terminal SDK が支払いをオンラインとオフラインのどちらで回収するかを自動的に判断します。ただし、ネットワーク接続がアクティブであっても (取引を迅速に回収する必要があり、ネットワーク接続が遅い場合など)、オフラインでの操作が必要になる場合があります。 `CreateConfiguration` オブジェクトを `OfflineBehavior` を `ForceOffline` に設定して渡すと、接続に関係なくオフラインで支払いを回収できます。 Terminal リーダーのネットワーク接続がアクティブな状態にあるときにオフラインで回収された支払いは、バックグラウンドで転送されます。 ```csharp // Your app might want to prevent offline payments for too large an amount. // Here, we require a network connection if the payment amount is over 1000 usd. // Otherwise, we allow collecting offline if the network connection is unavailable.var offlineBehavior = OfflineBehavior.PreferOnline; if (cart.total > 1000000) { offlineBehavior = OfflineBehavior.RequireOnline; } var createConfig = new CreateConfiguration.Builder() .SetOfflineBehavior(offlineBehavior) .Build(); var paymentIntent = await Terminal.Instance.CreatePaymentIntentAsync(paymentIntentParameters, createConfig); _logger.LogDebug("CreatePaymentIntentAsync succeeded"); // ...continue transaction ``` ## 支払い方法を収集する [クライアント側] > オフラインでリーダーを実行する間は、決済の責任をお客様が負うことになります。磁気ストライプデータはなりすましが簡単なため、Stripe はオフラインでの実行中はこのオプションを許可していません。*強力な顧客認証* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase) (SCA) が要求される市場では、カードのタップもサポートされていません。 オフラインでの支払いの回収は、[オンラインでの支払いの回収](https://docs.stripe.com/terminal/payments/collect-card-payment.md#collect-payment)と似ています。スマートリーダーは、利用可能な決済オプションを顧客に自動的に表示します。 > [承認前に決済手段の詳細を調査する](https://docs.stripe.com/terminal/payments/collect-card-payment.md?terminal-sdk-platform=dotnet#collect-inspect-payment-method)機能は、オフラインではサポートされていません。`CollectConfiguration` で `SetUpdatePaymentIntent` メソッドを引き続き使用できますが、SDK がオフラインで実行されている場合、PaymentIntent の `paymentMethod` フィールドは表示されません。 ```csharp try { var collectConfig = new CollectConfiguration.Builder() .Build(); var collectedPaymentIntent = await Terminal.Instance.CollectPaymentMethodAsync(paymentIntent, collectConfig); _logger.LogDebug("CollectPaymentMethodAsync succeeded"); // ... Confirm the payment } catch (TerminalException ex) { // Handle errors in your application. } ``` ## 支払いを確定する [クライアント側] オフラインでの支払いの確定は、[オンラインでの支払いの確定](https://docs.stripe.com/terminal/payments/collect-card-payment.md#confirm-payment)と似ています。主な違いは、Stripe が適用するオフライン取引の上限額である 1 万 USD、または運用通貨で相当する額を超えた場合などは、オフライン固有のエラーケースを自社のシステムで処理する必要がある点です。 場合によっては、SDK がオンラインで `PaymentIntent` を作成し、オフラインで確定することがあります。これが発生すると、`PaymentIntent` に null 以外の `Id` が含まれる可能性があります。オフラインで確定された場合は、`OfflineDetails` が定義され、入力されます。 ```csharp try { var confirmedPaymentIntent = await Terminal.Instance.ConfirmPaymentIntentAsync(collectedPaymentIntent); } catch (TerminalException ex) { // Handle offline-specific errors in your application (for example, // unsupported payment method). } ``` #### 領収書の提供 オフライン時に支払いの完了に使用されたカードの情報が必要になることがあります。たとえば、購入時の領収書を求める顧客に領収書を生成する必要がある場合などです。 PaymentIntent がオフラインで確定された場合、その OfflineCardPresentDetails を `paymentIntent.OfflineDetails.OfflineCardPresentDetails`、 から取得できます。 このハッシュには、領収書の生成に使用される ReceiptDetails プロパティのほか、カード保有者の名前やカードブランドなどのカード情報が含まれます。 オフラインで処理された PaymentIntents では、`account_type` および `authorization_response_code` の領収書フィールドを使用できません。[構築済みのメール領収書](https://docs.stripe.com/terminal/features/receipts.md#prebuilt)は接続が回復し、支払いのキャプチャーが成功するまで送信されません。 ## 支払いが転送されるまで待つ [クライアント側] ネットワーク接続が復旧すると、リーダーは保存されていたオフラインの支払いの転送を自動的に開始します。 リーダーは、ネットワークステータスがオフラインであっても支払いの転送を試みます。つまり、デバイスがオフラインの場合でも、接続トークンプロバイダーは、接続トークンの提供を求めるリクエストを受け取る可能性があります。 スマートリーダーの接続解除や電源オフのタイミングが早すぎると、支払いが転送されない可能性があります。`Terminal.OfflineStatus.Reader.NetworkStatus` をクエリすると、スマートリーダーがオンライン状態にあり、支払いを転送できるか確認することができます。また、`Terminal.OfflineStatus.Reader.OfflinePaymentsCount` をクエリすると、リーダー の転送が必要な支払いの件数を確認できます。 スマートリーダーが破損したり、支払い処理に使用できなくなった場合でも、多くの場合は保存された支払いを転送できます。Stripe への再接続を可能にするには、スマートリーダーと POS が接続されていることを確認し、インターネットへのアクセスを再確立してください。 ## 決済をキャプチャーする オフライン時には、`CaptureMethod` を `Automatic` に設定して、PaymentIntents を作成できます。 これらの PaymentIntent を確定すると、ステータスは `RequiresCapture` ではなく、`Succeeded` になります。Stripe は転送後の支払いを自動的にキャプチャーします。 手動キャプチャーを選択した場合、正常に転送されオーソリされた支払いは、バックエンドまたはアプリケーションからキャプチャーする必要があります。 - バックエンドから支払いをキャプチャーするには、[Webhook](https://docs.stripe.com/webhooks.md) を使用して、`requires_capture` ステータスの PaymentIntents をリッスンします。 - アプリケーションから支払いをキャプチャーするには、リーダーが各 PaymentIntent を転送するたびに、`OfflineListener.OnPaymentIntentForwarded` のコールをアプリケーションが受け取るのを待ちます。PaymentIntent のステータスが `RequiresCapture` であり、さらに `OfflineDetails` が null、あるいは `RequiresUpload` value of `false` の場合、キャプチャーする準備ができています。 ```csharp try { var confirmedPaymentIntent = await Terminal.Instance.ConfirmPaymentIntentAsync(collectedPaymentIntent); _logger.LogDebug("ConfirmPaymentIntentAsync succeeded"); if (paymentIntent.status == PaymentIntentStatus.RequiresCapture) {var offlineDetails = paymentIntent.OfflineDetails; if (offlineDetails?.RequiresUpload == true) { // Offline payment, wait for `OnPaymentIntentForwarded` (see snippet below) } else { // Online payment, can be captured now } } else { // handle other paymentIntent.Status results here } } catch (TerminalException ex) { // Handle offline-specific errors in your application (for example, // unsupported payment method). _logger.LogError(ex, "ConfirmPaymentIntentAsync failed"); } ``` オフライン決済は、 リーダーによって `IOfflineListener.OnPaymentIntentForwarded` で転送された後にキャプチャーします。 ```csharp using TerminalSdk.Api; namespace StripeExampleApi; public class CustomOfflineListener : IOfflineListener { public void OnPaymentIntentForwarded(PaymentIntent paymentIntent, TerminalException? e) { if (e != null) { // Handle the error appropriate for your application } else if (paymentIntent.Status == PaymentIntentStatus.RequiresCapture) { // The paymentIntent is ready to be captured } else { // Handle the paymentIntent.Status as appropriate. } } // ... } ``` ## オフラインで回収した支払いを調べる オーソリ後は、[PaymentIntents](https://docs.stripe.com/payments/payment-intents.md) API を使用して支払いのオフライン情報を調べることができます。`PaymentIntent` の[最新の Charge](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-latest_charge) オブジェクトの [payment method details](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-offline) にアクセスすると、オフラインで回収されたものであるかどうかを判定できます。 # iOS > This is a iOS for when terminal-card-present-integration is terminal and terminal-sdk-platform is ios and reader-type is simulated. View the full page at https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments?terminal-card-present-integration=terminal&terminal-sdk-platform=ios&reader-type=simulated. Terminal SDK を使用すると、アプリケーションではネットワーク接続なしで、シミュレーションされたリーダーを使用して支払いの回収を続行できます。 > オフラインで実行するときは、販売時に決済情報が収集されます。オーソリは接続の回復後にのみ試行され、支払いが転送されます。ユーザーであるお客様が、オフライン取引に関連する支払い拒否や改ざんに関するすべてのリスクを負います。改ざんされたリーダーが支払いを Stripe に転送できない場合、またはカード発行会社が取引を拒否した場合、売上を回収する方法はなく、すでに提供した商品やサービスへの顧客の支払いを受け取れなくなることがあります。 > > カード発行会社による拒否を減らすため、以下のことが推奨されます。 > > - できる限り早急にインターネット接続を再確立して、支払いを Stripe に記録します。 - 所定の金額を超える場合は取引を制限します。 - 合計すると所定の金額を超える複数の取引を SDK が保存した場合、[すべてのオフライン決済を失敗させます](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#managing-risk)。 ## オフライン中に決済を回収する オフライン決済の手順は、オンライン決済と同じで、決済の作成、回収、処理、およびキャプチャーが含まれます。このプロセスのどの段階でも、デバイスをオンラインからオフラインにできます。 1. [オフラインモードを有効にする](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#enable-offline-mode) 1. [オフライン中にリーダーに接続する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#connect-while-offline) 1. [オフラインイベントを処理する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#handle-offline-events) 1. [オフライン中に PaymentIntent を作成する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#create-payment-intent) 1. [支払い方法を収集する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#collect-payment-method) 1. [支払いを確定する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#confirm-payment) 1. [支払いが転送されるまで待つ](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#wait-for-forward) 1. (オプション) [支払いをキャプチャーする](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#capture-payment) 1. (オプション) [オフラインで回収した支払いを調べる](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#examine-offline) ## オフラインモードを有効にする オフラインモードを使用するには、アプリケーションが Terminal iOS SDK のバージョン `3.3.0` 以降を使用している必要があります。 オフラインモードを有効にするように、シミュレーションされたリーダーを設定します。 #### Swift ``` let simulatorConfiguration = Terminal.shared.simulatorConfiguration simulatorConfiguration.offlineEnabled = true ``` ## オフライン中にリーダーに接続する SDK はオンラインに接続した後、必要な `Location` 情報をローカルに保存します。後続のオフライン接続では、その `Location` に保存されている設定情報が使用されます。 オフライン時にスマートリーダーで支払いを回収するには、直前の 30 日以内のオンライン時に、あらかじめ同じ `Location` の同じタイプのモバイルリーダーに接続し、また期間内にリーダーのソフトウェアを更新する必要があります。 オフライン時にこれらの要件を満たさずリーダーに接続しようとすると、リクエストはエラーで失敗します。 | エラー | 解決策 | | ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | | **SDK がインターネットに接続されていません** | シミュレーションされたリーダーの `SimulatorConfiguration` でオフラインモードが有効になっていることを確認してください。それ以外の場合は、オンライン時に任意のリーダーに接続してから、オフライン時に同じタイプのリーダーに接続します。 | | **選択したリーダーをオフラインでの支払い回収に使用するには、ソフトウェアの更新が必要です。** | SDK の `SimulatorConfiguration` で `SimulateReaderUpdate` の値を `SimulateReaderUpdateRequiredForOffline` に設定しました。オフライン接続を許可するには、別の値を使用してください。 | | **選択したリーダーをオフラインでの支払い回収に使用するには、この場所でオンラインのペアリングを行う必要があります。** | POS がこれまでオンライン中に接続していないタイプのリーダーに接続しようとしています。まずオンライン中に、このリーダーまたは同じタイプのリーダーに接続する必要があります。または、オフライン中に接続する場合は、以前オンライン中に POS が接続していたタイプのリーダーに接続できます。 | ## オフラインイベントを処理する [クライアント側] - [OfflineDelegate (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Protocols/SCPOfflineDelegate.html) アプリケーションが SDK のネットワークステータスと転送された支払いの状態に関する更新を受信できるようにするには、`OfflineDelegate` プロトコルを実装して Terminal SDK に渡します。オフラインで支払いを回収する前に、`OfflineDelegate` を設定する必要があります。 #### Swift ```swift import StripeTerminal class CustomOfflineDelegate: OfflineDelegate { func terminal(_ terminal: Terminal, didChangeOfflineStatus offlineStatus: OfflineStatus) { // Check the value of `offlineStatus` and update your UI accordingly. For instance, // you can check the SDK's network status at `offlineStatus.sdk.networkStatus`. // // You can also check the SDK's current offline status using // `Terminal.shared.offlineStatus.sdk.networkStatus`. } func terminal(_ terminal: Terminal, didForwardPaymentIntent intent: PaymentIntent, error: Error?) { // The PaymentIntent was successfully forwarded, or an error occurred. // Reconcile any local state using the backend-generated `PaymentIntent.stripeId` // and the metadata you supplied when creating the PaymentIntent. // // Note that the `PaymentIntent.stripeId` may still be nil if creating the // PaymentIntent in the backend failed. } func terminal(_ terminal: Terminal, didReportForwardingError error: Error) { // A non-specific error occurred while forwarding a PaymentIntent. // Check the error message and your integration implementation to // troubleshoot. } } ``` #### Swift ```swift import UIKit import StripeTerminal @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { Terminal.initWithTokenProvider(APIClient.shared) Terminal.shared.offlineDelegate = CustomOfflineDelegate() // ... return true } // ... } ``` ## オフライン中に PaymentIntent を作成する [クライアント側] - [createPaymentIntent (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPTerminal.html#/c:objc\(cs\)SCPTerminal\(im\)createPaymentIntent:completion:) - [CreateConfiguration (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPCreateConfiguration.html) - [OfflineDetails (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPOfflineDetails.html) オフラインでの操作に対応するには、SDK の `createPaymentIntent` を使用して PaymentIntent オブジェクトを作成します。これにより、SDK はオフライン時に PaymentIntents を作成し、接続が再確立された後で Stripe に転送できます。 オフラインでの実行中、`PaymentIntent` オブジェクトは null の `stripeId` を保持します。PaymentIntent の[メタデータ](https://docs.stripe.com/payments/payment-intents.md#storing-information-in-metadata)にカスタム識別子を追加して、オフラインで作成された `PaymentIntent` オブジェクトをデータベースで照合できるようにすることをお勧めします。 [ステップ 7](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#wait-for-forward) で `PaymentIntent` が正常に Stripe に転送されたら、カスタム識別子を使用して `OfflineDelegate.didForwardPaymentIntent` コールバックで調整します。 #### Swift ```swift import UIKit import StripeTerminal class PaymentViewController: UIViewController { // Action for a "Checkout" button func checkoutAction() throws { // Populate the correct transaction amount from your application. let amount = UInt(10_00) // Build up parameters for creating a `PaymentIntent` let params = try PaymentIntentParametersBuilder( amount: amount, currency: "usd" ).setMetadata(["offlineId": UUID().uuidString]) .build() Terminal.shared.createPaymentIntent(params) { createResult, createError in if let error = createError { // Handle errors in your application. print("createPaymentIntent failed: \(error)") } else if let paymentIntent = createResult { print("createPaymentIntent succeeded")// If the `PaymentIntent` was created offline, its `stripeId` field will be nil. if let onlineCreatedId = paymentIntent.stripeId { print("created online"); } else { print("created offline") } } } } } ``` `Terminal.createPaymentIntent` は `CreateConfiguration` パラメーターを受け付けます。デフォルトでは、オフラインで実行している場合、Terminal SDK はすべてのオフライン決済を保存し、接続が回復したときに Stripe のバックエンドに転送します。 この動作をカスタマイズするには、`offlineBehavior` 属性を `REQUIRE_ONLINE`、`PREFER_ONLINE` または `FORCE_OFFLINE` に設定して `CreateConfiguration` オブジェクトを渡すことができます。 #### リスクの管理 `offlineBehavior` を `REQUIRE_ONLINE` に設定すると、現在の取引はオフラインでの操作時に失敗します。たとえば、一定の金額を越える取引を拒否したり、SDK に合計額が一定の金額を超える複数の取引が保存されている場合に、すべてのオフライン取引を拒否したりすることができます。 SDK では、リスクを管理しやすいように、次の 2 つのプロパティーを公開しています。 1. `Terminal.offlineStatus.sdk.offlinePaymentsCount` 1. `Terminal.offlineStatus.sdk.offlinePaymentAmountsByCurrency` #### オフライン時の遅延管理 ネットワーク接続に基づいて、Terminal SDK が支払いをオンラインとオフラインのどちらで回収するかを自動的に判断します。ただし、ネットワーク接続がアクティブであっても (取引を迅速に回収する必要があり、ネットワーク接続が遅い場合など)、オフラインでの操作が必要になる場合があります。 `CreateConfiguration` オブジェクトを `offlineBehavior` を `FORCE_OFFLINE` に設定して渡すと、接続に関係なくオフラインで支払いを回収できます。 Terminal SDK のネットワーク接続がアクティブな状態にあるときにオフラインで回収された支払いは、バックグラウンドで転送されます。 #### Swift ```swift import UIKit import StripeTerminal class PaymentViewController: UIViewController { // Action for a "Checkout" button func checkoutAction() throws { // ...build up parameters and callback for creating a `PaymentIntent` // Your app might want to prevent offline payments for too large an amount. // Here, we block the payment if the amount is over 1000 usd. // Otherwise, we allow collecting offline if the network connection is unavailable.let offlineBehavior: SCPOfflineBehavior = { if amount > UInt(1_000_00) { return .requireOnline } else { return .preferOnline } }() let createConfiguration = try CreateConfigurationBuilder().setOfflineBehavior(offlineBehavior).build() Terminal.shared.createPaymentIntent(params, createConfig: createConfiguration) { createResult, createError in // handle success or failure } } } ``` ## 支払い方法を収集する [クライアント側] - [CollectPaymentIntentConfiguration (iOS)](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPCollectPaymentIntentConfiguration.html) > オフラインでリーダーを実行する間は、決済の責任をお客様が負うことになります。磁気ストライプデータはなりすましが簡単なため、Stripe はオフラインでの実行中はこのオプションを許可していません。*強力な顧客認証* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase) (SCA) が要求される市場では、カードのタップもサポートされていません。 オフラインでの支払いの回収は、[オンラインでの支払いの回収](https://docs.stripe.com/terminal/payments/collect-card-payment.md#collect-payment)と似ています。`didRequestReaderInput` メソッドを使用して、有効なカード提示オプションを顧客に表示します。 > Readers don’t support [inspecting payment method details before authorization](https://docs.stripe.com/terminal/payments/collect-card-payment.md?terminal-sdk-platform=ios#collect-inspect-payment-method) while offline. Although you can still use the `initWithUpdatePaymentIntent` parameter in `CollectPaymentIntentConfiguration`, the `paymentMethod` field on the PaymentIntent is absent if the SDK is operating offline. #### Swift ```swift import UIKit import StripeTerminal class PaymentViewController: UIViewController { // Action for a "Checkout" button func checkoutAction() { Terminal.shared.collectPaymentMethod(paymentIntent) { collectResult, collectError in if let error = collectError { print("collectPaymentMethod failed: \(error)") } else if let paymentIntent = collectResult { print("collectPaymentMethod succeeded") // ... Confirm the payment } } } } ``` ## 支払いを確定する [クライアント側] オフラインでの支払いの確定は、[オンラインでの支払いの確定](https://docs.stripe.com/terminal/payments/collect-card-payment.md#confirm-payment)と似ています。主な違いは、Stripe が適用するオフライン取引の上限額である 1 万 USD、または運用通貨で相当する額を超えた場合などは、オフライン固有のエラーケースを自社のシステムで処理する必要がある点です。 場合によっては、SDK がオンラインで `PaymentIntent` を作成し、オフラインで確定することがあります。これが発生すると、`PaymentIntent` に null 以外の `stripeId` が含まれる可能性があります。オフラインで確定された場合は、`offlineDetails` が定義され、入力されます。 シミュレーション済みのテストカードを使用するように、シミュレーション済みのリーダーを設定できます。これにより、確定時にオフライン特有のさまざまなフローをテストできます。たとえば、次のことができます。 - シミュレーション済みの Interac テストカード番号を使用して、サポート対象ではない決済手段の `PaymentIntent` をオフラインで確定する際のエラーをテストする - [支払いが拒否される](https://docs.stripe.com/terminal/references/testing.md#test-cards-for-specific-error-cases)テストカード番号を使用して、保存されている `PaymentIntent` の転送の失敗をテストする 利用できるオプションの一覧については、[Stripe Terminal をテストする](https://docs.stripe.com/terminal/references/testing.md)をご覧ください。 #### Swift ```swift import UIKit import StripeTerminal class PaymentViewController: UIViewController { // Action for a "Checkout" button func checkoutAction() { Terminal.shared.confirmPaymentIntent(paymentIntent) { confirmResult, confirmError in if let error = confirmError { // Handle offline-specific errors in your application (for example, // unsupported payment method). print("confirmPaymentIntent failed: \(error)") } else if let confirmedPaymentIntent= confirmResult {print("confirmPaymentIntent succeeded") if let offlineDetails = paymentIntent.offlineDetails { print("confirmed offline"); } else { print("confirmed online") } } } } } ``` #### 領収書の提供 オフライン時に支払いの完了に使用されたカードの情報が必要になることがあります。たとえば、購入時の領収書を求める顧客に領収書を生成する必要がある場合などです。 PaymentIntent がオフラインで確定された場合、その [OfflineCardPresentDetails](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPOfflineCardPresentDetails.html)、 を `paymentIntent.offlineDetails.offlineCardPresentDetails` から取得できます。 このハッシュには、領収書の生成に使用される [ReceiptDetails](https://stripe.dev/stripe-terminal-ios/docs/Classes/SCPReceiptDetails.html)、 プロパティのほか、カード保有者の名前やカードブランドなどのカード情報が含まれます。 オフラインで処理された PaymentIntents では、`account_type` および `authorization_response_code` の領収書フィールドを使用できません。[構築済みのメール領収書](https://docs.stripe.com/terminal/features/receipts.md#prebuilt)は接続が回復し、支払いのキャプチャーが成功するまで送信されません。 ## 支払いが転送されるまで待つ [クライアント側] インターネットアクセスが復旧すると、SDK は保存されていたオフラインの支払いの転送を自動的に開始します。 SDK は、ネットワークステータスがオフラインであっても支払いの転送を試みます。つまり、デバイスがオフラインの場合でも、接続トークンプロバイダーは、接続トークンの提供を求めるリクエストを受け取る可能性があります。 POS デバイスの電源オフのタイミングが早すぎると、支払いが転送されない可能性があります。`Terminal.offlineStatus.sdk.networkStatus` をクエリすると、POS がオンライン状態にあり、支払いを転送できるか確認することができます。また、`Terminal.offlineStatus.sdk.offlinePaymentsCount` をクエリすると、Terminal SDK の転送が必要な支払いの件数を確認できます。 ## 決済をキャプチャーする オフライン時には、`captureMethod` を `automatic` に設定して、PaymentIntents を作成できます。 これらの PaymentIntent を確定すると、ステータスは `RequiresCapture` ではなく、`Succeeded` になります。Stripe は転送後の支払いを自動的にキャプチャーします。 手動キャプチャーを選択した場合、正常に転送されオーソリされた支払いは、バックエンドまたはアプリケーションからキャプチャーする必要があります。 - バックエンドから支払いをキャプチャーするには、[Webhook](https://docs.stripe.com/webhooks.md) を使用して、`requires_capture` ステータスの PaymentIntents をリッスンします。 - アプリケーションから支払いをキャプチャーするには、 SDK が各 PaymentIntent を転送するたびに、`OfflineDelegate.didForwardPayment` のコールをアプリケーションが受け取るのを待ちます。PaymentIntent のステータスが `RequiresCapture` であり、さらに `offlineDetails` が null、あるいは `requiresUpload` value of `NO` の場合、キャプチャーする準備ができています。 #### Swift ```swift Terminal.shared.confirmPaymentIntent(paymentIntent) { confirmResult, confirmError in if let error = confirmError { // Handle offline-specific errors in your application (for example, // unsupported payment method). print("confirmPaymentIntent failed: \(error)") } else if let confirmedPaymentIntent = confirmResult { if intent.status == .requiresCapture {if let offlineDetails = confirmedPaymentIntent.offlineDetails(), offlineDetails.requiresUpload { // Offline payment, wait for `didForwardPaymentIntent` (see snippet below) } else { // Online payment, can be captured now } } // else, handle other intent.status results here } } ``` オフライン決済は、 SDK によって OfflineDelegate の `didForwardPaymentIntent` で転送された後にキャプチャーします。 #### Swift ```swift import StripeTerminal class CustomOfflineDelegate: OfflineDelegate { // ... func terminal(_ terminal: Terminal, didForwardPaymentIntent intent: PaymentIntent, error: Error?) { if let error = error { // Handle the error appropriate for your application return } if intent.status == .requiresCapture { // The intent is ready to be captured. } else { // Handle the intent.status as appropriate. } } // ... } ``` ## オフラインで回収した支払いを調べる オーソリ後は、[PaymentIntents](https://docs.stripe.com/payments/payment-intents.md) API を使用して支払いのオフライン情報を調べることができます。`PaymentIntent` の[最新の Charge](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-latest_charge) オブジェクトの [payment method details](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-offline) にアクセスすると、オフラインで回収されたものであるかどうかを判定できます。 # Android > This is a Android for when terminal-card-present-integration is terminal and terminal-sdk-platform is android and reader-type is simulated. View the full page at https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments?terminal-card-present-integration=terminal&terminal-sdk-platform=android&reader-type=simulated. Terminal SDK を使用すると、アプリケーションではネットワーク接続なしで、シミュレーションされたリーダーを使用して支払いの回収を続行できます。 > オフラインで実行するときは、販売時に決済情報が収集されます。オーソリは接続の回復後にのみ試行され、支払いが転送されます。ユーザーであるお客様が、オフライン取引に関連する支払い拒否や改ざんに関するすべてのリスクを負います。改ざんされたリーダーが支払いを Stripe に転送できない場合、またはカード発行会社が取引を拒否した場合、売上を回収する方法はなく、すでに提供した商品やサービスへの顧客の支払いを受け取れなくなることがあります。 > > カード発行会社による拒否を減らすため、以下のことが推奨されます。 > > - できる限り早急にインターネット接続を再確立して、支払いを Stripe に記録します。 - 所定の金額を超える場合は取引を制限します。 - 合計すると所定の金額を超える複数の取引を SDK が保存した場合、[すべてのオフライン決済を失敗させます](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#managing-risk)。 ## オフライン中に決済を回収する オフライン決済の手順は、オンライン決済と同じで、決済の作成、回収、処理、およびキャプチャーが含まれます。このプロセスのどの段階でも、デバイスをオンラインからオフラインにできます。 1. [オフラインモードを有効にする](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#enable-offline-mode) 1. [オフライン中にリーダーに接続する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#connect-while-offline) 1. [オフラインイベントを処理する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#handle-offline-events) 1. [オフライン中に PaymentIntent を作成する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#create-payment-intent) 1. [支払い方法を収集する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#collect-payment-method) 1. [支払いを確定する](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#confirm-payment) 1. [支払いが転送されるまで待つ](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#wait-for-forward) 1. (オプション) [支払いをキャプチャーする](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#capture-payment) 1. (オプション) [オフラインで回収した支払いを調べる](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#examine-offline) ## オフラインモードを有効にする オフラインモードを使用するには、アプリケーションが Terminal Android SDK のバージョン `3.2.0` 以降を使用している必要があります。 オフラインモードを有効にするように、シミュレーションされたリーダーを設定します。 #### Kotlin ``` val simulatorConfig = SimulatorConfiguration( offlineEnabled = true ); Terminal.getInstance().setSimulatorConfiguration(simulatorConfig); ``` ## オフライン中にリーダーに接続する SDK はオンラインに接続した後、必要な `Location` 情報をローカルに保存します。後続のオフライン接続では、その `Location` に保存されている設定情報が使用されます。 オフライン時にスマートリーダーで支払いを回収するには、直前の 30 日以内のオンライン時に、あらかじめ同じ `Location` の同じタイプのモバイルリーダーに接続し、また期間内にリーダーのソフトウェアを更新する必要があります。 オフライン時にこれらの要件を満たさずリーダーに接続しようとすると、リクエストはエラーで失敗します。 | エラー | 解決策 | | ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | | **SDK がインターネットに接続されていません** | シミュレーションされたリーダーの `SimulatorConfiguration` でオフラインモードが有効になっていることを確認してください。それ以外の場合は、オンライン時に任意のリーダーに接続してから、オフライン時に同じタイプのリーダーに接続します。 | | **選択したリーダーをオフラインでの支払い回収に使用するには、ソフトウェアの更新が必要です。** | SDK の `SimulatorConfiguration` で `SimulateReaderUpdate` の値を `REQUIRED_FOR_OFFLINE` に設定しました。オフライン接続を許可するには、別の値を使用してください。 | | **選択したリーダーをオフラインでの支払い回収に使用するには、この場所でオンラインのペアリングを行う必要があります。** | POS がこれまでオンライン中に接続していないタイプのリーダーに接続しようとしています。まずオンライン中に、このリーダーまたは同じタイプのリーダーに接続する必要があります。または、オフライン中に接続する場合は、以前オンライン中に POS が接続していたタイプのリーダーに接続できます。 | ## オフラインイベントを処理する [クライアント側] - [OfflineListener (Android)](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.callable/-offline-listener/index.html) アプリケーションが SDK のネットワークステータスと転送された支払いの状態に関する更新を受信できるようにするには、`OfflineListener` インターフェイスを実装して Terminal SDK に渡します。オフラインで支払いを回収する前に、`OfflineListener` を設定する必要があります。 #### Kotlin ```kotlin class CustomOfflineListener : OfflineListener { override fun onOfflineStatusChange(offlineStatus: OfflineStatus) { // Check the value of `offlineStatus` and update your UI accordingly. For instance, // you can check the SDK's network status at `offlineStatus.sdk.networkStatus`. // // You can also check the SDK's current offline status using // `Terminal::offlineStatus`. } override fun onPaymentIntentForwarded(paymentIntent: PaymentIntent, e: TerminalException?) { // The PaymentIntent was successfully forwarded, or an error occurred. // Reconcile any local state using the backend-generated `PaymentIntent::id` // and the metadata you supplied when creating the PaymentIntent. // // Note that the `PaymentIntent::id` may still be null if creating the // PaymentIntent in the backend failed. } override fun onForwardingFailure(e: TerminalException) { // A non-specific error occurred while forwarding a PaymentIntent. // Check the error message and your integration implementation to // troubleshoot. } } ``` #### Kotlin ```kotlin Terminal.init( context = applicationContext, logLevel = LogLevel.VERBOSE, tokenProvider = CustomConnectionTokenProvider(), listener = CustomTerminalListener(), offlineListener = CustomOfflineListener(), ) ``` ## オフライン中に PaymentIntent を作成する [クライアント側] - [createPaymentIntent (Android)](https://stripe.dev/stripe-terminal-android/core/com.stripe.stripeterminal/-terminal/create-payment-intent.html) - [CreateConfiguration (Android)](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-create-configuration/index.html) - [OfflineDetails (Android)](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-offline-details/index.html) オフラインでの操作に対応するには、SDK の `createPaymentIntent` を使用して PaymentIntent オブジェクトを作成します。これにより、SDK はオフライン時に PaymentIntents を作成し、接続が再確立された後で Stripe に転送できます。 オフラインでの実行中、`PaymentIntent` オブジェクトは null の `id` を保持します。PaymentIntent の[メタデータ](https://docs.stripe.com/payments/payment-intents.md#storing-information-in-metadata)にカスタム識別子を追加して、オフラインで作成された `PaymentIntent` オブジェクトをデータベースで照合できるようにすることをお勧めします。 [ステップ 7](https://docs.stripe.com/terminal/features/operate-offline/collect-card-payments.md#wait-for-forward) で `PaymentIntent` が正常に Stripe に転送されたら、カスタム識別子を使用して `OfflineListener::onPaymentIntentForwarded` コールバックで調整します。 #### Kotlin ```kotlin private const val TAG = "PaymentActivity" class PaymentActivity : AppCompatActivity() { // Action for a "Checkout" button private fun onCheckout(cart: Cart) { // Build up parameters for creating a `PaymentIntent` val params = PaymentIntentParameters.Builder() .setAmount(cart.total) .setCurrency(cart.currency).setMetadata(mapOf("unique-id" to UUID.randomUUID().toString())) .build() val createPaymentCallback: PaymentIntentCallback = object : PaymentIntentCallback { override fun onSuccess(paymentIntent: PaymentIntent) { Log.d(TAG, "createPaymentIntent succeeded")// If the `PaymentIntent` was created offline, its `id` field will be null. if (paymentIntent.id != null) { Log.d(TAG, "created online") } else { Log.d(TAG, "created offline") } // ... Collect a PaymentMethod } override fun onFailure(e: TerminalException) { Log.e(TAG, "createPaymentIntent failed", e) // Handle errors in your application. } } Terminal.getInstance().createPaymentIntent(params, createPaymentCallback) } } ``` `Terminal.createPaymentIntent` は `CreateConfiguration` パラメーターを受け付けます。デフォルトでは、オフラインで実行している場合、Terminal SDK はすべてのオフライン決済を保存し、接続が回復したときに Stripe のバックエンドに転送します。 この動作をカスタマイズするには、`offlineBehavior` 属性を `REQUIRE_ONLINE`、`PREFER_ONLINE` または `FORCE_OFFLINE` に設定して `CreateConfiguration` オブジェクトを渡すことができます。 #### リスクの管理 `offlineBehavior` を `REQUIRE_ONLINE` に設定すると、現在の取引はオフラインでの操作時に失敗します。たとえば、一定の金額を越える取引を拒否したり、SDK に合計額が一定の金額を超える複数の取引が保存されている場合に、すべてのオフライン取引を拒否したりすることができます。 SDK では、リスクを管理しやすいように、次の 2 つのプロパティーを公開しています。 1. `Terminal.offlineStatus.sdk.offlinePaymentsCount` 1. `Terminal.offlineStatus.sdk.offlinePaymentAmountsByCurrency` #### オフライン時の遅延管理 ネットワーク接続に基づいて、Terminal SDK が支払いをオンラインとオフラインのどちらで回収するかを自動的に判断します。ただし、ネットワーク接続がアクティブであっても (取引を迅速に回収する必要があり、ネットワーク接続が遅い場合など)、オフラインでの操作が必要になる場合があります。 `CreateConfiguration` オブジェクトを `offlineBehavior` を `FORCE_OFFLINE` に設定して渡すと、接続に関係なくオフラインで支払いを回収できます。 Terminal SDK のネットワーク接続がアクティブな状態にあるときにオフラインで回収された支払いは、バックグラウンドで転送されます。 #### Kotlin ```kotlin private const val TAG = "PaymentActivity" class PaymentActivity : AppCompatActivity() { // Action for a "Checkout" button private fun onCheckout(cart: Cart) { // ...build up parameters and callback for creating a `PaymentIntent` // Your app might want to prevent offline payments for too large an amount. // Here, we require a network connection if the payment if the amount is over 1000 usd. // Otherwise, we allow collecting offline if the network connection is unavailable.val offlineBehavior = if (cart.total > 1000000) { OfflineBehavior.REQUIRE_ONLINE } else { OfflineBehavior.PREFER_ONLINE } val createConfig = CreateConfiguration(offlineBehavior) Terminal.getInstance().createPaymentIntent(params, createPaymentCallback, createConfig) } } ``` ## 支払い方法を収集する [クライアント側] - [CollectPaymentIntentConfiguration (Android)](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-collect-payment-intent-configuration/index.html) > オフラインでリーダーを実行する間は、決済の責任をお客様が負うことになります。磁気ストライプデータはなりすましが簡単なため、Stripe はオフラインでの実行中はこのオプションを許可していません。*強力な顧客認証* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase) (SCA) が要求される市場では、カードのタップもサポートされていません。 オフラインでの支払いの回収は、[オンラインでの支払いの回収](https://docs.stripe.com/terminal/payments/collect-card-payment.md#collect-payment)と似ています。`onRequestReaderInput` メソッドを使用して、有効なカード提示オプションを顧客に表示します。 > Readers don’t support [inspecting payment method details before authorization](https://docs.stripe.com/terminal/payments/collect-card-payment.md?terminal-sdk-platform=android#collect-inspect-payment-method) while offline. Although you can still set the `updatePaymentIntent` parameter in `CollectPaymentIntentConfiguration`, the `paymentMethod` field on the PaymentIntent is absent if the SDK is operating offline. #### Kotlin ```kotlin private const val TAG = "PaymentActivity" class PaymentActivity : AppCompatActivity() { // Action for a "Checkout" button private fun onCheckout(cart: Cart) { val collectPaymentCallback: PaymentIntentCallback = object : PaymentIntentCallback { override fun onSuccess(paymentIntent: PaymentIntent) { Log.d(TAG, "collectPaymentMethod succeeded") // ... Confirm the payment } override fun onFailure(e: TerminalException) { Log.d(TAG, "collectPaymentMethod failed:", e) } } val collectConfig = CollectPaymentIntentConfiguration.Builder().build() Terminal.getInstance().collectPaymentMethod(paymentIntent, collectPaymentCallback, collectConfig) } } ``` ## 支払いを確定する [クライアント側] オフラインでの支払いの確定は、[オンラインでの支払いの確定](https://docs.stripe.com/terminal/payments/collect-card-payment.md#confirm-payment)と似ています。主な違いは、Stripe が適用するオフライン取引の上限額である 1 万 USD、または運用通貨で相当する額を超えた場合などは、オフライン固有のエラーケースを自社のシステムで処理する必要がある点です。 場合によっては、SDK がオンラインで `PaymentIntent` を作成し、オフラインで確定することがあります。これが発生すると、`PaymentIntent` に null 以外の `id` が含まれる可能性があります。オフラインで確定された場合は、`offlineDetails` が定義され、入力されます。 シミュレーション済みのテストカードを使用するように、シミュレーション済みのリーダーを設定できます。これにより、確定時にオフライン特有のさまざまなフローをテストできます。たとえば、次のことができます。 - シミュレーション済みの Interac テストカード番号を使用して、サポート対象ではない決済手段の `PaymentIntent` をオフラインで確定する際のエラーをテストする - [支払いが拒否される](https://docs.stripe.com/terminal/references/testing.md#test-cards-for-specific-error-cases)テストカード番号を使用して、保存されている `PaymentIntent` の転送の失敗をテストする 利用できるオプションの一覧については、[Stripe Terminal をテストする](https://docs.stripe.com/terminal/references/testing.md)をご覧ください。 #### Kotlin ```kotlin private const val TAG = "PaymentActivity" class PaymentActivity : AppCompatActivity() { // Action for a "Checkout" button private fun onCheckout(cart: Cart) { val confirmPaymentIntentCallback: PaymentIntentCallback = object : PaymentIntentCallback { override fun onSuccess(paymentIntent: PaymentIntent) { Log.d(TAG, "confirmPaymentIntent succeeded")// If the `PaymentIntent` was confirmed offline, `paymentIntent.offlineDetails` will be defined if (paymentIntent.offlineDetails != null) { Log.d(TAG, "confirmed offline") } else { Log.d(TAG, "confirmed online") } } override fun onFailure(e: TerminalException) { // Handle offline-specific errors in your application (for example, // unsupported payment method). Log.e(TAG, "confirmPaymentIntent failed:", e) } } Terminal.getInstance().confirmPaymentIntent(paymentIntent, confirmPaymentIntentCallback) } } ``` #### 領収書の提供 オフライン時に支払いの完了に使用されたカードの情報が必要になることがあります。たとえば、購入時の領収書を求める顧客に領収書を生成する必要がある場合などです。 PaymentIntent がオフラインで確定された場合、その [OfflineCardPresentDetails](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-offline-card-present-details/index.html)、 を `paymentIntent.offlineDetails.offlineCardPresentDetails` から取得できます。 このハッシュには、領収書の生成に使用される [ReceiptDetails](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-receipt-details/index.html)、 プロパティのほか、カード保有者の名前やカードブランドなどのカード情報が含まれます。 オフラインで処理された PaymentIntents では、`account_type` および `authorization_response_code` の領収書フィールドを使用できません。[構築済みのメール領収書](https://docs.stripe.com/terminal/features/receipts.md#prebuilt)は接続が回復し、支払いのキャプチャーが成功するまで送信されません。 ## 支払いが転送されるまで待つ [クライアント側] インターネットアクセスが復旧すると、SDK は保存されていたオフラインの支払いの転送を自動的に開始します。 SDK は、ネットワークステータスがオフラインであっても支払いの転送を試みます。つまり、デバイスがオフラインの場合でも、接続トークンプロバイダーは、接続トークンの提供を求めるリクエストを受け取る可能性があります。 POS デバイスの電源オフのタイミングが早すぎると、支払いが転送されない可能性があります。`Terminal.offlineStatus.sdk.networkStatus` をクエリすると、POS がオンライン状態にあり、支払いを転送できるか確認することができます。また、`Terminal.offlineStatus.sdk.offlinePaymentsCount` をクエリすると、Terminal SDK の転送が必要な支払いの件数を確認できます。 ## 決済をキャプチャーする オフライン時には、`captureMethod` を `automatic` に設定して、PaymentIntents を作成できます。 これらの PaymentIntent を確定すると、ステータスは `REQUIRES_CAPTURE` ではなく、`SUCCEEDED` になります。Stripe は転送後の支払いを自動的にキャプチャーします。 手動キャプチャーを選択した場合、正常に転送されオーソリされた支払いは、バックエンドまたはアプリケーションからキャプチャーする必要があります。 - バックエンドから支払いをキャプチャーするには、[Webhook](https://docs.stripe.com/webhooks.md) を使用して、`requires_capture` ステータスの PaymentIntents をリッスンします。 - アプリケーションから支払いをキャプチャーするには、 SDK が各 PaymentIntent を転送するたびに、`OfflineListener::onPaymentIntentForwarded` のコールをアプリケーションが受け取るのを待ちます。PaymentIntent のステータスが `REQUIRES_CAPTURE` であり、さらに `offlineDetails` が null、あるいは `requiresUpload` value of `false` の場合、キャプチャーする準備ができています。 #### Kotlin ```kotlin private const val TAG = "PaymentActivity" class PaymentActivity : AppCompatActivity() { // Action for a "Checkout" button private fun onCheckout(cart: Cart) { val callback: PaymentIntentCallback = object : PaymentIntentCallback { override fun onSuccess(paymentIntent: PaymentIntent) { Log.d(TAG, "confirmPaymentIntent succeeded") if (paymentIntent.status == PaymentIntentStatus.REQUIRES_CAPTURE) {val offlineDetails = paymentIntent.offlineDetails if (offlineDetails?.requiresUpload == true) { // Offline payment, wait for `onPaymentIntentForwarded` (see snippet below) } else { // Online payment, can be captured now } } else { // Handle other status results here } } override fun onFailure(e: TerminalException) { // Handle offline-specific errors in your application (for example, // unsupported payment method). Log.e(TAG, "confirmPaymentIntent failed:", e) } } Terminal.getInstance().confirmPaymentIntent(paymentIntent, callback) } } ``` オフライン決済は、 SDK によって `OfflineListener::onPaymentIntentForwarded` で転送された後にキャプチャーします。 #### Kotlin ```kotlin class CustomOfflineListener : OfflineListener { // ... override fun onPaymentIntentForwarded(paymentIntent: PaymentIntent, e: TerminalException?) { if (e != null) { // Handle the error appropriate for your application } else if (paymentIntent.status == PaymentIntentStatus.REQUIRES_CAPTURE) { // The paymentIntent is ready to be captured } else { // Handle other status results here } } // ... } ``` ## オフラインで回収した支払いを調べる オーソリ後は、[PaymentIntents](https://docs.stripe.com/payments/payment-intents.md) API を使用して支払いのオフライン情報を調べることができます。`PaymentIntent` の[最新の Charge](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-latest_charge) オブジェクトの [payment method details](https://docs.stripe.com/api/charges/object.md#charge_object-payment_method_details-card_present-offline) にアクセスすると、オフラインで回収されたものであるかどうかを判定できます。