概要
Stripeの顧客にStripe.jsを使って追加したクレカ情報のPaymentMethodIdを紐づけてデフォルトの支払い方法に設定しようとしていた。一部でめっちゃ詰まったので簡単にまとめておく。
前提
本記事で紹介しているコードは「コピペすれば動く」というものではない。
エラーになるコード
下記はイケてないコードである。
/**
* 顧客に紐づくデフォルトの支払い方法を更新
*
* @param UserObject $userObject
* @param string $paymentMethodId
* @return void
*/
private function updateDefaultPaymentMethod(UserObject $userObject, string $paymentMethodId): void
{
$this->makeStripeClient();
try {
// NOTE: 顧客と支払い方法を紐づけ
$this->attachPaymentMethodToCustomer(paymentMethodId: $paymentMethodId, userObject: $userObject);
// NOTE: 紐づけた支払い方法をデフォルトに設定
$this->setDefaultPaymentMethodToCustomer(paymentMethodId: $paymentMethodId, userObject: $userObject);
} catch (ApiErrorException $e) {
throw $e;
}
return;
}
/**
* 顧客に支払い方法を紐付ける
*
* @param string $paymentMethodId
* @param UserObject $userObject
* @return PaymentMethod
*/
private function attachPaymentMethodToCustomer(string $paymentMethodId, UserObject $userObject): PaymentMethod
{
$this->makeStripeClient();
try {
$this->stripeClient->paymentMethods->attach(
$paymentMethodId,
[
'customer' => $userObject->getStripeCustomerId(),
]
);
} catch (ApiErrorException $e) {
throw $e;
}
}
/**
* 顧客にデフォルトの支払い方法を設定する
*
* @param string $paymentMethodId
* @param UserObject $userObject
* @return void
*/
private function setDefaultPaymentMethodToCustomer(string $paymentMethodId, UserObject $userObject): void
{
try {
$this->updateCustomer(
userObject: $userObject,
options: [
'invoice_settings' => [
'default_payment_method' => $paymentMethodId,
]
]
);
} catch (ApiErrorException $e) {
throw $e;
}
}
これを実行するとThe customer does not have a payment method with the ID pm_XXXXXXXXXXXXXX. The payment method must be attached to the customer.
のようなエラーが出てしまう。
実は原因は単純で、setDefaultPaymentMethodToCustomer()
の$this->updateCustomer()
でdefault_payment_method
に紐づいて渡すPaymentMethodIdはattachPaymentMethodToCustomer()
の$this->stripeClient->paymentMethods->attach()
が返すPaymentMethodのidである必要がある。↑のコードはリクエストでもたらされたPaymentMethodIdをdefault_payment_method
に紐づけて渡してしまっている。ここでエラーになる模様、、!
修正後のコード
下記だと正常に動作した。
/**
* 顧客に紐づくデフォルトの支払い方法を更新
*
* @param UserObject $userObject
* @param string $paymentMethodId
* @return void
*/
private function updateDefaultPaymentMethod(UserObject $userObject, string $paymentMethodId): void
{
$this->makeStripeClient();
try {
// NOTE: 顧客と支払い方法を紐づけ
$paymentMethod = $this->attachPaymentMethodToCustomer(paymentMethodId: $paymentMethodId, userObject: $userObject);
// NOTE: 紐づけた支払い方法をデフォルトに設定
$this->setDefaultPaymentMethodToCustomer(paymentMethod: $paymentMethod, userObject: $userObject);
} catch (ApiErrorException $e) {
throw $e;
}
return;
}
/**
* 顧客に支払い方法を紐付ける
*
* @param string $paymentMethodId
* @param UserObject $userObject
* @return PaymentMethod
*/
private function attachPaymentMethodToCustomer(string $paymentMethodId, UserObject $userObject): PaymentMethod
{
$this->makeStripeClient();
try {
$paymentMethod = $this->stripeClient->paymentMethods->attach(
$paymentMethodId,
[
'customer' => $userObject->getStripeCustomerId(),
]
);
} catch (ApiErrorException $e) {
throw $e;
}
return $paymentMethod;
}
/**
* 顧客にデフォルトの支払い方法を設定する
*
* @param PaymentMethod $paymentMethod
* @param UserObject $userObject
* @return void
*/
private function setDefaultPaymentMethodToCustomer(PaymentMethod $paymentMethod, UserObject $userObject): void
{
try {
$this->updateCustomer(
userObject: $userObject,
options: [
'invoice_settings' => [
'default_payment_method' => $paymentMethod->id,
]
]
);
} catch (ApiErrorException $e) {
throw $e;
}
}