178 lines
7.1 KiB
PHP
178 lines
7.1 KiB
PHP
<?php
|
||
|
||
namespace Tests\Unit\EcommerceFinance;
|
||
|
||
use Illuminate\Http\Client\Request;
|
||
use Illuminate\Support\Carbon;
|
||
use Illuminate\Support\Facades\Http;
|
||
use Modules\EcommerceFinance\Services\JushuitanOpenApiClient;
|
||
use RuntimeException;
|
||
use Tests\TestCase;
|
||
|
||
class JushuitanOpenApiClientTest extends TestCase
|
||
{
|
||
protected function setUp(): void
|
||
{
|
||
parent::setUp();
|
||
Carbon::setTestNow('2026-09-14 06:00:00');
|
||
config()->set('services.jushuitan', [
|
||
'base_url' => 'https://jushuitan.example.test/api/open/query.aspx',
|
||
'partner_id' => 'test-partner-id',
|
||
'partner_key' => 'test-partner-key',
|
||
'token' => 'test-token',
|
||
'timeout' => 20,
|
||
'product_operation_history_method' => 'worklog.query',
|
||
]);
|
||
Http::preventStrayRequests();
|
||
}
|
||
|
||
protected function tearDown(): void
|
||
{
|
||
Carbon::setTestNow();
|
||
parent::tearDown();
|
||
}
|
||
|
||
public function test_it_posts_signed_json_and_keeps_only_cost_price_operations(): void
|
||
{
|
||
Http::fake([
|
||
'https://jushuitan.example.test/*' => Http::response([
|
||
'code' => 0,
|
||
'page_size' => 2,
|
||
'page_index' => 1,
|
||
'has_next' => false,
|
||
'datas' => [[
|
||
'autoid' => 101,
|
||
'type' => '商品与库存管理导入',
|
||
'remark' => '采购价:72.2222->65',
|
||
'created' => '2026-06-06 14:32:02.993',
|
||
'creator_name' => '简尚',
|
||
'sku_id' => '15961G',
|
||
'i_id' => 'ZWJ0111',
|
||
'name' => '测试商品',
|
||
'properties_value' => '胡桃色',
|
||
'sku_type' => 'normal',
|
||
], [
|
||
'autoid' => 102,
|
||
'type' => '编辑',
|
||
'remark' => '商品名称:旧名称->新名称',
|
||
'created' => '2026-06-06 14:33:00',
|
||
'creator_name' => '测试人',
|
||
'sku_id' => '15961G',
|
||
]],
|
||
]),
|
||
]);
|
||
|
||
$result = (new JushuitanOpenApiClient())->getCostPriceOperationHistory(
|
||
Carbon::parse('2026-06-01 00:00:00'),
|
||
Carbon::parse('2026-06-08 00:00:00'),
|
||
1,
|
||
2000,
|
||
);
|
||
|
||
$this->assertSame(2, $result['source_rows']);
|
||
$this->assertCount(1, $result['records']);
|
||
$this->assertSame('101', $result['records'][0]['operation_id']);
|
||
$this->assertSame(72.2222, $result['records'][0]['before_price']);
|
||
$this->assertSame(65.0, $result['records'][0]['after_price']);
|
||
$this->assertEqualsWithDelta(-7.2222, $result['records'][0]['diff_amount'], 0.00001);
|
||
$this->assertSame('简尚', $result['records'][0]['operator_name']);
|
||
|
||
Http::assertSent(function (Request $request): bool {
|
||
parse_str((string) parse_url($request->url(), PHP_URL_QUERY), $query);
|
||
$timestamp = (string) Carbon::now()->timestamp;
|
||
|
||
return $request->method() === 'POST'
|
||
&& str_starts_with($request->url(), 'https://jushuitan.example.test/api/open/query.aspx?')
|
||
&& str_starts_with((string) $request->header('Content-Type')[0], 'application/json')
|
||
&& $query === [
|
||
'method' => 'worklog.query',
|
||
'partnerid' => 'test-partner-id',
|
||
'token' => 'test-token',
|
||
'ts' => $timestamp,
|
||
'sign' => md5('worklog.querytest-partner-idtokentest-tokents' . $timestamp . 'test-partner-key'),
|
||
]
|
||
&& $request->data() === [
|
||
'page_index' => 1,
|
||
'page_size' => 50,
|
||
'modified_begin' => '2026-06-01 00:00:00',
|
||
'modified_end' => '2026-06-08 00:00:00',
|
||
];
|
||
});
|
||
}
|
||
|
||
public function test_it_preserves_unparsed_cost_operation_content_without_inventing_prices(): void
|
||
{
|
||
Http::fake([
|
||
'*' => Http::response([
|
||
'code' => 0,
|
||
'page_index' => 1,
|
||
'has_next' => false,
|
||
'datas' => [[
|
||
'autoid' => 103,
|
||
'remark' => '采购价已由批量任务更新',
|
||
'created' => '2026-06-07 08:00:00',
|
||
'sku_id' => 'SKU-UNPARSED',
|
||
]],
|
||
]),
|
||
]);
|
||
|
||
$result = (new JushuitanOpenApiClient())->getCostPriceOperationHistory(
|
||
Carbon::parse('2026-06-01'),
|
||
Carbon::parse('2026-06-30'),
|
||
1,
|
||
100,
|
||
);
|
||
|
||
$this->assertCount(1, $result['records']);
|
||
$this->assertNull($result['records'][0]['before_price']);
|
||
$this->assertNull($result['records'][0]['after_price']);
|
||
$this->assertSame('采购价已由批量任务更新', $result['records'][0]['operation_description']);
|
||
}
|
||
|
||
public function test_it_rejects_missing_credentials_and_upstream_error_codes(): void
|
||
{
|
||
config()->set('services.jushuitan.token', null);
|
||
try {
|
||
(new JushuitanOpenApiClient())->getCostPriceOperationHistory(now(), now(), 1, 100);
|
||
$this->fail('Expected missing credential exception.');
|
||
} catch (RuntimeException $exception) {
|
||
$this->assertSame('jushuitan_classic_api_credentials_missing', $exception->getMessage());
|
||
}
|
||
|
||
config()->set('services.jushuitan.token', 'test-token');
|
||
Http::fake(['*' => Http::response(['code' => 10001, 'msg' => 'denied'])]);
|
||
|
||
$this->expectExceptionMessage('jushuitan_api_code_10001');
|
||
(new JushuitanOpenApiClient())->getCostPriceOperationHistory(now(), now(), 1, 100);
|
||
}
|
||
|
||
public function test_it_reports_an_invalid_classic_partner_id_without_exposing_upstream_text(): void
|
||
{
|
||
Http::fake(['*' => Http::response([
|
||
'code' => 100,
|
||
'msg' => '验证失败! partnerid 无效',
|
||
])]);
|
||
|
||
$this->expectExceptionMessage('jushuitan_classic_api_partner_id_invalid');
|
||
(new JushuitanOpenApiClient())->getCostPriceOperationHistory(now(), now(), 1, 50);
|
||
}
|
||
|
||
public function test_new_platform_app_credentials_do_not_replace_classic_credentials(): void
|
||
{
|
||
config()->set('services.jushuitan.partner_id', null);
|
||
config()->set('services.jushuitan.partner_key', null);
|
||
config()->set('services.jushuitan.token', null);
|
||
config()->set('services.jushuitan.app_key', 'new-platform-app-key');
|
||
config()->set('services.jushuitan.app_secret', 'new-platform-app-secret');
|
||
config()->set('services.jushuitan.access_token', 'new-platform-access-token');
|
||
|
||
try {
|
||
(new JushuitanOpenApiClient())->getCostPriceOperationHistory(now(), now(), 1, 50);
|
||
$this->fail('Expected missing classic credential exception.');
|
||
} catch (RuntimeException $exception) {
|
||
$this->assertSame('jushuitan_classic_api_credentials_missing', $exception->getMessage());
|
||
}
|
||
Http::assertNothingSent();
|
||
}
|
||
}
|