Files

164 lines
7.3 KiB
PHP
Raw Permalink 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\NoticeModel;
use App\Models\ProductModel;
use App\Models\StoreModel;
/**
* A2 等级价格体系(等级上浮比例):列表按等级换算价、批量调价(成本价)事务与调价通知、
* 等级上浮比例变更通知(门店即用户:通知按门店下发,一店一条)
*/
class ProductPriceTest extends ProcurementTestCase
{
/** 小程序商品列表按门店等级的上浮比例返回换算价(不同等级不同价) */
public function test_product_list_returns_price_for_store_level(): void
{
$levelA = CustomerLevelModel::factory()->create(['percent' => 30]);
$levelB = CustomerLevelModel::factory()->create(['percent' => 10]);
$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.00]);
$this->actingAsMiniStore($storeA);
$rowA = collect($this->getJson('/mini/product/list')->assertOk()->json('data.data'))
->firstWhere('id', $product->id);
$this->assertNotNull($rowA, '商品应出现在列表中');
$this->assertSame(13.00, (float) $rowA['price'], 'A 等级:10 元上浮 30% = 13.00');
$this->actingAsMiniStore($storeB);
$rowB = collect($this->getJson('/mini/product/list')->assertOk()->json('data.data'))
->firstWhere('id', $product->id);
$this->assertSame(11.00, (float) $rowB['price'], 'B 等级:10 元上浮 10% = 11.00');
}
/** 门店未设置客户等级:仍可浏览商品,但价格不可见(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->actingAsMiniStore($store);
$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_batch_price_updates_cost_and_notifies_all_stores(): void
{
$this->actingAsSysUser();
$storeA = StoreModel::factory()->create(['level_id' => CustomerLevelModel::factory()->create()->id]);
$storeB = StoreModel::factory()->create(['level_id' => CustomerLevelModel::factory()->create()->id]);
$product = ProductModel::factory()->create(['cost_price' => 10]);
$this->putJson('/product/goods/batchPrice', [
'updates' => [
['product_id' => $product->id, 'cost_price' => 12],
],
])->assertOk()->assertJsonPath('success', true);
$this->assertSame('12.00', (string) $product->refresh()->cost_price, '成本价应已更新');
$this->assertSame(
1,
NoticeModel::where('store_id', $storeA->id)->where('type', NoticeModel::TYPE_PRICE)->count(),
'成本价变更影响所有等级售价,门店应收到价格变更通知'
);
$this->assertSame(
1,
NoticeModel::where('store_id', $storeB->id)->where('type', NoticeModel::TYPE_PRICE)->count(),
'成本价变更影响所有等级售价,门店应收到价格变更通知'
);
}
/** 价格矩阵:行=商品 × 列=启用等级,等级格为按上浮比例换算的售价 */
public function test_price_matrix_structure(): void
{
$this->actingAsSysUser();
$level = CustomerLevelModel::factory()->create(['percent' => 20]);
$product = ProductModel::factory()->create(['cost_price' => 10]);
$response = $this->getJson('/product/goods/priceMatrix');
$response->assertOk()->assertJsonPath('success', true);
$levels = $response->json('data.levels');
$this->assertNotEmpty($levels);
$levelRow = collect($levels)->firstWhere('id', $level->id);
$this->assertSame(20.0, (float) $levelRow['percent'], '矩阵等级列应含上浮比例');
$row = collect($response->json('data.rows'))->firstWhere('id', $product->id);
$this->assertNotNull($row);
$this->assertSame(12.0, (float) $row['price_' . $level->id], '矩阵等级格应为换算价:10 元上浮 20% = 12.00');
}
/** 等级上浮比例变更:通知该等级下正常门店(不影响其他等级门店) */
public function test_level_percent_update_notifies_level_stores(): void
{
$this->actingAsSysUser();
$level = CustomerLevelModel::factory()->create(['percent' => 10]);
$otherLevel = CustomerLevelModel::factory()->create(['percent' => 20]);
$store = StoreModel::factory()->create(['level_id' => $level->id]);
$otherStore = StoreModel::factory()->create(['level_id' => $otherLevel->id]);
$this->putJson('/customer/level/' . $level->id, [
'name' => $level->name,
'percent' => 30,
])->assertOk()->assertJsonPath('success', true);
$this->assertSame('30.00', (string) $level->refresh()->percent, '上浮比例应已更新');
$this->assertSame(
1,
NoticeModel::where('store_id', $store->id)->where('type', NoticeModel::TYPE_PRICE)->count(),
'该等级门店应收到价格变更通知'
);
$this->assertSame(
0,
NoticeModel::where('store_id', $otherStore->id)->count(),
'其他等级门店不应收到通知'
);
}
/** 上浮比例未变化时不重复通知 */
public function test_level_update_without_percent_change_sends_no_notice(): void
{
$this->actingAsSysUser();
$level = CustomerLevelModel::factory()->create(['percent' => 10]);
$store = StoreModel::factory()->create(['level_id' => $level->id]);
$this->putJson('/customer/level/' . $level->id, [
'name' => $level->name . '(改)',
'percent' => 10,
])->assertOk()->assertJsonPath('success', true);
$this->assertSame(0, NoticeModel::where('store_id', $store->id)->count(), '上浮比例未变不应发通知');
}
/** 等级表单:上浮比例校验(负数/超限拒绝) */
public function test_level_percent_validation(): void
{
$this->actingAsSysUser();
$this->postJson('/customer/level', ['name' => '负比例等级', 'percent' => -1])
->assertOk()
->assertJsonPath('success', false)
->assertJsonPath('msg', '价格上浮比例不能小于 0');
$this->postJson('/customer/level', ['name' => '超比例等级', 'percent' => 1000])
->assertOk()
->assertJsonPath('success', false)
->assertJsonPath('msg', '价格上浮比例不能超过 999.99');
$this->assertSame(0, CustomerLevelModel::count(), '校验失败不应落库');
}
}