create(); $store = StoreModel::factory()->create(['level_id' => $level->id]); $product = ProductModel::factory()->create([ 'status' => ProductModel::STATUS_ON, 'cost_price' => $price, ]); return [$store, $product, $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_sees_level_price(): void { [$store, $product] = $this->makeStoreWithProduct('6.50'); $this->actingAsMiniStore($store); $data = $this->getJson("/mini/product/{$product->id}")->assertOk()->json('data'); $this->assertSame('6.50', $data['price']); } /** 商品详情:按门店等级上浮比例换算(成本价上浮 30%) */ public function test_product_detail_percent_price_calculated_from_cost(): void { [$store, $product, $level] = $this->makeStoreWithProduct(); $level->update(['percent' => 30]); $product->update(['cost_price' => '20.00']); $this->actingAsMiniStore($store); $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_sees_level_price(): void { [$store, $product] = $this->makeStoreWithProduct('7.00'); $this->actingAsMiniStore($store); $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']); } /** 商品列表:登录门店附加购物车行ID与数量,响应附悬浮球汇总 */ public function test_product_list_appends_cart_quantity_and_summary(): void { [$store, $product] = $this->makeStoreWithProduct('5.00'); $extra = ProductModel::factory()->create(['status' => ProductModel::STATUS_ON, 'cost_price' => '3.00']); $this->actingAsMiniStore($store); $this->postJson('/mini/cart', ['product_id' => $product->id, 'quantity' => 2]); $this->postJson('/mini/cart', ['product_id' => $extra->id, 'quantity' => 1]); $cartId = CartModel::where('product_id', $product->id)->first()->id; $data = $this->getJson('/mini/product/list')->assertOk()->json('data'); $row = collect($data['data'])->firstWhere('id', $product->id); $this->assertSame($cartId, $row['cart_id'], '在购物车的商品应附购物车行ID'); $this->assertSame('2.00', $row['cart_quantity']); // 不在购物车的商品:cart_id=0、cart_quantity='0.00' $other = ProductModel::factory()->create(['status' => ProductModel::STATUS_ON, 'cost_price' => '1.00']); $otherRow = collect($this->getJson('/mini/product/list')->json('data.data'))->firstWhere('id', $other->id); $this->assertSame(0, $otherRow['cart_id']); $this->assertSame('0.00', $otherRow['cart_quantity']); // 悬浮球汇总:2 种商品、总数量 3、总金额 5×2+3×1=13 $this->assertSame(2, $data['cart']['total_count']); $this->assertSame('3.00', $data['cart']['total_quantity']); $this->assertSame('13.00', $data['cart']['total_amount']); } /** 商品列表/详情:未登录时购物车字段为零值结构 */ public function test_product_list_guest_sees_zero_cart_fields(): void { [, $product] = $this->makeStoreWithProduct(); $data = $this->getJson('/mini/product/list')->assertOk()->json('data'); $row = collect($data['data'])->firstWhere('id', $product->id); $this->assertSame(0, $row['cart_id']); $this->assertSame('0.00', $row['cart_quantity']); $this->assertSame( ['total_count' => 0, 'total_quantity' => '0.00', 'total_amount' => '0.00'], $data['cart'] ); $detail = $this->getJson("/mini/product/{$product->id}")->assertOk()->json('data'); $this->assertSame(0, $detail['cart_id']); $this->assertSame('0.00', $detail['cart_quantity']); } /** 商品详情:登录门店附加购物车行ID与数量 */ public function test_product_detail_appends_cart_quantity(): void { [$store, $product] = $this->makeStoreWithProduct(); $this->actingAsMiniStore($store); $this->postJson('/mini/cart', ['product_id' => $product->id, 'quantity' => 4]); $cartId = CartModel::first()->id; $data = $this->getJson("/mini/product/{$product->id}")->assertOk()->json('data'); $this->assertSame($cartId, $data['cart_id']); $this->assertSame('4.00', $data['cart_quantity']); } /** 首页:登录门店附购物车悬浮球汇总,未登录为零值结构 */ public function test_home_appends_cart_summary(): void { [$store, $product] = $this->makeStoreWithProduct('5.00'); // 未登录:零值结构 $guest = $this->getJson('/mini/home')->assertOk()->json('data'); $this->assertSame( ['total_count' => 0, 'total_quantity' => '0.00', 'total_amount' => '0.00'], $guest['cart'] ); // 登录:汇总跟随购物车 $this->actingAsMiniStore($store); $this->postJson('/mini/cart', ['product_id' => $product->id, 'quantity' => 3]); $data = $this->getJson('/mini/home')->assertOk()->json('data'); $this->assertSame(1, $data['cart']['total_count']); $this->assertSame('3.00', $data['cart']['total_quantity']); $this->assertSame('15.00', $data['cart']['total_amount']); } }