'storno-cat-'.uniqid().'@example.test', 'password' => bcrypt('secret'), 'lang' => 'de', 'admin' => 0, 'm_level' => 1, ]); } /** * Buchung wie auf dem regulaeren Bestellweg: `status_turnover` bleibt ungesetzt. */ function stornoCatVolume(User $user, int $status, float $points, ?int $statusTurnover = null): UserSalesVolume { return UserSalesVolume::forceCreate([ 'user_id' => $user->id, 'user_invoice_id' => 4711, 'month' => 9, 'year' => 2026, 'date' => '2026-09-05', 'points' => $points, 'total_net' => $points, 'status' => $status, 'status_points' => 1, 'status_turnover' => $statusTurnover, ]); } it('kennzeichnet den Storno einer Shopbestellung als Shopgeschaeft', function () { $user = stornoCatUser(); $original = stornoCatVolume($user, 2, 100.0); $cancellation = SalesPointsVolume::cancelSalesPointsVolume($original, 9911); expect((int) $cancellation->status_turnover)->toBe(2); }); it('kennzeichnet den Storno einer Beraterbestellung als Eigengeschaeft', function () { $user = stornoCatUser(); $original = stornoCatVolume($user, 1, 100.0); $cancellation = SalesPointsVolume::cancelSalesPointsVolume($original, 9911); expect((int) $cancellation->status_turnover)->toBe(1); }); it('mindert beim Shop-Storno die Shop-Provisionsbasis statt der Eigenwerte', function () { $user = stornoCatUser(); $original = stornoCatVolume($user, 2, 100.0); SalesPointsVolume::cancelSalesPointsVolume($original, 9911); $last = UserSalesVolume::where('user_id', $user->id)->orderByDesc('id')->first(); expect((float) $last->month_shop_total_net)->toBe(0.0) ->and((float) $last->month_shop_points)->toBe(0.0) ->and((float) $last->month_total_net)->toBe(0.0) ->and((float) $last->month_KP_points)->toBe(0.0); }); it('mindert beim Eigen-Storno die Eigenwerte und laesst die Shop-Basis unberuehrt', function () { $user = stornoCatUser(); stornoCatVolume($user, 2, 50.0); $original = stornoCatVolume($user, 1, 100.0); SalesPointsVolume::cancelSalesPointsVolume($original, 9911); $last = UserSalesVolume::where('user_id', $user->id)->orderByDesc('id')->first(); expect((float) $last->month_KP_points)->toBe(0.0) ->and((float) $last->month_total_net)->toBe(0.0) ->and((float) $last->month_shop_total_net)->toBe(50.0) ->and((float) $last->month_shop_points)->toBe(50.0); }); it('zaehlt jede Zeile genau einmal — Shop-Storno mindert die Kundenpunkte', function () { $user = stornoCatUser(); stornoCatVolume($user, 2, 100.0); stornoCatVolume($user, 6, -100.0, 2); $rows = UserSalesVolume::query() ->where('user_id', $user->id) ->selectRaw(SalesVolumePoints::ownPoints().' as own') ->selectRaw(SalesVolumePoints::externalPoints().' as external') ->selectRaw(SalesVolumePoints::totalPoints().' as total') ->first(); expect((float) $rows->own)->toBe(0.0) ->and((float) $rows->external)->toBe(0.0) ->and((float) $rows->total)->toBe(0.0); }); it('laesst Altzeilen ohne Herkunft bei den Eigenpunkten', function () { $user = stornoCatUser(); stornoCatVolume($user, 2, 100.0); stornoCatVolume($user, 6, -100.0); $rows = UserSalesVolume::query() ->where('user_id', $user->id) ->selectRaw(SalesVolumePoints::ownPoints().' as own') ->selectRaw(SalesVolumePoints::externalPoints().' as external') ->selectRaw(SalesVolumePoints::totalPoints().' as total') ->first(); expect((float) $rows->own)->toBe(-100.0) ->and((float) $rows->external)->toBe(100.0) ->and((float) $rows->total)->toBe(0.0); }); it('spiegelt den Storno einer Gutschrift mit Shop-Umsatz vollstaendig', function () { $user = stornoCatUser(); $credit = stornoCatVolume($user, 4, 100.0, 2); SalesPointsVolume::reCalculateSalesPointsVolume($user->id, 9, 2026); $before = $credit->fresh(); expect((float) $before->month_KP_points)->toBe(100.0) ->and((float) $before->month_shop_total_net)->toBe(100.0) ->and((float) $before->month_shop_points)->toBe(0.0); $cancellation = SalesPointsVolume::cancelSalesPointsVolume($credit, 9911)->fresh(); // Punkte gehen wie im Gutschrift-Zweig auf KP, der Umsatz auf den Shop. expect((int) $cancellation->storno_origin_status)->toBe(4) ->and((float) $cancellation->month_KP_points)->toBe(0.0) ->and((float) $cancellation->month_shop_points)->toBe(0.0) ->and((float) $cancellation->month_shop_total_net)->toBe(0.0) ->and((float) $cancellation->month_total_net)->toBe(0.0); }); it('haelt die Ursprungsart der Stornobuchung fest', function () { $user = stornoCatUser(); expect((int) SalesPointsVolume::cancelSalesPointsVolume(stornoCatVolume($user, 2, 10.0), 1)->storno_origin_status)->toBe(2) ->and((int) SalesPointsVolume::cancelSalesPointsVolume(stornoCatVolume($user, 1, 10.0), 2)->storno_origin_status)->toBe(1) ->and((int) SalesPointsVolume::cancelSalesPointsVolume(stornoCatVolume($user, 5, 10.0), 3)->storno_origin_status)->toBe(5); }); it('zaehlt den Storno einer Gutschrift bei den Eigenpunkten', function () { $user = stornoCatUser(); $credit = stornoCatVolume($user, 4, 100.0, 2); SalesPointsVolume::cancelSalesPointsVolume($credit, 9911); $rows = UserSalesVolume::query() ->where('user_id', $user->id) ->selectRaw(SalesVolumePoints::ownPoints().' as own') ->selectRaw(SalesVolumePoints::externalPoints().' as external') ->selectRaw(SalesVolumePoints::totalPoints().' as total') ->first(); expect((float) $rows->own)->toBe(0.0) ->and((float) $rows->external)->toBe(0.0) ->and((float) $rows->total)->toBe(0.0); });