buildPlaceholderAddress(); $billing = $this->resolveBillingAddress($placeholder); $shipping = $this->resolveShippingAddress($billing); $subTotal = (float) ($this->sub_total ?? 0); $baseSubTotal = (float) ($this->base_sub_total ?? $subTotal); $discount = (float) ($this->discount_amount ?? 0); $baseDiscount = (float) ($this->base_discount_amount ?? $discount); $grandTotal = max(0, $subTotal - $discount); $baseGrandTotal = max(0, $baseSubTotal - $baseDiscount); return [ 'cart_id' => $this->id, 'is_guest' => $this->is_guest, 'customer_id' => $this->customer_id, 'customer_type' => $this->customer ? get_class($this->customer) : null, 'customer_email' => $this->customer_email ?? $placeholder['email'], 'customer_first_name' => $this->customer_first_name ?? $placeholder['first_name'], 'customer_last_name' => $this->customer_last_name ?? $placeholder['last_name'], 'channel_id' => $this->channel_id, 'channel_name' => $this->channel->name, 'channel_type' => get_class($this->channel), 'total_item_count' => $this->items_count, 'total_qty_ordered' => $this->items_qty, 'base_currency_code' => $this->base_currency_code, 'channel_currency_code' => $this->channel_currency_code, 'order_currency_code' => $this->cart_currency_code, 'grand_total' => $grandTotal, 'base_grand_total' => $baseGrandTotal, 'sub_total' => $subTotal, 'sub_total_incl_tax' => $subTotal, 'base_sub_total' => $baseSubTotal, 'base_sub_total_incl_tax' => $baseSubTotal, 'tax_amount' => 0, 'base_tax_amount' => 0, 'shipping_tax_amount' => 0, 'base_shipping_tax_amount' => 0, 'coupon_code' => $this->coupon_code, 'applied_cart_rule_ids' => $this->applied_cart_rule_ids, 'discount_amount' => $discount, 'base_discount_amount' => $baseDiscount, 'billing_address' => $billing, 'shipping_address' => $shipping, 'payment' => (new OrderPaymentResource($this->payment))->jsonSerialize(), 'items' => OrderItemResource::collection($this->items)->jsonSerialize(), ]; } /** * Pull the configured placeholder block and guarantee every key exists. */ private function buildPlaceholderAddress(): array { $defaults = [ 'first_name' => 'Express', 'last_name' => 'Checkout', 'email' => 'express-checkout@placeholder.local', 'address' => 'Pending gateway response', 'city' => 'Pending', 'state' => 'Pending', 'country' => 'US', 'postcode' => '00000', 'phone' => '0000000000', ]; $configured = (array) config('bagistoapi.express_checkout.placeholder_address', []); return array_merge($defaults, $configured); } /** * Prefer an existing billing address attached to the cart, otherwise * use the placeholder so OrderRepository can persist the order. */ private function resolveBillingAddress(array $placeholder): array { if ($this->billing_address) { return [ 'address_type' => 'order_billing', 'first_name' => $this->billing_address->first_name ?: $placeholder['first_name'], 'last_name' => $this->billing_address->last_name ?: $placeholder['last_name'], 'gender' => $this->billing_address->gender, 'company_name' => $this->billing_address->company_name, 'address' => $this->billing_address->address ?: $placeholder['address'], 'city' => $this->billing_address->city ?: $placeholder['city'], 'state' => $this->billing_address->state ?: $placeholder['state'], 'country' => $this->billing_address->country ?: $placeholder['country'], 'postcode' => $this->billing_address->postcode ?: $placeholder['postcode'], 'email' => $this->billing_address->email ?: $this->customer_email ?: $placeholder['email'], 'phone' => $this->billing_address->phone ?: $placeholder['phone'], 'vat_id' => $this->billing_address->vat_id, ]; } return [ 'address_type' => 'order_billing', 'first_name' => $placeholder['first_name'], 'last_name' => $placeholder['last_name'], 'gender' => null, 'company_name' => null, 'address' => $placeholder['address'], 'city' => $placeholder['city'], 'state' => $placeholder['state'], 'country' => $placeholder['country'], 'postcode' => $placeholder['postcode'], 'email' => $this->customer_email ?: $placeholder['email'], 'phone' => $placeholder['phone'], 'vat_id' => null, ]; } /** * Mirror the billing block into shipping when the cart has stockable * items; downloadable-only carts skip the shipping address entirely. */ private function resolveShippingAddress(array $billing): ?array { if (! $this->haveStockableItems()) { return null; } if ($this->shipping_address) { return [ 'address_type' => 'order_shipping', 'first_name' => $this->shipping_address->first_name ?: $billing['first_name'], 'last_name' => $this->shipping_address->last_name ?: $billing['last_name'], 'gender' => $this->shipping_address->gender, 'company_name' => $this->shipping_address->company_name, 'address' => $this->shipping_address->address ?: $billing['address'], 'city' => $this->shipping_address->city ?: $billing['city'], 'state' => $this->shipping_address->state ?: $billing['state'], 'country' => $this->shipping_address->country ?: $billing['country'], 'postcode' => $this->shipping_address->postcode ?: $billing['postcode'], 'email' => $this->shipping_address->email ?: $billing['email'], 'phone' => $this->shipping_address->phone ?: $billing['phone'], 'vat_id' => $this->shipping_address->vat_id, ]; } return array_merge($billing, ['address_type' => 'order_shipping']); } }