102 lines
3.6 KiB
PHP
102 lines
3.6 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit\EcommerceFinance;
|
|
|
|
use Illuminate\Http\Client\Request;
|
|
use Illuminate\Support\Carbon;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Modules\EcommerceFinance\Exceptions\DingTalkAttendanceException;
|
|
use Modules\EcommerceFinance\Services\DingTalkAttendanceClient;
|
|
use Tests\TestCase;
|
|
|
|
class DingTalkAttendanceClientTest extends TestCase
|
|
{
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
Cache::flush();
|
|
config([
|
|
'dingtalk.client_id' => 'test-client',
|
|
'dingtalk.client_secret' => 'test-secret',
|
|
'dingtalk.app_token_url' => 'https://example.test/token',
|
|
'dingtalk.timeout' => 3,
|
|
'dingtalk.attendance.page_size' => 2,
|
|
'dingtalk.attendance.max_pages' => 10,
|
|
]);
|
|
}
|
|
|
|
public function test_attendance_records_are_read_across_pages_and_deduplicated(): void
|
|
{
|
|
Http::fake(function (Request $request) {
|
|
if (str_starts_with($request->url(), 'https://example.test/token')) {
|
|
return Http::response([
|
|
'errcode' => 0,
|
|
'access_token' => 'test-token',
|
|
]);
|
|
}
|
|
|
|
$offset = (int) ($request->data()['offset'] ?? 0);
|
|
if ($offset === 0) {
|
|
return Http::response([
|
|
'errcode' => 0,
|
|
'errmsg' => 'ok',
|
|
'recordresult' => [
|
|
['id' => 1, 'userId' => 'user-a', 'workDate' => 1793721600000],
|
|
['id' => 2, 'userId' => 'user-a', 'workDate' => 1793721600000],
|
|
],
|
|
]);
|
|
}
|
|
|
|
return Http::response([
|
|
'errcode' => 0,
|
|
'errmsg' => 'ok',
|
|
'recordresult' => [
|
|
['id' => 2, 'userId' => 'user-a', 'workDate' => 1793721600000],
|
|
],
|
|
]);
|
|
});
|
|
|
|
$result = app(DingTalkAttendanceClient::class)->listRecords(
|
|
['user-a'],
|
|
Carbon::parse('2026-11-04 00:00:00', 'Asia/Shanghai'),
|
|
Carbon::parse('2026-11-04 23:59:59', 'Asia/Shanghai'),
|
|
);
|
|
|
|
$this->assertSame(2, $result['pages']);
|
|
$this->assertSame([1, 2], array_column($result['records'], 'id'));
|
|
Http::assertSentCount(3);
|
|
Http::assertSent(static fn (Request $request): bool =>
|
|
str_contains($request->url(), '/attendance/list?access_token=test-token')
|
|
&& ($request->data()['userIdList'] ?? []) === ['user-a']
|
|
&& ($request->data()['limit'] ?? null) === 2
|
|
);
|
|
}
|
|
|
|
public function test_missing_attendance_permission_has_a_stable_error_code(): void
|
|
{
|
|
Http::fake([
|
|
'https://example.test/token*' => Http::response([
|
|
'errcode' => 0,
|
|
'access_token' => 'test-token',
|
|
]),
|
|
'https://oapi.dingtalk.com/attendance/list*' => Http::response([
|
|
'errcode' => 60011,
|
|
'errmsg' => 'requiredScopes=[qyapi_attendance_isv_query_result,qyapi_get_attendance_data]',
|
|
]),
|
|
]);
|
|
|
|
try {
|
|
app(DingTalkAttendanceClient::class)->listRecords(
|
|
['user-a'],
|
|
Carbon::parse('2026-11-04 00:00:00', 'Asia/Shanghai'),
|
|
Carbon::parse('2026-11-04 23:59:59', 'Asia/Shanghai'),
|
|
);
|
|
$this->fail('缺少考勤查询权限时应抛出异常。');
|
|
} catch (DingTalkAttendanceException $exception) {
|
|
$this->assertSame('dingtalk_attendance_permission_required', $exception->errorCode);
|
|
}
|
|
}
|
|
}
|