mivita/tests/Feature/Incentive/DeletedAboSalesVolumeIncentiveTest.php
Kevin f6faad9ae7 Abo: extern-erledigt für gelöschte Abos + Lieferhistorie-Umzug (Ticket Kunz Mai-Punkte)
- AboExternalCompletionService: Bestellungen gelöschter/ersetzter Abos können
  nachträglich extern erledigt werden (Punkte + Status 8 + Versandstatus);
  das gelöschte Abo wird dabei nicht reaktiviert
- IncentiveTracker::trackSalesVolume: Abo-Zuordnung inkl. gelöschter Abos
  (withTrashed) - nachgebuchte Umsätze bereits getrackter Abos zählen weiter
- Neue Wartungs-Commands: abo:extern-done {shopping_order_id} und
  abo:move-orders {from_abo} {to_abo} (--dry-run, Guards: gleicher Kunde)
- Latent datumsabhängigen Alt-Test in AboExternalCompletionTest repariert
  (Buchung nutzt date(), nicht Carbon::setTestNow)

Fall Kunz (dev/2026-08-12-intensiv-tickets): Dannenhauers gelieferte, aber am
17.06. beim Nachtragen vergessene Mai-Order 53274 → abo:extern-done (+54 P);
Bockhackers Lieferhistorie von gelöschtem Abo 197 → 496 umgehängt (Zähler 4).
Bockhackers 24 P existieren bereits (Juni-Buchung der Mai-Lieferung).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 12:06:29 +00:00

122 lines
3.5 KiB
PHP

<?php
use App\Models\Country;
use App\Models\Incentive;
use App\Models\IncentiveNewAbo;
use App\Models\IncentiveParticipant;
use App\Models\IncentivePointsLog;
use App\Models\ShoppingOrder;
use App\Models\ShoppingUser;
use App\Models\UserAbo;
use App\Models\UserAboOrder;
use App\Models\UserSalesVolume;
use App\Services\Incentive\IncentiveTracker;
use App\User;
use Carbon\Carbon;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
beforeEach(function () {
Carbon::setTestNow(Carbon::parse('2026-08-19 12:00:00'));
});
afterEach(function () {
Carbon::setTestNow();
});
it('zaehlt nachgebuchte Umsatzpunkte auch, wenn das getrackte Kundenabo inzwischen geloescht ist', function () {
$consultant = User::forceCreate([
'email' => 'berater-'.uniqid('', true).'@example.com',
'password' => bcrypt('secret'),
'lang' => 'de',
]);
$incentive = Incentive::factory()->create([
'qualification_start' => '2026-04-01',
'qualification_end' => '2026-08-31',
'calculation_end' => '2026-08-31',
'status' => 1,
]);
$participant = IncentiveParticipant::factory()->create([
'incentive_id' => $incentive->id,
'user_id' => $consultant->id,
]);
$country = Country::firstOrCreate(['code' => 'DE'], [
'phone' => '49', 'en' => 'Germany', 'de' => 'Deutschland', 'es' => 'Alemania',
'fr' => 'Allemagne', 'it' => 'Germania', 'ru' => 'Германия',
]);
$shoppingUser = ShoppingUser::create([
'auth_user_id' => $consultant->id,
'member_id' => $consultant->id,
'billing_email' => 'kundin-'.uniqid('', true).'@example.com',
'billing_country_id' => $country->id,
'shipping_country_id' => $country->id,
'is_for' => 'ot',
]);
$abo = UserAbo::create([
'shopping_user_id' => $shoppingUser->id,
'member_id' => $consultant->id,
'is_for' => 'ot',
'email' => 'kundin-'.uniqid('', true).'@example.com',
'payone_userid' => 1,
'clearingtype' => 'cc',
'active' => true,
'status' => 2,
'abo_interval' => 5,
]);
IncentiveNewAbo::create([
'participant_id' => $participant->id,
'user_abo_id' => $abo->id,
'activated_at' => '2026-04-09',
]);
$order = ShoppingOrder::create([
'shopping_user_id' => $shoppingUser->id,
'auth_user_id' => $consultant->id,
'country_id' => $country->id,
'user_shop_id' => 1,
'payment_for' => 6,
'total' => 92.60,
'subtotal' => 82.79,
'points' => 54,
'paid' => false,
'is_abo' => true,
'mode' => 'live',
]);
UserAboOrder::create([
'user_abo_id' => $abo->id,
'shopping_order_id' => $order->id,
'status' => 8,
'paid' => false,
]);
// Abo wurde inzwischen geloescht (ersetzt) - wie im Fall Dannenhauer (#198)
$abo->delete();
$usv = UserSalesVolume::create([
'user_id' => $consultant->id,
'shopping_order_id' => $order->id,
'month' => 8,
'year' => 2026,
'points' => 54,
'status_points' => 1,
'total_net' => 82.79,
'status' => 2,
]);
IncentiveTracker::trackSalesVolume($usv);
$log = IncentivePointsLog::where('participant_id', $participant->id)
->where('user_sales_volume_id', $usv->id)
->where('is_storno', false)
->first();
expect($log)->not->toBeNull()
->and((int) $log->points_accumulated)->toBe(54)
->and((int) $log->month)->toBe(8);
});