Files
xin-procurement/tests/Feature/ContainerReturnTest.php
T
2026-08-14 23:47:49 +08:00

186 lines
7.5 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\Feature;
use App\Models\BillModel;
use App\Models\ContainerReturnModel;
use App\Models\CustomerLevelModel;
use App\Models\ProductModel;
use App\Models\ProductPriceModel;
use App\Models\PurchaseOrderModel;
use App\Models\StoreModel;
use App\Models\StoreOrderModel;
use App\Models\UserModel;
use Illuminate\Support\Facades\DB;
use Modules\SystemTool\Services\SysSiteConfigService;
/**
* 压回筐记录:周转筐/托盘跟账单走(生成账单时写入完整快照,只读);
* 数量正数=压筐(附加金额),负数=回筐(抵扣金额),数量为 0 不写记录;
* 门店表不再记录待回数量
*/
class ContainerReturnTest extends ProcurementTestCase
{
/** 注入站点配置:筐单价 5.00、托盘单价 20.00 */
private function seedContainerConfig(): void
{
DB::table('sys_site_config_group')->insert([
'id' => 100,
'title' => '业务配置',
'key' => 'services',
'remark' => '',
'created_at' => now(),
'updated_at' => now(),
]);
DB::table('sys_site_config_items')->insert([
[
'group_id' => 100, 'key' => 'box_amount', 'title' => '周转筐金额', 'describe' => '',
'values' => '5.00', 'type' => 'InputNumber', 'options' => null, 'props' => null, 'sort' => 0,
'created_at' => now(), 'updated_at' => now(),
],
[
'group_id' => 100, 'key' => 'tray_amount', 'title' => '周转托盘金额', 'describe' => '',
'values' => '20.00', 'type' => 'InputNumber', 'options' => null, 'props' => null, 'sort' => 1,
'created_at' => now(), 'updated_at' => now(),
],
]);
SysSiteConfigService::refreshSiteConfig();
}
/**
* 完整业务链造账单(商品 5.00 × 4 = 20.00,配送费 0),按指定筐/托盘数量生成
*
* @return array{0: StoreModel, 1: BillModel}
*/
private function makeBillWithContainers(int $boxNum, int $trayNum): array
{
$level = CustomerLevelModel::factory()->create();
$store = StoreModel::factory()->create(['level_id' => $level->id]);
$product = ProductModel::factory()->create(['status' => ProductModel::STATUS_ON]);
ProductPriceModel::factory()->create([
'product_id' => $product->id,
'level_id' => $level->id,
'price' => '5.00',
]);
$user = UserModel::factory()->forStore($store->id)->create();
$this->actingAsMiniUser($user);
$this->postJson('/mini/order', ['items' => [['product_id' => $product->id, 'quantity' => 4]]])
->assertJsonPath('success', true);
$order = StoreOrderModel::where('store_id', $store->id)->first();
$this->actingAsSysUser();
$this->putJson("/order/store/{$order->id}/status", ['status' => StoreOrderModel::STATUS_SUMMARIZED])
->assertJsonPath('success', true);
$this->postJson('/purchase/order/generate', ['purchase_date' => now()->toDateString()])
->assertJsonPath('success', true);
$purchase = PurchaseOrderModel::first();
$this->putJson("/purchase/order/{$purchase->id}/finish")->assertJsonPath('success', true);
$this->postJson("/purchase/order/{$purchase->id}/bill", [
'stores' => [[
'store_id' => $store->id,
'delivery_fee' => 0,
'box_num' => $boxNum,
'tray_num' => $trayNum,
]],
])->assertJsonPath('success', true);
return [$store, BillModel::where('store_id', $store->id)->first()];
}
/** 压筐(正数):附加金额增加账单总额,写入完整快照记录 */
public function test_press_containers_adds_amount_and_writes_record(): void
{
$this->seedContainerConfig();
[$store, $bill] = $this->makeBillWithContainers(3, 2);
// 附加 = 3×5 + 2×20 = 55;总额 = 20 + 55 = 75
$this->assertSame('55.00', (string) $bill->added_amount);
$this->assertSame('75.00', (string) $bill->total_amount);
$record = ContainerReturnModel::where('bill_id', $bill->id)->first();
$this->assertNotNull($record);
$this->assertSame($store->id, $record->store_id);
$this->assertSame(3, $record->box_num);
$this->assertSame(2, $record->tray_num);
$this->assertSame('5.00', (string) $record->box_price, '筐单价快照');
$this->assertSame('20.00', (string) $record->tray_price, '托盘单价快照');
$this->assertSame('55.00', (string) $record->amount);
}
/** 回筐(负数):抵扣账单金额,记录为负 */
public function test_return_containers_deducts_amount(): void
{
$this->seedContainerConfig();
[, $bill] = $this->makeBillWithContainers(-2, 0);
// 附加 = -2×5 + 0 = -10;总额 = 20 - 10 = 10
$this->assertSame('-10.00', (string) $bill->added_amount);
$this->assertSame('10.00', (string) $bill->total_amount);
$record = ContainerReturnModel::where('bill_id', $bill->id)->first();
$this->assertNotNull($record);
$this->assertSame(-2, $record->box_num);
$this->assertSame(0, $record->tray_num);
$this->assertSame('-10.00', (string) $record->amount);
}
/** 混合:筐回(负)+ 托盘压(正),金额按代数和计 */
public function test_mixed_sign_containers(): void
{
$this->seedContainerConfig();
[, $bill] = $this->makeBillWithContainers(-3, 1);
// 附加 = -3×5 + 1×20 = 5;总额 = 20 + 5 = 25
$this->assertSame('5.00', (string) $bill->added_amount);
$this->assertSame('25.00', (string) $bill->total_amount);
$record = ContainerReturnModel::where('bill_id', $bill->id)->first();
$this->assertNotNull($record);
$this->assertSame(-3, $record->box_num);
$this->assertSame(1, $record->tray_num);
$this->assertSame('5.00', (string) $record->amount);
}
/** 数量为 0:不写压回筐记录 */
public function test_zero_containers_writes_no_record(): void
{
$this->seedContainerConfig();
[, $bill] = $this->makeBillWithContainers(0, 0);
$this->assertSame('20.00', (string) $bill->total_amount);
$this->assertSame(0, ContainerReturnModel::where('bill_id', $bill->id)->count());
}
/** 筐/托盘数量非整数 → 拒绝 */
public function test_non_integer_containers_rejected(): void
{
$level = CustomerLevelModel::factory()->create();
$store = StoreModel::factory()->create(['level_id' => $level->id]);
$this->actingAsSysUser();
$purchase = PurchaseOrderModel::factory()->create(['status' => PurchaseOrderModel::STATUS_COMPLETED]);
$this->postJson("/purchase/order/{$purchase->id}/bill", [
'stores' => [[
'store_id' => $store->id,
'delivery_fee' => 0,
'box_num' => 1.5,
'tray_num' => 0,
]],
])->assertJsonPath('success', false);
}
/** 压回筐记录只读:手动登记/删除端点已下线 */
public function test_manual_create_and_delete_routes_removed(): void
{
$this->actingAsSysUser();
$this->postJson('/recon/container-return', [
'store_id' => 1,
'box_num' => 1,
'tray_num' => 0,
])->assertJsonPath('success', false);
$this->deleteJson('/recon/container-return/1')->assertJsonPath('success', false);
}
}