ExpressOrderResource.php 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  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. $this->mergeWhen($this->shipping_insurance_amount && $this->shipping_insurance_amount > 0, [
  67. 'shipping_insurance_amount' => $this->shipping_insurance_amount,
  68. 'base_shipping_insurance_amount' => $this->base_shipping_insurance_amount,
  69. ]),
  70. $this->mergeWhen($this->reward_points_used && $this->reward_points_used > 0, [
  71. 'reward_points_used' => $this->reward_points_used,
  72. 'reward_points_amount' => $this->reward_points_amount,
  73. 'base_reward_points_amount' => $this->base_reward_points_amount,
  74. ]),
  75. 'billing_address' => $billing,
  76. 'shipping_address' => $shipping,
  77. 'payment' => (new OrderPaymentResource($this->payment))->jsonSerialize(),
  78. 'items' => OrderItemResource::collection($this->items)->jsonSerialize(),
  79. ];
  80. }
  81. /**
  82. * Pull the configured placeholder block and guarantee every key exists.
  83. */
  84. private function buildPlaceholderAddress(): array
  85. {
  86. $defaults = [
  87. 'first_name' => 'Express',
  88. 'last_name' => 'Checkout',
  89. 'email' => 'express-checkout@placeholder.local',
  90. 'address' => 'Pending gateway response',
  91. 'city' => 'Pending',
  92. 'state' => 'Pending',
  93. 'country' => 'US',
  94. 'postcode' => '00000',
  95. 'phone' => '0000000000',
  96. ];
  97. $configured = (array) config('bagistoapi.express_checkout.placeholder_address', []);
  98. return array_merge($defaults, $configured);
  99. }
  100. /**
  101. * Prefer an existing billing address attached to the cart, otherwise
  102. * use the placeholder so OrderRepository can persist the order.
  103. */
  104. private function resolveBillingAddress(array $placeholder): array
  105. {
  106. if ($this->billing_address) {
  107. return [
  108. 'address_type' => 'order_billing',
  109. 'first_name' => $this->billing_address->first_name ?: $placeholder['first_name'],
  110. 'last_name' => $this->billing_address->last_name ?: $placeholder['last_name'],
  111. 'gender' => $this->billing_address->gender,
  112. 'company_name' => $this->billing_address->company_name,
  113. 'address' => $this->billing_address->address ?: $placeholder['address'],
  114. 'city' => $this->billing_address->city ?: $placeholder['city'],
  115. 'state' => $this->billing_address->state ?: $placeholder['state'],
  116. 'country' => $this->billing_address->country ?: $placeholder['country'],
  117. 'postcode' => $this->billing_address->postcode ?: $placeholder['postcode'],
  118. 'email' => $this->billing_address->email ?: $this->customer_email ?: $placeholder['email'],
  119. 'phone' => $this->billing_address->phone ?: $placeholder['phone'],
  120. 'vat_id' => $this->billing_address->vat_id,
  121. ];
  122. }
  123. return [
  124. 'address_type' => 'order_billing',
  125. 'first_name' => $placeholder['first_name'],
  126. 'last_name' => $placeholder['last_name'],
  127. 'gender' => null,
  128. 'company_name' => null,
  129. 'address' => $placeholder['address'],
  130. 'city' => $placeholder['city'],
  131. 'state' => $placeholder['state'],
  132. 'country' => $placeholder['country'],
  133. 'postcode' => $placeholder['postcode'],
  134. 'email' => $this->customer_email ?: $placeholder['email'],
  135. 'phone' => $placeholder['phone'],
  136. 'vat_id' => null,
  137. ];
  138. }
  139. /**
  140. * Mirror the billing block into shipping when the cart has stockable
  141. * items; downloadable-only carts skip the shipping address entirely.
  142. */
  143. private function resolveShippingAddress(array $billing): ?array
  144. {
  145. if (! $this->haveStockableItems()) {
  146. return null;
  147. }
  148. if ($this->shipping_address) {
  149. return [
  150. 'address_type' => 'order_shipping',
  151. 'first_name' => $this->shipping_address->first_name ?: $billing['first_name'],
  152. 'last_name' => $this->shipping_address->last_name ?: $billing['last_name'],
  153. 'gender' => $this->shipping_address->gender,
  154. 'company_name' => $this->shipping_address->company_name,
  155. 'address' => $this->shipping_address->address ?: $billing['address'],
  156. 'city' => $this->shipping_address->city ?: $billing['city'],
  157. 'state' => $this->shipping_address->state ?: $billing['state'],
  158. 'country' => $this->shipping_address->country ?: $billing['country'],
  159. 'postcode' => $this->shipping_address->postcode ?: $billing['postcode'],
  160. 'email' => $this->shipping_address->email ?: $billing['email'],
  161. 'phone' => $this->shipping_address->phone ?: $billing['phone'],
  162. 'vat_id' => $this->shipping_address->vat_id,
  163. ];
  164. }
  165. return array_merge($billing, ['address_type' => 'order_shipping']);
  166. }
  167. }