199 lines
14 KiB
PHP
199 lines
14 KiB
PHP
<?php
|
||
|
||
namespace Tests\Unit\EcommerceFinance;
|
||
|
||
use App\Models\Business\CourierSurchargeQuote;
|
||
use Illuminate\Database\Schema\Blueprint;
|
||
use Illuminate\Support\Facades\DB;
|
||
use Illuminate\Support\Facades\Schema;
|
||
use Modules\EcommerceFinance\Repositories\CourierSurchargeSettlementMirrorRepository;
|
||
use Modules\EcommerceFinance\Repositories\GenericBusinessMirrorRepository;
|
||
use Modules\EcommerceFinance\Services\BusinessMirrorDatasetRegistry;
|
||
use Tests\TestCase;
|
||
|
||
class CourierSurchargeSettlementMirrorRepositoryTest extends TestCase
|
||
{
|
||
private CourierSurchargeSettlementMirrorRepository $repository;
|
||
|
||
protected function setUp(): void
|
||
{
|
||
parent::setUp();
|
||
|
||
config([
|
||
'database.connections.business_mirror' => [
|
||
'driver' => 'sqlite', 'database' => ':memory:', 'prefix' => '',
|
||
],
|
||
'upstream_mirrors.connection' => 'business_mirror',
|
||
'upstream_mirrors.courier_surcharge_settlement.approved_values' => ['通过', '同意', '同意记账'],
|
||
'upstream_mirrors.datasets' => [
|
||
'jiansun.dbo.ekf_Bookkeeping' => [
|
||
'source_key' => 'jiansun', 'schema' => 'dbo', 'object' => 'ekf_Bookkeeping',
|
||
'target' => 'js_ekf_bookkeeping_surcharge', 'keys' => ['Id'], 'watermark' => 'CreationTime',
|
||
'columns' => ['Id', 'CreationTime', 'OrderNum', 'ExpressNum', 'ExpressName', 'ShopCode', 'Province', 'City', 'District', 'Address', 'SupplierName', 'SkuName', 'SkuCode', 'Result', 'UserName', 'Payfee', 'SecodaryCause', 'ReasonId', 'State', 'Delete', 'IsAgreeReason', 'ProcessingState', 'BookkeepingName', 'PayTime', 'Svolume', 'Skuweight', 'IfReturn', 'IfBuckle', 'FuZhuMain', 'FuZhuMinor', 'ShipExpressName', 'expressCause', 'receivingDepartment', 'returnCost', 'shopproid'],
|
||
'fixed_filters' => ['IsAgreeReason' => ['通过', '同意', '同意记账']],
|
||
],
|
||
'jiansun.dbo.express_Original' => [
|
||
'source_key' => 'jiansun', 'schema' => 'dbo', 'object' => 'express_Original',
|
||
'target' => 'js_express_original', 'keys' => ['Id'], 'watermark' => 'DeliveryTime',
|
||
'columns' => ['Id', 'ExpressName', 'OrderNum', 'DeliveryTime', 'Lenght', 'Width', 'Height', 'Volume', 'SkuCode', 'JiaoYiNum', 'ShopName', 'SetMoney', 'SetWeight', 'shopproid'],
|
||
],
|
||
'jiansun.dbo.ekf_BookkeepingConfig' => [
|
||
'source_key' => 'jiansun', 'schema' => 'dbo', 'object' => 'ekf_BookkeepingConfig',
|
||
'target' => 'js_ekf_bookkeeping_config', 'keys' => ['Id'], 'watermark' => 'CreateTime',
|
||
'columns' => ['Id', 'Name', 'ParentId', 'CreateTime'],
|
||
],
|
||
'jiansun.dbo.ekf_rCheck_Piece' => [
|
||
'source_key' => 'jiansun', 'schema' => 'dbo', 'object' => 'ekf_rCheck_Piece',
|
||
'target' => 'js_ekf_rcheck_piece', 'keys' => ['Id'], 'watermark' => 'UpdateTime',
|
||
'columns' => ['Id', 'CheckType', 'ExpressNum', 'OrderNum', 'CheckSDType', 'CheckReason', 'State', 'Accounting', 'ReturnState', 'CreationTime', 'UpdateTime', 'Delete', 'OmsSDName', 'DHLName', 'SkuCode', 'shopproid'],
|
||
],
|
||
'jiansun.dbo.ekf_rCheckPieceConfig' => [
|
||
'source_key' => 'jiansun', 'schema' => 'dbo', 'object' => 'ekf_rCheckPieceConfig',
|
||
'target' => 'js_ekf_rcheck_piece_config', 'keys' => ['Id'], 'watermark' => 'CreateTime',
|
||
'columns' => ['Id', 'ParentId', 'Name', 'Code', 'Type', 'Delete', 'CreateTime'],
|
||
],
|
||
'jiansun.dbo.jst_order_express_details' => [
|
||
'source_key' => 'jiansun', 'schema' => 'dbo', 'object' => 'jst_order_express_details',
|
||
'target' => 'js_jst_order_express_details', 'keys' => ['id'], 'watermark' => 'updatedAt',
|
||
'columns' => ['id', 'updatedAt', 'inner_order_id', 'so_id', 'logistic_id', 'logistic_company_name', 'logistic_status_name', 'platform_name', 'shop_name', 'warehouse_name', 'send_time', 'weight', 'f_weight'],
|
||
],
|
||
'jiansun.dbo.Jst_SendData_View_extension' => [
|
||
'source_key' => 'jiansun', 'schema' => 'dbo', 'object' => 'Jst_SendData_View_extension',
|
||
'target' => 'js_jst_send_data_view_extension', 'keys' => ['Id'], 'watermark' => null,
|
||
'columns' => ['Id', 'io_id', 'qty', 'l', 'w', 'h', 'sku_ids', 'sku_name', 'so_id', 'shop_site', 'shop_name', 'shop_i_id', 'supplier_name', 'receiver_state', 'receiver_city', 'receiver_district', 'expressName', 'wareHoursName', 'volume', 'weight'],
|
||
],
|
||
'jiansun.dbo.jst_salesOutboundInfo' => [
|
||
'source_key' => 'jiansun', 'schema' => 'dbo', 'object' => 'jst_salesOutboundInfo',
|
||
'target' => 'js_jst_sales_outbound_info', 'keys' => ['Id'], 'watermark' => 'updateTime',
|
||
'columns' => ['Id', 'io_id', 'modified', 'updateTime', 'f_weight', 'weight', 'f_freight', 'freight', 'pay_date', 'volume', 'f_volume'],
|
||
],
|
||
'jiansun.dbo.ekf_ReturnPickupManagement' => [
|
||
'source_key' => 'jiansun', 'schema' => 'dbo', 'object' => 'ekf_ReturnPickupManagement',
|
||
'target' => 'js_ekf_return_pickup_management', 'keys' => ['Id'], 'watermark' => 'updateTime',
|
||
'columns' => ['Id', 'orderId', 'returnExpressNo', 'transactionNo', 'updateTime'],
|
||
],
|
||
],
|
||
]);
|
||
DB::purge('business_mirror');
|
||
|
||
$schema = Schema::connection('business_mirror');
|
||
$schema->create('business_mirror_table_states', function (Blueprint $table): void {
|
||
$table->string('dataset_key')->primary();
|
||
$table->dateTime('initial_completed_at')->nullable();
|
||
$table->string('status')->nullable();
|
||
$table->dateTime('last_succeeded_at')->nullable();
|
||
$table->string('last_error_code')->nullable();
|
||
});
|
||
$this->createMirrorTables($schema);
|
||
|
||
$this->repository = new CourierSurchargeSettlementMirrorRepository(
|
||
app('db'),
|
||
new BusinessMirrorDatasetRegistry(),
|
||
new GenericBusinessMirrorRepository(app('db')),
|
||
);
|
||
}
|
||
|
||
public function test_it_maps_approved_bookkeeping_to_requested_fields_and_uses_outbound_weight(): void
|
||
{
|
||
$db = DB::connection('business_mirror');
|
||
$this->markReady($db);
|
||
|
||
$db->table('js_ekf_bookkeeping_config')->insert([
|
||
['Id' => 10, 'Name' => '退回', 'ParentId' => null],
|
||
['Id' => 20, 'Name' => '二级原因', 'ParentId' => 1],
|
||
]);
|
||
$db->table('js_ekf_rcheck_piece_config')->insert([
|
||
['Id' => 1, 'ParentId' => null, 'Name' => '一级查件', 'Code' => null, 'Type' => null, 'Delete' => null],
|
||
['Id' => 2, 'ParentId' => 1, 'Name' => '二级查件原因', 'Code' => null, 'Type' => null, 'Delete' => null],
|
||
]);
|
||
$db->table('js_ekf_bookkeeping_surcharge')->insert([
|
||
'Id' => 1, 'CreationTime' => '2026-09-27 10:00:00', 'OrderNum' => 'SO-1', 'ExpressNum' => 'WB-1',
|
||
'ExpressName' => '备用快递', 'ShopCode' => '备用店铺', 'SkuCode' => '备用编码', 'Payfee' => 3.2,
|
||
'SecodaryCause' => 20, 'ReasonId' => 10, 'IsAgreeReason' => '同意', 'Svolume' => 1.1,
|
||
'Skuweight' => 0.9, 'IfReturn' => '已退回', 'IfBuckle' => null, 'ShipExpressName' => null,
|
||
'expressCause' => null, 'shopproid' => '备用商品',
|
||
]);
|
||
$db->table('js_ekf_rcheck_piece')->insert([
|
||
'Id' => 1, 'CheckType' => 1, 'ExpressNum' => 'WB-1', 'OrderNum' => 'SO-1', 'CheckReason' => 2,
|
||
'OmsSDName' => '查件物流', 'DHLName' => '不作为快递名称', 'SkuCode' => 'CHECK-SKU', 'shopproid' => 'CHECK-ITEM',
|
||
]);
|
||
$db->table('js_express_original')->insert([
|
||
'Id' => 1, 'ExpressName' => '原始物流', 'OrderNum' => 'WB-1', 'Lenght' => 11, 'Width' => 22, 'Height' => 33,
|
||
'Volume' => 7260, 'SkuCode' => 'ORIGINAL-SKU', 'JiaoYiNum' => 'TRADE-1', 'ShopName' => '原始店铺',
|
||
'SetMoney' => 18.5, 'SetWeight' => 1.75, 'shopproid' => 'ORIGINAL-ITEM',
|
||
]);
|
||
$db->table('js_jst_order_express_details')->insert([
|
||
'id' => 1, 'updatedAt' => '2026-09-27 10:01:00', 'so_id' => 'SO-1', 'logistic_id' => 'WB-1',
|
||
'logistic_company_name' => '正式快递', 'shop_name' => '正式店铺', 'f_weight' => 0.8,
|
||
]);
|
||
$db->table('js_jst_send_data_view_extension')->insert([
|
||
'Id' => 1, 'io_id' => 100, 'so_id' => 'SO-1', 'shop_i_id' => 'ITEM-1', 'sku_ids' => 'SKU-1',
|
||
'shop_name' => '正式店铺', 'l' => 10, 'w' => 20, 'h' => 30, 'volume' => 6000, 'weight' => 0.7,
|
||
]);
|
||
$db->table('js_jst_sales_outbound_info')->insert([
|
||
'Id' => 1, 'io_id' => 100, 'f_weight' => 1.25, 'weight' => 1.2, 'f_volume' => 0.5, 'volume' => 0.4,
|
||
]);
|
||
|
||
$result = $this->repository->paginate([], 1, 25, collect());
|
||
$row = $result['data']->first();
|
||
|
||
$this->assertSame(1, $result['total']);
|
||
$this->assertSame('查件物流', $row['courier_name']);
|
||
$this->assertSame('ORIGINAL-ITEM', $row['platform_product_id']);
|
||
$this->assertSame('ORIGINAL-SKU', $row['product_code']);
|
||
$this->assertSame('原始店铺', $row['shop_name']);
|
||
$this->assertSame('TRADE-1', $row['online_order_no']);
|
||
$this->assertSame(11.0, $row['length']);
|
||
$this->assertSame(22.0, $row['width']);
|
||
$this->assertSame(33.0, $row['height']);
|
||
$this->assertSame('一级查件', $row['inspection_type']);
|
||
$this->assertSame('二级查件原因', $row['inspection_reason']);
|
||
$this->assertSame('退回费', $row['surcharge_type']);
|
||
$this->assertSame(1.75, $row['settlement_weight']);
|
||
$this->assertSame(7260.0, $row['volume']);
|
||
|
||
$thresholdResult = $this->repository->paginate([], 1, 25, collect([[
|
||
'status_code' => CourierSurchargeQuote::STATUS_ACTIVE,
|
||
'courier' => '查件物流', 'types' => ['退回费'],
|
||
'mode' => '按尺寸/最长边', 'standard' => '最长边 > 30 cm:8 元/单',
|
||
]]));
|
||
$this->assertSame(8.0, $thresholdResult['data']->first()['settlement_amount']);
|
||
|
||
$volumeResult = $this->repository->paginate([], 1, 25, collect([[
|
||
'status_code' => CourierSurchargeQuote::STATUS_ACTIVE,
|
||
'courier' => '查件物流', 'types' => ['退回费'],
|
||
'mode' => '按体积', 'standard' => '体积 ≤ 8000 cm³:50 元/单',
|
||
]]));
|
||
$this->assertSame(50.0, $volumeResult['data']->first()['settlement_amount']);
|
||
}
|
||
|
||
private function createMirrorTables($schema): void
|
||
{
|
||
$schema->create('js_ekf_bookkeeping_surcharge', function (Blueprint $table): void {
|
||
$table->integer('Id'); $table->dateTime('CreationTime')->nullable();
|
||
foreach (['OrderNum', 'ExpressNum', 'ExpressName', 'ShopCode', 'Province', 'City', 'District', 'Address', 'SupplierName', 'SkuName', 'SkuCode', 'Result', 'UserName', 'State', 'Delete', 'IsAgreeReason', 'ProcessingState', 'BookkeepingName', 'PayTime', 'IfReturn', 'IfBuckle', 'FuZhuMain', 'FuZhuMinor', 'ShipExpressName', 'expressCause', 'receivingDepartment', 'returnCost', 'shopproid'] as $column) $table->string($column)->nullable();
|
||
foreach (['Payfee', 'Svolume', 'Skuweight'] as $column) $table->decimal($column, 20, 4)->nullable();
|
||
foreach (['SecodaryCause', 'ReasonId'] as $column) $table->integer($column)->nullable();
|
||
});
|
||
$schema->create('js_ekf_bookkeeping_config', function (Blueprint $table): void { $table->integer('Id'); $table->string('Name')->nullable(); $table->integer('ParentId')->nullable(); $table->dateTime('CreateTime')->nullable(); });
|
||
$schema->create('js_ekf_rcheck_piece', function (Blueprint $table): void { $table->integer('Id'); foreach (['CheckType', 'CheckReason'] as $column) $table->integer($column)->nullable(); foreach (['ExpressNum', 'OrderNum', 'CheckSDType', 'State', 'Accounting', 'ReturnState', 'CreationTime', 'UpdateTime', 'Delete', 'OmsSDName', 'DHLName', 'SkuCode', 'shopproid'] as $column) $table->string($column)->nullable(); });
|
||
$schema->create('js_ekf_rcheck_piece_config', function (Blueprint $table): void { $table->integer('Id'); $table->integer('ParentId')->nullable(); foreach (['Name', 'Code', 'Type', 'Delete', 'CreateTime'] as $column) $table->string($column)->nullable(); });
|
||
$schema->create('js_jst_order_express_details', function (Blueprint $table): void { $table->integer('id'); foreach (['updatedAt', 'so_id', 'logistic_id', 'logistic_company_name', 'shop_name', 'f_weight'] as $column) $table->string($column)->nullable(); });
|
||
$schema->create('js_jst_send_data_view_extension', function (Blueprint $table): void { $table->integer('Id'); $table->integer('io_id')->nullable(); foreach (['so_id', 'shop_i_id', 'sku_ids', 'shop_name', 'l', 'w', 'h', 'volume', 'weight'] as $column) $table->string($column)->nullable(); });
|
||
$schema->create('js_jst_sales_outbound_info', function (Blueprint $table): void { $table->integer('Id'); $table->integer('io_id')->nullable(); foreach (['f_weight', 'weight', 'f_volume', 'volume'] as $column) $table->string($column)->nullable(); });
|
||
$schema->create('js_ekf_return_pickup_management', function (Blueprint $table): void { $table->integer('Id'); foreach (['orderId', 'returnExpressNo', 'transactionNo', 'updateTime'] as $column) $table->string($column)->nullable(); });
|
||
$schema->create('js_express_original', function (Blueprint $table): void { $table->integer('Id'); foreach (['ExpressName', 'OrderNum', 'DeliveryTime', 'Lenght', 'Width', 'Height', 'Volume', 'SkuCode', 'JiaoYiNum', 'ShopName', 'SetMoney', 'SetWeight', 'shopproid'] as $column) $table->string($column)->nullable(); });
|
||
}
|
||
|
||
private function markReady($db): void
|
||
{
|
||
$now = now()->toDateTimeString();
|
||
foreach (array_keys(config('upstream_mirrors.datasets')) as $dataset) {
|
||
$db->table('business_mirror_table_states')->insert([
|
||
'dataset_key' => $dataset, 'initial_completed_at' => '2026-09-27 09:00:00',
|
||
'status' => 'succeeded', 'last_succeeded_at' => $now,
|
||
]);
|
||
}
|
||
}
|
||
}
|