Skip to content

Commit 215602a

Browse files
onairmarcEncoreBot
andauthored
Add StripeCustomer::hasDefaultPaymentMethod() and StripeCustomer::withDefaultPaymentMethod() (#60)
Co-authored-by: EncoreBot <[email protected]>
1 parent b24d341 commit 215602a

File tree

5 files changed

+370
-8
lines changed

5 files changed

+370
-8
lines changed

.git-blame-ignore-revs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,5 @@ d97004494d4c686b50d44666de9fb933346ce856
2727
be38cf7d759454de7ae62450e710fddd687cc692
2828
cc49dd08428da674282d3ee3421ae9c47166bd2d
2929
26066d54ed49856a642f424d7269884cd75581c4
30+
753421ed297eb787e4eaf14a0dd759a304636217
31+
c40f4bf03470e0150b96d1e7494b8c2c07cc9f0d

src/php/Objects/Customer/StripeCustomer.php

Lines changed: 94 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use EncoreDigitalGroup\Stripe\Support\Traits\HasGet;
2121
use EncoreDigitalGroup\Stripe\Support\Traits\HasSave;
2222
use Illuminate\Support\Collection;
23+
use InvalidArgumentException;
2324
use PHPGenesis\Common\Traits\HasMake;
2425
use Stripe\Customer;
2526
use Stripe\StripeObject;
@@ -44,6 +45,9 @@ class StripeCustomer
4445
/** @var ?Collection<StripePaymentMethod> */
4546
private ?Collection $paymentMethods = null;
4647

48+
private ?bool $hasDefaultPaymentMethod = null;
49+
private ?string $defaultPaymentMethod = null;
50+
4751
/**
4852
* Create a StripeCustomer instance from a Stripe API Customer object
4953
*/
@@ -55,6 +59,14 @@ public static function fromStripeObject(Customer $stripeCustomer): self
5559
$instance = $instance->withId($stripeCustomer->id);
5660
}
5761

62+
$instance = self::applyBasicProperties($instance, $stripeCustomer);
63+
$instance = self::applyShippingIfPresent($instance, $stripeCustomer);
64+
65+
return self::applyDefaultPaymentMethod($instance, $stripeCustomer);
66+
}
67+
68+
private static function applyBasicProperties(self $instance, Customer $stripeCustomer): self
69+
{
5870
if (isset($stripeCustomer->address)) {
5971
/** @var StripeObject $stripeAddress */
6072
$stripeAddress = $stripeCustomer->address;
@@ -74,17 +86,45 @@ public static function fromStripeObject(Customer $stripeCustomer): self
7486
}
7587

7688
if ($stripeCustomer->phone ?? null) {
77-
$instance = $instance->withPhone($stripeCustomer->phone);
89+
return $instance->withPhone($stripeCustomer->phone);
7890
}
7991

80-
if (isset($stripeCustomer->shipping)) {
81-
/** @var StripeObject $stripeShipping */
82-
$stripeShipping = $stripeCustomer->shipping;
83-
$shipping = self::extractShipping($stripeShipping);
92+
return $instance;
93+
}
8494

85-
if ($shipping instanceof StripeShipping) {
86-
$instance = $instance->withShipping($shipping);
87-
}
95+
private static function applyShippingIfPresent(self $instance, Customer $stripeCustomer): self
96+
{
97+
if (!isset($stripeCustomer->shipping)) {
98+
return $instance;
99+
}
100+
101+
/** @var StripeObject $stripeShipping */
102+
$stripeShipping = $stripeCustomer->shipping;
103+
$shipping = self::extractShipping($stripeShipping);
104+
105+
if ($shipping instanceof StripeShipping) {
106+
return $instance->withShipping($shipping);
107+
}
108+
109+
return $instance;
110+
}
111+
112+
private static function applyDefaultPaymentMethod(self $instance, Customer $stripeCustomer): self
113+
{
114+
if (!isset($stripeCustomer->invoice_settings)) {
115+
return $instance;
116+
}
117+
118+
$defaultPaymentMethod = $stripeCustomer->invoice_settings->default_payment_method ?? null;
119+
120+
if (is_string($defaultPaymentMethod)) {
121+
$instance->defaultPaymentMethod = $defaultPaymentMethod;
122+
$instance->hasDefaultPaymentMethod = true;
123+
}
124+
125+
if (is_object($defaultPaymentMethod)) {
126+
$instance->defaultPaymentMethod = $defaultPaymentMethod->id;
127+
$instance->hasDefaultPaymentMethod = true;
88128
}
89129

90130
return $instance;
@@ -178,6 +218,39 @@ public function createSetupIntent(): StripeSetupIntent
178218
return StripeSetupIntent::make()->withCustomer($this->id);
179219
}
180220

221+
public function hasDefaultPaymentMethod(): bool
222+
{
223+
if (is_null($this->id)) {
224+
throw new ClassPropertyNullException("id");
225+
}
226+
227+
if (!is_null($this->hasDefaultPaymentMethod)) {
228+
return $this->hasDefaultPaymentMethod;
229+
}
230+
231+
$this->hasDefaultPaymentMethod = $this->service()->hasDefaultPaymentMethod($this->id);
232+
233+
return $this->hasDefaultPaymentMethod;
234+
}
235+
236+
public function save(): self
237+
{
238+
if (!is_null($this->defaultPaymentMethod)) {
239+
if (is_null($this->id)) {
240+
throw new ClassPropertyNullException("id");
241+
}
242+
243+
$paymentMethods = $this->paymentMethods();
244+
$paymentMethodExists = $paymentMethods->contains(fn ($pm): bool => $pm->id() === $this->defaultPaymentMethod);
245+
246+
if (!$paymentMethodExists) {
247+
throw new InvalidArgumentException("Payment method {$this->defaultPaymentMethod} is not attached to customer {$this->id}");
248+
}
249+
}
250+
251+
return is_null($this->id) ? $this->service()->create($this) : $this->service()->update($this->id, $this);
252+
}
253+
181254
public function service(): StripeCustomerService
182255
{
183256
return app(StripeCustomerService::class);
@@ -195,6 +268,12 @@ public function toArray(): array
195268
"shipping" => $this->shipping?->toArray(),
196269
];
197270

271+
if (!is_null($this->defaultPaymentMethod)) {
272+
$array["invoice_settings"] = [
273+
"default_payment_method" => $this->defaultPaymentMethod,
274+
];
275+
}
276+
198277
return Arr::whereNotNull($array);
199278
}
200279

@@ -248,6 +327,13 @@ public function withShipping(StripeShipping $shipping): self
248327
return $this;
249328
}
250329

330+
public function withDefaultPaymentMethod(string $defaultPaymentMethod): self
331+
{
332+
$this->defaultPaymentMethod = $defaultPaymentMethod;
333+
334+
return $this;
335+
}
336+
251337
// Getter methods
252338
public function id(): ?string
253339
{

src/php/Services/StripeCustomerService.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,12 @@ public function search(string $query, array $params = []): Collection
8585
return collect($stripeCustomers->data)
8686
->map(fn ($stripeCustomer): StripeCustomer => StripeCustomer::fromStripeObject($stripeCustomer));
8787
}
88+
89+
/** @throws ApiErrorException */
90+
public function hasDefaultPaymentMethod(string $customerId): bool
91+
{
92+
$stripeCustomer = $this->stripe->customers->retrieve($customerId);
93+
94+
return isset($stripeCustomer->invoice_settings->default_payment_method);
95+
}
8896
}

tests/Feature/StripeCustomerServiceTest.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,4 +230,59 @@
230230
->toHaveCount(2)
231231
->and($customers->first())->toBeInstanceOf(StripeCustomer::class)
232232
->and($fake)->toHaveCalledStripeMethod("customers.search");
233+
});
234+
235+
test("can check if customer has default payment method", function (): void {
236+
// Arrange
237+
$fake = Stripe::fake([
238+
StripeMethod::CustomersRetrieve->value => StripeFixtures::customer([
239+
"id" => "cus_test123",
240+
"invoice_settings" => [
241+
"default_payment_method" => "pm_test123",
242+
],
243+
]),
244+
]);
245+
246+
// Act
247+
$service = StripeCustomerService::make();
248+
$result = $service->hasDefaultPaymentMethod("cus_test123");
249+
250+
// Assert
251+
expect($result)->toBeTrue()
252+
->and($fake)->toHaveCalledStripeMethod(StripeMethod::CustomersRetrieve);
253+
});
254+
255+
test("returns false when customer has no default payment method", function (): void {
256+
// Arrange
257+
$fake = Stripe::fake([
258+
StripeMethod::CustomersRetrieve->value => StripeFixtures::customer([
259+
"id" => "cus_test123",
260+
"invoice_settings" => [],
261+
]),
262+
]);
263+
264+
// Act
265+
$service = StripeCustomerService::make();
266+
$result = $service->hasDefaultPaymentMethod("cus_test123");
267+
268+
// Assert
269+
expect($result)->toBeFalse()
270+
->and($fake)->toHaveCalledStripeMethod(StripeMethod::CustomersRetrieve);
271+
});
272+
273+
test("returns false when customer invoice_settings is null", function (): void {
274+
// Arrange
275+
$fake = Stripe::fake([
276+
StripeMethod::CustomersRetrieve->value => StripeFixtures::customer([
277+
"id" => "cus_test123",
278+
]),
279+
]);
280+
281+
// Act
282+
$service = StripeCustomerService::make();
283+
$result = $service->hasDefaultPaymentMethod("cus_test123");
284+
285+
// Assert
286+
expect($result)->toBeFalse()
287+
->and($fake)->toHaveCalledStripeMethod(StripeMethod::CustomersRetrieve);
233288
});

0 commit comments

Comments
 (0)