CaiWuXiTong/tests/Unit/EcommerceFinance/DingWorklogPenaltyCalculatorTest.php

95 lines
4.1 KiB
PHP

<?php
namespace Tests\Unit\EcommerceFinance;
use App\Services\Auth\FinanceRoster;
use Illuminate\Support\Carbon;
use Mockery;
use Modules\EcommerceFinance\Repositories\DingWorklogMirrorRepository;
use Modules\EcommerceFinance\Services\DingWorklogPenaltyCalculator;
use Tests\TestCase;
class DingWorklogPenaltyCalculatorTest extends TestCase
{
public function test_penalties_double_for_each_person_and_accumulate(): void
{
config([
'dingtalk.worklog.penalty_start_date' => '2026-10-10',
'app.timezone' => 'Asia/Shanghai',
]);
$submitted = [];
$misses = [
'jiangling' => ['2026-10-10', '2026-10-12', '2026-10-18'],
'qiuxiang' => ['2026-10-12', '2026-10-18'],
];
foreach (['jiangling' => '江陵', 'qiuxiang' => '秋香'] as $userId => $name) {
for ($day = 10; $day <= 18; $day++) {
$date = sprintf('2026-10-%02d', $day);
if (! in_array($date, $misses[$userId], true)) {
$submitted[] = [
'creator_userid' => $userId,
'creator_name' => $name,
'statistics_date' => $date,
];
}
}
}
$repository = Mockery::mock(DingWorklogMirrorRepository::class);
$repository->shouldReceive('earliestStatisticsDate')->once()->andReturn('2026-10-01');
$repository->shouldReceive('submittedDatesByUser')
->once()->with('2026-10-10', '2026-10-18')->andReturn($submitted);
$roster = Mockery::mock(FinanceRoster::class);
$roster->shouldReceive('cachedFinanceMembers')->once()->andReturn([
['userid' => 'jiangling', 'name' => '江陵'],
['userid' => 'qiuxiang', 'name' => '秋香'],
]);
$result = (new DingWorklogPenaltyCalculator($repository, $roster))->summary(
'2026-10-10',
'2026-10-18',
Carbon::parse('2026-10-20 10:00:00', 'Asia/Shanghai'),
);
$this->assertSame('2026-10-10', $result['start_date']);
$this->assertSame('2026-10-18', $result['end_date']);
$this->assertSame('江陵', $result['members'][0]['name']);
$this->assertSame(['2026-10-10', '2026-10-12', '2026-10-18'], $result['members'][0]['missed_dates']);
$this->assertSame(3, $result['members'][0]['missed_count']);
$this->assertSame('10 + 20 + 40', $result['members'][0]['penalty_formula']);
$this->assertSame('70', $result['members'][0]['penalty_points']);
$this->assertSame('秋香', $result['members'][1]['name']);
$this->assertSame('10 + 20', $result['members'][1]['penalty_formula']);
$this->assertSame('30', $result['members'][1]['penalty_points']);
$this->assertSame('100', $result['total_points']);
$this->assertSame('100', $result['total_points_formatted']);
}
public function test_dates_before_november_fourth_are_not_charged(): void
{
config([
'dingtalk.worklog.penalty_start_date' => '2026-11-04',
'app.timezone' => 'Asia/Shanghai',
]);
$repository = Mockery::mock(DingWorklogMirrorRepository::class);
$repository->shouldReceive('earliestStatisticsDate')->once()->andReturn('2026-10-21');
$repository->shouldReceive('submittedDatesByUser')
->once()->with('2026-11-04', '2026-11-04')->andReturn([]);
$roster = Mockery::mock(FinanceRoster::class);
$roster->shouldReceive('cachedFinanceMembers')->once()->andReturn([
['userid' => 'jiangling', 'name' => '江陵'],
]);
$result = (new DingWorklogPenaltyCalculator($repository, $roster))->summary(
'2026-10-22',
'2026-11-04',
Carbon::parse('2026-11-05 13:00:00', 'Asia/Shanghai'),
);
$this->assertSame('2026-11-04', $result['start_date']);
$this->assertSame('2026-11-04', $result['end_date']);
$this->assertSame(['2026-11-04'], $result['members'][0]['missed_dates']);
$this->assertSame('10', $result['total_points']);
}
}