[ 'driver' => 'sqlite', 'database' => ':memory:', 'prefix' => '', ]]); DB::purge('business_mirror'); $this->createTables(); } public function test_after_sales_reads_complete_rows_from_shared_mirror(): void { $db = DB::connection('business_mirror'); $db->table('ops_jst_orders')->insert([ 'o_id' => 1, 'so_id' => 'SO-1', 'pay_date' => '2026-08-01 08:00:00', 'end_time' => '2026-08-02 12:00:00', 'send_date' => '2026-08-02 10:00:00', 'order_date' => '2026-08-01 09:00:00', 'shop_name' => '京东店铺', 'shop_id' => 'SHOP-1', 'shop_site' => 'jd', 'type' => '普通订单', 'labels' => '正常', 'wms_co_id' => 'WH-1', 'l_id' => 'EXP-1', 'logistics_company' => '物流', 'receiver_state' => '江苏', 'receiver_city' => '常州', 'creator_name' => '销售员', 'free_amount' => 2, 'freight' => 5, ]); $db->table('ops_jst_order_item')->insert([ 'oi_id' => 11, 'o_id' => 1, 'outer_oi_id' => 'SUB-1', 'sku_id' => 'SKU-1', 'i_id' => 'STYLE-1', 'shop_sku_id' => 'SHOP-SKU-1', 'shop_i_id' => '1001', 'properties_value' => '黑色', 'name' => '线上商品', 'qty' => 2, 'amount' => 100, 'buyer_paid_amount' => 95, 'seller_income_amount' => 98, 'is_gift' => 0, 'src_combine_sku_id' => null, 'send_warehouse' => 'WH-1', ]); $db->table('ops_jst_sku')->insert([ 'autoid' => 1, 'sku_type' => 'normal', 'sku_id' => 'SKU-1', 'brand' => '品牌A', 'category' => '家具', 'vc_name' => '桌子', 'cost_price' => 20, 'name' => '镜像商品', 'supplier_id' => 'SUP-1', 'supplier_name' => '供应商A', ]); $db->table('ops_jst_warehouse_info')->insert([ 'wms_co_id' => 'WH-1', 'name' => '主仓', 'remark1' => '运营云仓', ]); $db->table('ops_jst_return_refund_info')->insert([ 'as_id' => 21, 'outer_as_id' => 'AF-1', 'o_id' => 1, 'as_date' => '2026-08-02 12:00:00', 'type' => '退货退款', 'question_type' => '质量问题', 'labels' => '售后', 'refund' => 50, 'free_amount' => 3, ]); $db->table('ops_jst_return_refund_item')->insert([ 'as_id' => 21, 'outer_oi_id' => 'SUB-1', 'sku_id' => 'SKU-1', 'type' => '退货', 'qty' => 1, 'amount' => 50, 'r_qty' => 1, 'shop_amount' => 50, 'defective_qty' => 1, ]); $mirror = Mockery::mock(GenericBusinessMirrorRepository::class); $mirror->shouldReceive('connection')->andReturn($db); $repository = new OrderDataMirrorRepository( Mockery::mock(BusinessMirrorDatasetRegistry::class), $mirror, ); $result = $repository->afterSales([ 'from' => '2026-08-01', 'to' => '2026-08-02', 'order_no' => '', 'shop_name' => '', 'sku_id' => '', ], 1, 25); $this->assertCount(1, $result['rows']); $row = $result['rows'][0]; $this->assertSame('SO-1', $row['online_order_no']); $this->assertSame('AF-1', $row['after_sales_no']); $this->assertSame(40.0, $row['product_cost']); $this->assertSame(1.0, $row['post_return_quantity']); $this->assertSame('https://item.jd.com/1001.html', $row['product_link']); $this->assertNull($row['account_8001201']); } public function test_promotion_expenses_read_the_shared_statistics_and_sku_mapping(): void { $db = DB::connection('business_mirror'); $db->table('ops_item_sales_cost_ratio')->insert([ 'stat_date' => '2026-08-09 00:00:00', 'shop_name' => '京东店铺', 'item_id' => 'ITEM-1', 'push_fee' => 9.05, ]); $db->table('ops_jst_shop_info')->insert(['shop_id' => 8, 'shop_name' => '京东店铺']); $db->table('ops_jst_sku_map')->insert([ 'shop_i_id' => 'ITEM-1', 'shop_id' => 8, 'sku_id' => 'SKU-1', 'i_id' => 'STYLE-1', 'shop_sku_id' => 'SHOP-SKU-1', 'properties_value' => '黑色', 'modified' => '2026-08-09 10:00:00', ]); $mirror = Mockery::mock(GenericBusinessMirrorRepository::class); $mirror->shouldReceive('connection')->andReturn($db); $repository = new OrderDataMirrorRepository( Mockery::mock(BusinessMirrorDatasetRegistry::class), $mirror, ); $result = $repository->promotionExpenses([ 'date' => '2026-08-09', 'shop_name' => '', 'sku_id' => '', ], 1, 25); $this->assertSame('2026-08-09', $result['date']); $this->assertSame('SKU-1', $result['rows'][0]['product_code']); $this->assertSame(9.05, $result['rows'][0]['promotion_fee']); } private function createTables(): void { $schema = Schema::connection('business_mirror'); $schema->create('ops_jst_orders', function (Blueprint $t): void { $t->integer('o_id'); $t->string('so_id')->nullable(); $t->dateTime('pay_date')->nullable(); $t->dateTime('end_time')->nullable(); $t->dateTime('send_date')->nullable(); $t->dateTime('order_date'); $t->string('shop_name'); $t->string('shop_id')->nullable(); $t->string('shop_site')->nullable(); $t->string('type')->nullable(); $t->string('labels')->nullable(); $t->string('wms_co_id')->nullable(); $t->string('l_id')->nullable(); $t->string('logistics_company')->nullable(); $t->string('receiver_state')->nullable(); $t->string('receiver_city')->nullable(); $t->string('creator_name')->nullable(); $t->decimal('free_amount')->nullable(); $t->decimal('freight')->nullable(); }); $schema->create('ops_jst_order_item', function (Blueprint $t): void { $t->integer('oi_id'); $t->integer('o_id'); $t->string('outer_oi_id')->nullable(); $t->string('sku_id'); $t->string('i_id')->nullable(); $t->string('shop_sku_id')->nullable(); $t->string('shop_i_id')->nullable(); $t->string('properties_value')->nullable(); $t->string('name')->nullable(); $t->decimal('qty')->nullable(); $t->decimal('amount')->nullable(); $t->decimal('buyer_paid_amount')->nullable(); $t->decimal('seller_income_amount')->nullable(); $t->integer('is_gift')->nullable(); $t->string('src_combine_sku_id')->nullable(); $t->string('send_warehouse')->nullable(); }); $schema->create('ops_jst_sku', function (Blueprint $t): void { $t->integer('autoid'); $t->string('sku_type'); $t->string('sku_id'); $t->string('brand')->nullable(); $t->string('category')->nullable(); $t->string('vc_name')->nullable(); $t->decimal('cost_price')->nullable(); $t->string('name')->nullable(); $t->string('supplier_id')->nullable(); $t->string('supplier_name')->nullable(); }); $schema->create('ops_jst_warehouse_info', function (Blueprint $t): void { $t->string('wms_co_id'); $t->string('name')->nullable(); $t->string('remark1')->nullable(); }); $schema->create('ops_jst_return_refund_info', function (Blueprint $t): void { $t->integer('as_id'); $t->string('outer_as_id')->nullable(); $t->integer('o_id'); $t->dateTime('as_date'); $t->string('type')->nullable(); $t->string('question_type')->nullable(); $t->string('labels')->nullable(); $t->decimal('refund')->nullable(); $t->decimal('free_amount')->nullable(); }); $schema->create('ops_jst_return_refund_item', function (Blueprint $t): void { $t->integer('as_id'); $t->string('outer_oi_id')->nullable(); $t->string('sku_id')->nullable(); $t->string('type')->nullable(); $t->decimal('qty')->nullable(); $t->decimal('amount')->nullable(); $t->decimal('r_qty')->nullable(); $t->decimal('shop_amount')->nullable(); $t->decimal('defective_qty')->nullable(); }); $schema->create('ops_item_sales_cost_ratio', function (Blueprint $t): void { $t->dateTime('stat_date'); $t->string('shop_name'); $t->string('item_id'); $t->decimal('push_fee'); }); $schema->create('ops_jst_sku_map', function (Blueprint $t): void { $t->string('shop_i_id'); $t->integer('shop_id'); $t->string('sku_id')->nullable(); $t->string('i_id')->nullable(); $t->string('shop_sku_id')->nullable(); $t->string('properties_value')->nullable(); $t->dateTime('modified')->nullable(); }); $schema->create('ops_jst_shop_info', function (Blueprint $t): void { $t->integer('shop_id'); $t->string('shop_name'); }); } }