ExpressOrderResource.php 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. <?php
  2. namespace Webkul\BagistoApi\Transformers;
  3. use Illuminate\Http\Resources\Json\JsonResource;
  4. use Webkul\Sales\Transformers\OrderItemResource;
  5. use Webkul\Sales\Transformers\OrderPaymentResource;
  6. /**
  7. * Express-checkout flavoured replacement for
  8. * \Webkul\Sales\Transformers\OrderResource.
  9. *
  10. * Two key deviations vs. the stock resource:
  11. *
  12. * - shipping_amount / tax_amount are forced to 0 because the buyer
  13. * pays only the subtotal at checkout (the real shipping/tax can be
  14. * reconciled after the gateway returns the verified address).
  15. * - billing/shipping address blocks are filled from the placeholder
  16. * defined in config('bagistoapi.express_checkout.placeholder_address')
  17. * so OrderRepository::create() never trips on null addresses.
  18. */
  19. class ExpressOrderResource extends JsonResource
  20. {
  21. public $preserveKeys = true;
  22. /**
  23. * @param \Illuminate\Http\Request $request
  24. */
  25. public function toArray($request): array
  26. {
  27. $placeholder = $this->buildPlaceholderAddress();
  28. $billing = $this->resolveBillingAddress($placeholder);
  29. $shipping = $this->resolveShippingAddress($billing);
  30. $subTotal = (float) ($this->sub_total ?? 0);
  31. $baseSubTotal = (float) ($this->base_sub_total ?? $subTotal);
  32. $discount = (float) ($this->discount_amount ?? 0);
  33. $baseDiscount = (float) ($this->base_discount_amount ?? $discount);
  34. $grandTotal = max(0, $subTotal - $discount);
  35. $baseGrandTotal = max(0, $baseSubTotal - $baseDiscount);
  36. return [
  37. 'cart_id' => $this->id,
  38. 'is_guest' => $this->is_guest,
  39. 'customer_id' => $this->customer_id,
  40. 'customer_type' => $this->customer ? get_class($this->customer) : null,
  41. 'customer_email' => $this->customer_email ?? $placeholder['email'],
  42. 'customer_first_name' => $this->customer_first_name ?? $placeholder['first_name'],
  43. 'customer_last_name' => $this->customer_last_name ?? $placeholder['last_name'],
  44. 'channel_id' => $this->channel_id,
  45. 'channel_name' => $this->channel->name,
  46. 'channel_type' => get_class($this->channel),
  47. 'total_item_count' => $this->items_count,
  48. 'total_qty_ordered' => $this->items_qty,
  49. 'base_currency_code' => $this->base_currency_code,
  50. 'channel_currency_code' => $this->channel_currency_code,
  51. 'order_currency_code' => $this->cart_currency_code,
  52. 'grand_total' => $grandTotal,
  53. 'base_grand_total' => $baseGrandTotal,
  54. 'sub_total' => $subTotal,
  55. 'sub_total_incl_tax' => $subTotal,
  56. 'base_sub_total' => $baseSubTotal,
  57. 'base_sub_total_incl_tax' => $baseSubTotal,
  58. 'tax_amount' => 0,
  59. 'base_tax_amount' => 0,
  60. 'shipping_tax_amount' => 0,
  61. 'base_shipping_tax_amount' => 0,
  62. 'coupon_code' => $this->coupon_code,
  63. 'applied_cart_rule_ids' => $this->applied_cart_rule_ids,
  64. 'discount_amount' => $discount,
  65. 'base_discount_amount' => $baseDiscount,
  66. 'billing_address' => $billing,
  67. 'shipping_address' => $shipping,
  68. 'payment' => (new OrderPaymentResource($this->payment))->jsonSerialize(),
  69. 'items' => OrderItemResource::collection($this->items)->jsonSerialize(),
  70. ];
  71. }
  72. /**
  73. * Pull the configured placeholder block and guarantee every key exists.
  74. */
  75. private function buildPlaceholderAddress(): array
  76. {
  77. $defaults = [
  78. 'first_name' => 'Express',
  79. 'last_name' => 'Checkout',
  80. 'email' => 'express-checkout@placeholder.local',
  81. 'address' => 'Pending gateway response',
  82. 'city' => 'Pending',
  83. 'state' => 'Pending',
  84. 'country' => 'US',
  85. 'postcode' => '00000',
  86. 'phone' => '0000000000',
  87. ];
  88. $configured = (array) config('bagistoapi.express_checkout.placeholder_address', []);
  89. return array_merge($defaults, $configured);
  90. }
  91. /**
  92. * Prefer an existing billing address attached to the cart, otherwise
  93. * use the placeholder so OrderRepository can persist the order.
  94. */
  95. private function resolveBillingAddress(array $placeholder): array
  96. {
  97. if ($this->billing_address) {
  98. return [
  99. 'address_type' => 'order_billing',
  100. 'first_name' => $this->billing_address->first_name ?: $placeholder['first_name'],
  101. 'last_name' => $this->billing_address->last_name ?: $placeholder['last_name'],
  102. 'gender' => $this->billing_address->gender,
  103. 'company_name' => $this->billing_address->company_name,
  104. 'address' => $this->billing_address->address ?: $placeholder['address'],
  105. 'city' => $this->billing_address->city ?: $placeholder['city'],
  106. 'state' => $this->billing_address->state ?: $placeholder['state'],
  107. 'country' => $this->billing_address->country ?: $placeholder['country'],
  108. 'postcode' => $this->billing_address->postcode ?: $placeholder['postcode'],
  109. 'email' => $this->billing_address->email ?: $this->customer_email ?: $placeholder['email'],
  110. 'phone' => $this->billing_address->phone ?: $placeholder['phone'],
  111. 'vat_id' => $this->billing_address->vat_id,
  112. ];
  113. }
  114. return [
  115. 'address_type' => 'order_billing',
  116. 'first_name' => $placeholder['first_name'],
  117. 'last_name' => $placeholder['last_name'],
  118. 'gender' => null,
  119. 'company_name' => null,
  120. 'address' => $placeholder['address'],
  121. 'city' => $placeholder['city'],
  122. 'state' => $placeholder['state'],
  123. 'country' => $placeholder['country'],
  124. 'postcode' => $placeholder['postcode'],
  125. 'email' => $this->customer_email ?: $placeholder['email'],
  126. 'phone' => $placeholder['phone'],
  127. 'vat_id' => null,
  128. ];
  129. }
  130. /**
  131. * Mirror the billing block into shipping when the cart has stockable
  132. * items; downloadable-only carts skip the shipping address entirely.
  133. */
  134. private function resolveShippingAddress(array $billing): ?array
  135. {
  136. if (! $this->haveStockableItems()) {
  137. return null;
  138. }
  139. if ($this->shipping_address) {
  140. return [
  141. 'address_type' => 'order_shipping',
  142. 'first_name' => $this->shipping_address->first_name ?: $billing['first_name'],
  143. 'last_name' => $this->shipping_address->last_name ?: $billing['last_name'],
  144. 'gender' => $this->shipping_address->gender,
  145. 'company_name' => $this->shipping_address->company_name,
  146. 'address' => $this->shipping_address->address ?: $billing['address'],
  147. 'city' => $this->shipping_address->city ?: $billing['city'],
  148. 'state' => $this->shipping_address->state ?: $billing['state'],
  149. 'country' => $this->shipping_address->country ?: $billing['country'],
  150. 'postcode' => $this->shipping_address->postcode ?: $billing['postcode'],
  151. 'email' => $this->shipping_address->email ?: $billing['email'],
  152. 'phone' => $this->shipping_address->phone ?: $billing['phone'],
  153. 'vat_id' => $this->shipping_address->vat_id,
  154. ];
  155. }
  156. return array_merge($billing, ['address_type' => 'order_shipping']);
  157. }
  158. }