PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.3.27
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.3.27
1.6.6 1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 All 49 releases
fluent-cart / app / Helpers / AdminOrderProcessor.php

AdminOrderProcessor.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.3.27, at app/Helpers/AdminOrderProcessor.php

658 lines 26.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCart\App\Helpers;
4
5 use FluentCart\Api\StoreSettings;
6 use FluentCart\App\Models\Cart;
7 use FluentCart\App\Models\Coupon;
8 use FluentCart\App\Models\Order;
9 use FluentCart\App\Models\OrderItem;
10 use FluentCart\App\Models\Product;
11 use FluentCart\App\Models\ProductVariation;
12 use FluentCart\App\Models\Subscription;
13 use FluentCart\App\Services\Payments\PaymentHelper;
14 use FluentCart\Framework\Support\Arr;
15 use FluentCart\App\Helpers\Helper;
16
17 class AdminOrderProcessor
18 {
19 private $args = [];
20 private $checkoutItems = [];
21
22 // Order Related Data
23 private $formattedIOrderItems = [];
24 private $orderData = [];
25 private $subscriptionData = [];
26
27 // Models
28
29 private $orderModel;
30
31 private $transactionModel;
32
33 private $subscriptionModel;
34
35 // Store Settings
36 private $storeSettings;
37
38
39 private $couponDiscountTotal = 0;
40
41 private $manualDiscountTotal = 0;
42
43 public function __construct($checkoutItems = [], $args = [])
44 {
45 $this->storeSettings = new StoreSettings();
46 $this->checkoutItems = $checkoutItems;
47 $this->checkoutItems = Helper::loadBundleChild($checkoutItems, ['*']);
48 $this->args = $args;
49
50 $this->prepareData();
51 }
52
53 private function prepareData()
54 {
55 $this->prepareOrderItems();
56 $this->prepareOrderData();
57 $this->prepareSubscriptionData();
58 }
59
60 private function prepareOrderItems()
61 {
62 $formattedItems = [];
63
64 foreach ($this->checkoutItems as $checkoutItem) {
65 $unitPrice = (int)Arr::get($checkoutItem, 'unit_price', 0);
66 $quantity = (int)Arr::get($checkoutItem, 'quantity', 1);
67
68 //TODO: right now discount total from admin only comes from coupon applied discount, is same as coupon_discount
69 $this->couponDiscountTotal += (int)Arr::get($checkoutItem, 'discount_total', 0);
70 $this->manualDiscountTotal += (int)Arr::get($checkoutItem, 'manual_discount', 0);
71
72 $discountTotal = (int)Arr::get($checkoutItem, 'manual_discount', 0) + (int)Arr::get($checkoutItem, 'discount_total', 0);
73
74 $shippingCharge = (int)Arr::get($checkoutItem, 'shipping_charge', 0);
75 $tax = 0;
76 $subtotal = $unitPrice * $quantity;
77 $args = Arr::get($checkoutItem, 'other_info', []);
78 $paymentType = Arr::get($args, 'payment_type', 'default');
79
80 $postTitle = Arr::get($checkoutItem, 'product_title', '');
81 $variationTitle = Arr::get($checkoutItem, 'variation_title', '');
82
83 if (!$postTitle) {
84 $product = Product::query()->find(Arr::get($checkoutItem, 'post_id', 0));
85 if ($product) {
86 $postTitle = $product->post_title;
87 }
88 }
89
90 if (!$variationTitle) {
91 $variation = ProductVariation::query()->find(Arr::get($checkoutItem, 'object_id', 0));
92 if ($variation) {
93 $variationTitle = $variation->variation_title;
94 }
95 }
96
97
98 $item = [
99 'payment_type' => $paymentType,
100 'post_id' => Arr::get($checkoutItem, 'post_id'),
101 'object_id' => Arr::get($checkoutItem, 'object_id'),
102 'post_title' => $postTitle,
103 'title' => $variationTitle,
104 'fulfillment_type' => Arr::get($checkoutItem, 'fulfillment_type', 'digital'),
105 'quantity' => $quantity,
106 'cost' => (int)Arr::get($checkoutItem, 'cost', 0),
107 'unit_price' => $unitPrice,
108 'subtotal' => $subtotal,
109 'tax_amount' => $tax,
110 'shipping_charge' => $shippingCharge,
111 'discount_total' => $discountTotal,
112 'other_info' => $args,
113 'line_meta' => []
114 ];
115
116 $childItem = null;
117 if ($paymentType === 'subscription' && Arr::get($checkoutItem, 'other_info.signup_fee', 0)) {
118 // We have a signup fee for subscription
119 $singupFeeAmount = (int)Arr::get($checkoutItem, 'other_info.signup_fee', 0);
120
121 $childDiscontTotal = 0;
122 $signupFeeSubtotal = $singupFeeAmount * $quantity;
123 if ($discountTotal) {
124 // Distribute discount with signup fee and item
125 $childDiscontTotal = (int)($discountTotal / ($subtotal + $signupFeeSubtotal) * $signupFeeSubtotal);
126 $discountTotal -= $childDiscontTotal;
127 }
128
129 $childItem = [
130 'payment_type' => 'signup_fee',
131 'post_id' => $item['post_id'],
132 'object_id' => $item['object_id'],
133 'post_title' => $item['post_title'],
134 'title' => Arr::get($checkoutItem, 'other_info.signup_fee_name', __('Signup Fee', 'fluent-cart')),
135 'fulfillment_type' => $item['fulfillment_type'],
136 'quantity' => $quantity,
137 'cost' => 0,
138 'unit_price' => $singupFeeAmount,
139 'subtotal' => $signupFeeSubtotal,
140 'tax_amount' => 0,
141 'shipping_charge' => 0,
142 'discount_total' => $childDiscontTotal,
143 'line_meta' => []
144 ];
145
146 $item['discount_total'] = $discountTotal;
147 $item['additional_items'] = [$childItem];
148
149 Arr::set($item, 'other_info.signup_fee', $singupFeeAmount);
150 Arr::set($item, 'other_info.signup_discount', $childDiscontTotal);
151 }
152
153 if (Arr::get($checkoutItem, 'other_info.is_bundle_product', 'no') == 'yes') {
154 $bundleItems = Arr::get($checkoutItem, 'child_variants', []);
155
156 foreach ($bundleItems as $bundleItem) {
157 $bundleChildItem = [
158 'payment_type' => 'bundle',
159 'post_id' => Arr::get($bundleItem, 'post_id', 0),
160 'object_id' => Arr::get($bundleItem, 'id', 0),
161 'post_title' => Arr::get($bundleItem, 'post_title', ''),
162 'title' => Arr::get($bundleItem, 'variation_title', ''),
163 'fulfillment_type' => Arr::get($bundleItem, 'fulfillment_type', 'digital'),
164 'quantity' => $quantity,
165 'cost' => 0,
166 'unit_price' => 0,
167 'subtotal' => 0,
168 'tax_amount' => 0,
169 'shipping_charge' => 0,
170 'discount_total' => 0,
171 'other_info' => [
172 'bundle_parent_product_id' => Arr::get($checkoutItem, 'post_id', 0),
173 'bundle_parent_variation_id' => Arr::get($checkoutItem, 'object_id', 0)
174 ],
175 ];
176
177 //TODO: if bundleItem price is included on for the bundle, then we need to set the price to the bundleItem price
178 // if (Arr::get($bundleItem, 'other_info.is_price_included', 'no') == 'yes') {
179 // $bundleChildItem['unit_price'] = Arr::get($bundleItem, 'unit_price', 0);
180 // $bundleChildItem['subtotal'] = Arr::get($bundleItem, 'subtotal', 0);
181 // $bundleChildItem['tax_amount'] = Arr::get($bundleItem, 'tax_amount', 0);
182 // $bundleChildItem['shipping_charge'] = Arr::get($bundleItem, 'shipping_charge', 0);
183 // $bundleChildItem['discount_total'] = Arr::get($bundleItem, 'discount_total', 0);
184 // }
185
186 $item['bundle_items'][] = $bundleChildItem;
187
188 }
189
190 }
191
192
193 $formattedItems[] = $item;
194 if ($childItem) {
195 $formattedItems[] = $childItem;
196 }
197 }
198
199 $this->formattedIOrderItems = $formattedItems;
200 }
201
202 private function prepareOrderData()
203 {
204 $hasPhysical = array_filter($this->formattedIOrderItems, function ($item) {
205 return $item['fulfillment_type'] === 'physical';
206 });
207
208 $hasSubscription = array_filter($this->formattedIOrderItems, function ($item) {
209 return $item['payment_type'] === 'subscription';
210 });
211
212
213 $itemsSubtotal = array_reduce($this->formattedIOrderItems, function ($carry, $item) {
214 if (Arr::get($item, 'other_info.trial_days', 0) > 0) {
215 return $carry;
216 }
217 return $carry + $item['subtotal'];
218 }, 0);
219
220 $orderData = [
221 'status' => Status::ORDER_ON_HOLD,
222 'fulfillment_type' => $hasPhysical ? Status::FULFILLMENT_TYPE_PHYSICAL : Status::FULFILLMENT_TYPE_DIGITAL,
223 'type' => $hasSubscription ? Status::ORDER_TYPE_SUBSCRIPTION : Status::ORDER_TYPE_PAYMENT, // revisit this on manual renewal
224 'mode' => $this->storeSettings->get('order_mode'),
225 'shipping_status' => $hasPhysical ? 'unshipped' : '',
226 'customer_id' => '',
227 'payment_method' => Arr::get($this->args, 'payment_method', ''),
228 'payment_status' => Status::PAYMENT_PENDING,
229 'payment_method_title' => '',
230 'currency' => $this->storeSettings->get('currency'),
231 'subtotal' => $itemsSubtotal,
232 'discount_tax' => 0,
233 'manual_discount_total' => $this->manualDiscountTotal,
234 'coupon_discount_total' => $this->couponDiscountTotal,
235 'shipping_tax' => 0,
236 'shipping_total' => Arr::get($this->args, 'shipping_total', 0),
237 'tax_total' => 0,
238 // 'total_amount' => $this->orderTotals['total_amount'],
239 'total_paid' => 0,
240 'total_refund' => 0,
241 'rate' => 1,
242 'note' => Arr::get($this->args, 'note', ''),
243 'ip_address' => Arr::get($this->args, 'ip_address', ''),
244 'config' => [
245 'user_tz' => Arr::get($this->args, 'user_tz', ''),
246 ],
247 ];
248
249 $totalAmount = $orderData['subtotal'] - $orderData['coupon_discount_total'] - $orderData['manual_discount_total'] + $orderData['shipping_total'] + $orderData['tax_total'];
250 $orderData['total_amount'] = $totalAmount > 0 ? $totalAmount : 0;
251 $this->orderData = $orderData;
252 }
253
254
255 public function createDraftOrder($prevOrder = null)
256 {
257 $customerId = Arr::get($this->args, 'customer_id', '');
258 if (!$customerId) {
259 return new \WP_Error('customer_id_missing', __('Customer ID is required to create a draft order.', 'fluent-cart'));
260 }
261
262 $orderData = $this->orderData;
263 $orderData['customer_id'] = $customerId;
264 $this->orderModel = \FluentCart\App\Models\Order::query()->create($orderData);
265
266 if (!$this->orderModel) {
267 return new \WP_Error('order_creation_failed', __('Failed to create order.', 'fluent-cart'));
268 }
269
270 // Let's create the order items
271 $normalOrderItems = array_filter($this->formattedIOrderItems, function ($item) {
272 return $item['payment_type'] != 'signup_fee';
273 });
274
275
276 foreach ($normalOrderItems as $orderItem) {
277 $orderItem['order_id'] = $this->orderModel->id;
278 $orderItem['line_total'] = $orderItem['subtotal'] - $orderItem['discount_total'];
279 $additionalItems = [];
280 $bundleItems = [];
281 if ($orderItem['payment_type'] == 'subscription') {
282 // this is a subscription type. We may have additional_items
283 $additionalItems = Arr::get($orderItem, 'additional_items', []);
284 unset($orderItem['additional_items']);
285 }
286
287 if (Arr::get($orderItem, 'other_info.is_bundle_product', 'no') == 'yes') {
288 $bundleItems = Arr::get($orderItem, 'bundle_items', []);
289 unset($orderItem['bundle_items']);
290 }
291
292 $createdItem = OrderItem::query()->create($orderItem);
293
294 if ($additionalItems) {
295 $additionalItemIds = [];
296 foreach ($additionalItems as $additionalItem) {
297 $additionalItem['order_id'] = $this->orderModel->id;
298 $additionalItem['line_total'] = $additionalItem['subtotal'] - $additionalItem['discount_total'];
299 $mata = Arr::get($additionalItem, 'line_meta', []);
300 $mata['parent_item_id'] = $createdItem->id;
301 $additionalItem['line_meta'] = $mata;
302 OrderItem::query()->create($additionalItem);
303 }
304
305 $createdItem->fill([
306 'line_meta' => array_merge(
307 $createdItem->line_meta,
308 [
309 'additional_item_ids' => $additionalItemIds
310 ]
311 )
312 ])->save();
313 }
314
315 if ($bundleItems) {
316 $bundleItemIds = [];
317 foreach ($bundleItems as $bundleItem) {
318 $bundleItem['order_id'] = $this->orderModel->id;
319 $bundleItem['line_total'] = Arr::get($bundleItem, 'subtotal', 0) - Arr::get($bundleItem, 'discount_total', 0);
320 $bundleItem['payment_type'] = 'bundle';
321 $meta = Arr::get($bundleItem, 'line_meta', []);
322 $meta['bundle_parent_item_id'] = $createdItem->id;
323 $bundleItem['line_meta'] = $meta;
324 $bundleItem = OrderItem::query()->create($bundleItem);
325 $bundleItemIds[] = $bundleItem->id;
326 }
327
328 $createdItem->fill([
329 'line_meta' => array_merge(
330 $createdItem->line_meta,
331 [
332 'bundle_item_ids' => $bundleItemIds
333 ]
334 )
335 ])->save();
336 }
337 }
338
339 // Let's create the subscription if exists
340 if ($this->subscriptionData) {
341 $subscriptionData = $this->subscriptionData;
342 $subscriptionData['customer_id'] = $customerId;
343 $subscriptionData['parent_order_id'] = $this->orderModel->id;
344 $this->subscriptionModel = Subscription::query()->create($subscriptionData);
345 }
346
347 // Let's create the transaction
348 $transactionData = [
349 'order_id' => $this->orderModel->id,
350 'order_type' => $this->orderModel->type,
351 'transaction_type' => Status::TRANSACTION_TYPE_CHARGE,
352 'subscription_id' => $this->subscriptionModel ? $this->subscriptionModel->id : NULL,
353 'payment_method' => $this->orderModel->payment_method,
354 'payment_mode' => $this->orderModel->mode,
355 'payment_method_type' => '',
356 'status' => Status::PAYMENT_PENDING,
357 'currency' => $this->orderModel->currency,
358 'total' => $this->orderModel->total_amount,
359 'rate' => 1,
360 'meta' => [],
361 ];
362
363 $this->transactionModel = \FluentCart\App\Models\OrderTransaction::query()->create($transactionData);
364
365 // insert the applied coupons
366 $this->insertAppliedCoupons(Arr::get($this->args, 'applied_coupons', []));
367
368 $cartHash = Arr::get($this->args, 'cart_hash', '');
369 if ($cartHash) {
370 $cart = Cart::query()->where('cart_hash', $cartHash)->first();
371 if ($cart) {
372 $cart->order_id = $this->orderModel->id;
373 $cart->customer_id = $this->orderModel->customer_id;
374 $cart->stage = 'intended';
375 $cart->save();
376 $actions = Arr::get($cart->checkout_data, '__after_draft_created_actions__', []);
377 if ($actions) {
378 foreach ($actions as $actionName) {
379 $actionName = (string)$actionName;
380 if (has_action($actionName)) {
381 do_action($actionName, [
382 'order' => $this->orderModel,
383 'cart' => $cart,
384 ]);
385 }
386 }
387 }
388 }
389 }
390
391 // We are almost done!
392 return $this->orderModel;
393 }
394
395
396 private function insertAppliedCoupons($appliedCoupons, $removeOldCoupons = false): void
397 {
398 if ($removeOldCoupons) {
399 $this->orderModel->appliedCoupons()->delete();
400 }
401
402 $couponCodes = array_keys($appliedCoupons);
403
404 if (!empty($couponCodes)) {
405 $coupons = Coupon::query()->whereIn('code', $couponCodes)->get()
406 ->keyBy('code')
407 ->toArray();
408
409 foreach ($coupons as $code => &$coupon) {
410 $coupon['coupon_id'] = $appliedCoupons[$code]['id'];
411 $coupon['amount'] = $appliedCoupons[$code]['discount'];
412 }
413 $this->orderModel->appliedCoupons()->createMany($coupons);
414
415 Coupon::query()
416 ->whereIn('code', $couponCodes)
417 ->increment('use_count', 1);
418 }
419 }
420
421 public function getTransaction()
422 {
423 return $this->transactionModel;
424 }
425
426 public function getOrder()
427 {
428 return $this->orderModel;
429 }
430
431 public function getSubscription()
432 {
433 return $this->subscriptionModel;
434 }
435 private function prepareSubscriptionData()
436 {
437 $subscriptionItems = array_filter($this->formattedIOrderItems, function ($item) {
438 return $item['payment_type'] === 'subscription';
439 });
440
441 $signupFeeItems = array_filter($this->formattedIOrderItems, function ($item) {
442 return $item['payment_type'] === 'signup_fee';
443 });
444
445 if (!$subscriptionItems) {
446 return;
447 }
448
449 if (count($subscriptionItems) > 1) {
450 return;
451 }
452
453 $item = reset($subscriptionItems);
454 $signupFeeItem = reset($signupFeeItems) ?? [];
455
456 $totalSignup = Arr::get($item, 'other_info.signup_fee', 0) - Arr::get($item, 'other_info.signup_discount', 0);
457 $firstPrice = Arr::get($item, 'subtotal') + $totalSignup - Arr::get($item, 'discount_total', 0);
458 $recurringPrice = Arr::get($item, 'subtotal', 0) + Arr::get($item, 'tax_amount', 0);
459
460 if ($firstPrice < $recurringPrice) {
461 Arr::set($item, 'other_info.trial_days', PaymentHelper::getIntervalDays(Arr::get($item, 'other_info.repeat_interval')));
462 Arr::set($item, 'other_info.signup_fee', $firstPrice);
463 Arr::set($item, 'other_info.manage_setup_fee', 'yes');
464 Arr::set($item, 'other_info.times', Arr::get($item, 'other_info.times', 0) > 1 ? Arr::get($item, 'other_info.times', 0) - 1 : 0);
465 } else if ($firstPrice > $recurringPrice) {
466 Arr::set($item, 'other_info.signup_fee', $firstPrice - $recurringPrice);
467 Arr::set($item, 'other_info.manage_setup_fee', 'yes');
468 Arr::set($item, 'other_info.trial_days', 0);
469 }
470
471 $subscriptionPricing = $this->convertToSubscriptionFormat([
472 'initial_trial_days' => Arr::get($item, 'other_info.trial_days', 0),
473 'repeat_interval' => Arr::get($item, 'other_info.repeat_interval', 'monthly'),
474 'times' => Arr::get($item, 'other_info.times', 0),
475 'recurring_amount' => $item['subtotal'],
476 'signup_fee' => $signupFeeItem ? $signupFeeItem['subtotal'] : 0,
477 'total_discount' => $item['discount_total'] + Arr::get($signupFeeItem, 'discount_total', 0)
478 ]);
479
480 // removable upon discussion
481 $subscriptionItem = [
482 'product_id' => $item['post_id'],
483 'current_payment_method' => Arr::get($this->orderData, 'payment_method'),
484 'object_id' => $item['object_id'],
485 'recurring_tax_total' => 0,
486 'recurring_total' => $subscriptionPricing['recurring_amount'], //use price not line_total to ignore discount
487 'item_name' => $item['post_title'] . ' - ' . $item['title'],
488 'bill_count' => 0,
489 'quantity' => 1,
490 'variation_id' => Arr::get($item, 'object_id', 0),
491 'status' => Status::SUBSCRIPTION_PENDING,
492 'config' => [
493 'currency' => $this->orderData['currency'],
494 'is_trial_days_simulated' => Arr::get($subscriptionPricing, 'is_trial_days_simulated', 'no'),
495 ]
496 ];
497
498 $this->subscriptionData = wp_parse_args($subscriptionPricing, $subscriptionItem);
499 }
500
501 /**
502 * @param $inputData
503 * @return array
504 */
505 private function convertToSubscriptionFormat($inputData)
506 {
507
508 /**
509 * Normal Subscription $100/month
510 * {
511 * 'trial_days' => 0,
512 * 'repeat_interval' => 'month',
513 * 'times' => 0, // 0 means unlimited
514 * 'recurring_amount' => 100,
515 * 'signup_fee' => 0
516 * }
517 *
518 * 30 Days Trial $100/month
519 * {
520 * 'trial_days' => 30,
521 * 'repeat_interval' => 'month',
522 * 'times' => 0, // 0 means unlimited
523 * 'recurring_amount' => 100,
524 * }
525 *
526 * $100/month - 30 days Trial with $40 signup fee
527 * {
528 * 'trial_days' => 30,
529 * 'repeat_interval' => 'month',
530 * 'times' => 0, // 0 means unlimited
531 * 'recurring_amount' => 100,
532 * 'signup_fee' => 40
533 * }
534 *
535 * $100 / month with $40 signup fee
536 * {
537 * 'trial_days' => 0,
538 * 'repeat_interval' => 'month',
539 * 'times' => 0, // 0 means unlimited
540 * 'recurring_amount' => 100,
541 * 'signup_fee' => 40
542 * }
543 *
544 * $100 per month but 30% discount on first month
545 * {
546 * 'trial_days' => 30,
547 * 'repeat_interval' => 'month',
548 * 'times' => 0, // 0 means unlimited
549 * 'recurring_amount' => 100,
550 * 'signup_fee' => 70
551 * }
552 *
553 * $100 per month but 50% extra on first month
554 * {
555 * 'trial_days' => 0,
556 * 'repeat_interval' => 'month',
557 * 'times' => 0, // 0 means unlimited
558 * 'recurring_amount' => 100,
559 * 'signup_fee' => 50
560 * }
561 *
562 * $100 per month and 1 month trial and service_fee = $50
563 * {
564 * 'trial_days' => 30,
565 * 'repeat_interval' => 'month',
566 * 'times' => 0, // 0 means unlimited
567 * 'recurring_amount' => 100,
568 * 'signup_fee' => 50
569 * }
570 *
571 *
572 * $100 per month, signup fee $200 - First Month 50% discount
573 *
574 * $first Month = 100 + 200 = 300 - 50% discount = 150
575 * {
576 * 'trial_days' => 30,
577 * 'repeat_interval' => 'month',
578 * 'times' => 0, // 0 means unlimited
579 * 'recurring_amount' => 100,
580 * 'signup_fee' => 150
581 * }
582 *
583 * // prefered when signup_fee > recurring_amount
584 * {
585 * 'trial_days' => 0,
586 * 'repeat_interval' => 'month',
587 * 'times' => 0, // 0 means unlimited
588 * 'recurring_amount' => 100,
589 * 'signup_fee' => 50
590 * }
591 */
592
593
594 // Extract and validate input data
595 $trialDays = (int)($inputData['initial_trial_days'] ?? 0);
596 $repeatInterval = strtolower(trim($inputData['repeat_interval'] ?? 'yearly'));
597 $times = (int)($inputData['times'] ?? 0);
598 $recurringAmount = (int)($inputData['recurring_amount'] ?? 0);
599 $signupFee = (int)($inputData['signup_fee'] ?? 0);
600 $totalDiscount = (int)($inputData['total_discount'] ?? 0);
601
602 // Convert repeat_interval to standard format
603 $intervalMap = Helper::getAvailableSubscriptionIntervalMaps();
604 $standardInterval = Helper::translateIntervalToStandardFormat($repeatInterval);
605
606
607 // Initialize result array
608 $result = [
609 'trial_days' => $trialDays,
610 'repeat_interval' => $standardInterval,
611 'times' => $times,
612 'recurring_amount' => $recurringAmount,
613 ];
614
615
616 // Calculate signup fee logic
617 if ($totalDiscount > 0) {
618
619 $firstCycleCost = $recurringAmount + $signupFee - $totalDiscount;
620
621 if ($firstCycleCost < $recurringAmount) {
622 $adjustedTrialDays = Helper::calculateAdjustedTrialDaysForInterval($trialDays, $repeatInterval);
623
624 $result['trial_days'] = $adjustedTrialDays;
625 $result['is_trial_days_simulated'] = 'yes';
626 $result['signup_fee'] = $firstCycleCost;
627 $result['manage_setup_fee'] = 'yes';
628 $result['times'] = $times > 0 ? $times - 1 : 0;
629 } else if ($firstCycleCost > $recurringAmount) {
630 $result['trial_days'] = 0;
631 $result['signup_fee'] = $firstCycleCost - $recurringAmount;
632 $result['manage_setup_fee'] = 'yes';
633 } else if ($firstCycleCost == $recurringAmount) {
634 $result['trial_days'] = 0;
635 $result['signup_fee'] = 0;
636 $result['manage_setup_fee'] = 'no';
637 }
638
639 } else {
640 $result['signup_fee'] = $signupFee;
641 }
642
643 // inverse the repeat interval to match the expected format
644
645 $result['repeat_interval'] = array_flip($intervalMap)[$result['repeat_interval']] ?? 'yearly';
646
647
648 return [
649 'billing_interval' => $result['repeat_interval'],
650 'bill_times' => $result['times'],
651 'trial_days' => $result['trial_days'],
652 'is_trial_days_simulated' => Arr::get($result, 'is_trial_days_simulated', 'no'),
653 'recurring_amount' => $result['recurring_amount'],
654 'signup_fee' => $result['signup_fee'] ?? 0,
655 ];
656 }
657 }
658