Skip to content

Commit 7426139

Browse files
authored
Merge pull request #50 from FLUX-SE/idempotency_key
Avoid duplicate using idempotency key
2 parents f056efd + 017c1b6 commit 7426139

File tree

5 files changed

+105
-20
lines changed

5 files changed

+105
-20
lines changed

src/Action/AbstractCaptureAction.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,41 @@ protected function processNotNew(BaseArrayObject $model, Generic $request): void
6363
$this->gateway->execute(new Sync($model));
6464
}
6565

66+
/**
67+
* @return array<string, mixed>
68+
*/
69+
protected function getApiResourceOptions(Generic $request): array
70+
{
71+
$options = [];
72+
73+
$idempotencyKey = $this->getIdempotencyKey($request);
74+
if (null !== $idempotencyKey) {
75+
$options['idempotency_key'] = $idempotencyKey;
76+
}
77+
78+
return $options;
79+
}
80+
81+
protected function getIdempotencyKey(Generic $request): ?string
82+
{
83+
$token = $request->getToken();
84+
if (null === $token) {
85+
return null;
86+
}
87+
88+
$id = $token->getDetails()->getId();
89+
if (false === is_scalar($id)) {
90+
return null;
91+
}
92+
93+
$id = (string) $id;
94+
if ('' === $id) {
95+
return null;
96+
}
97+
98+
return md5($id);
99+
}
100+
66101
abstract protected function createApiResource(BaseArrayObject $model, Generic $request): ApiResource;
67102

68103
abstract protected function render(ApiResource $captureResource, Generic $request): void;

src/Action/StripeCheckoutSession/CaptureAction.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ protected function createApiResource(ArrayObject $model, Generic $request): ApiR
2222
$model->offsetSet('success_url', $token->getAfterUrl());
2323
$model->offsetSet('cancel_url', $token->getAfterUrl());
2424

25-
$createRequest = new CreateSession($model->getArrayCopy());
25+
$createRequest = new CreateSession(
26+
$model->getArrayCopy(),
27+
$this->getApiResourceOptions($request)
28+
);
2629
$this->gateway->execute($createRequest);
2730

2831
return $createRequest->getApiResource();

src/Action/StripeJs/CaptureAction.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ class CaptureAction extends AbstractCaptureAction
1616
{
1717
protected function createApiResource(ArrayObject $model, Generic $request): ApiResource
1818
{
19-
$createRequest = new CreatePaymentIntent($model->getArrayCopy());
19+
$createRequest = new CreatePaymentIntent(
20+
$model->getArrayCopy(),
21+
$this->getApiResourceOptions($request)
22+
);
2023
$this->gateway->execute($createRequest);
2124

2225
return $createRequest->getApiResource();

tests/Action/StripeCheckoutSession/CaptureActionTest.php

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,19 @@ public function testShouldDoASyncIfPaymentHasId(): void
5555
$gatewayMock
5656
->expects($this->exactly(2))
5757
->method('execute')
58-
->withConsecutive(
59-
[$this->isInstanceOf(Sync::class)],
60-
[$this->isInstanceOf(CaptureAuthorized::class)]
61-
)
58+
->with($this->callback(function ($request) {
59+
static $callCount = 0;
60+
$callCount++;
61+
62+
switch ($callCount) {
63+
case 1:
64+
return $request instanceof Sync;
65+
case 2:
66+
return $request instanceof CaptureAuthorized;
67+
default:
68+
return false;
69+
}
70+
}))
6271
;
6372

6473
$token = new Token();
@@ -99,13 +108,26 @@ public function executeCaptureAction(array $model, string $objectName): void
99108
$gatewayMock
100109
->expects($this->exactly(3))
101110
->method('execute')
102-
->withConsecutive(
103-
[$this->isInstanceOf(CreateSession::class)],
104-
[$this->isInstanceOf(Sync::class)],
105-
[$this->isInstanceOf(RedirectToCheckout::class)]
106-
)
111+
->with($this->callback(function ($request) {
112+
static $callCount = 0;
113+
$callCount++;
114+
115+
switch ($callCount) {
116+
case 1:
117+
return $request instanceof CreateSession;
118+
case 2:
119+
return $request instanceof Sync;
120+
case 3:
121+
return $request instanceof RedirectToCheckout;
122+
default:
123+
return false;
124+
}
125+
}))
107126
->willReturnOnConsecutiveCalls(
108127
$this->returnCallback(function (CreateSession $request) {
128+
$this->assertEquals([
129+
'idempotency_key' => md5(1),
130+
], $request->getOptions());
109131
$this->assertInstanceOf(ArrayObject::class, $request->getModel());
110132
$request->setApiResource(new Session('sess_0001'));
111133
}),

tests/Action/StripeJs/CaptureActionTest.php

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,19 @@ public function testShouldDoASyncIfPaymentHasId(): void
5252
$gatewayMock
5353
->expects($this->exactly(2))
5454
->method('execute')
55-
->withConsecutive(
56-
[$this->isInstanceOf(Sync::class)],
57-
[$this->isInstanceOf(CaptureAuthorized::class)]
58-
)
55+
->with($this->callback(function ($arg) {
56+
static $callCount = 0;
57+
$callCount++;
58+
59+
switch ($callCount) {
60+
case 1:
61+
return $arg instanceof Sync;
62+
case 2:
63+
return $arg instanceof CaptureAuthorized;
64+
default:
65+
return false;
66+
}
67+
}))
5968
;
6069

6170
$token = new Token();
@@ -96,13 +105,26 @@ public function executeCaptureAction(array $model): void
96105
$gatewayMock
97106
->expects($this->exactly(3))
98107
->method('execute')
99-
->withConsecutive(
100-
[$this->isInstanceOf(CreatePaymentIntent::class)],
101-
[$this->isInstanceOf(Sync::class)],
102-
[$this->isInstanceOf(RenderStripeJs::class)]
103-
)
108+
->with($this->callback(function ($arg) {
109+
static $callCount = 0;
110+
$callCount++;
111+
112+
switch ($callCount) {
113+
case 1:
114+
return $arg instanceof CreatePaymentIntent;
115+
case 2:
116+
return $arg instanceof Sync;
117+
case 3:
118+
return $arg instanceof RenderStripeJs;
119+
default:
120+
return false;
121+
}
122+
}))
104123
->willReturnOnConsecutiveCalls(
105124
$this->returnCallback(function (CreatePaymentIntent $request) {
125+
$this->assertEquals([
126+
'idempotency_key' => md5(1),
127+
], $request->getOptions());
106128
$this->assertInstanceOf(ArrayObject::class, $request->getModel());
107129
$request->setApiResource(new PaymentIntent('pi_0001'));
108130
}),

0 commit comments

Comments
 (0)