移除对账

This commit is contained in:
liu
2026-08-14 15:54:53 +08:00
parent 629d28a369
commit f0927e57e9
20 changed files with 1 additions and 2363 deletions
-191
View File
@@ -1,191 +0,0 @@
<?php
namespace Tests\Feature;
use App\Models\CustomerLevelModel;
use App\Models\ProductModel;
use App\Models\ProductPriceModel;
use App\Models\ReconciliationItemModel;
use App\Models\ReconciliationModel;
use App\Models\SettlementModel;
use App\Models\StoreModel;
use App\Models\StoreOrderModel;
use App\Models\SupplierModel;
use App\Models\UserModel;
/**
* 财务对账:明细构建(已完成订单直读,品类/供应商筛选)、D4 修改后差额与头汇总重算、D8 标记、D9 结算
* publish = 订货金额;actual = 采购成本(称重>0 ? 称重×单价 : 数量×单价,单价 = 成本/包规)
*/
class ReconciliationTest extends ProcurementTestCase
{
/**
* 构造已完成订单链路:2 门店下单(2/3 件,等级价 10.00;成本 8,包规 1斤 → 单价 8.00),订单置为已完成
* 预期:publish 20/30actual 16/24diff 4/6
*
* @return array{0: array<int, StoreModel>, 1: SupplierModel}
*/
private function buildCompletedOrders(): array
{
$level = CustomerLevelModel::factory()->create();
$supplier = SupplierModel::factory()->create();
$product = ProductModel::factory()->create([
'status' => ProductModel::STATUS_ON,
'supplier_id' => $supplier->id,
'cost_price' => 8,
'spec' => '1斤',
]);
ProductPriceModel::factory()->create(['product_id' => $product->id, 'level_id' => $level->id, 'price' => '10.00']);
$stores = [];
foreach ([2, 3] as $qty) {
$store = StoreModel::factory()->create(['level_id' => $level->id]);
$stores[] = $store;
$this->actingAsMiniUser(UserModel::factory()->forStore($store->id)->create());
$this->postJson('/mini/order', ['items' => [['product_id' => $product->id, 'quantity' => $qty]]])
->assertJsonPath('success', true);
}
// 订单完成(对账数据源为已完成订单的订货明细)
StoreOrderModel::query()->update(['status' => StoreOrderModel::STATUS_COMPLETED]);
return [$stores, $supplier];
}
private function createRecon(array $extra = []): int
{
$response = $this->postJson('/recon/list', array_merge([
'title' => '测试对账',
'period_start' => now()->toDateString(),
'period_end' => now()->toDateString(),
], $extra));
$response->assertJsonPath('success', true);
return (int) $response->json('data.id');
}
/** 构建明细:publish=订货金额,actual=采购成本(数量×单价),diff=publish-actual,头汇总回写 */
public function test_build_creates_reconciliation_items(): void
{
[$stores] = $this->buildCompletedOrders();
$this->actingAsSysUser();
$reconId = $this->createRecon();
$this->postJson("/recon/list/{$reconId}/build")->assertJsonPath('success', true);
$items = ReconciliationItemModel::where('recon_id', $reconId)->get();
$this->assertCount(2, $items, '两门店已完成订单 → 两条对账明细');
$byStore = $items->keyBy('store_id');
$this->assertSame('20.00', (string) $byStore[$stores[0]->id]->publish_amount, '订货金额 2×10');
$this->assertSame('16.00', (string) $byStore[$stores[0]->id]->actual_amount, '采购成本 2×8');
$this->assertSame('4.00', (string) $byStore[$stores[0]->id]->diff_amount);
$this->assertSame('30.00', (string) $byStore[$stores[1]->id]->publish_amount);
$this->assertSame('24.00', (string) $byStore[$stores[1]->id]->actual_amount);
$recon = ReconciliationModel::find($reconId);
$this->assertSame('50.00', (string) $recon->publish_amount);
$this->assertSame('40.00', (string) $recon->actual_amount);
$this->assertSame('10.00', (string) $recon->diff_amount);
$this->assertSame(ReconciliationModel::STATUS_WORKING, $recon->status);
}
/** 未完成订单不计入对账 */
public function test_build_excludes_unfinished_orders(): void
{
[$stores] = $this->buildCompletedOrders();
// 第二家门店订单回退为配送中 → 仅第一家进入对账
StoreOrderModel::where('store_id', $stores[1]->id)
->update(['status' => StoreOrderModel::STATUS_DISTRIBUTION]);
$this->actingAsSysUser();
$reconId = $this->createRecon();
$this->postJson("/recon/list/{$reconId}/build")->assertJsonPath('success', true);
$items = ReconciliationItemModel::where('recon_id', $reconId)->get();
$this->assertCount(1, $items);
$this->assertSame($stores[0]->id, $items->first()->store_id);
}
/** 供应商筛选:仅拉取该供应商的订单数据 */
public function test_build_filters_by_supplier(): void
{
[, $supplier] = $this->buildCompletedOrders();
$this->actingAsSysUser();
// 无关供应商 → 无数据报错
$other = SupplierModel::factory()->create();
$reconId = $this->createRecon(['supplier_id' => $other->id]);
$this->postJson("/recon/list/{$reconId}/build")->assertJsonPath('success', false);
// 正确供应商 → 构建成功
$reconId2 = $this->createRecon(['supplier_id' => $supplier->id]);
$this->postJson("/recon/list/{$reconId2}/build")->assertJsonPath('success', true);
$this->assertSame(2, ReconciliationItemModel::where('recon_id', $reconId2)->count());
}
/** D4 修改明细:自动重算本行 diff 与对账单头汇总 */
public function test_update_item_recalculates_diff_and_header(): void
{
$this->buildCompletedOrders();
$this->actingAsSysUser();
$reconId = $this->createRecon();
$this->postJson("/recon/list/{$reconId}/build");
$item = ReconciliationItemModel::where('recon_id', $reconId)->orderBy('id')->first();
$this->putJson("/recon/item/{$item->id}", ['actual_amount' => '25.00'])
->assertJsonPath('success', true);
$item = $item->fresh();
$this->assertSame('-5.00', (string) $item->diff_amount, '20.00 - 25.00');
$recon = ReconciliationModel::find($reconId);
$this->assertSame('49.00', (string) $recon->actual_amount, '25 + 24');
$this->assertSame('1.00', (string) $recon->diff_amount, '50 - 49');
}
/** D8 对账状态标记翻转 */
public function test_toggle_reconciled_flag(): void
{
$this->buildCompletedOrders();
$this->actingAsSysUser();
$reconId = $this->createRecon();
$this->postJson("/recon/list/{$reconId}/build");
$item = ReconciliationItemModel::where('recon_id', $reconId)->first();
$this->assertSame(0, $item->is_reconciled);
$this->putJson("/recon/item/{$item->id}/toggle")->assertJsonPath('success', true);
$this->assertSame(1, $item->fresh()->is_reconciled);
$this->putJson("/recon/item/{$item->id}/toggle")->assertJsonPath('success', true);
$this->assertSame(0, $item->fresh()->is_reconciled);
}
/** D9 结算:按门店生成结算表,对账单转为已结算且不可重复结算 */
public function test_settle_creates_settlements_per_store(): void
{
[$stores] = $this->buildCompletedOrders();
$this->actingAsSysUser();
$reconId = $this->createRecon();
$this->postJson("/recon/list/{$reconId}/build");
$this->postJson("/recon/list/{$reconId}/settle")->assertJsonPath('success', true);
$settlements = SettlementModel::where('recon_id', $reconId)->get();
$this->assertCount(2, $settlements, '按门店各生成一张结算表');
$byStore = $settlements->keyBy('store_id');
$this->assertSame('20.00', (string) $byStore[$stores[0]->id]->total_amount);
$this->assertSame('16.00', (string) $byStore[$stores[0]->id]->actual_amount);
$this->assertSame('4.00', (string) $byStore[$stores[0]->id]->diff_amount);
$this->assertStringStartsWith('JS', $byStore[$stores[0]->id]->settlement_no);
$this->assertSame(ReconciliationModel::STATUS_SETTLED, ReconciliationModel::find($reconId)->status);
// 已结算不可重复结算
$this->postJson("/recon/list/{$reconId}/settle")->assertJsonPath('success', false);
}
}