- 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>
122 lines
3.5 KiB
PHP
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);
|
|
});
|