修复一些错误
This commit is contained in:
@@ -11,6 +11,7 @@ use App\Models\PurchaseOrderModel;
|
||||
use App\Models\StoreModel;
|
||||
use App\Models\StoreOrderModel;
|
||||
use App\Models\UserModel;
|
||||
use Modules\SystemTool\Models\SysFileModel;
|
||||
|
||||
/**
|
||||
* 账单链路与支付:订单状态随业务链自动推进(采购单完成→配送中、生成账单→已完成);
|
||||
@@ -206,4 +207,73 @@ class BillPaymentTest extends ProcurementTestCase
|
||||
$this->assertSame(0, $bill->payment_id, '账单释放可重新付款');
|
||||
$this->assertSame('0.00', (string) $store->fresh()->total_purchase_amount);
|
||||
}
|
||||
|
||||
/** 后台门店订单:列表显示关联账单与支付进度,详情附带完整账单 */
|
||||
public function test_admin_order_list_and_detail_show_bill_info(): void
|
||||
{
|
||||
[$store, $order, $bill] = $this->makeBillViaChain();
|
||||
$this->actingAsSysUser();
|
||||
|
||||
// 列表:账单摘要 + 支付进度(待支付)
|
||||
$rows = $this->getJson('/order/store')->assertOk()->json('data.data');
|
||||
$row = collect($rows)->firstWhere('id', $order->id);
|
||||
$this->assertNotNull($row['bill'], '已出账订单列表应附账单');
|
||||
$this->assertSame($bill->bill_no, $row['bill']['bill_no']);
|
||||
$this->assertSame('20.00', $row['bill']['total_amount']);
|
||||
$this->assertSame(BillModel::PAY_STATE_UNPAID, $row['bill']['pay_state']);
|
||||
$this->assertSame('待支付', $row['bill']['pay_state_name']);
|
||||
|
||||
// 详情:完整账单字段 + 支付进度
|
||||
$detail = $this->getJson("/order/store/{$order->id}")->assertOk()->json('data');
|
||||
$this->assertSame($bill->bill_no, $detail['bill']['bill_no']);
|
||||
$this->assertSame('20.00', $detail['bill']['product_amount']);
|
||||
$this->assertSame(BillModel::PAY_STATE_UNPAID, $detail['bill']['pay_state']);
|
||||
|
||||
// 收款后列表支付进度变为已支付
|
||||
$this->putJson("/recon/bill/{$bill->id}/pay")->assertJsonPath('success', true);
|
||||
$rows = $this->getJson('/order/store')->assertOk()->json('data.data');
|
||||
$row = collect($rows)->firstWhere('id', $order->id);
|
||||
$this->assertSame(BillModel::PAY_STATE_PAID, $row['bill']['pay_state']);
|
||||
$this->assertSame('已支付', $row['bill']['pay_state_name']);
|
||||
}
|
||||
|
||||
/** 支付记录详情:凭证图片解析 preview_url(回归:preview_url 为访问器不能 pluck) */
|
||||
public function test_payment_detail_returns_voucher_urls(): void
|
||||
{
|
||||
$store = StoreModel::factory()->create();
|
||||
$user = UserModel::factory()->forStore($store->id)->create();
|
||||
|
||||
$makeFile = static function (string $path): int {
|
||||
return (int) SysFileModel::create([
|
||||
'group_id' => 4,
|
||||
'disk' => 'local',
|
||||
'channel' => 20,
|
||||
'file_type' => 10,
|
||||
'file_name' => basename($path),
|
||||
'file_path' => $path,
|
||||
'file_size' => 1024,
|
||||
'file_ext' => 'jpg',
|
||||
'uploader_id' => 1,
|
||||
])->id;
|
||||
};
|
||||
$fileA = $makeFile('voucher/a.jpg');
|
||||
$fileB = $makeFile('voucher/b.jpg');
|
||||
|
||||
$payment = PaymentModel::create([
|
||||
'payment_no' => 'ZF202608140003',
|
||||
'store_id' => $store->id,
|
||||
'user_id' => $user->id,
|
||||
'amount' => '100.00',
|
||||
'pay_method' => PaymentModel::METHOD_BANK,
|
||||
'voucher_ids' => [$fileA, $fileB],
|
||||
'status' => PaymentModel::STATUS_PENDING,
|
||||
]);
|
||||
|
||||
$this->actingAsSysUser();
|
||||
$data = $this->getJson("/recon/payment/{$payment->id}")->assertOk()->json('data');
|
||||
|
||||
$this->assertCount(2, $data['payment']['voucher_urls']);
|
||||
$this->assertStringContainsString('voucher/a.jpg', $data['payment']['voucher_urls'][0]);
|
||||
$this->assertStringContainsString('voucher/b.jpg', $data['payment']['voucher_urls'][1], '凭证顺序保持提交顺序');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use App\Models\StoreModel;
|
||||
use App\Models\StoreOrderItemModel;
|
||||
use App\Models\StoreOrderModel;
|
||||
use App\Models\UserModel;
|
||||
use Modules\SystemTool\Models\SysFileModel;
|
||||
|
||||
/**
|
||||
* 小程序账单:支付进度推导(待支付/审核中/已支付)、应结算日期(回款周期)、
|
||||
@@ -149,6 +150,18 @@ class MiniBillTest extends ProcurementTestCase
|
||||
[$store, $user] = $this->makeStoreWithUser(0);
|
||||
$this->actingAsMiniUser($user);
|
||||
|
||||
$file = SysFileModel::create([
|
||||
'group_id' => 1,
|
||||
'disk' => 'local',
|
||||
'channel' => 10,
|
||||
'file_type' => 10,
|
||||
'file_name' => '白菜.jpg',
|
||||
'file_path' => 'product/baicai.jpg',
|
||||
'file_size' => 1024,
|
||||
'file_ext' => 'jpg',
|
||||
'uploader_id' => 1,
|
||||
]);
|
||||
|
||||
$bill = $this->makeBill($store);
|
||||
$product = ProductModel::factory()->create(['status' => ProductModel::STATUS_ON]);
|
||||
$order = StoreOrderModel::factory()->create([
|
||||
@@ -164,9 +177,12 @@ class MiniBillTest extends ProcurementTestCase
|
||||
'store_id' => $store->id,
|
||||
'product_id' => $product->id,
|
||||
'product_name' => '白菜',
|
||||
'product_spec' => '30斤/筐',
|
||||
'unit' => '筐',
|
||||
'price' => '5.00',
|
||||
'quantity' => 20,
|
||||
'amount' => '100.00',
|
||||
'image_ids' => (string) $file->id,
|
||||
]);
|
||||
|
||||
$data = $this->getJson("/mini/bill/{$bill->id}")->assertOk()->json('data');
|
||||
@@ -178,9 +194,13 @@ class MiniBillTest extends ProcurementTestCase
|
||||
|
||||
$this->assertCount(1, $data['items']);
|
||||
$this->assertSame('白菜', $data['items'][0]['product_name']);
|
||||
$this->assertSame('30斤/筐', $data['items'][0]['product_spec'], '明细附规格');
|
||||
$this->assertSame('筐', $data['items'][0]['unit'], '明细附单位');
|
||||
$this->assertSame('5.00', $data['items'][0]['price'], '合并明细单价 = Σ金额 ÷ Σ数量');
|
||||
$this->assertSame(20, $data['items'][0]['quantity']);
|
||||
$this->assertSame('100.00', $data['items'][0]['amount']);
|
||||
$this->assertStringContainsString('baicai.jpg', (string) $data['items'][0]['image'], '明细附首图URL');
|
||||
$this->assertArrayNotHasKey('image_ids', $data['items'][0], 'image_ids 解析后不输出');
|
||||
|
||||
$this->assertCount(1, $data['orders']);
|
||||
$this->assertSame($order->order_no, $data['orders'][0]['order_no']);
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\CustomerLevelModel;
|
||||
use App\Models\ProductModel;
|
||||
use App\Models\ProductPriceModel;
|
||||
use App\Models\StoreModel;
|
||||
use App\Models\UserModel;
|
||||
|
||||
/**
|
||||
* 小程序商品:商品详情接口(免登录浏览,登录门店按等级显示换算价);
|
||||
* 商品列表回归:登录门店场景曾数组误用对象访问 + 价格行缺失导致 500
|
||||
*/
|
||||
class MiniProductTest extends ProcurementTestCase
|
||||
{
|
||||
/**
|
||||
* 造门店 + 上架商品 + 等级价(固定价 5.00)
|
||||
*
|
||||
* @return array{0: StoreModel, 1: ProductModel, 2: UserModel, 3: CustomerLevelModel}
|
||||
*/
|
||||
private function makeStoreWithProduct(string $price = '5.00'): array
|
||||
{
|
||||
$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' => $price,
|
||||
]);
|
||||
|
||||
return [$store, $product, UserModel::factory()->forStore($store->id)->create(), $level];
|
||||
}
|
||||
|
||||
/** 商品详情:未登录浏览 price=null,基础字段完整 */
|
||||
public function test_product_detail_guest_sees_null_price(): void
|
||||
{
|
||||
[, $product] = $this->makeStoreWithProduct();
|
||||
|
||||
$data = $this->getJson("/mini/product/{$product->id}")->assertOk()->json('data');
|
||||
|
||||
$this->assertSame($product->name, $data['name']);
|
||||
$this->assertSame($product->spec, $data['spec']);
|
||||
$this->assertSame($product->unit, $data['unit']);
|
||||
$this->assertNull($data['price'], '未登录不显示价格');
|
||||
$this->assertArrayNotHasKey('cost_price', $data, '成本价不得输出到小程序端');
|
||||
}
|
||||
|
||||
/** 商品详情:登录门店按等级显示固定价 */
|
||||
public function test_product_detail_store_user_sees_level_price(): void
|
||||
{
|
||||
[, $product, $user] = $this->makeStoreWithProduct('6.50');
|
||||
$this->actingAsMiniUser($user);
|
||||
|
||||
$data = $this->getJson("/mini/product/{$product->id}")->assertOk()->json('data');
|
||||
|
||||
$this->assertSame('6.50', $data['price']);
|
||||
}
|
||||
|
||||
/** 商品详情:百分比计价按最新成本价上浮换算 */
|
||||
public function test_product_detail_percent_price_calculated_from_cost(): void
|
||||
{
|
||||
[, $product, $user, $level] = $this->makeStoreWithProduct();
|
||||
ProductPriceModel::where('product_id', $product->id)->where('level_id', $level->id)
|
||||
->update(['price_type' => ProductPriceModel::PRICE_TYPE_PERCENT, 'percent' => '30']);
|
||||
$product->update(['cost_price' => '20.00']);
|
||||
$this->actingAsMiniUser($user);
|
||||
|
||||
$data = $this->getJson("/mini/product/{$product->id}")->assertOk()->json('data');
|
||||
|
||||
$this->assertSame('26.00', $data['price'], '20 元上浮 30% = 26.00');
|
||||
}
|
||||
|
||||
/** 商品详情:下架/不存在拒绝 */
|
||||
public function test_product_detail_off_shelf_or_missing_rejected(): void
|
||||
{
|
||||
[, $product] = $this->makeStoreWithProduct();
|
||||
$product->update(['status' => ProductModel::STATUS_OFF]);
|
||||
|
||||
$this->getJson("/mini/product/{$product->id}")->assertJsonPath('success', false);
|
||||
$this->getJson('/mini/product/99999')->assertJsonPath('success', false);
|
||||
}
|
||||
|
||||
/** 商品列表:登录门店显示等级价(回归:曾数组误用对象访问导致 500) */
|
||||
public function test_product_list_store_user_sees_level_price(): void
|
||||
{
|
||||
[, $product, $user] = $this->makeStoreWithProduct('7.00');
|
||||
$this->actingAsMiniUser($user);
|
||||
|
||||
$rows = $this->getJson('/mini/product/list')->assertOk()->json('data.data');
|
||||
$row = collect($rows)->firstWhere('id', $product->id);
|
||||
|
||||
$this->assertNotNull($row);
|
||||
$this->assertSame('7.00', $row['price']);
|
||||
$this->assertArrayNotHasKey('cost_price', $row, '成本价不得输出到小程序端');
|
||||
}
|
||||
|
||||
/** 商品列表:未登录 price=null */
|
||||
public function test_product_list_guest_sees_null_price(): void
|
||||
{
|
||||
[, $product] = $this->makeStoreWithProduct();
|
||||
|
||||
$rows = $this->getJson('/mini/product/list')->assertOk()->json('data.data');
|
||||
$row = collect($rows)->firstWhere('id', $product->id);
|
||||
|
||||
$this->assertNotNull($row);
|
||||
$this->assertNull($row['price']);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ use App\Models\ProductPriceModel;
|
||||
use App\Models\StoreModel;
|
||||
use App\Models\StoreOrderModel;
|
||||
use App\Models\UserModel;
|
||||
use Modules\SystemTool\Models\SysFileModel;
|
||||
|
||||
/**
|
||||
* 小程序下单:等级价快照、服务端重算总价、取消限制、门店数据隔离
|
||||
@@ -321,4 +322,48 @@ class StoreOrderTest extends ProcurementTestCase
|
||||
])->assertJsonPath('success', false);
|
||||
$this->assertSame(StoreOrderModel::STATUS_SUMMARIZED, $pending1->fresh()->status);
|
||||
}
|
||||
|
||||
/** 订单列表商品预览:附带首图/规格/单位供小程序端展示 */
|
||||
public function test_order_list_preview_includes_image_spec_and_unit(): void
|
||||
{
|
||||
$file = SysFileModel::create([
|
||||
'group_id' => 1,
|
||||
'disk' => 'local',
|
||||
'channel' => 10,
|
||||
'file_type' => 10,
|
||||
'file_name' => '白菜.jpg',
|
||||
'file_path' => 'product/baicai.jpg',
|
||||
'file_size' => 1024,
|
||||
'file_ext' => 'jpg',
|
||||
'uploader_id' => 1,
|
||||
]);
|
||||
|
||||
$level = CustomerLevelModel::factory()->create();
|
||||
$store = StoreModel::factory()->create(['level_id' => $level->id]);
|
||||
$product = ProductModel::factory()->create([
|
||||
'status' => ProductModel::STATUS_ON,
|
||||
'spec' => '30斤/筐',
|
||||
'unit' => '筐',
|
||||
'image_ids' => (string) $file->id,
|
||||
]);
|
||||
ProductPriceModel::factory()->create([
|
||||
'product_id' => $product->id,
|
||||
'level_id' => $level->id,
|
||||
'price' => '5.00',
|
||||
]);
|
||||
$user = UserModel::factory()->forStore($store->id)->create();
|
||||
|
||||
$this->actingAsMiniUser($user);
|
||||
$this->postJson('/mini/order', ['items' => [['product_id' => $product->id, 'quantity' => 2]]])
|
||||
->assertJsonPath('success', true);
|
||||
|
||||
$rows = $this->getJson('/mini/order')->assertOk()->json('data.data');
|
||||
$preview = $rows[0]['items'][0];
|
||||
|
||||
$this->assertSame($product->name, $preview['product_name']);
|
||||
$this->assertSame('30斤/筐', $preview['product_spec'], '预览附规格');
|
||||
$this->assertSame('筐', $preview['unit'], '预览附单位');
|
||||
$this->assertStringContainsString('baicai.jpg', (string) $preview['image'], '预览附首图URL');
|
||||
$this->assertArrayNotHasKey('image_ids', $preview, 'image_ids 解析后不输出');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user