账单生成

This commit is contained in:
liu
2026-08-14 00:15:28 +08:00
parent 61a70319a0
commit e35c951a59
19 changed files with 728 additions and 631 deletions
-164
View File
@@ -11,9 +11,6 @@ use App\Models\StoreOrderItemModel;
use App\Models\StoreOrderModel;
use App\Models\SupplierModel;
use App\Models\UserModel;
use Illuminate\Support\Facades\Cache;
use Modules\SystemTool\Models\SysSiteConfigGroupModel;
use Modules\SystemTool\Models\SysSiteConfigItemsModel;
/**
* C4 采购单数据修改:详情矩阵(商品行 × 门店列)、门店单元格下钻编辑/同步、行级成本,
@@ -55,23 +52,6 @@ class PurchaseEditTest extends ProcurementTestCase
return [PurchaseOrderModel::first(), $product, [$storeA, $storeB]];
}
/** 播种站点配置:周转框单价 2.00、周转托盘单价 10.00 */
private function seedContainerConfig(): void
{
$group = SysSiteConfigGroupModel::create(['title' => '业务配置', 'key' => 'services']);
foreach ([['box_amount', '周转框单价', '2.00'], ['tray_amount', '周转托盘单价', '10.00']] as [$key, $title, $value]) {
SysSiteConfigItemsModel::create([
'group_id' => $group->id,
'key' => $key,
'title' => $title,
'type' => 'InputNumber',
'values' => $value,
'sort' => 0,
]);
}
Cache::forget('site_config');
}
/** 详情返回「商品行 × 门店列」矩阵:cells 按门店聚合数量 */
public function test_detail_returns_store_matrix(): void
{
@@ -460,148 +440,4 @@ class PurchaseEditTest extends ProcurementTestCase
->assertOk()
->assertJsonPath('data.items.0.editable', false);
}
/** 详情返回周转框/托盘合并记录:按门店聚合全部订单(含底层订单明细与单价) */
public function test_detail_returns_container_summary(): void
{
$this->seedContainerConfig();
[$purchase, , $stores] = $this->buildPurchase();
StoreOrderModel::where('store_id', $stores[0]->id)->update(['box_num' => 2, 'tray_num' => 1]);
StoreOrderModel::where('store_id', $stores[1]->id)->update(['box_num' => 3, 'tray_num' => 0]);
$this->actingAsSysUser();
$containers = $this->getJson("/purchase/order/{$purchase->id}")
->assertOk()
->assertJsonPath('success', true)
->json('data.containers');
$this->assertCount(2, $containers);
$this->assertSame($stores[0]->id, $containers[0]['store_id'], '与门店列同序');
$row = $containers[0];
$this->assertSame($stores[0]->name, $row['store_name']);
$this->assertSame(2, $row['box_num']);
$this->assertSame(1, $row['tray_num']);
$this->assertSame('2.00', $row['box_price']);
$this->assertSame('10.00', $row['tray_price']);
$this->assertSame('14.00', $row['added_amount'], '2×2.00 + 1×10.00');
$this->assertSame(1, $row['order_count']);
$this->assertCount(1, $row['orders']);
$order = $row['orders'][0];
$this->assertStringStartsWith('SO', $order['order_no']);
$this->assertSame(2, $order['box_num']);
$this->assertSame(1, $order['tray_num']);
$this->assertSame(3, $containers[1]['box_num']);
$this->assertSame('6.00', $containers[1]['added_amount']);
}
/** 合并记录修改:逐笔更新订单数量并重算附加金额与订单总金额,其他门店不受影响 */
public function test_update_container_syncs_order_amounts(): void
{
$this->seedContainerConfig();
[$purchase, , $stores] = $this->buildPurchase();
$order = StoreOrderModel::where('store_id', $stores[0]->id)->first();
$this->assertSame('20.00', (string) $order->product_amount, '下单时应写入商品金额');
$this->putJson("/purchase/order/{$purchase->id}/container/{$stores[0]->id}", [
'orders' => [['order_id' => $order->id, 'box_num' => 3, 'tray_num' => 1]],
])->assertOk()->assertJsonPath('success', true);
$order->refresh();
$this->assertSame(3, $order->box_num);
$this->assertSame(1, $order->tray_num);
$this->assertSame('16.00', (string) $order->added_amount, '3×2.00 + 1×10.00');
$this->assertSame('20.00', (string) $order->product_amount);
$this->assertSame('36.00', (string) $order->total_amount, '20.00 + 16.00');
$other = StoreOrderModel::where('store_id', $stores[1]->id)->first();
$this->assertSame(0, $other->box_num, '其他门店订单不受影响');
$this->assertSame('30.00', (string) $other->total_amount);
}
/** 采购单已完成:合并记录修改拒绝,数量与金额不变 */
public function test_update_container_rejected_when_purchase_completed(): void
{
$this->seedContainerConfig();
[$purchase, , $stores] = $this->buildPurchase();
$order = StoreOrderModel::where('store_id', $stores[0]->id)->first();
$purchase->update(['status' => PurchaseOrderModel::STATUS_COMPLETED]);
$this->putJson("/purchase/order/{$purchase->id}/container/{$stores[0]->id}", [
'orders' => [['order_id' => $order->id, 'box_num' => 5, 'tray_num' => 5]],
])->assertJsonPath('success', false)
->assertJsonPath('msg', '采购单已完成,不允许修改周转框/托盘');
$this->assertSame(0, $order->fresh()->box_num, '被拒绝后数量不变');
}
/** 提交必须覆盖该门店全部订单;跨门店/跨采购单订单拒绝 */
public function test_update_container_rejects_incomplete_or_foreign_orders(): void
{
$this->seedContainerConfig();
$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' => 10.00]);
$this->actingAsMiniUser(UserModel::factory()->forStore($store->id)->create());
foreach ([1, 2] as $qty) {
$this->postJson('/mini/order', ['items' => [['product_id' => $product->id, 'quantity' => $qty]]])
->assertJsonPath('success', true);
}
StoreOrderModel::query()->update(['status' => StoreOrderModel::STATUS_SUMMARIZED]);
$this->actingAsSysUser();
$this->postJson('/purchase/order/generate', ['purchase_date' => now()->toDateString()])
->assertJsonPath('success', true);
$purchase = PurchaseOrderModel::first();
$orders = StoreOrderModel::where('purchase_id', $purchase->id)->orderBy('id')->get();
$this->assertCount(2, $orders, '同一门店两笔订单');
// 只提交一笔 → 缺少另一笔,整批拒绝
$this->putJson("/purchase/order/{$purchase->id}/container/{$store->id}", [
'orders' => [['order_id' => $orders[0]->id, 'box_num' => 1, 'tray_num' => 0]],
])->assertJsonPath('success', false)
->assertJsonPath('msg', '提交不完整,缺少订单:' . $orders[1]->id);
// 混入其他门店订单(同一采购单另一门店)→ 拒绝
$otherStore = StoreModel::factory()->create(['level_id' => $level->id]);
$this->actingAsMiniUser(UserModel::factory()->forStore($otherStore->id)->create());
$this->postJson('/mini/order', ['items' => [['product_id' => $product->id, 'quantity' => 1]]])
->assertJsonPath('success', true);
$foreign = StoreOrderModel::where('store_id', $otherStore->id)->first();
$this->actingAsSysUser();
$this->putJson("/purchase/order/{$purchase->id}/container/{$store->id}", [
'orders' => [
['order_id' => $orders[0]->id, 'box_num' => 1, 'tray_num' => 0],
['order_id' => $orders[1]->id, 'box_num' => 1, 'tray_num' => 0],
['order_id' => $foreign->id, 'box_num' => 1, 'tray_num' => 0],
],
])->assertJsonPath('success', false)
->assertJsonPath('msg', '包含不属于该采购单该门店的订单');
$this->assertSame(0, $orders[0]->fresh()->box_num, '被拒绝后数量不变');
}
/** 数量为负/重复订单时校验失败 */
public function test_update_container_validates_negative_and_duplicate_orders(): void
{
$this->seedContainerConfig();
[$purchase, , $stores] = $this->buildPurchase();
$order = StoreOrderModel::where('store_id', $stores[0]->id)->first();
$this->putJson("/purchase/order/{$purchase->id}/container/{$stores[0]->id}", [
'orders' => [['order_id' => $order->id, 'box_num' => -1, 'tray_num' => 0]],
])->assertJsonPath('success', false)
->assertJsonPath('msg', '周转框数量不能小于 0');
$this->putJson("/purchase/order/{$purchase->id}/container/{$stores[0]->id}", [
'orders' => [
['order_id' => $order->id, 'box_num' => 1, 'tray_num' => 0],
['order_id' => $order->id, 'box_num' => 1, 'tray_num' => 0],
],
])->assertJsonPath('success', false);
}
}
+2 -3
View File
@@ -122,12 +122,11 @@ class StoreOrderItemTest extends ProcurementTestCase
->assertJsonPath('data.items.0.supplier.name', $supplier->name);
}
/** 修改明细:重算单品金额与订单总量/总额(总额 = 商品 + 附加 */
/** 修改明细:重算单品金额与订单总量/总额(总额 = 商品金额,附加金额已迁入账单 */
public function test_update_item_recalculates_order_totals(): void
{
[$store, $product, $user] = $this->makeStoreWithProduct('5.00');
$order = $this->placeOrder($product, $user, 2, StoreOrderModel::STATUS_SUMMARIZED);
$order->update(['added_amount' => '6.00']); // 已有附加金额
$item = $order->items->first();
$supplier = SupplierModel::factory()->create();
@@ -158,7 +157,7 @@ class StoreOrderItemTest extends ProcurementTestCase
$this->assertSame(5, $order->total_quantity, '订货总量 = 明细合计');
$this->assertSame('2.500', (string) $order->total_weight, '总重量 = 明细合计');
$this->assertSame('30.00', (string) $order->product_amount, '商品总金额 = 明细金额合计');
$this->assertSame('36.00', (string) $order->total_amount, '订单总金额 = 商品 30 + 附加 6');
$this->assertSame('30.00', (string) $order->total_amount, '订单总金额 = 商品金额');
}
/** 已完成/已取消订单不允许修改明细 */