Files
xin-procurement/tests/Feature/PurchaseEditTest.php
T

589 lines
27 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\CustomerLevelModel;
use App\Models\ProductModel;
use App\Models\PurchaseOrderModel;
use App\Models\StoreModel;
use App\Models\StoreOrderItemModel;
use App\Models\StoreOrderModel;
use App\Models\SupplierModel;
/**
* C4 采购单数据修改:详情矩阵(商品行 × 门店列)、门店单元格下钻编辑、行级修改同步商品档案、
* 门店购买详情单品增删改,修改后重算订单/采购单汇总
* (金额口径:订单=数量×单价;采购单预估成本=Σ数量×每包成本价)
*/
class PurchaseEditTest extends ProcurementTestCase
{
/**
* 造采购链路:门店A 2 件 + 门店B 3 件(同一商品,等级上浮 0% → 售价=成本价 10.00,包规 10斤/箱),
* 接单后生成采购单
*
* @return array{0: PurchaseOrderModel, 1: ProductModel, 2: array<int, StoreModel>}
*/
private function buildPurchase(): array
{
$level = CustomerLevelModel::factory()->create();
$storeA = StoreModel::factory()->create(['level_id' => $level->id]);
$storeB = StoreModel::factory()->create(['level_id' => $level->id]);
$product = ProductModel::factory()->create([
'status' => ProductModel::STATUS_ON,
'cost_price' => 10,
'spec' => '10斤/箱',
'unit' => '斤',
]);
foreach ([[$storeA, 2], [$storeB, 3]] as [$store, $qty]) {
$this->actingAsMiniStore($store);
$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);
return [PurchaseOrderModel::first(), $product, [$storeA, $storeB]];
}
/** 详情返回「商品行 × 门店列」矩阵:cells 按门店聚合数量 */
public function test_detail_returns_store_matrix(): void
{
[$purchase, $product, $stores] = $this->buildPurchase();
$this->actingAsSysUser();
$response = $this->getJson("/purchase/order/{$purchase->id}")
->assertOk()
->assertJsonPath('success', true);
$data = $response->json('data');
$this->assertCount(2, $data['stores']);
$this->assertCount(1, $data['items']);
$row = $data['items'][0];
$this->assertSame($product->id, $row['product_id']);
$this->assertSame('10斤/箱', $row['product_spec']);
$this->assertSame('斤', $row['unit']);
$this->assertSame('10.00', (string) $row['cost_price']);
$this->assertSame('50.00', (string) $row['amount'], '订货金额 = Σ明细 amount5 × 10.00');
$this->assertSame(5, $row['quantity'], '2+3');
$cells = $row['cells'];
$this->assertSame(2, $cells[$stores[0]->id]);
$this->assertSame(3, $cells[$stores[1]->id]);
}
/** 门店单元格数量/单价修改 → 明细金额重算(数量×单价),订单与采购单汇总同步 */
public function test_update_cell_syncs_order_item_and_totals(): void
{
[$purchase, , $stores] = $this->buildPurchase();
$this->actingAsSysUser();
$item = StoreOrderItemModel::where('store_id', $stores[0]->id)->first();
$this->putJson("/purchase/order/cell/{$item->id}", ['quantity' => 5, 'price' => 10])
->assertJsonPath('success', true);
$item = $item->fresh();
$this->assertSame(5, $item->quantity);
$this->assertSame('50.00', (string) $item->amount, '5 × 订货单价 10.00');
$order = StoreOrderModel::find($item->order_id);
$this->assertSame(5, $order->total_quantity);
$this->assertSame('50.00', (string) $order->total_amount);
$purchase = $purchase->fresh();
$this->assertSame('8.00', (string) $purchase->total_quantity, '5+3');
$this->assertSame('80.00', (string) $purchase->estimate_amount, '8 包 × 每包成本 10.00');
}
/** 行级成本修改 → 同步该商品全部订货明细与商品档案,采购单预估成本重算 */
public function test_update_row_cost_syncs_all_order_items(): void
{
[$purchase, $product] = $this->buildPurchase();
$this->actingAsSysUser();
$this->putJson("/purchase/order/{$purchase->id}/row/{$product->id}", [
'product_name' => $product->name,
'supplier_id' => SupplierModel::factory()->create()->id,
'product_spec' => $product->spec,
'unit' => $product->unit,
'cost_price' => 30,
])->assertJsonPath('success', true)
->assertJsonPath('data.count', 2);
$this->assertSame(2, StoreOrderItemModel::where('cost_price', '30.00')->count());
$this->assertSame('30.00', (string) $product->fresh()->cost_price, '商品档案成本价应同步更新');
$purchase = $purchase->fresh();
$this->assertSame('150.00', (string) $purchase->estimate_amount, '5 包 × 每包成本 30.00');
}
/** 行级属性修改不影响称重(重量为手动录入,仅作参考) */
public function test_update_row_does_not_touch_manual_weight(): void
{
[$purchase, $product, $stores] = $this->buildPurchase();
$supplier = SupplierModel::factory()->create();
$this->actingAsSysUser();
// 先录入一笔手动称重
$item = StoreOrderItemModel::where('store_id', $stores[0]->id)->first();
$this->putJson("/purchase/order/cell/{$item->id}", ['quantity' => 2, 'price' => 10, 'weight' => 4.5])
->assertJsonPath('success', true);
$this->putJson("/purchase/order/{$purchase->id}/row/{$product->id}", [
'product_name' => $product->name,
'supplier_id' => $supplier->id,
'product_spec' => $product->spec,
'unit' => $product->unit,
'cost_price' => 30,
])->assertJsonPath('success', true);
$this->assertSame('4.500', (string) $item->fresh()->weight, '重量保持手动录入值,不受行修改影响');
}
/** 行级属性修改:品名/供应商/包规/单位/成本一键同步该商品全部订货明细与商品档案 */
public function test_update_row_syncs_product_attributes(): void
{
[$purchase, $product] = $this->buildPurchase();
$supplier = SupplierModel::factory()->create();
$this->actingAsSysUser();
$this->putJson("/purchase/order/{$purchase->id}/row/{$product->id}", [
'product_name' => '优选土豆',
'supplier_id' => $supplier->id,
'product_spec' => '5斤/袋',
'unit' => '袋',
'cost_price' => 25,
])->assertJsonPath('success', true)
->assertJsonPath('data.count', 2);
$items = StoreOrderItemModel::all();
$this->assertCount(2, $items);
foreach ($items as $item) {
$this->assertSame('优选土豆', $item->product_name);
$this->assertSame($supplier->id, $item->supplier_id);
$this->assertSame('5斤/袋', $item->product_spec);
$this->assertSame('袋', $item->unit);
$this->assertSame('25.00', (string) $item->cost_price);
}
// 商品档案同步保存(商品列表可见)
$product = $product->fresh();
$this->assertSame('优选土豆', $product->name);
$this->assertSame($supplier->id, $product->supplier_id);
$this->assertSame('5斤/袋', $product->spec);
$this->assertSame('袋', $product->unit);
$this->assertSame('25.00', (string) $product->cost_price);
$this->assertSame('125.00', (string) $purchase->fresh()->estimate_amount, '5 包 × 每包成本 25.00');
}
/** 行级修改:商品已软删除时明细照常更新、跳过档案同步 */
public function test_update_row_skips_catalog_sync_when_product_deleted(): void
{
[$purchase, $product] = $this->buildPurchase();
$supplier = SupplierModel::factory()->create();
$this->actingAsSysUser();
$product->delete(); // 软删除
$this->putJson("/purchase/order/{$purchase->id}/row/{$product->id}", [
'product_name' => '已删商品新名',
'supplier_id' => $supplier->id,
'product_spec' => '5斤/袋',
'unit' => '袋',
'cost_price' => 25,
])->assertOk()
->assertJsonPath('success', true)
->assertJsonPath('msg', '已同步 2 条订货明细;商品已删除,档案未同步;门店单价已按等级上浮比例重算');
$this->assertSame('已删商品新名', StoreOrderItemModel::first()->product_name, '订货明细照常更新');
$this->assertNotSame('已删商品新名', $product->fresh()->name, '商品档案不同步');
}
/** 行级修改:必填字段校验(空 payload 拒绝) */
public function test_update_row_requires_at_least_one_field(): void
{
[$purchase, $product] = $this->buildPurchase();
$this->actingAsSysUser();
$this->putJson("/purchase/order/{$purchase->id}/row/{$product->id}", [])
->assertJsonPath('success', false);
}
/** 单元格数量校验:负数拒绝 */
public function test_update_cell_rejects_negative_quantity(): void
{
[$purchase, , $stores] = $this->buildPurchase();
$this->actingAsSysUser();
$item = StoreOrderItemModel::where('store_id', $stores[0]->id)->first();
$this->putJson("/purchase/order/cell/{$item->id}", ['quantity' => -1, 'price' => 10])
->assertJsonPath('success', false);
}
/** 单元格下钻:返回该门店该商品的全部订货明细(订单号/状态/快照),其他门店无明细 */
public function test_cell_detail_returns_items_with_order_info(): void
{
[$purchase, $product, $stores] = $this->buildPurchase();
$this->actingAsSysUser();
$response = $this->getJson("/purchase/order/{$purchase->id}/cell?product_id={$product->id}&store_id={$stores[0]->id}")
->assertOk()
->assertJsonPath('success', true);
$data = $response->json('data');
$this->assertSame($stores[0]->name, $data['store']['name']);
$this->assertSame($product->name, $data['product']['name']);
$this->assertCount(1, $data['items']);
$item = $data['items'][0];
$this->assertArrayHasKey('order_no', $item);
$this->assertSame(2, $item['quantity']);
$this->assertSame('20.00', (string) $item['amount']);
$this->assertSame(StoreOrderModel::STATUS_DELIVERING, $item['order_status'], '生成采购单后源订单为采购中');
// 其他门店 → 另一条明细
$this->getJson("/purchase/order/{$purchase->id}/cell?product_id={$product->id}&store_id={$stores[1]->id}")
->assertOk()
->assertJsonPath('data.items.0.quantity', 3);
}
/** 单元格下钻参数校验:缺少商品/门店参数拒绝 */
public function test_cell_detail_rejects_missing_params(): void
{
[$purchase] = $this->buildPurchase();
$this->actingAsSysUser();
$this->getJson("/purchase/order/{$purchase->id}/cell")
->assertJsonPath('success', false);
}
/** 单元格称重修改 → 明细/订货单/采购单重量与金额汇总级联重算 */
public function test_update_cell_weight_cascades_totals(): void
{
[$purchase, , $stores] = $this->buildPurchase();
$this->actingAsSysUser();
$item = StoreOrderItemModel::where('store_id', $stores[0]->id)->first();
$this->putJson("/purchase/order/cell/{$item->id}", ['quantity' => 5, 'price' => 10, 'weight' => 4.5])
->assertJsonPath('success', true);
$item = $item->fresh();
$this->assertSame('4.500', (string) $item->weight);
$this->assertSame('50.00', (string) $item->amount, '5 × 订货单价 10.00');
$order = StoreOrderModel::find($item->order_id);
$this->assertSame('4.500', (string) $order->total_weight);
$this->assertSame('50.00', (string) $order->total_amount);
$purchase = $purchase->fresh();
$this->assertSame('4.500', (string) $purchase->total_weight);
$this->assertSame('80.00', (string) $purchase->estimate_amount, '8 包 × 每包成本 10.00(称重仅参考,不参与金额)');
}
/** 行级成本修改 → 明细单价按各门店等级上浮比例重算,订单与采购单汇总级联 */
public function test_update_row_cost_change_reprices_items_by_store_level(): void
{
// 门店A 上浮 0%(售价=成本),门店B 上浮 50%
$levelA = CustomerLevelModel::factory()->create(['percent' => 0]);
$levelB = CustomerLevelModel::factory()->create(['percent' => 50]);
$storeA = StoreModel::factory()->create(['level_id' => $levelA->id]);
$storeB = StoreModel::factory()->create(['level_id' => $levelB->id]);
$product = ProductModel::factory()->create(['status' => ProductModel::STATUS_ON, 'cost_price' => 10]);
foreach ([[$storeA, 2], [$storeB, 3]] as [$store, $qty]) {
$this->actingAsMiniStore($store);
$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();
// 下单时快照:A 店 10.0010 上浮 0%),B 店 15.0010 上浮 50%
$itemA = StoreOrderItemModel::where('store_id', $storeA->id)->first();
$itemB = StoreOrderItemModel::where('store_id', $storeB->id)->first();
$this->assertSame('10.00', (string) $itemA->price);
$this->assertSame('15.00', (string) $itemB->price);
// 行修改成本 10 → 20:单价按各店等级上浮比例重算
$this->putJson("/purchase/order/{$purchase->id}/row/{$product->id}", [
'product_name' => $product->name,
'supplier_id' => SupplierModel::factory()->create()->id,
'product_spec' => $product->spec,
'unit' => $product->unit,
'cost_price' => 20,
])->assertOk()
->assertJsonPath('success', true)
->assertJsonPath('msg', '已同步 2 条订货明细与商品档案;门店单价已按等级上浮比例重算');
$itemA->refresh();
$this->assertSame('20.00', (string) $itemA->cost_price);
$this->assertSame('20.00', (string) $itemA->price, 'A 店:20 上浮 0% = 20.00');
$this->assertSame('40.00', (string) $itemA->amount, '20.00 × 2');
$itemB->refresh();
$this->assertSame('30.00', (string) $itemB->price, 'B 店:20 上浮 50% = 30.00');
$this->assertSame('90.00', (string) $itemB->amount, '30.00 × 3');
$this->assertSame('40.00', (string) StoreOrderModel::where('store_id', $storeA->id)->first()->total_amount);
$this->assertSame('90.00', (string) StoreOrderModel::where('store_id', $storeB->id)->first()->total_amount);
$this->assertSame('100.00', (string) $purchase->fresh()->estimate_amount, '5 包 × 新成本 20.00');
}
/** 行修改未改成本 → 明细单价保持不变(不覆盖单元格的手工改价) */
public function test_update_row_without_cost_change_keeps_item_price(): void
{
[$purchase, $product, $stores] = $this->buildPurchase();
$this->actingAsSysUser();
// 先通过单元格手工改价 10 → 12
$item = StoreOrderItemModel::where('store_id', $stores[0]->id)->first();
$this->putJson("/purchase/order/cell/{$item->id}", ['quantity' => 2, 'price' => 12])
->assertJsonPath('success', true);
// 行修改只改品名(成本不变)
$this->putJson("/purchase/order/{$purchase->id}/row/{$product->id}", [
'product_name' => '只改品名',
'supplier_id' => SupplierModel::factory()->create()->id,
'product_spec' => $product->spec,
'unit' => $product->unit,
'cost_price' => 10,
])->assertOk()
->assertJsonPath('success', true)
->assertJsonPath('msg', '已同步 2 条订货明细与商品档案');
$this->assertSame('12.00', (string) $item->fresh()->price, '成本未变时保留手工改价');
}
/** 门店购买详情-新增单品:挂靠最新一笔订单,汇总级联重算;重复添加拒绝 */
public function test_store_item_add_creates_item_and_recalculates(): void
{
[$purchase, , $stores] = $this->buildPurchase();
$extra = ProductModel::factory()->create(['status' => ProductModel::STATUS_ON, 'cost_price' => 8]);
$this->actingAsSysUser();
$this->postJson("/purchase/order/{$purchase->id}/store/{$stores[0]->id}/item", [
'product_id' => $extra->id,
'quantity' => 4,
'weight' => 1.5,
])->assertOk()->assertJsonPath('success', true);
$item = StoreOrderItemModel::where('product_id', $extra->id)->first();
$this->assertNotNull($item);
$this->assertSame($stores[0]->id, $item->store_id);
$this->assertSame($purchase->id, $item->purchase_id);
$this->assertSame('8.00', (string) $item->price, '等级上浮 0% → 单价=成本价');
$this->assertSame('32.00', (string) $item->amount, '8.00 × 4');
$this->assertSame('1.500', (string) $item->weight);
$order = StoreOrderModel::find($item->order_id);
$this->assertSame(6, $order->total_quantity, '2+4');
$this->assertSame('52.00', (string) $order->total_amount, '20+32');
$purchase = $purchase->fresh();
$this->assertSame('9.00', (string) $purchase->total_quantity, '2+3+4');
$this->assertSame('82.00', (string) $purchase->estimate_amount, '50+324 包 × 成本 8.00');
$this->assertSame('1.500', (string) $purchase->total_weight);
// 重复添加同一商品 → 拒绝
$this->postJson("/purchase/order/{$purchase->id}/store/{$stores[0]->id}/item", [
'product_id' => $extra->id,
'quantity' => 1,
])->assertJsonPath('success', false)
->assertJsonPath('msg', '该商品已在此门店采购明细中,请直接修改数量');
}
/** 门店购买详情-修改单品:同商品多笔订单明细合并到最早一条,涉及订单逐一重算 */
public function test_store_item_update_merges_multi_order_rows(): void
{
$level = CustomerLevelModel::factory()->create();
$store = StoreModel::factory()->create(['level_id' => $level->id]);
$product = ProductModel::factory()->create(['status' => ProductModel::STATUS_ON, 'cost_price' => 10]);
// 同一门店两笔订单各订 2 件(同商品)→ 同一采购单
$this->actingAsMiniStore($store);
foreach ([2, 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();
$this->assertSame(2, StoreOrderItemModel::count(), '两笔订单各一条明细');
$this->putJson("/purchase/order/{$purchase->id}/store/{$store->id}/item/{$product->id}", [
'quantity' => 10,
'price' => 12,
'weight' => 5,
])->assertJsonPath('success', true);
$this->assertSame(1, StoreOrderItemModel::count(), '多笔明细合并为一条');
$item = StoreOrderItemModel::first();
$this->assertSame(10, $item->quantity);
$this->assertSame('12.00', (string) $item->price);
$this->assertSame('120.00', (string) $item->amount);
$this->assertSame('5.000', (string) $item->weight);
// 保留行所在订单重算;被合并订单清零
$survivedOrder = StoreOrderModel::find($item->order_id);
$this->assertSame(10, $survivedOrder->total_quantity);
$this->assertSame('120.00', (string) $survivedOrder->total_amount);
$mergedOrder = StoreOrderModel::where('id', '<>', $item->order_id)->first();
$this->assertSame(0, $mergedOrder->total_quantity);
$this->assertSame('0.00', (string) $mergedOrder->total_amount);
$purchase = $purchase->fresh();
$this->assertSame('10.00', (string) $purchase->total_quantity);
$this->assertSame('100.00', (string) $purchase->estimate_amount, '10 包 × 成本 10.00');
$this->assertSame('5.000', (string) $purchase->total_weight);
}
/** 门店购买详情-移除单品:明细删除,订单与采购单汇总级联重算 */
public function test_store_item_remove_deletes_and_recalculates(): void
{
[$purchase, $product, $stores] = $this->buildPurchase();
$this->actingAsSysUser();
$this->deleteJson("/purchase/order/{$purchase->id}/store/{$stores[0]->id}/item/{$product->id}")
->assertOk()->assertJsonPath('success', true);
$this->assertSame(0, StoreOrderItemModel::where('store_id', $stores[0]->id)->count());
$this->assertSame(1, StoreOrderItemModel::count(), '门店B 明细不受影响');
$order = StoreOrderModel::where('store_id', $stores[0]->id)->first();
$this->assertSame(0, $order->total_quantity);
$this->assertSame('0.00', (string) $order->total_amount);
$purchase = $purchase->fresh();
$this->assertSame('3.00', (string) $purchase->total_quantity, '仅剩门店B 3 件');
$this->assertSame('30.00', (string) $purchase->estimate_amount);
}
/** 门店购买详情:按商品聚合该门店采购汇总(数量/包规/单位/单价/预计金额),仅含该门店明细 */
public function test_store_summary_returns_aggregated_items(): void
{
[$purchase, $product, $stores] = $this->buildPurchase();
$this->actingAsSysUser();
$response = $this->getJson("/purchase/order/{$purchase->id}/store?store_id={$stores[0]->id}")
->assertOk()
->assertJsonPath('success', true);
$data = $response->json('data');
$this->assertSame($stores[0]->name, $data['store']['name']);
$this->assertCount(1, $data['items']);
$row = $data['items'][0];
$this->assertSame($product->id, $row['product_id']);
$this->assertSame('10斤/箱', $row['product_spec']);
$this->assertSame('斤', $row['unit']);
$this->assertSame('10.00', (string) $row['price']);
$this->assertSame(2, $row['quantity']);
$this->assertSame('20.00', (string) $row['amount']);
// 另一门店只见自身明细
$this->getJson("/purchase/order/{$purchase->id}/store?store_id={$stores[1]->id}")
->assertOk()
->assertJsonPath('data.items.0.quantity', 3)
->assertJsonPath('data.items.0.amount', '30.00');
}
/** 门店购买详情:同一商品多笔订单不同单价 → 数量合计、金额求和、单价为加权平均 */
public function test_store_summary_aggregates_multiple_orders_with_weighted_price(): void
{
$level = CustomerLevelModel::factory()->create();
$store = StoreModel::factory()->create(['level_id' => $level->id]);
$product = ProductModel::factory()->create([
'status' => ProductModel::STATUS_ON,
'cost_price' => 10,
'spec' => '10斤/箱',
'unit' => '斤',
]);
$this->actingAsMiniStore($store);
foreach ([2, 3] 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();
// 第二笔明细单价改为 20.00,构造同商品双单价:2×10 + 3×20
$secondItem = StoreOrderItemModel::orderBy('id')->skip(1)->first();
$this->putJson("/purchase/order/cell/{$secondItem->id}", ['quantity' => 3, 'price' => 20])
->assertJsonPath('success', true);
$this->getJson("/purchase/order/{$purchase->id}/store?store_id={$store->id}")
->assertOk()
->assertJsonPath('data.items.0.quantity', 5)
->assertJsonPath('data.items.0.price', '16.00', '(20+60) ÷ 5 加权平均')
->assertJsonPath('data.items.0.amount', '80.00');
}
/** 门店购买详情参数校验:缺少门店参数 / 采购单不存在均拒绝 */
public function test_store_summary_rejects_missing_or_invalid_params(): void
{
[$purchase] = $this->buildPurchase();
$this->actingAsSysUser();
$this->getJson("/purchase/order/{$purchase->id}/store")
->assertJsonPath('success', false)
->assertJsonPath('msg', '缺少门店参数');
$this->getJson('/purchase/order/99999/store?store_id=1')
->assertJsonPath('success', false)
->assertJsonPath('msg', '采购单不存在');
}
/** 采购单已完成:单元格编辑、行修改、门店单品增删改均拒绝,明细不变 */
public function test_edits_rejected_when_purchase_completed(): void
{
[$purchase, $product, $stores] = $this->buildPurchase();
$item = StoreOrderItemModel::where('store_id', $stores[0]->id)->first();
$supplier = SupplierModel::factory()->create();
$purchase->update(['status' => PurchaseOrderModel::STATUS_COMPLETED]);
$this->actingAsSysUser();
$this->putJson("/purchase/order/cell/{$item->id}", ['quantity' => 5, 'price' => 10])
->assertJsonPath('success', false)
->assertJsonPath('msg', '采购单已完成,不允许修改明细');
$this->putJson("/purchase/order/{$purchase->id}/row/{$product->id}", [
'product_name' => '改名',
'supplier_id' => $supplier->id,
'product_spec' => '5斤/袋',
'unit' => '袋',
'cost_price' => 30,
])->assertJsonPath('success', false)
->assertJsonPath('msg', '采购单已完成,不允许修改明细');
$this->postJson("/purchase/order/{$purchase->id}/store/{$stores[0]->id}/item", [
'product_id' => $product->id,
'quantity' => 1,
])->assertJsonPath('success', false);
$this->putJson("/purchase/order/{$purchase->id}/store/{$stores[0]->id}/item/{$product->id}", [
'quantity' => 5,
])->assertJsonPath('success', false);
$this->deleteJson("/purchase/order/{$purchase->id}/store/{$stores[0]->id}/item/{$product->id}")
->assertJsonPath('success', false);
$this->assertSame(2, $item->fresh()->quantity, '被拒绝后明细不变');
$this->assertSame('10.00', (string) $item->fresh()->cost_price);
}
}