'2026-04-01', 'qualification_end' => '2026-07-31', 'calculation_end' => '2026-08-31', ]); expect($incentive->isInQualificationPeriod(Carbon::parse('2026-05-15')))->toBeTrue() ->and($incentive->isInQualificationPeriod(Carbon::parse('2026-04-01')))->toBeTrue() ->and($incentive->isInQualificationPeriod(Carbon::parse('2026-07-31')))->toBeTrue() ->and($incentive->isInQualificationPeriod(Carbon::parse('2026-03-31')))->toBeFalse() ->and($incentive->isInQualificationPeriod(Carbon::parse('2026-08-01')))->toBeFalse(); }); it('detects calculation period correctly', function () { $incentive = new Incentive([ 'qualification_start' => '2026-04-01', 'qualification_end' => '2026-07-31', 'calculation_end' => '2026-08-31', ]); expect($incentive->isInCalculationPeriod(Carbon::parse('2026-08-15')))->toBeTrue() ->and($incentive->isInCalculationPeriod(Carbon::parse('2026-04-01')))->toBeTrue() ->and($incentive->isInCalculationPeriod(Carbon::parse('2026-09-01')))->toBeFalse() ->and($incentive->isInCalculationPeriod(Carbon::parse('2026-03-31')))->toBeFalse(); }); it('checks date in scope by month/year', function () { $incentive = new Incentive([ 'qualification_start' => '2026-04-01', 'calculation_end' => '2026-08-31', ]); expect($incentive->isDateInScope(4, 2026))->toBeTrue() ->and($incentive->isDateInScope(8, 2026))->toBeTrue() ->and($incentive->isDateInScope(9, 2026))->toBeFalse() ->and($incentive->isDateInScope(3, 2026))->toBeFalse(); }); it('returns correct calculation months', function () { $incentive = new Incentive([ 'qualification_start' => '2026-04-01', 'calculation_end' => '2026-08-31', ]); $months = $incentive->getCalculationMonths(); expect($months)->toHaveCount(5) ->and($months[0])->toBe(['month' => 4, 'year' => 2026]) ->and($months[1])->toBe(['month' => 5, 'year' => 2026]) ->and($months[4])->toBe(['month' => 8, 'year' => 2026]); }); // === Incentive: Status === it('detects status types correctly', function () { $draft = new Incentive(['status' => 0]); $active = new Incentive(['status' => 1]); $closed = new Incentive(['status' => 2]); expect($draft->isDraft())->toBeTrue() ->and($draft->isActive())->toBeFalse() ->and($active->isActive())->toBeTrue() ->and($active->isDraft())->toBeFalse() ->and($closed->isClosed())->toBeTrue() ->and($closed->isActive())->toBeFalse(); }); it('returns correct status colors', function () { expect((new Incentive(['status' => 0]))->getStatusColor())->toBe('warning') ->and((new Incentive(['status' => 1]))->getStatusColor())->toBe('success') ->and((new Incentive(['status' => 2]))->getStatusColor())->toBe('secondary'); }); // === IncentiveParticipant: Qualifikation === it('qualifies with enough partners and abos', function () { $incentive = new Incentive(['min_direct_partners' => 4, 'min_customer_abos' => 6]); $participant = new IncentiveParticipant([ 'qualified_partners' => 4, 'qualified_abos' => 6, ]); $participant->setRelation('incentive', $incentive); expect($participant->checkQualification())->toBeTrue() ->and($participant->is_qualified)->toBeTrue(); }); it('does not qualify with insufficient partners', function () { $incentive = new Incentive(['min_direct_partners' => 4, 'min_customer_abos' => 6]); $participant = new IncentiveParticipant([ 'qualified_partners' => 3, 'qualified_abos' => 6, ]); $participant->setRelation('incentive', $incentive); expect($participant->checkQualification())->toBeFalse() ->and($participant->is_qualified)->toBeFalse(); }); it('does not qualify with insufficient abos', function () { $incentive = new Incentive(['min_direct_partners' => 4, 'min_customer_abos' => 6]); $participant = new IncentiveParticipant([ 'qualified_partners' => 5, 'qualified_abos' => 5, ]); $participant->setRelation('incentive', $incentive); expect($participant->checkQualification())->toBeFalse(); }); it('does not qualify with zero partners and zero abos', function () { $incentive = new Incentive(['min_direct_partners' => 4, 'min_customer_abos' => 6]); $participant = new IncentiveParticipant([ 'qualified_partners' => 0, 'qualified_abos' => 0, ]); $participant->setRelation('incentive', $incentive); expect($participant->checkQualification())->toBeFalse(); }); it('qualifies with exact minimums', function () { $incentive = new Incentive(['min_direct_partners' => 4, 'min_customer_abos' => 6]); $participant = new IncentiveParticipant([ 'qualified_partners' => 4, 'qualified_abos' => 6, ]); $participant->setRelation('incentive', $incentive); expect($participant->checkQualification())->toBeTrue(); }); it('qualifies with more than minimums', function () { $incentive = new Incentive(['min_direct_partners' => 4, 'min_customer_abos' => 6]); $participant = new IncentiveParticipant([ 'qualified_partners' => 10, 'qualified_abos' => 12, ]); $participant->setRelation('incentive', $incentive); expect($participant->checkQualification())->toBeTrue(); }); // === IncentiveParticipant: Winner === it('is winner when qualified and rank within max_winners', function () { $incentive = new Incentive(['max_winners' => 30]); $participant = new IncentiveParticipant([ 'is_qualified' => true, 'rank' => 5, ]); $participant->setRelation('incentive', $incentive); expect($participant->isWinner())->toBeTrue(); }); it('is winner at rank boundary', function () { $incentive = new Incentive(['max_winners' => 30]); $participant = new IncentiveParticipant([ 'is_qualified' => true, 'rank' => 30, ]); $participant->setRelation('incentive', $incentive); expect($participant->isWinner())->toBeTrue(); }); it('is not winner when rank exceeds max_winners', function () { $incentive = new Incentive(['max_winners' => 30]); $participant = new IncentiveParticipant([ 'is_qualified' => true, 'rank' => 31, ]); $participant->setRelation('incentive', $incentive); expect($participant->isWinner())->toBeFalse(); }); it('is not winner when not qualified even with good rank', function () { $incentive = new Incentive(['max_winners' => 30]); $participant = new IncentiveParticipant([ 'is_qualified' => false, 'rank' => 1, ]); $participant->setRelation('incentive', $incentive); expect($participant->isWinner())->toBeFalse(); }); it('is not winner when rank is null', function () { $incentive = new Incentive(['max_winners' => 30]); $participant = new IncentiveParticipant([ 'is_qualified' => true, 'rank' => null, ]); $participant->setRelation('incentive', $incentive); expect($participant->isWinner())->toBeFalse(); }); // === IncentivePointsLog: Helpers === it('calculates total points from onetime and accumulated', function () { $log = new IncentivePointsLog([ 'points_onetime' => 600, 'points_accumulated' => 150, ]); expect($log->getTotalPoints())->toBe(750); }); it('formats month/year correctly', function () { $log = new IncentivePointsLog(['month' => 4, 'year' => 2026]); expect($log->getFormattedMonthYear())->toBe('04/2026'); $log2 = new IncentivePointsLog(['month' => 12, 'year' => 2026]); expect($log2->getFormattedMonthYear())->toBe('12/2026'); });