'/'.$name.'/'.implode('/', $parameters) ); } function makePortalAboFixture(array $cardOverride = []): array { $shoppingUser = ShoppingUser::create([ 'auth_user_id' => 1, 'billing_firstname' => 'Karl', 'billing_lastname' => 'Kunde', 'billing_address' => 'Kundenweg 2', 'billing_zipcode' => '11111', 'billing_city' => 'Kundenstadt', 'billing_country_id' => 1, 'shipping_country_id' => 1, 'billing_email' => 'kunde@example.com', 'same_as_billing' => true, 'mode' => 'test', 'wp_order_number' => 0, ]); $abo = UserAbo::create([ 'user_id' => 1, 'shopping_user_id' => $shoppingUser->id, 'email' => 'kunde@example.com', 'clearingtype' => 'cc', 'wallettype' => '', 'payone_userid' => 111, 'carddata' => array_merge([ 'pseudocardpan' => 'OLD_PSEUDO', 'truncatedcardpan' => '411111XXXXXX0000', 'cardexpiredate' => '2501', ], $cardOverride), 'abo_interval' => 5, 'status' => 2, 'card_update_pending_at' => now(), ]); $customer = Customer::create([ 'name' => 'Karl Kunde', 'email' => 'kunde@example.com', 'shopping_user_id' => $shoppingUser->id, ]); return compact('shoppingUser', 'abo', 'customer'); } it('formats the masked card from token data only', function () { $abo = new UserAbo([ 'clearingtype' => 'cc', 'carddata' => ['truncatedcardpan' => '411111XXXXXX1234', 'cardexpiredate' => '3012'], ]); expect($abo->maskedCard())->toBe('411111XXXXXX1234 (12/30)'); $noToken = new UserAbo(['clearingtype' => 'cc', 'carddata' => ['pseudocardpan' => 'X']]); expect($noToken->maskedCard())->toBeNull(); }); it('renders the portal credit-card form with current card and cc fields', function () { stubMissingRoutes(); $abo = makePortalAboFixture()['abo']; $html = view('portal.abo._payment_method_form', ['user_abo' => $abo])->render(); expect($html) ->toContain('name="cc_cardpan"') ->toContain('name="cc_cardcvc2"') ->toContain('name="cc_cardexpiremonth"') ->toContain('411111XXXXXX0000 (01/25)') ->toContain(__('abo.update_payment_method')) ->toContain(__('abo.card_security_notice')); }); it('applies the stashed card on a successful 3-D Secure return', function () { stubMissingRoutes(); $fixture = makePortalAboFixture(); $this->actingAs($fixture['customer'], 'customers'); session(['abo_card_update.'.$fixture['abo']->id => [ 'carddata' => ['pseudocardpan' => 'NEW_PSEUDO', 'truncatedcardpan' => '555555XXXXXX9999', 'cardexpiredate' => '3011'], 'userid' => 777, ]]); (new AboController)->paymentMethodReturn( $fixture['abo']->id, 'success', app(AboPaymentMethodService::class) ); $abo = $fixture['abo']->fresh(); expect($abo->carddata['pseudocardpan'])->toBe('NEW_PSEUDO') ->and($abo->payone_userid)->toEqual(777) ->and($abo->card_update_pending_at)->toBeNull() ->and($abo->card_changes()->count())->toBe(1) ->and($abo->card_changes()->first()->source)->toBe('portal') ->and($abo->card_changes()->first()->masked_card)->toBe('555555XXXXXX9999 (11/30)'); }); it('clears the pending trace and keeps the card on a cancelled 3-D Secure return', function () { stubMissingRoutes(); $fixture = makePortalAboFixture(); $this->actingAs($fixture['customer'], 'customers'); (new AboController)->paymentMethodReturn( $fixture['abo']->id, 'cancel', app(AboPaymentMethodService::class) ); $abo = $fixture['abo']->fresh(); expect($abo->carddata['pseudocardpan'])->toBe('OLD_PSEUDO') ->and($abo->payone_userid)->toEqual(111) ->and($abo->card_update_pending_at)->toBeNull(); });