'DE', 'phone' => '49', 'en' => 'Germany', 'de' => 'Deutschland', 'es' => 'Alemania', 'fr' => 'Allemagne', 'it' => 'Germania', 'ru' => 'Германия', ]); $shipping = Shipping::create(['name' => 'Standard', 'active' => true]); ShippingCountry::create(['shipping_id' => $shipping->id, 'country_id' => $country->id]); $account = UserAccount::create([ 'salutation' => 'Herr', 'first_name' => 'Max', 'last_name' => 'Muster', 'address' => 'Musterstr. 1', 'zipcode' => '12345', 'city' => 'Musterstadt', 'country_id' => $country->id, 'phone' => '123456', 'same_as_billing' => 1, 'language' => 'de', ]); $user = User::forceCreate([ 'email' => 'consultant-'.uniqid('', true).'@example.com', 'password' => bcrypt('secret'), 'lang' => 'de', 'account_id' => $account->id, ]); $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' => $user->email, 'shipping_email' => $user->email, 'billing_firstname' => 'Max', 'billing_lastname' => 'Muster', 'shipping_firstname' => 'Max', 'shipping_lastname' => 'Muster', 'same_as_billing' => 1, 'is_for' => 'me', 'is_from' => 'user_order', ]); ShoppingOrder::create([ 'shopping_user_id' => $shoppingUser->id, 'auth_user_id' => $user->id, 'member_id' => $user->id, 'country_id' => $country->id, 'user_shop_id' => $userShop->id, 'payment_for' => 3, 'total' => 100, 'subtotal' => 90, 'total_shipping' => 100, 'paid' => true, 'is_abo' => true, 'txaction' => 'paid', 'mode' => 'test', ]); $abo = UserAbo::create([ 'user_id' => $user->id, 'member_id' => $user->id, 'shopping_user_id' => $shoppingUser->id, 'is_for' => 'me', 'email' => $user->email, 'payone_userid' => 900200, 'clearingtype' => 'cc', 'active' => true, 'status' => 2, 'abo_interval' => 5, 'next_date' => now()->toDateString(), ]); $aboProduct = makeProduct(['12'], 119, 19); $oneTimeProduct = makeProduct(['2'], 50, 19); UserAboItem::create([ 'user_abo_id' => $abo->id, 'product_id' => $aboProduct->id, 'qty' => 1, 'comp' => 0, 'status' => 1, ]); UserAboOneTimeItem::create([ 'user_abo_id' => $abo->id, 'product_id' => $oneTimeProduct->id, 'qty' => 2, 'confirmed_qty' => 2, 'confirmed_at' => now(), 'price' => 50.0, 'price_net' => 42.017, 'tax_rate' => 19.0, 'tax' => 7.983, 'points' => 7, 'status' => 1, ]); return [ 'abo' => $abo->fresh(), 'aboProductId' => $aboProduct->id, 'oneTimeProductId' => $oneTimeProduct->id, ]; } it('schreibt verbindlich bestätigte Einmal-Artikel mit is_abo_addon in die Bestellung', function () { $fixture = makeMakeOrderFixture(); $userMakeOrder = new UserMakeOrder($fixture['abo']); $userMakeOrder->createShoppingUser(); $order = $userMakeOrder->makeShoppingOrder(); expect($order)->not->toBeFalse(); $aboItem = $order->shopping_order_items() ->where('product_id', $fixture['aboProductId']) ->first(); $addonItem = $order->shopping_order_items() ->where('product_id', $fixture['oneTimeProductId']) ->first(); expect($aboItem)->not->toBeNull() ->and((bool) $aboItem->is_abo_addon)->toBeFalse() ->and($addonItem)->not->toBeNull() ->and((bool) $addonItem->is_abo_addon)->toBeTrue() ->and((int) $addonItem->qty)->toBe(2); }); it('lässt user_abos.amount der reine Abo-Betrag (ohne Einmal-Artikel)', function () { $fixture = makeMakeOrderFixture(); $userMakeOrder = new UserMakeOrder($fixture['abo']); $userMakeOrder->createShoppingUser(); $order = $userMakeOrder->makeShoppingOrder(); $pureAboAmount = (float) $fixture['abo']->fresh()->amount; // Cent, nur Abo $combinedTotal = (float) $order->total_shipping * 100; // Cent, inkl. Einmal-Artikel // Der kombinierte Abbuchungsbetrag enthält die Einmal-Artikel, der gespeicherte // Abo-Betrag jedoch nicht -> kombiniert ist größer. expect($combinedTotal)->toBeGreaterThan($pureAboAmount); }); it('nimmt nur bestätigte Einmal-Artikel auf, offene Entwürfe nicht', function () { $fixture = makeMakeOrderFixture(); $abo = $fixture['abo']; // Zusätzlicher, NICHT bestätigter Einmal-Artikel $pendingProduct = makeProduct(['2'], 30, 19); UserAboOneTimeItem::create([ 'user_abo_id' => $abo->id, 'product_id' => $pendingProduct->id, 'qty' => 1, 'price' => 30.0, 'tax_rate' => 19.0, 'status' => 0, ]); $userMakeOrder = new UserMakeOrder($abo); $userMakeOrder->createShoppingUser(); $order = $userMakeOrder->makeShoppingOrder(); expect($order->shopping_order_items()->where('product_id', $pendingProduct->id)->exists())->toBeFalse() ->and($order->shopping_order_items()->where('product_id', $fixture['oneTimeProductId'])->exists())->toBeTrue(); }); it('entfernt beim Purge ALLE Einmal-Artikel (bestätigt, offen und soft-deleted)', function () { $fixture = makeMakeOrderFixture(); $abo = $fixture['abo']; // zusätzlich ein offener und ein soft-deleted Artikel $pending = makeProduct(['2'], 30, 19); UserAboOneTimeItem::create([ 'user_abo_id' => $abo->id, 'product_id' => $pending->id, 'qty' => 1, 'price' => 30.0, 'tax_rate' => 19.0, 'status' => 0, ]); $trashed = makeProduct(['2'], 20, 19); $trashedItem = UserAboOneTimeItem::create([ 'user_abo_id' => $abo->id, 'product_id' => $trashed->id, 'qty' => 1, 'confirmed_qty' => 1, 'confirmed_at' => now(), 'price' => 20.0, 'tax_rate' => 19.0, 'status' => 1, ]); $trashedItem->delete(); expect(UserAboOneTimeItem::withTrashed()->where('user_abo_id', $abo->id)->count())->toBe(3); AboOneTimeService::purgeAfterExecution($abo); expect(UserAboOneTimeItem::withTrashed()->where('user_abo_id', $abo->id)->count())->toBe(0); }); it('reduziert nach dem Purge nicht mehr benötigte Kompensationsprodukte', function () { $fixture = makeMakeOrderFixture(); $abo = $fixture['abo']; // Ein Comp-Abo-Artikel, der nach Wegfall der Einmal-Artikel nicht mehr nötig ist. $compProduct = makeProduct(['12'], 0, 0); UserAboItem::create([ 'user_abo_id' => $abo->id, 'product_id' => $compProduct->id, 'comp' => 1, 'qty' => 1, 'status' => 1, ]); expect(UserAboItem::where('user_abo_id', $abo->id)->where('comp', '>', 0)->count())->toBe(1); AboOneTimeService::purgeAfterExecution($abo); expect(UserAboItem::where('user_abo_id', $abo->id)->where('comp', '>', 0)->count())->toBe(0) ->and(UserAboOneTimeItem::withTrashed()->where('user_abo_id', $abo->id)->count())->toBe(0); }); it('entfernt durch reine Bestellerstellung KEINE Einmal-Artikel (behalten bei Fehler)', function () { $fixture = makeMakeOrderFixture(); $abo = $fixture['abo']; $userMakeOrder = new UserMakeOrder($abo); $userMakeOrder->createShoppingUser(); $userMakeOrder->makeShoppingOrder(); // makeShoppingOrder läuft sowohl im Erfolgs- als auch im Fehlerfall; der Purge // erfolgt ausschließlich separat im Erfolgszweig. Daher bleiben die Artikel hier erhalten. expect(UserAboOneTimeItem::where('user_abo_id', $abo->id)->count())->toBe(1); });