createPriceSources($schema); $mirror->table('ops_jst_sku')->insert([ ['sku_id' => 'SKU-CATALOG', 'sku_type' => 'normal', 'cost_price' => 12], ['sku_id' => 'SKU-PURCHASE', 'sku_type' => 'normal', 'cost_price' => 0], ]); $mirror->table('product_purchase_price_mirror_rows')->insert([ [ 'item_id' => 1, 'sku_id' => 'SKU-CATALOG', 'unit_price' => 20, 'document_status' => 'Finished', 'finished_at' => '2026-09-10 10:00:00', 'created_at' => '2026-09-10 10:00:00', 'updated_at' => '2026-09-10 10:00:00', ], [ 'item_id' => 2, 'sku_id' => 'SKU-PURCHASE', 'unit_price' => 5.5, 'document_status' => 'Finished', 'finished_at' => '2026-09-11 10:00:00', 'created_at' => '2026-09-11 10:00:00', 'updated_at' => '2026-09-11 10:00:00', ], ]); $mirror->table('ding_online_daifa_price_mirror')->insert([ 'process_instance_id' => 'PROC-1', 'detail_index' => 0, 'product_id' => '9001', 'ship_qty' => 3, 'daifa_amount' => 21, 'workflow_created_at' => '2026-09-12 10:00:00', ]); $mirror->table('ops_jst_sku_map')->insert([ 'shop_i_id' => '9001', 'sku_id' => 'SKU-DING', ]); $mirror->table('store_receipt_product_cost_rows')->insert([ $this->row('catalog', 'SKU-CATALOG', 2, 9, 18), $this->row('purchase', 'SKU-PURCHASE', 3, 8, 24), $this->row('ding', 'SKU-DING', 4, 7, 28), $this->row('missing', 'SKU-MISSING', 5, 6, 30), ]); $this->artisan('store-receipt:product-cost:sync', [ 'month' => '2026-09', '--refresh-realtime-prices-only' => true, ])->assertExitCode(Command::SUCCESS); $rows = $mirror->table('store_receipt_product_cost_rows') ->orderBy('row_key') ->get() ->keyBy('row_key'); $this->assertSame(12.0, (float) $rows['catalog']->realtime_unit_price); $this->assertSame(24.0, (float) $rows['catalog']->realtime_product_cost); $this->assertSame(5.5, (float) $rows['purchase']->realtime_unit_price); $this->assertSame(16.5, (float) $rows['purchase']->realtime_product_cost); $this->assertSame(7.0, (float) $rows['ding']->realtime_unit_price); $this->assertSame(28.0, (float) $rows['ding']->realtime_product_cost); $this->assertNull($rows['missing']->realtime_unit_price); $this->assertNull($rows['missing']->realtime_product_cost); $historical = [ 'catalog' => [9.0, 18.0], 'purchase' => [8.0, 24.0], 'ding' => [7.0, 28.0], 'missing' => [6.0, 30.0], ]; foreach ($rows as $key => $row) { $this->assertSame($historical[$key][0], (float) $row->unit_price, $key); $this->assertSame($historical[$key][1], (float) $row->product_cost, $key); $this->assertSame('保留历史口径', $row->remark, $key); } $csv = $this->loginAs()->get(route( 'business.financial-operations.product-costs.export', ['month' => '2026-09'], ))->assertOk()->streamedContent(); $this->assertStringContainsString( '平台,发生时间,店铺名称,线上单号,发货仓库,仓库简称,品牌,类目,供应商,是否包邮厂家,商品编码,商品数量,商品单价,商品成本,商品实时价,商品实时成本', $csv, ); $this->assertStringContainsString(',12.00,24.00', $csv); $selectedCsv = $this->get(route( 'business.financial-operations.product-costs.export', [ 'month' => '2026-09', 'columns' => 'platform,product_code,realtime_unit_price', ], ))->assertOk()->streamedContent(); $this->assertStringContainsString("平台,商品编码,商品实时价\n", $selectedCsv); $this->assertStringContainsString('京东账单,SKU-CATALOG,12.00', $selectedCsv); $this->assertStringNotContainsString('店铺名称', $selectedCsv); } private function createPriceSources($schema): void { if (! $schema->hasTable('ops_jst_sku')) { $schema->create('ops_jst_sku', function (Blueprint $table): void { $table->string('sku_id'); $table->string('sku_type')->nullable(); $table->decimal('cost_price', 20, 4)->nullable(); }); } if (! $schema->hasTable('ops_jst_sku_map')) { $schema->create('ops_jst_sku_map', function (Blueprint $table): void { $table->string('shop_i_id'); $table->string('sku_id'); }); } if (! $schema->hasTable('product_purchase_price_mirror_rows')) { $schema->create('product_purchase_price_mirror_rows', function (Blueprint $table): void { $table->unsignedBigInteger('item_id')->primary(); $table->string('sku_id')->nullable(); $table->decimal('unit_price', 20, 4)->nullable(); $table->string('document_status')->nullable(); $table->dateTime('finished_at')->nullable(); $table->dateTime('document_created_at')->nullable(); $table->dateTime('purchase_updated_at')->nullable(); $table->timestamps(); }); } if (! $schema->hasTable('ding_online_daifa_price_mirror')) { $schema->create('ding_online_daifa_price_mirror', function (Blueprint $table): void { $table->string('process_instance_id'); $table->unsignedTinyInteger('detail_index')->default(0); $table->string('product_id')->nullable(); $table->unsignedInteger('ship_qty')->nullable(); $table->decimal('daifa_amount', 14, 2)->nullable(); $table->string('workflow_created_at')->nullable(); $table->primary(['process_instance_id', 'detail_index']); }); } } /** @return array */ private function row( string $rowKey, string $productCode, int $quantity, float $historicalUnitPrice, float $historicalCost, ): array { return [ 'report_month' => '2026-09-01', 'row_key' => $rowKey, 'platform' => '京东账单', 'occurred_date' => '2026-09-01', 'store_name' => '测试店铺', 'online_order_no' => 'ORDER-' . $rowKey, 'warehouse' => '简尚-崔桥工厂仓', 'warehouse_short_name' => '崔桥工厂仓', 'product_code' => $productCode, 'product_quantity' => $quantity, 'unit_price' => $historicalUnitPrice, 'product_cost' => $historicalCost, 'remark' => '保留历史口径', 'imported_at' => now(), ]; } }