loginAs(); Storage::fake('uploads'); $file = UploadedFile::fake()->createWithContent('orders.csv', implode("\n", [ 'external_order_id,external_line_id,order_status,item_name,quantity', 'order-001,line-001,completed,Wireless Mouse,1', ])); $response = $this->withHeaders($this->apiHeaders()) ->post(route('api.ecommerce-finance.import-files.store'), ['source_file' => $file]) ->assertCreated() ->assertJsonStructure(['source_file', 'checksum']); Storage::disk('uploads')->assertExists($response->json('source_file')); $this->assertSame(hash_file('sha256', $file->getRealPath()), $response->json('checksum')); } public function test_it_creates_a_channel_for_the_current_company(): void { $request = [ 'code' => 'taobao', 'name' => 'Taobao', 'type' => 'marketplace', 'enabled' => true, ]; $this->loginAs(); $this->withHeaders($this->apiHeaders()) ->postJson(route('api.ecommerce-finance.channels.store'), $request) ->assertCreated() ->assertJsonPath('company_id', company_id()) ->assertJsonPath('code', 'taobao'); $this->assertDatabaseHas('ec_channels', [ 'company_id' => company_id(), 'code' => 'taobao', 'name' => 'Taobao', ]); } public function test_it_rejects_a_duplicate_import_batch(): void { $this->loginAs(); Storage::fake('uploads'); $channel = Channel::create([ 'company_id' => company_id(), 'code' => 'jd', 'name' => 'JD', 'type' => 'marketplace', ]); $store = Store::create([ 'company_id' => company_id(), 'channel_id' => $channel->id, 'name' => 'JD Flagship Store', 'external_id' => 'jd-flagship', ]); $sourceFile = 'ecommerce-finance/imports/jd-orders-20260718.csv'; Storage::disk('uploads')->put($sourceFile, implode("\n", [ 'external_order_id,external_line_id,order_status,item_name,quantity,sale_amount,gross_amount,buyer_paid_amount,currency_code,completed_at', 'order-001,line-001,completed,Wireless Mouse,2,99.80,99.80,99.80,CNY,2026-07-18 10:00:00', ])); $request = [ 'store_id' => $store->id, 'source_type' => 'orders', 'source_file' => $sourceFile, 'checksum' => str_repeat('a', 64), ]; $this->withHeaders($this->apiHeaders()) ->postJson(route('api.ecommerce-finance.import-batches.store'), $request) ->assertCreated() ->assertJsonPath('status', 'completed'); $this->assertDatabaseHas('ec_orders', [ 'company_id' => company_id(), 'store_id' => $store->id, 'external_order_id' => 'order-001', ]); $this->assertDatabaseHas('ec_order_items', [ 'company_id' => company_id(), 'external_line_id' => 'line-001', 'name' => 'Wireless Mouse', ]); $settlementFile = 'ecommerce-finance/imports/jd-settlement-20260718.csv'; Storage::disk('uploads')->put($settlementFile, implode("\n", [ 'external_settlement_id,external_line_id,line_type,external_order_id,line_amount,currency_code,settled_at', 'settlement-001,settlement-line-001,order_payment,order-001,99.80,CNY,2026-07-19 10:00:00', ])); $this->withHeaders($this->apiHeaders()) ->postJson(route('api.ecommerce-finance.import-batches.store'), [ 'store_id' => $store->id, 'source_type' => 'settlements', 'source_file' => $settlementFile, 'checksum' => str_repeat('b', 64), ]) ->assertCreated() ->assertJsonPath('status', 'completed'); $this->assertDatabaseHas('ec_reconciliation_matches', [ 'company_id' => company_id(), 'status' => 'auto_matched', 'matched_amount' => '99.8', ]); $this->withExceptionHandling(); $this->withHeaders($this->apiHeaders()) ->postJson(route('api.ecommerce-finance.import-batches.store'), $request) ->assertBadRequest(); } private function apiHeaders(): array { return [ 'Authorization' => 'Basic ' . base64_encode('test@company.com:123456'), ]; } }