service = app(OrderProcessingService::class); } private function mockCalc(int $finalAmount = 100000): void { /** @var OrderCalculationService&MockObject $mock */ $mock = $this->createMock(OrderCalculationService::class); $summary = new Summary( subtotal: $finalAmount, finalAmount: $finalAmount, paymentAmount: $finalAmount, ); $result = new OrderCalculationResult( items: [], summary: $summary, promotions: new PromotionsSummary, ); $mock->method('calculate')->willReturn($result); $this->app->instance(OrderCalculationService::class, $mock); $this->service = app(OrderProcessingService::class); } /** * 배송정책 + 단일 국가 설정(활성) 생성. */ private function makePolicyForCountry(string $countryCode): ShippingPolicy { $policy = ShippingPolicy::create([ 'name' => ['ko' => '테스트 정책', 'en' => 'Test Policy'], 'is_active' => true, 'is_default' => false, 'sort_order' => 1, ]); $policy->countrySettings()->create([ 'country_code' => $countryCode, 'shipping_method' => 'parcel', 'currency_code' => 'KRW', 'charge_policy' => 'fixed', 'base_fee' => 3000, 'is_active' => true, ]); return $policy->load('countrySettings'); } private function makeTempOrder(User $user, array $items, int $finalAmount = 100000) { return TempOrderFactory::new() ->forUser($user) ->withItems($items) ->withCalculationResult([ 'summary' => ['final_amount' => $finalAmount, 'subtotal' => $finalAmount], 'items' => [], 'promotions' => [ 'product_promotions' => ['coupons' => [], 'discount_codes' => [], 'events' => []], 'order_promotions' => ['coupons' => [], 'discount_codes' => [], 'events' => []], ], 'validation_errors' => [], ]) ->create(); } public function test_b2_international_address_fields_are_persisted(): void { $user = User::factory()->create(); $tempOrder = $this->makeTempOrder($user, []); $this->mockCalc(); $order = $this->service->createFromTempOrder( $tempOrder, ['name' => 'John Doe', 'phone' => '010-1111-2222', 'email' => 'john@example.com'], [ 'recipient_name' => 'John Doe', 'recipient_phone' => '010-1111-2222', 'country_code' => 'US', 'address_line_1' => '123 Main St', 'address_line_2' => 'Apt 4', 'intl_city' => 'New York', 'intl_state' => 'NY', 'intl_postal_code' => '10001', ], 'card', 100000, ); $address = $order->addresses()->where('address_type', 'shipping')->first(); $this->assertNotNull($address); $this->assertSame('US', $address->recipient_country_code); $this->assertSame('123 Main St', $address->address_line_1); $this->assertSame('Apt 4', $address->address_line_2); $this->assertSame('New York', $address->intl_city); $this->assertSame('NY', $address->intl_state); $this->assertSame('10001', $address->intl_postal_code); } public function test_b5_snapshot_preserves_shipping_country_and_zipcode(): void { $user = User::factory()->create(); $tempOrder = $this->makeTempOrder($user, []); $this->mockCalc(); $order = $this->service->createFromTempOrder( $tempOrder, ['name' => '홍길동', 'phone' => '010-1234-5678', 'email' => 'test@example.com'], ['recipient_name' => '홍길동', 'recipient_phone' => '010-1234-5678', 'country_code' => 'KR', 'zipcode' => '63000', 'address' => '제주시', 'address_detail' => '101호'], 'card', 100000, ); $snapshot = $order->shipping_policy_applied_snapshot; $this->assertIsArray($snapshot); $this->assertArrayHasKey('address', $snapshot); $this->assertSame('KR', $snapshot['address']['country_code']); $this->assertSame('63000', $snapshot['address']['zipcode']); } public function test_d1_blocks_order_when_product_not_shippable_to_selected_country(): void { $user = User::factory()->create(); // 배송정책: KR 만 설정 (US 미지원) $policy = $this->makePolicyForCountry('KR'); $product = Product::factory()->create(['shipping_policy_id' => $policy->id]); $option = ProductOption::factory()->create(['product_id' => $product->id]); $tempOrder = $this->makeTempOrder($user, [ ['cart_id' => 1, 'product_id' => $product->id, 'product_option_id' => $option->id, 'quantity' => 1], ]); $this->mockCalc(); $this->expectException(CartUnavailableException::class); // US 로 주문 시도 → 정책에 US 설정 없음 → 전체 차단 $this->service->createFromTempOrder( $tempOrder, ['name' => 'John', 'phone' => '010-1111-2222', 'email' => 'john@example.com'], [ 'recipient_name' => 'John', 'recipient_phone' => '010-1111-2222', 'country_code' => 'US', 'address_line_1' => '123 Main St', 'intl_city' => 'NYC', 'intl_postal_code' => '10001', ], 'card', 100000, ); } public function test_d1_allows_order_when_product_shippable_to_selected_country(): void { $user = User::factory()->create(); $policy = $this->makePolicyForCountry('US'); $product = Product::factory()->create(['shipping_policy_id' => $policy->id]); $option = ProductOption::factory()->create(['product_id' => $product->id]); $tempOrder = $this->makeTempOrder($user, [ ['cart_id' => 1, 'product_id' => $product->id, 'product_option_id' => $option->id, 'quantity' => 1], ]); $this->mockCalc(); $order = $this->service->createFromTempOrder( $tempOrder, ['name' => 'John', 'phone' => '010-1111-2222', 'email' => 'john@example.com'], [ 'recipient_name' => 'John', 'recipient_phone' => '010-1111-2222', 'country_code' => 'US', 'address_line_1' => '123 Main St', 'intl_city' => 'NYC', 'intl_postal_code' => '10001', ], 'card', 100000, ); $this->assertNotNull($order->id); } }