130 lines
5.7 KiB
PHP
130 lines
5.7 KiB
PHP
<?php
|
||
|
||
namespace Tests\Feature;
|
||
|
||
use App\Models\CustomerLevelModel;
|
||
use App\Models\NoticeModel;
|
||
use App\Models\ProductModel;
|
||
use App\Models\ProductPriceModel;
|
||
use App\Models\StoreModel;
|
||
use App\Models\UserModel;
|
||
|
||
/**
|
||
* A2 等级价格体系:等级价匹配、批量调价事务与调价通知
|
||
*/
|
||
class ProductPriceTest extends ProcurementTestCase
|
||
{
|
||
/** 小程序商品列表返回当前门店等级对应的价格 */
|
||
public function test_product_list_returns_price_for_store_level(): void
|
||
{
|
||
$levelA = CustomerLevelModel::factory()->create();
|
||
$levelB = CustomerLevelModel::factory()->create();
|
||
$store = StoreModel::factory()->create(['level_id' => $levelA->id]);
|
||
$product = ProductModel::factory()->create(['status' => ProductModel::STATUS_ON]);
|
||
ProductPriceModel::factory()->create(['product_id' => $product->id, 'level_id' => $levelA->id, 'price' => 5.50]);
|
||
ProductPriceModel::factory()->create(['product_id' => $product->id, 'level_id' => $levelB->id, 'price' => 3.00]);
|
||
|
||
$this->actingAsMiniUser(UserModel::factory()->forStore($store->id)->create());
|
||
|
||
$response = $this->getJson('/mini/product/list');
|
||
$response->assertOk()->assertJsonPath('success', true);
|
||
|
||
$row = collect($response->json('data.data'))->firstWhere('id', $product->id);
|
||
$this->assertNotNull($row, '商品应出现在列表中');
|
||
$this->assertSame(5.50, (float) $row['price'], '应返回门店所在等级的价格');
|
||
}
|
||
|
||
/** 门店未设置客户等级:仍可浏览商品,但价格不可见(price=null) */
|
||
public function test_store_without_level_sees_products_without_price(): void
|
||
{
|
||
$store = StoreModel::factory()->create(['level_id' => 0]);
|
||
$product = ProductModel::factory()->create(['status' => ProductModel::STATUS_ON]);
|
||
$this->actingAsMiniUser(UserModel::factory()->forStore($store->id)->create());
|
||
|
||
$response = $this->getJson('/mini/product/list');
|
||
$response->assertOk()->assertJsonPath('success', true);
|
||
|
||
$row = collect($response->json('data.data'))->firstWhere('id', $product->id);
|
||
$this->assertNotNull($row, '未设等级的门店仍应能看到商品');
|
||
$this->assertNull($row['price'], '未设等级时价格应为 null');
|
||
}
|
||
|
||
/** 未绑定门店:可浏览商品与分类,但价格不可见;加购仍被拦截(购买前置校验不变) */
|
||
public function test_unbound_user_can_browse_products_without_price_but_cannot_cart(): void
|
||
{
|
||
$product = ProductModel::factory()->create(['status' => ProductModel::STATUS_ON]);
|
||
$this->actingAsMiniUser(UserModel::factory()->create()); // type=0 待绑定
|
||
|
||
$list = $this->getJson('/mini/product/list');
|
||
$list->assertOk()->assertJsonPath('success', true);
|
||
|
||
$row = collect($list->json('data.data'))->firstWhere('id', $product->id);
|
||
$this->assertNotNull($row, '未绑定门店应能看到商品');
|
||
$this->assertNull($row['price'], '未绑定门店不得看到价格');
|
||
|
||
$this->getJson('/mini/product/categories')
|
||
->assertOk()
|
||
->assertJsonPath('success', true);
|
||
|
||
$this->postJson('/mini/cart', ['product_id' => $product->id, 'quantity' => 1])
|
||
->assertJsonPath('success', false)
|
||
->assertJsonPath('msg', '尚未绑定门店,请联系客服处理');
|
||
}
|
||
|
||
/** 批量调价:事务写入 + 通知受影响门店用户(不影响无关门店) */
|
||
public function test_batch_price_updates_and_notifies_affected_stores(): void
|
||
{
|
||
$this->actingAsSysUser();
|
||
|
||
$level = CustomerLevelModel::factory()->create();
|
||
$affectedStore = StoreModel::factory()->create(['level_id' => $level->id]);
|
||
$unaffectedStore = StoreModel::factory()->create(['level_id' => CustomerLevelModel::factory()->create()->id]);
|
||
$affectedUser = UserModel::factory()->forStore($affectedStore->id)->create();
|
||
$unaffectedUser = UserModel::factory()->forStore($unaffectedStore->id)->create();
|
||
|
||
$product = ProductModel::factory()->create();
|
||
ProductPriceModel::factory()->create(['product_id' => $product->id, 'level_id' => $level->id, 'price' => 5.00]);
|
||
|
||
$this->putJson('/product/goods/batchPrice', [
|
||
'updates' => [
|
||
['product_id' => $product->id, 'level_id' => $level->id, 'price' => 8.80],
|
||
],
|
||
])->assertOk()->assertJsonPath('success', true);
|
||
|
||
$this->assertSame(
|
||
8.80,
|
||
(float) ProductPriceModel::forProductLevel($product->id, $level->id)->first()->price,
|
||
'等级价格应已更新'
|
||
);
|
||
|
||
$this->assertSame(
|
||
1,
|
||
NoticeModel::where('user_id', $affectedUser->id)->where('type', NoticeModel::TYPE_PRICE)->count(),
|
||
'受影响门店用户应收到价格变更通知'
|
||
);
|
||
$this->assertSame(
|
||
0,
|
||
NoticeModel::where('user_id', $unaffectedUser->id)->count(),
|
||
'无关门店用户不应收到通知'
|
||
);
|
||
}
|
||
|
||
/** 价格矩阵:行=商品 × 列=启用等级 */
|
||
public function test_price_matrix_structure(): void
|
||
{
|
||
$this->actingAsSysUser();
|
||
|
||
$level = CustomerLevelModel::factory()->create();
|
||
$product = ProductModel::factory()->create();
|
||
ProductPriceModel::factory()->create(['product_id' => $product->id, 'level_id' => $level->id, 'price' => 6.00]);
|
||
|
||
$response = $this->getJson('/product/goods/priceMatrix');
|
||
$response->assertOk()->assertJsonPath('success', true);
|
||
|
||
$this->assertNotEmpty($response->json('data.levels'));
|
||
$row = collect($response->json('data.rows'))->firstWhere('id', $product->id);
|
||
$this->assertNotNull($row);
|
||
$this->assertSame(6.0, (float) $row['price_' . $level->id]);
|
||
}
|
||
}
|