# Issuing とプラットフォーム向け Treasury のサンプルアプリ

Stripe Next.js のサンプルアプリを使用して、独自の Issuing およびプラットフォーム向け Treasury の実装を始めることができます。

> #### 従来の実装
> 
> Treasury for platforms の v1 は従来の実装であり、[Treasury for platforms v2](https://docs.stripe.com/treasury/connect.md) で導入された機能の多くをサポートしていません。新しい v1 の実装を構築しないでください。

Stripe Issuing と Stripe プラットフォーム向け Stripe Treasury のドキュメントおよび SDK 一式に加えて、Next.js のサンプルアプリも提供しています。

[baas.stripe.dev](https://baas.stripe.dev) にあるサンプルアプリのデモか、[GitHub リポジトリ](https://github.com/stripe-samples/issuing-treasury) をご覧ください。

## コードにアクセスする

サンプルアプリは、TypeScript、React、Material UI を活用した Next.js アプリです。[Stripe サンプルの GitHub リポジトリ](https://github.com/stripe-samples/issuing-treasury)からプロジェクトをフォークして、含まれているコンポーネントをアプリの開始点として使用することができます。

## アプリの機能

このアプリでは、次のようなさまざまな使用方法の例を紹介しています。

- Stripe Connect アカウント登録を使用して、規制に準拠した連結アカウントの登録用に顧客確認 (KYC) 情報を収集する
- アカウント情報と残高を表示する
- 金融口座の取引表示
- ACH または電信送金を使用した外部口座への送金をシミュレーションする
- ACH クレジットの受け取りをシミュレーションする
- [ApexCharts](https://github.com/apexcharts/apexcharts.js) を使用してインバウンドとアウトバウンドの資金のフローを視覚化する
- 規則に準拠した方法でカード保有者を作成する
- 金融口座を発行可能残高としてカードを作成
- 機密情報であるカード番号を PCI に準拠した方法で表示する
- カードのオーソリをシミュレーションする
- 決済用リンクから支払いを受けて、Stripe 決済残高から金融口座に資金を送金します
- テストヘルパーを利用してアカウントに影響する操作をシミュレーションする

## コンポーネントの内訳

以降のセクションでは、サンプルアプリの各コンポーネントの仕組みを大まかに紹介します。

[Issuing API と機能](https://docs.stripe.com/issuing.md)、または[金融口座 API](https://docs.stripe.com/api/treasury/financial_accounts.md) と[機能](https://docs.stripe.com/treasury/connect/legacy/v1.md)の詳細を確認できます。

### アカウントの作成

アカウント作成フローは以下の 4 つのステップで構成されています。

1. [連結アカウント](https://docs.stripe.com/treasury/connect/legacy/v1/account-management/connected-accounts.md)を作成し、次の機能を付与できます: `transfers`、`card_issuing`、`treasury`。

```javascript
const account = await stripe.accounts.create({
  country: 'US',
  email: email,
  capabilities: {
    transfers: {requested: true},
    treasury: {requested: true},
    card_issuing: {requested: true},
  },
  controller: {
    dashboard: {type: "none"},
    losses: {payments: "application"},
    requirement_collection: "application",
    fees: {payer: "application"}
  },
});
```

1. [金融口座](https://docs.stripe.com/treasury/connect/legacy/v1/account-management/financial-accounts.md)を作成します。

```javascript
const financialAccount = await stripe.treasury.financialAccounts.create(
  {
    supported_currencies: ['usd'],
    features: {
      card_issuing: {requested: true},
      deposit_insurance: {requested: true},
      financial_addresses: {aba: {requested: true}},
      inbound_transfers: {ach: {requested: true}},
      intra_stripe_flows: {requested: true},
      outbound_payments: {
        ach: {requested: true},
        us_domestic_wire: {requested: true},
      },
      outbound_transfers: {
        ach: {requested: true},
        us_domestic_wire: {requested: true},
      },
    },
  },
  {stripeAccount: account.id},
);
```

1. Connect アカウント登録リンクを作成し、そのリンクを使用して新規連結アカウントをリダイレクトして、リクエストされたケイパビリティに必要なプロフィール情報を収集します。

```javascript
const { url } = await stripe.accountLinks.create({
  type: 'account_onboarding',
  account: accountId,
  refresh_url: host + '/onboard',
  return_url: host + '/onboard',
  collect: 'eventually_due',
});
```

### アカウント残高

アカウント残高カードは `stripe.treasury.financialAccounts.list` API のみを使用します。

```javascript
const financialAccounts = await stripe.treasury.financialAccounts.list({
  stripeAccount: StripeAccountID,
});
const financialAccount = financialAccounts.data[0];
```

上記のコマンドのペイロードには、現在の[残高](https://docs.stripe.com/treasury/connect/legacy/v1/account-management/working-with-balances-and-transactions.md) (現金) とアウトバウンド資金からなる残高オブジェクトが含まれています。

```json
{
  "id": "fa_...",
 ...
  "balance": {
    "cash": { "usd": 534214 },
    "inbound_pending": { "usd": 0 },
    "outbound_pending": { "usd": 2200 }
  },
 ...
  "supported_currencies": [ "usd" ]
}
```

### 入出金チャート

資金移動チャートは `stripe.treasury.transactions.list` API のみを使用します。

```javascript
const fa_transactions = await stripe.treasury.transactions.list(
  {
    financial_account: financialAccount.id,
    order_by: 'created',
    limit: 100,
  },
  {stripeAccount: StripeAccountID},
);
```

レスポンスは、プラス/マイナスの残高および作成日でグループ化されます。その後、データは [ApexCharts](https://github.com/apexcharts/apexcharts.js) に移植され、売上フローの動的な表示が作成されます。

```json
{
  "id": "{{TRANSACTION_ID}}",
  "object": "treasury.transaction",
  "created": "{{T}}",
  ...
  "flow": "{{OUTBOUND_PAYMENT_ID}}",
  "flow_type": "outbound_payment",
  "status": "open",
  "amount": -1000,
  "currency": "usd",
  "balance_impact": {
    "cash": -1000,
    "inbound_pending": 0,
    "outbound_pending": 1000
  },
  "entries": {
    "data": [
      {
        "id": "{{TRANSACTION_ENTRY_ID}}",
        "object": "treasury.transaction_entry",
        ...
        "created": "{{T}}",
        "effective_at": "{{T}}",
        "currency": "usd",
        "balance_impact": {
          "cash": -1000,
          "inbound_pending": 0,
          "outbound_pending": 1000
        }
      }
    ],
    "has_more": false,
    "object": "list",
    "url": "/v1/treasury/transaction_entries?financial_account={{FINANCIAL_ACCOUNT_ID}}&transaction={{TRANSACTION_ID}}"
  }
}
```

### 取引リスト

取引リストは `stripe.treasury.transactions.list` API を使用します。

```javascript
const fa_transactions = await stripe.treasury.transactions.list(
  {
    financial_account: financialAccount.id,
    order_by: 'created',
    limit: 100,
  },
  {stripeAccount: StripeAccountID},
);
```

transactions テーブルの列は、次のマッピングを使用して `transaction` オブジェクトから解析されます。

- `created` → 日付
- `amount` → 金額 / 通貨
- `flow_type` → タイプ
- `status` → ステータス
- `description` → 説明

### 送金インターフェイス

サンプルアプリの送金機能は、Treasury for platforms の [OutboundPayments](https://docs.stripe.com/treasury/connect/legacy/v1/moving-money/out-of/outbound-payments.md) 機能を使用しています。`OutboundPayments` を使って、第三者の外部口座に送金できます。

```javascript
const outboundPayment = await stripe.treasury.outboundPayments.create(
  {
    financial_account: financialAccount.id,
    amount: amount,
    currency: 'usd',
    statement_descriptor: req.descriptor,
    destination_payment_method_data: {
      type: 'us_bank_account',
      us_bank_account: {
        account_holder_type: 'individual',
        routing_number: '110000000',
        account_number: '000000000009',
      }
    }
  },
  {
    stripeAccount: StripeAccountId
  },
);
```

### Issuing カード保有者の作成

金融口座からの資金を使用するために Stripe Issuing を使用してカードを発行する前に、`Cardholder` を作成する必要があります。カード会員を作成するには、`stripe.issuing.cardholders.create` API を使用します。

```javascript
const cardholder = await stripe.issuing.cardholders.create(
  {
    type: 'individual',
    name: firstName + ' ' + lastName,
    email: email,
    individual: {
      first_name: firstName,
      last_name: lastName,
      dob: {day: day, month: month, year: year}
    },
    billing: {
      address: {
        city: city,
        line1: address1,
        state: state,
        postal_code: postalCode,
        country: country,
      },
    },
  },
  {
    stripeAccount: StripeAccountId,
  }
);
```

### カードを発行する

`Cardholder` を作成した後、`stripe.issuing.cards.create` API を使用して `Cardholder` にカードを発行できます。

```javascript
const card = await stripe.issuing.cards.create(
  {
    cardholder: req.body.cardholderid,
    financial_account: financialAccount.id,
    currency: 'usd',
    type: 'virtual',
    status: 'active',
  },
  {stripeAccount: StripeAccountId},
);
```

### カードのリスト

`stripe.issuing.cards.list` API からのデータを使用して、カードのリストをレンダリングします。

```javascript
const cards = await stripe.issuing.cards.list(
  {limit: 10},
  {stripeAccount: StripeAccountID},
);
```

### カードのオーソリリスト

`stripe.issuing.authorizations.list` API を使用して、特定のカードのオーソリを取得します。次の例では、リストに表示するオーソリを最新の 10 件に制限しています。

```javascript
const card_authorizations = await stripe.issuing.authorizations.list(
  {
    card: cardId,
    limit: 10,
  },
  {stripeAccount: StripeAccountID},
);
```

authorization テーブルの列は、次のマッピングを使用して response オブジェクトから解析されます。

- `created` → 日付
- `amount` → 金額 / 金額の通貨
- `card.cardholder.name` → カードに記載されている名前
- `card.last4` → 末尾 4 桁
- `approved` → 承認済み
- `status` → ステータス
- `merchant_data.name` → 加盟店
- `merchant_data.category` → 加盟店カテゴリー

## テストヘルパー

サンプルアプリは、口座への資金の追加、連結アカウントの資金を回収するための決済用リンクの作成、金融口座への入金などの特定のアクションを実行できるテスト環境のヘルパーを備えています。ほとんどのテストヘルパーには、**テストデータを生成** ボタンまたは **テストデータ** をクリックするとアクセスできます。

### 受領したクレジットのテストヘルパー

テスト環境では、[ReceivedCredit Test Helpers](https://docs.stripe.com/api/treasury/received_credits/test_mode_create.md) を使用して、金融口座に資金を追加できます。このテストヘルパーは、外部の銀行口座から金融口座への送金をシミュレートします。

```javascript
const receivedCredit = await stripe.testHelpers.treasury.receivedCredits.create(
  {
    amount: 50000,
    currency: 'usd',
    financial_account: financialAccount.id,
    network: 'ach',
  },
  {stripeAccount: StripeAccountId},
);
```

### 決済フォームへのリンクと入金

決済用リンクを使用して、金融口座に関連付けられている連結アカウントに資金を追加できます。

1. 支払い完了後に連結アカウントに追加される金額を決定する `Price` を作成します。

```javascript
const prices = await stripe.prices.list(
  {
    limit: 1,
    active: true,
    type: 'one_time',
  },
  {stripeAccount: StripeAccountId,},
);

let price;

if (prices.data.length < 1) {
  price = await stripe.prices.create(
    {
      unit_amount: 1000,
      currency: 'usd',
      product_data:
        {
          name: 'Unit',
      },
    },
    {stripeAccount: StripeAccountId,},
  );
} else {
  price = prices.data[0];
}
```

1. 価格を取得した後、Stripe は `PaymentLink` を作成し、お客様は決済を完了するために顧客をリダイレクトします。前のステップの `Price` `id` を使用して `price` パラメーターの値を設定します。デフォルト値を使用する場合は、このパラメーターを含めないでください。

```javascript
const paymentLink = await stripe.paymentLinks.create(
  {
    line_items: [
      {
        price: price.id,
        quantity: 1,
        adjustable_quantity: {enabled: true},
      },
    ],
  },
  {stripeAccount: StripeAccountId,},
);
```

### 連結アカウントの支払い残高からの入金

[Payouts](https://docs.stripe.com/treasury/connect/legacy/v1/moving-money/payouts.md#payouts) を使用すると、連結アカウントの決済残高からその金融口座に資金を送れます。入金を実行するには、以下の手順に従ってください。

1. 連結アカウント用に外部口座が設定されているかどうかを確認します。そのためには、[accounts.retrieve](https://docs.stripe.com/api/accounts/retrieve.md) API を使用して、[Account オブジェクト](https://docs.stripe.com/api/accounts/object.md) を取得し、`external_account` プロパティが設定されているかどうかを確認します。

```javascript
const responseAccount = await stripe.accounts.retrieve(StripeAccountID);
const accountExternalAccount = responseAccount.external_accounts.data[0];

let hasExternalAccount = false;

if (accountExternalAccount) {
  hasExternalAccount = true;
}
```

1. 連結アカウントに外部口座がない場合、金融口座を外部口座として設定できます。

```javascript
const financialAccounts = await stripe.treasury.financialAccounts.list(
  {expand: ['data.financial_addresses.aba.account_number']},
  {
    stripeAccount: StripeAccountId,
  },
);

const financialAccount = financialAccounts.data[0];

await stripe.accounts.createExternalAccount(StripeAccountId, {
  external_account: {
    object: 'bank_account',
    country: 'US',
    currency: 'usd',
    account_number:
      financialAccount.financial_addresses[0].aba.account_number,
    routing_number:
      financialAccount.financial_addresses[0].aba.routing_number,
  },
});
```

1. 連結アカウントの外部口座への Payouts を開始します。この場合、外部口座は金融口座です。

```javascript
const balance = await stripe.balance.retrieve({
  stripeAccount: StripeAccountId,
});

const payout = await stripe.payouts.create(
  {
    amount: balance.available[0].amount,
    currency: 'usd',
  },
  {stripeAccount: StripeAccountId},
);
```
