'u-'.uniqid(), 'name' => 'Owner', 'email' => uniqid().'@example.com', ]); } protected function setUp(): void { parent::setUp(); $this->withoutMiddleware(EnsurePlatformSession::class); $this->withoutVite(); config(['crm.url' => 'https://crm.test/api', 'crm.key' => 'test-crm-key']); } private function csv(string $content): UploadedFile { return UploadedFile::fake()->createWithContent('products.csv', $content); } public function test_restaurant_import_creates_local_products_and_categories(): void { $user = $this->user(); PosLocation::create(['owner_ref' => $user->public_id, 'name' => 'Main register', 'currency' => 'GHS', 'service_style' => 'restaurant']); $csv = "name,sku,price,category,active\n" ."Coffee,CFE-01,15.00,Drinks,yes\n" ."Latte,LAT-02,18.50,Drinks,yes\n" ."Croissant,,8.00,Pastry,no\n" .",NONAME,5.00,Drinks,yes\n" // skipped: no name ."Bad,BAD-1,notaprice,Drinks,yes\n"; // skipped: bad price $this->actingAs($user) ->post(route('pos.products.import'), ['file' => $this->csv($csv)]) ->assertRedirect(route('pos.products.index')) ->assertSessionHas('success'); $this->assertSame(3, PosProduct::where('owner_ref', $user->public_id)->count()); $coffee = PosProduct::where('owner_ref', $user->public_id)->where('name', 'Coffee')->firstOrFail(); $this->assertSame(1500, $coffee->price_minor); $this->assertNotNull($coffee->category_id); $this->assertFalse((bool) PosProduct::where('name', 'Croissant')->firstOrFail()->is_active); // Drinks + Pastry created once each. $this->assertSame(2, PosCategory::where('owner_ref', $user->public_id)->count()); } public function test_retail_import_batches_to_crm_bulk_endpoint(): void { Http::fake([ 'crm.test/api/products/bulk' => Http::response(['imported' => 2], 201), 'crm.test/api/*' => Http::response(['data' => []], 200), ]); $user = $this->user(); // retail by default (no restaurant location) $csv = "name,sku,price,description,active\n" ."Mug,MUG-01,25.00,Ceramic,yes\n" ."Tee,TSH-02,60.00,Cotton,yes\n"; $this->actingAs($user) ->post(route('pos.products.import'), ['file' => $this->csv($csv)]) ->assertRedirect(route('pos.products.index')) ->assertSessionHas('success'); Http::assertSent(function ($request) { return str_contains($request->url(), '/products/bulk') && count($request['products']) === 2 && $request['products'][0]['name'] === 'Mug' && $request['products'][0]['unit_price_minor'] === 2500 && $request['products'][0]['type'] === 'product'; }); // No local products created in retail mode. $this->assertSame(0, PosProduct::where('owner_ref', $user->public_id)->count()); } public function test_template_download_is_csv(): void { $response = $this->actingAs($this->user()) ->get(route('pos.products.import.template')) ->assertOk() ->assertHeader('content-disposition', 'attachment; filename=pos-products-template.csv'); $this->assertStringContainsString('text/csv', $response->headers->get('content-type')); $this->assertStringContainsString('name', $response->streamedContent()); } }