[ 'driver' => 'sqlite', 'database' => ':memory:', 'prefix' => '', ], 'upstream_mirrors.connection' => 'business_mirror', ]); DB::purge('business_mirror'); $this->createMirrorTables(); } public function test_offset_metric_details_group_by_store_and_bill_item_and_reconcile_to_total(): void { $mirror = DB::connection('business_mirror'); $mirror->table('store_receipt_order_match_rows')->insert([ $this->row('row-a1', '店铺A', -100), $this->row('row-a2', '店铺A', -200), $this->row('row-b1', '店铺B', -50), ]); $mirror->table('store_receipt_order_match_metric_details')->insert([ $this->detail('detail-a1', 'row-a1', '账单扣款', -60), $this->detail('detail-a2', 'row-a1', '售后扣减', -40), $this->detail('detail-a3', 'row-a2', '账单扣款', -200), $this->detail('detail-b1', 'row-b1', '账单扣款', -50), ]); $response = $this->loginAs()->getJson(route( 'business.financial-operations.performance-details.metric-details', [ 'metric' => 'offset_amount', 'month' => '2026-09', 'store_name' => ['店铺A'], ], )); $response ->assertOk() ->assertJsonPath('label', '冲减收入') ->assertJsonPath('total', -300) ->assertJsonPath('detail_total', -300) ->assertJsonPath('balance', 0) ->assertJsonPath('balanced', true); $rows = $response->json('rows'); $this->assertCount(2, $rows); $this->assertContains([ 'platform' => '京东账单', 'store_name' => '店铺A', 'bill_item' => '账单扣款', 'amount' => -260, 'line_count' => 2, ], $rows); $this->assertContains([ 'platform' => '京东账单', 'store_name' => '店铺A', 'bill_item' => '售后扣减', 'amount' => -40, 'line_count' => 1, ], $rows); } public function test_same_bill_item_is_split_by_platform_for_summary(): void { $mirror = DB::connection('business_mirror'); $mirror->table('store_receipt_order_match_rows')->insert([ $this->row('row-jd', '京东店铺', -100, '京东账单'), $this->row('row-pdd', '拼多多店铺', -50, '拼多多'), ]); $mirror->table('store_receipt_order_match_metric_details')->insert([ $this->detail('detail-jd', 'row-jd', '账单扣款', -100, '京东账单'), $this->detail('detail-pdd', 'row-pdd', '账单扣款', -50, '拼多多'), ]); $response = $this->loginAs()->getJson(route( 'business.financial-operations.performance-details.metric-details', [ 'metric' => 'offset_amount', 'month' => '2026-09', ], )); $response ->assertOk() ->assertJsonPath('total', -150) ->assertJsonPath('detail_total', -150) ->assertJsonPath('balanced', true); $this->assertContains([ 'platform' => '京东账单', 'store_name' => '京东店铺', 'bill_item' => '账单扣款', 'amount' => -100, 'line_count' => 1, ], $response->json('rows')); $this->assertContains([ 'platform' => '拼多多', 'store_name' => '拼多多店铺', 'bill_item' => '账单扣款', 'amount' => -50, 'line_count' => 1, ], $response->json('rows')); } public function test_paid_metric_uses_the_amount_used_by_the_matching_basis(): void { $mirror = DB::connection('business_mirror'); $mirror->table('store_receipt_order_match_rows')->insert([ array_merge($this->row('row-basis', '店铺A', 0), [ 'income_amount' => 10.00, 'paid_amount' => 13079.80, 'difference' => -13069.80, 'remark' => '订单实付按应付/已付核对', ]), array_merge($this->row('row-normal', '店铺B', 0), [ 'income_amount' => 80.00, 'paid_amount' => 100.00, 'difference' => -20.00, ]), ]); $response = $this->loginAs()->getJson(route( 'business.financial-operations.performance-details.metric-details', [ 'metric' => 'paid_amount', 'month' => '2026-09', ], )); $response ->assertOk() ->assertJsonPath('label', '订单核对金额') ->assertJsonPath('total', 110) ->assertJsonPath('detail_total', 110) ->assertJsonPath('balanced', true); $this->assertContains([ 'platform' => '京东账单', 'store_name' => '店铺A', 'bill_item' => '订单核对金额', 'amount' => 10, 'line_count' => 1, ], $response->json('rows')); $this->assertContains([ 'platform' => '京东账单', 'store_name' => '店铺B', 'bill_item' => '订单核对金额', 'amount' => 100, 'line_count' => 1, ], $response->json('rows')); } private function row(string $rowKey, string $storeName, float $offset, string $platform = '京东账单'): array { return [ 'report_month' => '2026-09-01', 'platform' => $platform, 'row_key' => $rowKey, 'occurred_date' => '2026-09-01', 'store_name' => $storeName, 'online_order_no' => 'ORDER-' . $rowKey, 'payment_count' => 1, 'income_amount' => 0, 'discount_amount' => 0, 'offset_amount' => $offset, 'default_compensation_amount' => 0, 'refund_amount' => 0, 'planting_amount' => null, 'paid_amount' => 0, 'difference' => 0, 'cross_month_balanced' => false, 'match_status' => '已匹配', 'remark' => null, 'imported_at' => now(), ]; } private function detail( string $detailKey, string $rowKey, string $billItem, float $amount, string $platform = '京东账单' ): array { return [ 'report_month' => '2026-09-01', 'detail_key' => $detailKey, 'row_key' => $rowKey, 'platform' => $platform, 'metric' => 'offset', 'bill_item' => $billItem, 'amount' => $amount, 'line_count' => 1, 'imported_at' => now(), ]; } private function createMirrorTables(): void { $schema = Schema::connection('business_mirror'); $schema->create('store_receipt_order_match_rows', function (Blueprint $table): void { $table->date('report_month'); $table->string('platform'); $table->string('row_key'); $table->date('occurred_date')->nullable(); $table->string('store_name')->nullable(); $table->string('online_order_no')->nullable(); $table->unsignedInteger('payment_count')->default(0); $table->decimal('income_amount', 20, 4)->default(0); $table->decimal('discount_amount', 20, 4)->nullable(); $table->decimal('offset_amount', 20, 4)->nullable(); $table->decimal('default_compensation_amount', 20, 4)->nullable(); $table->decimal('refund_amount', 20, 4)->nullable(); $table->decimal('planting_amount', 20, 4)->nullable(); $table->decimal('paid_amount', 20, 4)->nullable(); $table->decimal('difference', 20, 4)->nullable(); $table->boolean('cross_month_balanced')->default(false); $table->string('match_status', 32)->nullable(); $table->string('remark', 191)->nullable(); $table->dateTime('imported_at'); }); $schema->create('store_receipt_order_match_metric_details', function (Blueprint $table): void { $table->date('report_month'); $table->string('detail_key'); $table->string('row_key'); $table->string('platform'); $table->string('metric'); $table->string('bill_item'); $table->decimal('amount', 20, 4)->default(0); $table->unsignedInteger('line_count')->default(1); $table->dateTime('imported_at'); }); } }