1: <?php
2: namespace Opencart\Catalog\Controller\Cron;
3: /**
4: * Class Subscription
5: *
6: * @package Opencart\Catalog\Controller\Cron
7: */
8: class Subscription extends \Opencart\System\Engine\Controller {
9: /**
10: * Index
11: *
12: * @param int $cron_id
13: * @param string $code
14: * @param string $cycle
15: * @param string $date_added
16: * @param string $date_modified
17: *
18: * @return void
19: */
20: public function index(int $cron_id, string $code, string $cycle, string $date_added, string $date_modified): void {
21: $this->load->language('cron/subscription');
22:
23: // Check if there is an order, the order status is complete and subscription status is active
24: $filter_data = [
25: 'filter_date_next' => date('Y-m-d H:i:s'),
26: 'filter_subscription_status_id' => $this->config->get('config_subscription_active_status_id'),
27: 'start' => 0,
28: 'limit' => 10
29: ];
30:
31: // Get all
32: $this->load->model('checkout/subscription');
33: $this->load->model('checkout/order');
34:
35: $results = $this->model_checkout_subscription->getSubscriptions($filter_data);
36:
37: foreach ($results as $result) {
38: $order_info = $this->model_checkout_order->getOrder($result['order_id']);
39:
40: if (($result['trial_status'] && $result['trial_remaining']) || ($result['duration'] && $result['remaining'])) {
41: $error = '';
42:
43: // 1. Language
44: $this->load->model('localisation/language');
45:
46: $language_info = $this->model_localisation_language->getLanguage($result['language_id']);
47:
48: if (!$language_info) {
49: $error = $this->language->get('error_language');
50: }
51:
52: // 2. Currency
53: $this->load->model('localisation/currency');
54:
55: $currency_info = $this->model_localisation_currency->getCurrency($result['currency_id']);
56:
57: if (!$currency_info) {
58: $error = $this->language->get('error_currency');
59: }
60:
61: // 3. Create new instance of a store
62: if (!$error) {
63: $this->load->model('setting/store');
64:
65: $store = $this->model_setting_store->createStoreInstance($result['store_id'], $language_info['code']);
66:
67: // Login
68: $this->load->model('account/customer');
69:
70: $customer_info = $this->model_account_customer->getCustomer($result['customer_id']);
71:
72: if ($customer_info && $this->customer->login($customer_info['email'], '', true)) {
73: // Add customer details into session
74: $store->session->data['customer'] = $customer_info;
75: } else {
76: $error = $this->language->get('error_customer');
77: }
78: }
79:
80: // 4. Add product
81: if (!$error) {
82: $this->load->model('catalog/product');
83:
84: $product_info = $this->model_catalog_product->getProduct($result['product_id']);
85:
86: if ($product_info) {
87: $price = $result['price'];
88:
89: if ($result['trial_status'] && (!$result['trial_duration'] || $result['trial_remaining'])) {
90: $price = $result['trial_price'];
91: }
92:
93: $store->cart->add($result['product_id'], $result['quantity'], $result['option'], $result['subscription_plan_id'], true, $price);
94: } else {
95: $error = $this->language->get('error_product');
96: }
97: }
98:
99: // 5. Add Shipping Address
100: if (!$error && $store->cart->hasShipping()) {
101: $this->load->model('account/address');
102:
103: $shipping_address_info = $this->model_account_address->getAddress($result['customer_id'], $result['shipping_address_id']);
104:
105: if ($shipping_address_info) {
106: $store->session->data['shipping_address'] = $shipping_address_info;
107: } else {
108: $error = $this->language->get('error_shipping_address');
109: }
110:
111: // 5. Shipping Methods
112: if (!$error) {
113: $this->load->model('checkout/shipping_method');
114:
115: $shipping_methods = $this->model_checkout_shipping_method->getMethods($shipping_address_info);
116:
117: // Validate shipping method
118: if (isset($order_info['shipping_method']['code']) && $shipping_methods) {
119: $shipping = explode('.', $order_info['shipping_method']['code']);
120:
121: if (isset($shipping[0]) && isset($shipping[1]) && isset($shipping_methods[$shipping[0]]['quote'][$shipping[1]])) {
122: $store->session->data['shipping_method'] = $shipping_methods[$shipping[0]]['quote'][$shipping[1]];
123: } else {
124: $error = $this->language->get('error_shipping_method');
125: }
126: } else {
127: $error = $this->language->get('error_shipping_method');
128: }
129: }
130: }
131:
132: // 6. Payment Address
133: if (!$error) {
134: if ($this->config->get('config_checkout_payment_address')) {
135: $this->load->model('account/address');
136:
137: $payment_address_info = $this->model_account_address->getAddress($order_info['customer_id'], $result['payment_address_id']);
138:
139: if ($payment_address_info) {
140: $store->session->data['payment_address'] = $payment_address_info;
141: } else {
142: $error = $this->language->get('error_payment_address');
143: }
144: } else {
145: $payment_address_info = [];
146: }
147: }
148:
149: // 7. Payment Methods
150: if (!$error) {
151: $this->load->model('checkout/payment_method');
152:
153: $payment_methods = $this->model_checkout_payment_method->getMethods($store->session->data['payment_address']);
154:
155: // Validate payment methods
156: if (isset($order_info['payment_method']['code']) && $payment_methods) {
157: $payment = explode('.', $order_info['payment_method']['code']);
158:
159: if (isset($payment[0]) && isset($payment[1]) && isset($payment_methods[$payment[0]]['option'][$payment[1]])) {
160: $store->session->data['payment_method'] = $payment_methods[$payment[0]]['option'][$payment[1]];
161: } else {
162: $error = $this->language->get('error_payment_method');
163: }
164: } else {
165: $error = $this->language->get('error_payment_method');
166: }
167: }
168:
169: if (!$error) {
170: // Subscription
171: $order_data = [];
172:
173: $order_data['subscription_id'] = $order_info['subscription_id'];
174:
175: // Store Details
176: $order_data['invoice_prefix'] = $order_info['invoice_prefix'];
177: $order_data['store_id'] = $order_info['store_id'];
178: $order_data['store_name'] = $order_info['store_name'];
179: $order_data['store_url'] = $order_info['store_url'];
180:
181: // Customer Details
182: $order_data['customer_id'] = $customer_info['customer_id'];
183: $order_data['customer_group_id'] = $customer_info['customer_group_id'];
184: $order_data['firstname'] = $customer_info['firstname'];
185: $order_data['lastname'] = $customer_info['lastname'];
186: $order_data['email'] = $customer_info['email'];
187: $order_data['telephone'] = $customer_info['telephone'];
188: $order_data['custom_field'] = $customer_info['custom_field'];
189:
190: // Payment Details
191: if ($payment_address_info) {
192: $order_data['payment_address_id'] = $payment_address_info['address_id'];
193: $order_data['payment_firstname'] = $payment_address_info['firstname'];
194: $order_data['payment_lastname'] = $payment_address_info['lastname'];
195: $order_data['payment_company'] = $payment_address_info['company'];
196: $order_data['payment_address_1'] = $payment_address_info['address_1'];
197: $order_data['payment_address_2'] = $payment_address_info['address_2'];
198: $order_data['payment_city'] = $payment_address_info['city'];
199: $order_data['payment_postcode'] = $payment_address_info['postcode'];
200: $order_data['payment_zone'] = $payment_address_info['zone'];
201: $order_data['payment_zone_id'] = $payment_address_info['zone_id'];
202: $order_data['payment_country'] = $payment_address_info['country'];
203: $order_data['payment_country_id'] = $payment_address_info['country_id'];
204: $order_data['payment_address_format'] = $payment_address_info['address_format'];
205: $order_data['payment_custom_field'] = $payment_address_info['custom_field'];
206: } else {
207: $order_data['payment_address_id'] = 0;
208: $order_data['payment_firstname'] = '';
209: $order_data['payment_lastname'] = '';
210: $order_data['payment_company'] = '';
211: $order_data['payment_address_1'] = '';
212: $order_data['payment_address_2'] = '';
213: $order_data['payment_city'] = '';
214: $order_data['payment_postcode'] = '';
215: $order_data['payment_zone'] = '';
216: $order_data['payment_zone_id'] = 0;
217: $order_data['payment_country'] = '';
218: $order_data['payment_country_id'] = 0;
219: $order_data['payment_address_format'] = '';
220: $order_data['payment_custom_field'] = [];
221: }
222:
223: $order_data['payment_method'] = $store->session->data['payment_method'];
224:
225: // Shipping Details
226: if ($store->cart->hasShipping()) {
227: $order_data['shipping_address_id'] = $shipping_address_info['address_id'];
228: $order_data['shipping_firstname'] = $shipping_address_info['firstname'];
229: $order_data['shipping_lastname'] = $shipping_address_info['lastname'];
230: $order_data['shipping_company'] = $shipping_address_info['company'];
231: $order_data['shipping_address_1'] = $shipping_address_info['address_1'];
232: $order_data['shipping_address_2'] = $shipping_address_info['address_2'];
233: $order_data['shipping_city'] = $shipping_address_info['city'];
234: $order_data['shipping_postcode'] = $shipping_address_info['postcode'];
235: $order_data['shipping_zone'] = $shipping_address_info['zone'];
236: $order_data['shipping_zone_id'] = $shipping_address_info['zone_id'];
237: $order_data['shipping_country'] = $shipping_address_info['country'];
238: $order_data['shipping_country_id'] = $shipping_address_info['country_id'];
239: $order_data['shipping_address_format'] = $shipping_address_info['address_format'];
240: $order_data['shipping_custom_field'] = $shipping_address_info['custom_field'];
241:
242: $order_data['shipping_method'] = $store->session->data['shipping_method'];
243: } else {
244: $order_data['shipping_address_id'] = 0;
245: $order_data['shipping_firstname'] = '';
246: $order_data['shipping_lastname'] = '';
247: $order_data['shipping_company'] = '';
248: $order_data['shipping_address_1'] = '';
249: $order_data['shipping_address_2'] = '';
250: $order_data['shipping_city'] = '';
251: $order_data['shipping_postcode'] = '';
252: $order_data['shipping_zone'] = '';
253: $order_data['shipping_zone_id'] = 0;
254: $order_data['shipping_country'] = '';
255: $order_data['shipping_country_id'] = 0;
256: $order_data['shipping_address_format'] = '';
257: $order_data['shipping_custom_field'] = [];
258:
259: $order_data['shipping_method'] = [];
260: }
261:
262: // Products
263: $order_data['products'] = [];
264:
265: $products = $store->model_checkout_cart->getProducts();
266:
267: foreach ($products as $product) {
268: $order_data['products'][] = [
269: 'product_id' => $product['product_id'],
270: 'master_id' => $product['master_id'],
271: 'name' => $product['name'],
272: 'model' => $product['model'],
273: 'option' => $product['option'],
274: 'subscription' => [],
275: 'download' => $product['download'],
276: 'quantity' => $product['quantity'],
277: 'subtract' => $product['subtract'],
278: 'price' => $product['price'],
279: 'total' => $product['total'],
280: 'tax' => $this->tax->getTax($price, $product['tax_class_id']),
281: 'reward' => $product['reward']
282: ];
283: }
284:
285: // Vouchers can not be in subscriptions
286: $order_data['vouchers'] = [];
287:
288: // Order Totals
289: $totals = [];
290: $taxes = $store->cart->getTaxes();
291: $total = 0;
292:
293: $store->load->model('checkout/cart');
294:
295: ($store->model_checkout_cart->getTotals)($totals, $taxes, $total);
296:
297: $total_data = [
298: 'totals' => $totals,
299: 'taxes' => $taxes,
300: 'total' => $total
301: ];
302:
303: $order_data = array_merge($order_data, $total_data);
304:
305: $order_data['affiliate_id'] = 0;
306: $order_data['commission'] = 0;
307: $order_data['marketing_id'] = 0;
308: $order_data['tracking'] = '';
309:
310: if (isset($this->session->data['tracking'])) {
311: $subtotal = $this->cart->getSubTotal();
312:
313: // Affiliate
314: if ($this->config->get('config_affiliate_status')) {
315: $this->load->model('account/affiliate');
316:
317: $affiliate_info = $this->model_account_affiliate->getAffiliateByTracking($this->session->data['tracking']);
318:
319: if ($affiliate_info) {
320: $order_data['affiliate_id'] = $affiliate_info['customer_id'];
321: $order_data['commission'] = ($subtotal / 100) * $affiliate_info['commission'];
322: $order_data['tracking'] = $this->session->data['tracking'];
323: }
324: }
325:
326: $this->load->model('marketing/marketing');
327:
328: $marketing_info = $this->model_marketing_marketing->getMarketingByCode($this->session->data['tracking']);
329:
330: if ($marketing_info) {
331: $order_data['marketing_id'] = $marketing_info['marketing_id'];
332: }
333: }
334:
335: // Language
336: $order_data['language_id'] = $language_info['language_id'];
337: $order_data['language_code'] = $language_info['code'];
338:
339: // Currency
340: $order_data['currency_id'] = $currency_info['currency_id'];
341: $order_data['currency_code'] = $currency_info['code'];
342: $order_data['currency_value'] = $currency_info['value'];
343:
344: $order_data['ip'] = $result['ip'];
345: $order_data['forwarded_ip'] = $result['forwarded_ip'];
346: $order_data['user_agent'] = $result['user_agent'];
347: $order_data['accept_language'] = $result['accept_language'];
348:
349: $this->load->model('checkout/order');
350:
351: $store->session->data['order_id'] = $this->model_checkout_order->addOrder($order_data);
352:
353: // Validate if payment extension installed
354: $this->load->model('setting/extension');
355:
356: $extension_info = $this->model_setting_extension->getExtensionByCode('payment', $payment[0]);
357:
358: // Load payment method used by the subscription
359: $this->load->model('extension/' . $extension_info['extension'] . '/payment/' . $extension_info['code']);
360:
361: $callable = [$this->{'model_extension_' . $extension_info['extension'] . '_payment_' . $extension_info['code']}, 'charge'];
362:
363: if (is_callable($callable)) {
364: // Process payment
365: $response_info = $this->{'model_extension_' . $order_data['payment_method']['extension'] . '_payment_' . $order_data['payment_method']['code']}->charge($this->customer->getId(), $this->session->data['order_id'], $order_info['total'], $order_data['payment_method']['code']);
366:
367: if (isset($response_info['order_status_id'])) {
368: $order_status_id = $response_info['order_status_id'];
369: } else {
370: $order_status_id = 0;
371: }
372:
373: if ($response_info['message']) {
374: $message = $response_info['message'];
375: } else {
376: $message = '';
377: }
378:
379: $this->model_checkout_order->addHistory($store->session->data['order_id'], $order_status_id, $message, false);
380: $this->model_checkout_order->addHistory($store->session->data['order_id'], $order_status_id);
381:
382: // If payment order status is active or processing
383: if (!in_array($order_status_id, (array)$this->config->get('config_processing_status') + (array)$this->config->get('config_complete_status'))) {
384: $remaining = 0;
385: $date_next = '';
386:
387: if ($result['trial_status'] && $result['trial_remaining'] > 1) {
388: $remaining = $result['trial_remaining'] - 1;
389: $date_next = date('Y-m-d', strtotime('+' . $result['trial_cycle'] . ' ' . $result['trial_frequency']));
390:
391: $this->model_account_subscription->editTrialRemaining($result['subscription_id'], $remaining);
392: } elseif ($result['duration'] && $result['remaining']) {
393: $remaining = $result['remaining'] - 1;
394: $date_next = date('Y-m-d', strtotime('+' . $result['cycle'] . ' ' . $result['frequency']));
395:
396: // If duration make sure there is remaining
397: $this->model_account_subscription->editRemaining($result['subscription_id'], $remaining);
398: } elseif (!$result['duration']) {
399: // If duration is unlimited
400: $date_next = date('Y-m-d', strtotime('+' . $result['cycle'] . ' ' . $result['frequency']));
401: }
402:
403: if ($date_next) {
404: $this->load->model('checkout/subscription');
405: $this->model_checkout_subscription->editDateNext($result['subscription_id'], $date_next);
406: }
407:
408: $this->model_checkout_subscription->addHistory($result['subscription_id'], $this->config->get('config_subscription_active_status_id'), $this->language->get('text_success'), true);
409: } else {
410: // If payment failed change subscription history to failed
411: $this->model_checkout_subscription->addHistory($result['subscription_id'], $this->config->get('config_subscription_failed_status_id'), $message, true);
412: }
413: } else {
414: // Add subscription history failed if no charge method
415: $this->model_checkout_subscription->addHistory($result['subscription_id'], $this->config->get('config_subscription_failed_status_id'), $this->language->get('error_payment_method'), true);
416: }
417: } else {
418: // Errors add to
419: $this->model_checkout_subscription->addHistory($result['subscription_id'], $this->config->get('config_subscription_failed_status_id'), $error, true);
420: }
421: }
422: }
423: }
424: }
425: