Verhindert das Anlegen eines zweiten Abos (eigenes oder Kundenabo) wenn bereits eines initiiert ist bzw. ein offener Abo-Payment-Link existiert (redirectIfAboAlreadyInitiated). Payment-Links koennen jetzt geloescht werden, abgesichert ueber canDeleteInstance + Shop-Zugehoerigkeit, mit Erfolgs-/Fehler-Flash. Kundenabo-Uebersicht zeigt den Pending-Initial- Payment-Status (wartend / in Bearbeitung / fehlgeschlagen). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
223 lines
7.5 KiB
PHP
223 lines
7.5 KiB
PHP
<?php
|
|
|
|
use App\Models\Country;
|
|
use App\Models\Shipping;
|
|
use App\Models\ShippingCountry;
|
|
use App\Models\ShoppingInstance;
|
|
use App\Models\ShoppingOrder;
|
|
use App\Models\ShoppingPayment;
|
|
use App\Models\ShoppingUser;
|
|
use App\Models\UserAbo;
|
|
use App\Models\UserAboOrder;
|
|
use App\Models\UserShop;
|
|
use App\Services\AboHelper;
|
|
use App\Services\OrderPaymentService;
|
|
use App\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\URL;
|
|
use Tests\TestCase;
|
|
|
|
uses(TestCase::class, RefreshDatabase::class);
|
|
|
|
it('behandelt neue noch nicht bestaetigte Eigen-Abos als vorhandenes Abo', function (): void {
|
|
$fixture = createPendingInitialAboFixture();
|
|
|
|
expect(AboHelper::userHasAbo($fixture['user']))->toBeTrue()
|
|
->and($fixture['userAbo']->isPendingInitialPayment())->toBeTrue()
|
|
->and($fixture['userAbo']->hasInitialPaymentStatus())->toBeFalse()
|
|
->and($fixture['userAbo']->canDeletePendingInitialPayment())->toBeFalse();
|
|
});
|
|
|
|
it('behandelt neue Kunden-Abos anhand der E-Mail als vorhandenes Abo', function (): void {
|
|
$fixture = createPendingInitialAboFixture(['is_for' => 'ot']);
|
|
|
|
expect(AboHelper::hasAboByEmail($fixture['shoppingUser']->billing_email))->toBeTrue()
|
|
->and(AboHelper::memberHasAbo($fixture['shoppingUser']))->toBeTrue();
|
|
});
|
|
|
|
it('erlaubt das Loeschen eines neuen Abo-Eintrags erst bei fehlgeschlagener Erstzahlung', function (): void {
|
|
$fixture = createPendingInitialAboFixture(paymentOverrides: ['txaction' => 'failed']);
|
|
|
|
expect($fixture['userAbo']->fresh()->hasInitialPaymentStatus())->toBeTrue()
|
|
->and($fixture['userAbo']->fresh()->hasFailedInitialPayment())->toBeTrue()
|
|
->and($fixture['userAbo']->fresh()->canDeletePendingInitialPayment())->toBeTrue();
|
|
});
|
|
|
|
it('erlaubt Abo-Zahlungslink-Loeschung nur vor Zahlung oder nach Fehler', function (): void {
|
|
foreach ([0, 1, 5, 6] as $status) {
|
|
$instance = new ShoppingInstance(['status' => $status]);
|
|
expect(OrderPaymentService::canDeleteInstance($instance))->toBeTrue();
|
|
}
|
|
|
|
foreach ([2, 3, 4, 10] as $status) {
|
|
$instance = new ShoppingInstance(['status' => $status]);
|
|
expect(OrderPaymentService::canDeleteInstance($instance))->toBeFalse();
|
|
}
|
|
});
|
|
|
|
it('zeigt gesendete Abo-Zahlungslinks in der Kunden-Abo-Uebersicht', function (): void {
|
|
URL::resolveMissingNamedRoutesUsing(fn (string $name, array $parameters) => '/'.$name.'/'.implode('/', $parameters));
|
|
|
|
$fixture = createPendingInitialAboFixture();
|
|
$this->actingAs($fixture['user']);
|
|
$paymentLink = new ShoppingInstance([
|
|
'identifier' => 'paylink-'.uniqid(),
|
|
'user_shop_id' => $fixture['userShop']->id,
|
|
'payment' => 6,
|
|
'subdomain' => 'test.local',
|
|
'country_id' => $fixture['countryId'],
|
|
'amount' => 99.50,
|
|
'shopping_user_id' => $fixture['shoppingUser']->id,
|
|
'status' => 0,
|
|
'shopping_data' => [
|
|
'is_for' => 'abo-ot-customer',
|
|
'is_abo' => true,
|
|
'billing_email' => $fixture['shoppingUser']->billing_email,
|
|
],
|
|
]);
|
|
$paymentLink->created_at = now();
|
|
|
|
$html = view('user.abo.index', [
|
|
'user_abos' => collect(),
|
|
'abo_payment_links' => collect([$paymentLink]),
|
|
'view' => 'ot',
|
|
'isAdmin' => false,
|
|
])->render();
|
|
|
|
expect($html)
|
|
->toContain(__('abo.payment_link_sent_title'))
|
|
->toContain($paymentLink->identifier)
|
|
->toContain($fixture['shoppingUser']->billing_email)
|
|
->toContain(__('delete'));
|
|
});
|
|
|
|
it('blendet Abo-Zahlungslinks aus sobald daraus ein Abo existiert', function (): void {
|
|
$fixture = createPendingInitialAboFixture(['is_for' => 'ot']);
|
|
$paymentLink = new ShoppingInstance([
|
|
'user_shop_id' => $fixture['userShop']->id,
|
|
'payment' => 6,
|
|
'shopping_user_id' => $fixture['shoppingUser']->id,
|
|
'status' => 3,
|
|
'shopping_data' => [
|
|
'is_for' => 'abo-ot-customer',
|
|
'is_abo' => true,
|
|
'shopping_user_id' => $fixture['shoppingUser']->id,
|
|
'billing_email' => $fixture['shoppingUser']->billing_email,
|
|
],
|
|
]);
|
|
|
|
expect(OrderPaymentService::hasUserAboForPaymentLink($paymentLink, $fixture['user']))->toBeTrue();
|
|
});
|
|
|
|
/**
|
|
* @return array{user: User, userShop: UserShop, shoppingUser: ShoppingUser, userAbo: UserAbo, payment: ShoppingPayment, countryId: int}
|
|
*/
|
|
function createPendingInitialAboFixture(array $aboOverrides = [], array $paymentOverrides = []): array
|
|
{
|
|
$country = Country::create([
|
|
'code' => 'DE',
|
|
'phone' => '49',
|
|
'en' => 'Germany',
|
|
'de' => 'Deutschland',
|
|
'es' => 'Alemania',
|
|
'fr' => 'Allemagne',
|
|
'it' => 'Germania',
|
|
'ru' => 'Deutschland',
|
|
]);
|
|
|
|
$shipping = Shipping::create([
|
|
'name' => 'Standard',
|
|
'active' => true,
|
|
]);
|
|
|
|
$shippingCountry = ShippingCountry::create([
|
|
'shipping_id' => $shipping->id,
|
|
'country_id' => $country->id,
|
|
]);
|
|
|
|
$user = User::forceCreate([
|
|
'email' => 'pending-abo-'.uniqid('', true).'@example.com',
|
|
'password' => bcrypt('secret'),
|
|
'lang' => 'de',
|
|
]);
|
|
|
|
$userShop = UserShop::create([
|
|
'user_id' => $user->id,
|
|
'name' => 'TS'.substr(uniqid('', true), 0, 8),
|
|
'slug' => 'ts-'.uniqid(),
|
|
'active' => true,
|
|
]);
|
|
|
|
$shoppingUser = ShoppingUser::create([
|
|
'auth_user_id' => $user->id,
|
|
'member_id' => $user->id,
|
|
'billing_country_id' => $country->id,
|
|
'shipping_country_id' => $country->id,
|
|
'billing_email' => 'pending-customer-'.uniqid('', true).'@example.com',
|
|
'shipping_email' => $user->email,
|
|
'is_for' => $aboOverrides['is_for'] ?? 'me',
|
|
'is_from' => 'user_order',
|
|
]);
|
|
|
|
$shoppingOrder = ShoppingOrder::create([
|
|
'shopping_user_id' => $shoppingUser->id,
|
|
'auth_user_id' => $user->id,
|
|
'member_id' => $user->id,
|
|
'country_id' => $shippingCountry->id,
|
|
'user_shop_id' => $userShop->id,
|
|
'payment_for' => 2,
|
|
'is_abo' => true,
|
|
'abo_interval' => 5,
|
|
'paid' => false,
|
|
'mode' => 'test',
|
|
'total' => 100,
|
|
'subtotal' => 90,
|
|
]);
|
|
|
|
$payment = ShoppingPayment::create(array_merge([
|
|
'shopping_order_id' => $shoppingOrder->id,
|
|
'reference' => 'pending-ref-'.uniqid(),
|
|
'amount' => 10000,
|
|
'currency' => 'EUR',
|
|
'clearingtype' => 'cc',
|
|
'abo_interval' => 5,
|
|
'mode' => 'test',
|
|
], $paymentOverrides));
|
|
|
|
if (array_key_exists('txaction', $paymentOverrides)) {
|
|
$payment->txaction = $paymentOverrides['txaction'];
|
|
$payment->save();
|
|
}
|
|
|
|
$userAbo = UserAbo::create(array_merge([
|
|
'user_id' => $user->id,
|
|
'member_id' => $user->id,
|
|
'shopping_user_id' => $shoppingUser->id,
|
|
'email' => $shoppingUser->billing_email,
|
|
'is_for' => $aboOverrides['is_for'] ?? 'me',
|
|
'payone_userid' => 0,
|
|
'clearingtype' => 'cc',
|
|
'amount' => 10000,
|
|
'status' => 1,
|
|
'abo_interval' => 5,
|
|
'start_date' => now(),
|
|
'last_date' => now(),
|
|
'next_date' => now()->addMonth(),
|
|
], $aboOverrides));
|
|
|
|
UserAboOrder::create([
|
|
'user_abo_id' => $userAbo->id,
|
|
'shopping_order_id' => $shoppingOrder->id,
|
|
'status' => 1,
|
|
'paid' => false,
|
|
]);
|
|
|
|
return [
|
|
'user' => $user,
|
|
'userShop' => $userShop,
|
|
'shoppingUser' => $shoppingUser,
|
|
'userAbo' => $userAbo,
|
|
'payment' => $payment,
|
|
'countryId' => $shippingCountry->id,
|
|
];
|
|
}
|