小程序接口
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\BillModel;
|
||||
use App\Models\ProductModel;
|
||||
use App\Models\PurchaseOrderModel;
|
||||
use App\Models\StoreModel;
|
||||
use App\Models\StoreOrderItemModel;
|
||||
use App\Models\StoreOrderModel;
|
||||
use App\Models\UserModel;
|
||||
|
||||
/**
|
||||
* 小程序账单:支付进度推导(待支付/审核中/已支付)、应结算日期(回款周期)、
|
||||
* 待支付汇总、可付款筛选、门店数据隔离、详情归属校验
|
||||
*/
|
||||
class MiniBillTest extends ProcurementTestCase
|
||||
{
|
||||
private static int $billSeq = 0;
|
||||
|
||||
/**
|
||||
* 造一个绑定正常门店的小程序用户
|
||||
*
|
||||
* @return array{0: StoreModel, 1: UserModel}
|
||||
*/
|
||||
private function makeStoreWithUser(int $cycleDays = 3): array
|
||||
{
|
||||
$store = StoreModel::factory()->paymentCycle($cycleDays)->create();
|
||||
|
||||
return [$store, UserModel::factory()->forStore($store->id)->create()];
|
||||
}
|
||||
|
||||
/** 造一张账单(默认 2026-08-10 出账,总额 140.00,未支付) */
|
||||
private function makeBill(StoreModel $store, array $attributes = []): BillModel
|
||||
{
|
||||
$seq = ++self::$billSeq;
|
||||
|
||||
return BillModel::create(array_merge([
|
||||
'bill_no' => 'ZD' . str_pad((string) $seq, 12, '0', STR_PAD_LEFT),
|
||||
'purchase_id' => PurchaseOrderModel::factory()->create()->id,
|
||||
'store_id' => $store->id,
|
||||
'bill_date' => '2026-08-10',
|
||||
'product_amount' => '100.00',
|
||||
'delivery_fee' => '10.00',
|
||||
'box_num' => 2,
|
||||
'tray_num' => 1,
|
||||
'box_price' => '5.00',
|
||||
'tray_price' => '20.00',
|
||||
'added_amount' => '30.00',
|
||||
'total_amount' => '140.00',
|
||||
'status' => BillModel::STATUS_UNPAID,
|
||||
], $attributes));
|
||||
}
|
||||
|
||||
/** 支付进度推导与应结算日期(账单日期 + 门店回款周期) */
|
||||
public function test_bill_list_derives_pay_state_and_settlement_date(): void
|
||||
{
|
||||
[$store, $user] = $this->makeStoreWithUser(3);
|
||||
$this->actingAsMiniUser($user);
|
||||
|
||||
$unpaid = $this->makeBill($store);
|
||||
$reviewing = $this->makeBill($store, ['payment_id' => 99]);
|
||||
$paid = $this->makeBill($store, ['status' => BillModel::STATUS_PAID, 'paid_at' => '2026-08-12 10:00:00']);
|
||||
|
||||
$rows = collect($this->getJson('/mini/bill')->assertOk()->json('data.data'))->keyBy('id');
|
||||
|
||||
$unpaidRow = $rows[$unpaid->id];
|
||||
$this->assertSame(BillModel::PAY_STATE_UNPAID, $unpaidRow['pay_state']);
|
||||
$this->assertSame('待支付', $unpaidRow['pay_state_name']);
|
||||
$this->assertTrue($unpaidRow['can_pay']);
|
||||
$this->assertSame('2026-08-13', $unpaidRow['settlement_date'], '账单日期 2026-08-10 + 回款周期 3 天');
|
||||
$this->assertArrayNotHasKey('operator_id', $unpaidRow, '小程序端不输出后台操作人字段');
|
||||
$this->assertArrayNotHasKey('paid_operator_id', $unpaidRow);
|
||||
|
||||
$reviewingRow = $rows[$reviewing->id];
|
||||
$this->assertSame(BillModel::PAY_STATE_REVIEWING, $reviewingRow['pay_state']);
|
||||
$this->assertSame('审核中', $reviewingRow['pay_state_name']);
|
||||
$this->assertFalse($reviewingRow['can_pay']);
|
||||
|
||||
$paidRow = $rows[$paid->id];
|
||||
$this->assertSame(BillModel::PAY_STATE_PAID, $paidRow['pay_state']);
|
||||
$this->assertSame('已支付', $paidRow['pay_state_name']);
|
||||
$this->assertFalse($paidRow['can_pay']);
|
||||
$this->assertSame('2026-08-12 10:00:00', $paidRow['paid_at']);
|
||||
}
|
||||
|
||||
/** 待支付汇总:未支付笔数/金额(含审核中),不受列表筛选影响 */
|
||||
public function test_bill_list_summary_aggregates_unpaid(): void
|
||||
{
|
||||
[$store, $user] = $this->makeStoreWithUser();
|
||||
$this->actingAsMiniUser($user);
|
||||
|
||||
$this->makeBill($store, ['total_amount' => '100.00']);
|
||||
$this->makeBill($store, ['total_amount' => '50.50', 'payment_id' => 99]);
|
||||
$this->makeBill($store, ['total_amount' => '200.00', 'status' => BillModel::STATUS_PAID]);
|
||||
|
||||
$response = $this->getJson('/mini/bill?status=1')->assertOk();
|
||||
$this->assertSame(1, $response->json('data.total'), 'status 筛选只影响列表');
|
||||
$this->assertSame(2, $response->json('data.summary.unpaid_count'));
|
||||
$this->assertSame('150.50', $response->json('data.summary.unpaid_amount'));
|
||||
}
|
||||
|
||||
/** 可付款筛选:仅未支付且未锁定到支付记录的账单(合并付款选择页) */
|
||||
public function test_bill_list_payable_filter(): void
|
||||
{
|
||||
[$store, $user] = $this->makeStoreWithUser();
|
||||
$this->actingAsMiniUser($user);
|
||||
|
||||
$payable = $this->makeBill($store);
|
||||
$this->makeBill($store, ['payment_id' => 99]);
|
||||
$this->makeBill($store, ['status' => BillModel::STATUS_PAID]);
|
||||
|
||||
$rows = $this->getJson('/mini/bill?payable=1')->assertOk()->json('data.data');
|
||||
$this->assertCount(1, $rows);
|
||||
$this->assertSame($payable->id, $rows[0]['id']);
|
||||
}
|
||||
|
||||
/** 账单日期区间筛选 */
|
||||
public function test_bill_list_filters_by_bill_date_range(): void
|
||||
{
|
||||
[$store, $user] = $this->makeStoreWithUser();
|
||||
$this->actingAsMiniUser($user);
|
||||
|
||||
$this->makeBill($store, ['bill_date' => '2026-08-01']);
|
||||
$this->makeBill($store, ['bill_date' => '2026-08-05']);
|
||||
$this->makeBill($store, ['bill_date' => '2026-08-10']);
|
||||
|
||||
$this->getJson('/mini/bill?start_date=2026-08-03')->assertJsonPath('data.total', 2);
|
||||
$this->getJson('/mini/bill?start_date=2026-08-03&end_date=2026-08-06')->assertJsonPath('data.total', 1);
|
||||
$this->getJson('/mini/bill?end_date=2026-08-06')->assertJsonPath('data.total', 2);
|
||||
}
|
||||
|
||||
/** 门店数据隔离:只能查看本店账单 */
|
||||
public function test_bill_data_isolated_between_stores(): void
|
||||
{
|
||||
[$storeA] = $this->makeStoreWithUser();
|
||||
$billOfA = $this->makeBill($storeA);
|
||||
|
||||
[, $userB] = $this->makeStoreWithUser();
|
||||
$this->actingAsMiniUser($userB);
|
||||
|
||||
$this->getJson('/mini/bill')->assertJsonPath('data.total', 0);
|
||||
$this->getJson("/mini/bill/{$billOfA->id}")->assertJsonPath('success', false);
|
||||
}
|
||||
|
||||
/** 详情:格式化账单 + 合并商品明细 + 关联订单 */
|
||||
public function test_bill_detail_outputs_bill_items_and_orders(): void
|
||||
{
|
||||
[$store, $user] = $this->makeStoreWithUser(0);
|
||||
$this->actingAsMiniUser($user);
|
||||
|
||||
$bill = $this->makeBill($store);
|
||||
$product = ProductModel::factory()->create(['status' => ProductModel::STATUS_ON]);
|
||||
$order = StoreOrderModel::factory()->create([
|
||||
'store_id' => $store->id,
|
||||
'purchase_id' => $bill->purchase_id,
|
||||
'bill_id' => $bill->id,
|
||||
'total_amount' => '100.00',
|
||||
]);
|
||||
StoreOrderItemModel::factory()->create([
|
||||
'order_id' => $order->id,
|
||||
'purchase_id' => $bill->purchase_id,
|
||||
'bill_id' => $bill->id,
|
||||
'store_id' => $store->id,
|
||||
'product_id' => $product->id,
|
||||
'product_name' => '白菜',
|
||||
'price' => '5.00',
|
||||
'quantity' => 20,
|
||||
'amount' => '100.00',
|
||||
]);
|
||||
|
||||
$data = $this->getJson("/mini/bill/{$bill->id}")->assertOk()->json('data');
|
||||
|
||||
$this->assertSame($bill->bill_no, $data['bill']['bill_no']);
|
||||
$this->assertSame('待支付', $data['bill']['pay_state_name']);
|
||||
$this->assertSame('2026-08-10', $data['bill']['settlement_date'], '回款周期 0 天,出账当天应结算');
|
||||
$this->assertSame($bill->purchase->purchase_no, $data['bill']['purchase']['purchase_no']);
|
||||
|
||||
$this->assertCount(1, $data['items']);
|
||||
$this->assertSame('白菜', $data['items'][0]['product_name']);
|
||||
$this->assertSame('5.00', $data['items'][0]['price'], '合并明细单价 = Σ金额 ÷ Σ数量');
|
||||
$this->assertSame(20, $data['items'][0]['quantity']);
|
||||
$this->assertSame('100.00', $data['items'][0]['amount']);
|
||||
|
||||
$this->assertCount(1, $data['orders']);
|
||||
$this->assertSame($order->order_no, $data['orders'][0]['order_no']);
|
||||
}
|
||||
}
|
||||
@@ -130,6 +130,68 @@ class StoreOrderTest extends ProcurementTestCase
|
||||
$this->getJson('/mini/order')->assertJsonPath('data.total', 0);
|
||||
}
|
||||
|
||||
/** 列表输出:状态名 / 可取消标记 / 商品预览(前 3 条)与明细种数 */
|
||||
public function test_order_list_outputs_status_name_and_item_preview(): void
|
||||
{
|
||||
$level = CustomerLevelModel::factory()->create();
|
||||
$store = StoreModel::factory()->create(['level_id' => $level->id]);
|
||||
$this->actingAsMiniUser(UserModel::factory()->forStore($store->id)->create());
|
||||
|
||||
$items = [];
|
||||
foreach (['白菜', '土豆', '番茄', '黄瓜'] as $name) {
|
||||
$product = ProductModel::factory()->create(['name' => $name, 'status' => ProductModel::STATUS_ON]);
|
||||
ProductPriceModel::factory()->create(['product_id' => $product->id, 'level_id' => $level->id, 'price' => 5.00]);
|
||||
$items[] = ['product_id' => $product->id, 'quantity' => 2];
|
||||
}
|
||||
$this->postJson('/mini/order', ['items' => $items])->assertJsonPath('success', true);
|
||||
$order = StoreOrderModel::where('store_id', $store->id)->first();
|
||||
|
||||
$row = collect($this->getJson('/mini/order')->assertOk()->json('data.data'))->firstWhere('id', $order->id);
|
||||
$this->assertSame('待接单', $row['status_name']);
|
||||
$this->assertTrue($row['can_cancel']);
|
||||
$this->assertSame(4, $row['item_count']);
|
||||
$this->assertCount(3, $row['items'], '预览仅输出前 3 条明细,完整明细走详情接口');
|
||||
$this->assertSame('白菜', $row['items'][0]['product_name']);
|
||||
$this->assertSame(2, $row['items'][0]['quantity']);
|
||||
|
||||
// 已接单后状态名变化且不可取消
|
||||
$order->update(['status' => StoreOrderModel::STATUS_SUMMARIZED]);
|
||||
$row = collect($this->getJson('/mini/order')->json('data.data'))->firstWhere('id', $order->id);
|
||||
$this->assertSame('已接单', $row['status_name']);
|
||||
$this->assertFalse($row['can_cancel']);
|
||||
}
|
||||
|
||||
/** 订货日期区间筛选(配合 /order/summary 周期下钻) */
|
||||
public function test_order_list_filters_by_order_date_range(): void
|
||||
{
|
||||
[$store, $product, $user] = $this->makeStoreWithProduct();
|
||||
$this->actingAsMiniUser($user);
|
||||
|
||||
foreach ([1, 1, 1] as $qty) {
|
||||
$this->postJson('/mini/order', ['items' => [['product_id' => $product->id, 'quantity' => $qty]]])
|
||||
->assertJsonPath('success', true);
|
||||
}
|
||||
$orders = StoreOrderModel::where('store_id', $store->id)->orderBy('id')->get();
|
||||
$orders[0]->update(['order_date' => '2026-08-01']);
|
||||
$orders[1]->update(['order_date' => '2026-08-05']);
|
||||
$orders[2]->update(['order_date' => '2026-08-10']);
|
||||
|
||||
$this->getJson('/mini/order?start_date=2026-08-03')->assertJsonPath('data.total', 2);
|
||||
$this->getJson('/mini/order?start_date=2026-08-03&end_date=2026-08-06')->assertJsonPath('data.total', 1);
|
||||
$this->getJson('/mini/order?end_date=2026-08-06')->assertJsonPath('data.total', 2);
|
||||
}
|
||||
|
||||
/** 非法筛选参数被拦截(状态枚举 / 分页上限 / 日期区间倒置) */
|
||||
public function test_order_list_rejects_invalid_filters(): void
|
||||
{
|
||||
[, , $user] = $this->makeStoreWithProduct();
|
||||
$this->actingAsMiniUser($user);
|
||||
|
||||
$this->getJson('/mini/order?status=7')->assertJsonPath('success', false);
|
||||
$this->getJson('/mini/order?pageSize=100')->assertJsonPath('success', false);
|
||||
$this->getJson('/mini/order?start_date=2026-08-10&end_date=2026-08-01')->assertJsonPath('success', false);
|
||||
}
|
||||
|
||||
/** 造一笔指定状态的订单(商品 5.00 × 2 = 10.00) */
|
||||
private function makeOrderWithStatus(int $status): StoreOrderModel
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user