CaiWuXiTong/tests/Unit/EcommerceFinance/JushuitanOpenApiClientTest.php

151 lines
5.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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',
'app_key' => 'test-app-key',
'app_secret' => 'test-app-secret',
'access_token' => 'test-access-token',
'timeout' => 20,
'product_operation_history_path' => '/open/webapi/itemapi/itemsku/queryitemskuopshistory',
]);
Http::preventStrayRequests();
}
protected function tearDown(): void
{
Carbon::setTestNow();
parent::tearDown();
}
public function test_it_posts_signed_form_and_keeps_only_cost_price_operations(): void
{
Http::fake([
'https://jushuitan.example.test/*' => Http::response([
'code' => 0,
'data' => [
'page' => ['current_page' => 1, 'page_size' => 2000, 'count' => 2, 'pages' => 1],
'list' => [[
'autoid' => 101,
'operation_type' => '商品与库存管理导入',
'operation_description' => '采购价: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,
'operation_type' => '编辑',
'operation_description' => '商品名称:旧名称->新名称',
'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-30 23:59:59'),
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 {
$data = $request->data();
$sign = $data['sign'] ?? null;
unset($data['sign']);
ksort($data, SORT_STRING);
$plain = 'test-app-secret';
foreach ($data as $key => $value) {
$plain .= $key . (string) $value;
}
$biz = json_decode((string) ($data['biz'] ?? ''), true);
return $request->method() === 'POST'
&& $request->url() === 'https://jushuitan.example.test/open/webapi/itemapi/itemsku/queryitemskuopshistory'
&& str_starts_with((string) $request->header('Content-Type')[0], 'application/x-www-form-urlencoded')
&& $sign === md5($plain)
&& $biz === [
'current_page' => 1,
'page_size' => 2000,
'start_time' => '2026-06-01 00:00:00',
'end_time' => '2026-06-30 23:59:59',
];
});
}
public function test_it_preserves_unparsed_cost_operation_content_without_inventing_prices(): void
{
Http::fake([
'*' => Http::response([
'code' => 0,
'data' => [
'page' => ['current_page' => 1, 'count' => 1, 'pages' => 1],
'list' => [[
'autoid' => 103,
'operation_description' => '采购价已由批量任务更新',
'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.access_token', null);
try {
(new JushuitanOpenApiClient())->getCostPriceOperationHistory(now(), now(), 1, 100);
$this->fail('Expected missing credential exception.');
} catch (RuntimeException $exception) {
$this->assertSame('jushuitan_api_credentials_missing', $exception->getMessage());
}
config()->set('services.jushuitan.access_token', 'test-access-token');
Http::fake(['*' => Http::response(['code' => 10001, 'msg' => 'denied'])]);
$this->expectExceptionMessage('jushuitan_api_code_10001');
(new JushuitanOpenApiClient())->getCostPriceOperationHistory(now(), now(), 1, 100);
}
}