生成采购单基础

This commit is contained in:
liu
2026-08-11 21:08:01 +08:00
parent 06c7bd9f88
commit 5d26f04ba2
13 changed files with 362 additions and 68 deletions
+6
View File
@@ -9,6 +9,7 @@ use App\Models\PurchaseAllocationModel;
use App\Models\PurchaseOrderItemModel;
use App\Models\PurchaseOrderModel;
use App\Models\StoreModel;
use App\Models\StoreOrderModel;
use App\Models\UserModel;
/**
@@ -35,6 +36,9 @@ class AllocationTest extends ProcurementTestCase
->assertJsonPath('success', true);
}
// 接单后生成采购单(生成来源为已接单订单)
StoreOrderModel::query()->update(['status' => StoreOrderModel::STATUS_SUMMARIZED]);
$this->actingAsSysUser();
$this->postJson('/purchase/order/generate', ['purchase_date' => now()->toDateString()])
->assertJsonPath('success', true);
@@ -131,6 +135,8 @@ class AllocationTest extends ProcurementTestCase
$this->actingAsMiniUser(UserModel::factory()->forStore($store->id)->create());
$this->postJson('/mini/order', ['items' => [['product_id' => $product->id, 'quantity' => 1]]]);
StoreOrderModel::query()->update(['status' => StoreOrderModel::STATUS_SUMMARIZED]);
$this->actingAsSysUser();
$this->postJson('/purchase/order/generate', ['purchase_date' => now()->toDateString()]);
$purchase = PurchaseOrderModel::first();
+4
View File
@@ -9,6 +9,7 @@ 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 Maatwebsite\Excel\Facades\Excel;
@@ -39,6 +40,9 @@ class ExportTest extends ProcurementTestCase
['product_id' => $meat->id, 'quantity' => 1],
]])->assertJsonPath('success', true);
// 接单后生成采购单
StoreOrderModel::query()->update(['status' => StoreOrderModel::STATUS_SUMMARIZED]);
$this->actingAsSysUser();
$this->postJson('/purchase/order/generate', ['purchase_date' => now()->toDateString()])
->assertJsonPath('success', true);
+56 -12
View File
@@ -16,10 +16,10 @@ use App\Models\UserModel;
class PurchaseGenerateTest extends ProcurementTestCase
{
/**
* 造当日待汇总订单:门店A 两单各 3 件 + 门店B 一单 4 件(同一商品)
* 造当日已接单订单:门店A 两单各 3 件 + 门店B 一单 4 件(同一商品),下单后统一接单
* 商品设两个等级价 5.00 / 4.00,估算单价应取最低 4.00
*/
private function seedPendingOrders(): ProductModel
private function seedAcceptedOrders(): ProductModel
{
$level = CustomerLevelModel::factory()->create();
$levelLow = CustomerLevelModel::factory()->create();
@@ -35,13 +35,16 @@ class PurchaseGenerateTest extends ProcurementTestCase
->assertJsonPath('success', true);
}
// 后台接单:待接单 → 已接单(生成采购单的来源状态)
StoreOrderModel::query()->update(['status' => StoreOrderModel::STATUS_SUMMARIZED]);
return $product;
}
/** 多门店多订单按商品聚合,估算单价取最低等级价 */
public function test_generate_aggregates_orders_by_product(): void
{
$this->seedPendingOrders();
$this->seedAcceptedOrders();
$admin = $this->actingAsSysUser();
$this->postJson('/purchase/order/generate', ['purchase_date' => now()->toDateString()])
@@ -63,33 +66,71 @@ class PurchaseGenerateTest extends ProcurementTestCase
$this->assertSame('40.00', (string) $purchase->estimate_amount);
}
/** 源订单状态回写为已汇总 */
/** 源订单状态回写为采购中,并关联 purchase_id */
public function test_generate_writes_back_order_status(): void
{
$this->seedPendingOrders();
$this->seedAcceptedOrders();
$this->actingAsSysUser();
$this->postJson('/purchase/order/generate', ['purchase_date' => now()->toDateString()])
->assertJsonPath('success', true);
$this->assertSame(0, StoreOrderModel::where('status', StoreOrderModel::STATUS_PENDING)->count());
$this->assertSame(3, StoreOrderModel::where('status', StoreOrderModel::STATUS_SUMMARIZED)->count());
$purchase = PurchaseOrderModel::first();
$this->assertSame(0, StoreOrderModel::where('status', StoreOrderModel::STATUS_SUMMARIZED)->count());
$this->assertSame(3, StoreOrderModel::where('status', StoreOrderModel::STATUS_DELIVERING)->count());
$this->assertSame(3, StoreOrderModel::where('purchase_id', $purchase->id)->count());
}
/** 当日无待汇总订单 → 报错 */
public function test_generate_without_pending_orders_fails(): void
/** 仅有待接单订单时不可生成(待接单不再被归集)→ 报错 */
public function test_generate_without_accepted_orders_fails(): void
{
$this->actingAsSysUser();
$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]);
$this->actingAsMiniUser(UserModel::factory()->forStore($store->id)->create());
$this->postJson('/mini/order', ['items' => [['product_id' => $product->id, 'quantity' => 1]]])
->assertJsonPath('success', true);
$this->actingAsSysUser();
$this->postJson('/purchase/order/generate', ['purchase_date' => now()->toDateString()])
->assertJsonPath('success', false);
$this->assertSame(0, PurchaseOrderModel::count());
$this->assertSame(1, StoreOrderModel::where('status', StoreOrderModel::STATUS_PENDING)->count());
}
/** 幂等:已汇总订单不会被重复归集 */
/** 指定订单合并:仅归集 order_ids 内的已接单订单,混入非已接单则整批拒绝 */
public function test_generate_with_selected_order_ids(): void
{
$this->seedAcceptedOrders();
$this->actingAsSysUser();
$selected = StoreOrderModel::query()->orderBy('id')->limit(2)->pluck('id')->all();
$this->postJson('/purchase/order/generate', [
'purchase_date' => now()->toDateString(),
'order_ids' => $selected,
])->assertJsonPath('success', true);
$purchase = PurchaseOrderModel::first();
$this->assertSame(2, StoreOrderModel::where('purchase_id', $purchase->id)->count());
$this->assertSame(1, StoreOrderModel::where('status', StoreOrderModel::STATUS_SUMMARIZED)->count(), '未选中的订单保持已接单');
// 混入非已接单订单 → 整批拒绝
$remaining = StoreOrderModel::where('status', StoreOrderModel::STATUS_SUMMARIZED)->value('id');
$done = StoreOrderModel::where('status', StoreOrderModel::STATUS_DELIVERING)->value('id');
$this->postJson('/purchase/order/generate', [
'purchase_date' => now()->toDateString(),
'order_ids' => [$remaining, $done],
])->assertJsonPath('success', false);
$this->assertSame(1, PurchaseOrderModel::count(), '整批拒绝,不产生新采购单');
}
/** 幂等:已归集订单不会被重复归集 */
public function test_generate_is_idempotent(): void
{
$this->seedPendingOrders();
$this->seedAcceptedOrders();
$this->actingAsSysUser();
$this->postJson('/purchase/order/generate', ['purchase_date' => now()->toDateString()])
@@ -128,6 +169,9 @@ class PurchaseGenerateTest extends ProcurementTestCase
$this->postJson('/mini/order', ['items' => [['product_id' => $product->id, 'quantity' => 3]]])
->assertJsonPath('success', true);
// 接单后生成
StoreOrderModel::query()->update(['status' => StoreOrderModel::STATUS_SUMMARIZED]);
$this->actingAsSysUser();
$this->postJson('/purchase/order/generate', ['purchase_date' => now()->toDateString()])
->assertJsonPath('success', true);
+4
View File
@@ -10,6 +10,7 @@ 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;
@@ -42,6 +43,9 @@ class ReconciliationTest extends ProcurementTestCase
->assertJsonPath('success', true);
}
// 接单后生成采购单
StoreOrderModel::query()->update(['status' => StoreOrderModel::STATUS_SUMMARIZED]);
$this->actingAsSysUser();
$this->postJson('/purchase/order/generate', ['purchase_date' => now()->toDateString()])
->assertJsonPath('success', true);