makeShop('shopoff', enabled: false); $this->get('http://shopoff.service.mir.md/shop')->assertNotFound(); } public function test_catalog_lists_published_parts_only(): void { $ctx = $this->makeShop('shopon', enabled: true); Part::create(['name' => 'Filtru public', 'sell_price' => 100, 'qty' => 5, 'unit' => 'buc', 'is_active' => true, 'is_published' => true]); Part::create(['name' => 'Filtru privat', 'sell_price' => 100, 'qty' => 5, 'unit' => 'buc', 'is_active' => true, 'is_published' => false]); $resp = $this->get('http://shopon.service.mir.md/shop'); $resp->assertOk(); $resp->assertSee('Filtru public'); $resp->assertDontSee('Filtru privat'); } public function test_search_matches_cross_reference(): void { $ctx = $this->makeShop('shopcross', enabled: true); $part = Part::create(['name' => 'Filtru ulei', 'article' => 'OEM-1', 'sell_price' => 50, 'qty' => 3, 'unit' => 'buc', 'is_active' => true, 'is_published' => true]); PartCrossRef::create(['part_id' => $part->id, 'cross_article' => 'W811-80', 'brand' => 'MANN']); // searchPublished should find the part by its cross article. $found = Part::searchPublished('W811-80')->get(); $this->assertCount(1, $found); $this->assertEquals($part->id, $found->first()->id); } public function test_place_order_creates_order_with_token_and_items(): void { $ctx = $this->makeShop('shopbuy', enabled: true); $part = Part::create(['name' => 'Plăcuțe frână', 'sell_price' => 200, 'qty' => 10, 'unit' => 'buc', 'is_active' => true, 'is_published' => true]); $base = 'http://shopbuy.service.mir.md/shop'; // Add to cart (session persists across requests in the same test). $this->post("$base/part/{$part->id}/add", ['qty' => 2])->assertRedirect(); $resp = $this->post("$base/checkout", [ 'customer_name' => 'Ion Pop', 'customer_phone' => '+37369123456', 'customer_email' => 'ion@example.com', 'delivery_method' => 'pickup', ]); $resp->assertRedirect(); $order = OnlineOrder::first(); $this->assertNotNull($order); $this->assertEquals('Ion Pop', $order->customer_name); $this->assertNotEmpty($order->tracking_token); $this->assertEquals(400.0, (float) $order->total); // 2 × 200, pickup = no fee $this->assertEquals(1, $order->items()->count()); // Confirmation page reachable by token. $this->get($order->trackingUrl())->assertOk()->assertSee($order->number); } public function test_fulfill_issues_stock_via_warehouse(): void { $ctx = $this->makeShop('shopfulfill', enabled: true); $svc = app(WarehouseService::class); $part = Part::create(['name' => 'Amortizor', 'sell_price' => 500, 'qty' => 0, 'unit' => 'buc', 'is_active' => true, 'is_published' => true]); $svc->receive($part, 10, 300.0); $order = OnlineOrder::create([ 'number' => OnlineOrder::generateNumber($ctx['company']->id), 'customer_name' => 'X', 'customer_phone' => '+37360000000', 'delivery_method' => 'pickup', 'status' => 'new', ]); $order->items()->create([ 'company_id' => $ctx['company']->id, 'part_id' => $part->id, 'name' => $part->name, 'qty' => 3, 'price' => 500, ]); // Simulate the fulfill action body. $svc->issue($part, 3, null, $order, 'test'); $part->refresh(); $this->assertEquals(7.0, (float) $part->qty); $this->assertEquals(1, WarehouseEvent::where('part_id', $part->id)->where('type', 'issue')->count()); } public function test_order_token_isolated_across_tenants(): void { $a = $this->makeShop('shopa', enabled: true); $partA = Part::create(['name' => 'P', 'sell_price' => 10, 'qty' => 1, 'unit' => 'buc', 'is_active' => true, 'is_published' => true]); $orderA = OnlineOrder::create([ 'number' => OnlineOrder::generateNumber($a['company']->id), 'customer_name' => 'A', 'customer_phone' => '1', 'delivery_method' => 'pickup', 'status' => 'new', ]); $this->makeShop('shopb', enabled: true); // Tenant B cannot view tenant A's order token. $this->get('http://shopb.service.mir.md/order/' . $orderA->tracking_token)->assertNotFound(); } private function makeShop(string $slug, bool $enabled): array { $plan = Plan::firstOrCreate(['slug' => 'test'], ['name' => 'T', 'price' => 0, 'features' => []]); $company = Company::create([ 'plan_id' => $plan->id, 'slug' => $slug, 'name' => ucfirst($slug), 'status' => 'active', 'settings' => ['shop' => ['enabled' => $enabled, 'delivery_methods' => ['pickup', 'courier'], 'delivery_fee' => 50, 'free_delivery_over' => 1000]], ]); app(TenantManager::class)->setCurrent($company); $wh = Warehouse::create(['code' => 'MAIN', 'name' => 'D', 'is_default' => true, 'is_active' => true]); $company->forceFill(['default_warehouse_id' => $wh->id])->saveQuietly(); return compact('company', 'wh'); } }