@@ -132,45 +132,7 @@ public function handlesAPaidFirstPayment()
132132
133133 Event::fake ();
134134
135- $ molliePayment = new MolliePayment (new MollieApiClient );
136- $ molliePayment ->id = 'tr_unique_payment_id ' ;
137- $ molliePayment ->paidAt = Carbon::now ()->toIso8601String ();
138- $ molliePayment ->mandateId = 'mdt_unique_mandate_id ' ;
139- $ molliePayment ->amount = (object ) [
140- 'currency ' => 'EUR ' ,
141- 'value ' => '0.05 ' ,
142- ];
143- $ molliePayment ->metadata = json_decode (json_encode ([
144- 'owner ' => [
145- 'type ' => get_class ($ this ->user ),
146- 'id ' => 1 ,
147- ],
148- 'actions ' => [
149- [
150- 'handler ' => StartSubscription::class,
151- 'description ' => 'Monthly payment ' ,
152- 'subtotal ' => [
153- 'value ' => '0.00 ' ,
154- 'currency ' => 'EUR ' ,
155- ],
156- 'taxPercentage ' => 20 ,
157- 'plan ' => 'monthly-10-1 ' ,
158- 'name ' => 'default ' ,
159- 'quantity ' => 1 ,
160- 'nextPaymentAt ' => now ()->addDays (12 )->toIso8601String (),
161- 'trialUntil ' => now ()->addDays (5 )->toIso8601String (),
162- ],
163- [
164- 'handler ' => AddGenericOrderItem::class,
165- 'description ' => 'Test mandate payment ' ,
166- 'subtotal ' => [
167- 'value ' => '0.04 ' ,
168- 'currency ' => 'EUR ' ,
169- ],
170- 'taxPercentage ' => 20 ,
171- ],
172- ],
173- ]));
135+ $ molliePayment = $ this ->getPaidFirstPayment ();
174136
175137 Cashier::$ paymentModel ::createFromMolliePayment ($ molliePayment , $ this ->user );
176138
@@ -208,6 +170,41 @@ public function handlesAPaidFirstPayment()
208170 $ this ->assertSame (Order::first ()->items ->first ()->description_extra_lines [0 ], 'From 2019-01-01 to 2019-02-01 ' );
209171 }
210172
173+ #[Test]
174+ public function ignoresADuplicatePaidFirstPaymentWebhook ()
175+ {
176+ Event::fake ();
177+
178+ $ molliePayment = $ this ->getPaidFirstPayment ();
179+
180+ Cashier::$ paymentModel ::createFromMolliePayment ($ molliePayment , $ this ->user );
181+
182+ $ this ->withMockedGetMolliePayment (2 , $ molliePayment );
183+ $ this ->withMockedGetMollieMandateAccepted (2 );
184+ $ this ->withMockedGetMollieCustomer (2 );
185+ $ this ->withMockedUpdateMolliePayment ();
186+
187+ $ firstResponse = $ this ->post (route ('webhooks.mollie.first_payment ' , [
188+ 'id ' => 'tr_unique_payment_id ' ,
189+ ]));
190+
191+ $ secondResponse = $ this ->post (route ('webhooks.mollie.first_payment ' , [
192+ 'id ' => 'tr_unique_payment_id ' ,
193+ ]));
194+
195+ $ firstResponse ->assertStatus (200 );
196+ $ secondResponse ->assertStatus (200 );
197+
198+ $ this ->assertSame (1 , Order::count ());
199+ $ this ->assertSame (1 , Order::query ()->where ('mollie_payment_id ' , 'tr_unique_payment_id ' )->count ());
200+ $ this ->assertSame (1 , Cashier::$ paymentModel ::count ());
201+ $ this ->assertNotNull (Cashier::$ paymentModel ::first ()->order_id );
202+
203+ Event::assertDispatched (OrderProcessed::class, 1 );
204+ Event::assertDispatched (FirstPaymentPaid::class, 1 );
205+ Event::assertDispatched (SubscriptionStarted::class, 1 );
206+ }
207+
211208 #[Test]
212209 public function testWithCouponNoTrialValidatesCoupon ()
213210 {
@@ -270,6 +267,51 @@ public function testHandlesNoTrialMode()
270267 );
271268 }
272269
270+ protected function getPaidFirstPayment (): MolliePayment
271+ {
272+ $ molliePayment = new MolliePayment (new MollieApiClient );
273+ $ molliePayment ->id = 'tr_unique_payment_id ' ;
274+ $ molliePayment ->paidAt = Carbon::now ()->toIso8601String ();
275+ $ molliePayment ->mandateId = 'mdt_unique_mandate_id ' ;
276+ $ molliePayment ->amount = (object ) [
277+ 'currency ' => 'EUR ' ,
278+ 'value ' => '0.05 ' ,
279+ ];
280+ $ molliePayment ->metadata = json_decode (json_encode ([
281+ 'owner ' => [
282+ 'type ' => get_class ($ this ->user ),
283+ 'id ' => 1 ,
284+ ],
285+ 'actions ' => [
286+ [
287+ 'handler ' => StartSubscription::class,
288+ 'description ' => 'Monthly payment ' ,
289+ 'subtotal ' => [
290+ 'value ' => '0.00 ' ,
291+ 'currency ' => 'EUR ' ,
292+ ],
293+ 'taxPercentage ' => 20 ,
294+ 'plan ' => 'monthly-10-1 ' ,
295+ 'name ' => 'default ' ,
296+ 'quantity ' => 1 ,
297+ 'nextPaymentAt ' => now ()->addDays (12 )->toIso8601String (),
298+ 'trialUntil ' => now ()->addDays (5 )->toIso8601String (),
299+ ],
300+ [
301+ 'handler ' => AddGenericOrderItem::class,
302+ 'description ' => 'Test mandate payment ' ,
303+ 'subtotal ' => [
304+ 'value ' => '0.04 ' ,
305+ 'currency ' => 'EUR ' ,
306+ ],
307+ 'taxPercentage ' => 20 ,
308+ ],
309+ ],
310+ ]));
311+
312+ return $ molliePayment ;
313+ }
314+
273315 /**
274316 * @return \Laravel\Cashier\SubscriptionBuilder\FirstPaymentSubscriptionBuilder
275317 */
0 commit comments