7); zusätzlich war user_abo_one_time_items.points noch * eine INT-Spalte. Die Punkte fließen über shopping_orders.points in * user_sales_volumes und damit in die Provisionsberechnung ein, der Verlust war * also nicht nur ein Anzeigefehler auf der Rechnung. */ use App\Models\Product; use App\Models\UserAboOneTimeItem; use App\Services\AboOneTimeService; use App\Services\AboOrderCart; use App\Services\Facade\Yard; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\DB; use Tests\TestCase; uses(TestCase::class, RefreshDatabase::class); /** Setzt die Punkte am Produkt an der Datenbank vorbei am Mutator-freien Weg. */ function makeProductWithPoints(array $showOn, float $points): Product { $product = makeProduct($showOn); DB::table('products')->where('id', $product->id)->update(['points' => $points]); return Product::findOrFail($product->id); } describe('Abo-Einmalartikel mit Dezimal-Punkten', function () { beforeEach(function () { makeShopEnv(); $this->service = new AboOneTimeService; }); it('behält halbe Punkte im Preis-Snapshot', function () { $abo = makeMeAbo(); $product = makeProductWithPoints(['2'], 7.5); $snapshot = AboOrderCart::buildOneTimeSnapshot($product, $abo); expect($snapshot['points'])->toBe(7.5); }); it('persistiert halbe Punkte am Einmal-Artikel', function () { $abo = makeMeAbo(); $product = makeProductWithPoints(['2'], 7.5); $message = $this->service->handleAction($abo, ['action' => 'add', 'product_id' => $product->id]); expect($message)->toBeNull(); $item = UserAboOneTimeItem::where('user_abo_id', $abo->id)->firstOrFail(); expect((float) $item->points)->toBe(7.5) ->and((float) DB::table('user_abo_one_time_items')->where('id', $item->id)->value('points'))->toBe(7.5); }); it('übernimmt halbe Punkte in den Abo-Yard', function () { $abo = makeMeAbo(); $product = makeProductWithPoints(['2'], 7.5); $this->service->handleAction($abo, ['action' => 'add', 'product_id' => $product->id]); $item = UserAboOneTimeItem::where('user_abo_id', $abo->id)->firstOrFail(); $item->update(['qty' => 2, 'confirmed_qty' => 2, 'confirmed_at' => now()]); AboOrderCart::addOneTimeItemsToYard($abo->fresh()); expect(Yard::instance(AboOrderCart::INSTANCE)->points())->toBe(15.0); }); it('lässt ganzzahlige Punkte unverändert', function () { $abo = makeMeAbo(); $product = makeProductWithPoints(['2'], 14.0); $snapshot = AboOrderCart::buildOneTimeSnapshot($product, $abo); expect($snapshot['points'])->toBe(14.0); }); })->group('abo');