Service::createFromCart()   F
last analyzed

Complexity

Conditions 22
Paths 4491

Size

Total Lines 168

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 427.3476

Importance

Changes 0
Metric Value
cc 22
nc 4491
nop 2
dl 0
loc 168
ccs 7
cts 122
cp 0.0574
crap 427.3476
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * BoxBilling
4
 *
5
 * @copyright BoxBilling, Inc (http://www.boxbilling.com)
6
 * @license   Apache-2.0
7
 *
8
 * Copyright BoxBilling, Inc
9
 * This source file is subject to the Apache-2.0 License that is bundled
10
 * with this source code in the file LICENSE
11
 */
12
13
namespace Box\Mod\Cart;
14
15
use Box\InjectionAwareInterface;
16
17
class Service implements InjectionAwareInterface
18
{
19
20
    protected $di;
21
22 43
    public function setDi($di)
23
    {
24 43
        $this->di = $di;
25 43
    }
26
27 1
    public function getDi()
28
    {
29 1
        return $this->di;
30
    }
31
32 1
    public function getSearchQuery($data)
33
    {
34
        $sql = "
35
            SELECT cart.id FROM cart
36
            LEFT JOIN currency ON cart.currency_id = currency.id
37 1
            LEFT JOIN promo ON cart.promo_id = promo.id";
38
39 1
        return array($sql, array());
40
    }
41
42
    /**
43
     * @return \Model_Cart
44
     */
45 8
    public function getSessionCart()
46
    {
47 3
        $sqlBindings = array(':session_id' => $this->di['session']->getId());
48 3
        $cart        = $this->di['db']->findOne('Cart', 'session_id = :session_id', $sqlBindings);
49
50 3
        if ($cart instanceof \Model_Cart) {
51 1
            return $cart;
52
        }
53
54 2
        $cc = $this->di['mod_service']('currency');
55
56 2
        if ($this->di['session']->get('client_id')) {
57 1
            $client_id = $this->di['session']->get('client_id');
58 1
            $currency  = $cc->getCurrencyByClientId($client_id);
59 1
        } else {
60 1
            $currency = $cc->getDefault();
61
        }
62
63 8
        $cart              = $this->di['db']->dispense('Cart');
64 2
        $cart->session_id  = $this->di['session']->getId();
65 2
        $cart->currency_id = $currency->id;
66 2
        $cart->created_at  = date('Y-m-d H:i:s');
67 2
        $cart->updated_at  = date('Y-m-d H:i:s');
68 2
        $this->di['db']->store($cart);
69
70 2
        return $cart;
71
    }
72
73 6
    public function addItem(\Model_Cart $cart, \Model_Product $product, array $data)
74
    {
75 6
        $event_params = array_merge($data, array('cart_id' => $cart->id, 'product_id' => $product->id));
76 6
        $this->di['events_manager']->fire(array('event' => 'onBeforeProductAddedToCart', 'params' => $event_params));
77
78 6
        $productService = $product->getService();
79
80 6
        if ($this->isRecurrentPricing($product)) {
81
            $required = array(
82 2
                'period' => 'Period parameter not passed',
83 2
            );
84 2
            $this->di['validator']->checkRequiredParamsForArray($required, $data);
85
86 1
            if (!$this->isPeriodEnabledForProduct($product, $data['period'])) {
87 1
                throw new \Box_Exception('Selected billing period is not valid');
88
            }
89
        }
90
91 4
        $qty =  $this->di['array_get']($data, 'quantity', 1);
92
        // check stock
93 4
        if (!$this->isStockAvailable($product, $qty)) {
94 1
            throw new \Box_Exception("I'm afraid we are out of stock.");
95
        }
96
97 3
        $addons =  $this->di['array_get']($data, 'addons', array());
98 3
        unset($data['id']);
99 3
        unset($data['addons']);
100
101 3
        $list   = array();
102 3
        $list[] = array(
103 3
            'product' => $product,
104 3
            'config'  => $data,
105
        );
106
107
        //check for required domain product
108 3
        if (method_exists($productService, 'getDomainProductFromConfig')) {
109 1
            $dc = $productService->getDomainProductFromConfig($product, $data);
110 1
            if (isset($dc['config']) && $dc['product'] && $dc['product'] instanceof \Model_Product) {
111 1
                $list[] = $dc;
112 1
            }
113 1
        }
114
115 3
        $productService = $this->di['mod_service']('Product');
116 3
        foreach ($addons as $id => $ac) {
117
            if (isset($ac['selected']) && (bool)$ac['selected']) {
118
                $addon = $productService->getAddonById($id);
119
                if ($addon instanceof \Model_Product) {
120
                    if ($this->isRecurrentPricing($addon)) {
121
122
                        $required = array(
123
                            'period' => 'Addon period parameter not passed',
124
                        );
125
                        $this->di['validator']->checkRequiredParamsForArray($required, $ac);
126
127
                        if (!$this->isPeriodEnabledForProduct($addon, $ac['period'])) {
128
                            throw new \Box_Exception('Selected billing period is not valid for addon');
129
                        }
130
                    }
131
                    $ac['parent_id'] = $product->id;
132
133
                    $list[] = array(
134
                        'product' => $addon,
135
                        'config'  => $ac,
136
                    );
137
                } else {
138
                    error_log('Addon not found by id ' . $id);
139
                }
140
            }
141 3
        }
142
143 3
        foreach ($list as $c) {
144 3
            $productFromList = $c['product'];
145 3
            $productFromListConfig = $c['config'];
146
147 3
            $productServiceFromList = $productFromList->getService();
148
149
            //@deprecated logic
150 3
            if (method_exists($productServiceFromList, 'prependOrderConfig')) {
151 1
                $productFromListConfig = $productServiceFromList->prependOrderConfig($productFromList, $productFromListConfig);
152 1
            }
153
154 3
            if (method_exists($productServiceFromList, 'attachOrderConfig')) {
155 1
                $model = $this->di['db']->load('Product', $productFromList->id);
156 1
                $productFromListConfig    = $productServiceFromList->attachOrderConfig($model, $productFromListConfig);
157 1
            }
158 3
            if (method_exists($productServiceFromList, 'validateOrderData')) {
159 2
                $productServiceFromList->validateOrderData($productFromListConfig);
160 2
            }
161 3
            if (method_exists($productServiceFromList, 'validateCustomForm')) {
162 1
                $productServiceFromList->validateCustomForm($productFromListConfig, $this->di['db']->toArray($productFromList));
163 1
            }
164 3
            $this->addProduct($cart, $productFromList, $productFromListConfig);
165 3
        }
166
167 3
        $this->di['logger']->info('Added "%s" to shopping cart', $product->title);
168
169 3
        $this->di['events_manager']->fire(array('event' => 'onAfterProductAddedToCart', 'params' => $event_params));
170
171 3
        return true;
172
    }
173
174 2
    public function isStockAvailable(\Model_Product $product, $qty)
175
    {
176 2
        if ($product->stock_control) {
177 1
            return ($product->quantity_in_stock >= $qty);
178
        }
179
180 1
        return TRUE;
181
    }
182
183 1
    public function isRecurrentPricing(\Model_Product $model)
184
    {
185 1
        $productTable = $model->getTable();
186 1
        $pricing        = $productTable->getPricingArray($model);
187 1
        return (isset($pricing['type']) && $pricing['type'] == \Model_ProductPayment::RECURRENT);
188
    }
189
190 2
    public function isPeriodEnabledForProduct(\Model_Product $model, $period)
191
    {
192 2
        $productTable = $model->getTable();
193 2
        $pricing        = $productTable->getPricingArray($model);
194 2
        if ($pricing['type'] == \Model_ProductPayment::RECURRENT) {
195 1
            return (bool)$pricing['recurrent'][$period]['enabled'];
196
        }
197
198 1
        return true;
199
    }
200
201 1
    protected function addProduct(\Model_Cart $cart, \Model_Product $product, array $data)
202
    {
203 1
        $item             = $this->di['db']->dispense('CartProduct');
204 1
        $item->cart_id    = $cart->id;
205 1
        $item->product_id = $product->id;
206 1
        $item->config     = json_encode($data);
207 1
        $this->di['db']->store($item);
208
209 1
        return true;
210
    }
211
212 2
    public function removeProduct(\Model_Cart $cart, $id, $removeAddons = true)
213
    {
214
        $bindings = array(
215 2
            ':cart_id' => $cart->id,
216
            ':id'      => $id
217 2
        );
218
219 2
        $cartProduct = $this->di['db']->findOne('CartProduct', 'id = :id AND cart_id = :cart_id', $bindings);
220 2
        if (!$cartProduct instanceof \Model_CartProduct) {
221 1
            throw new \Box_Exception('Product not found');
222
        }
223
224 1
        if ($removeAddons) {
225 1
            $allCartProducts = $this->di['db']->find('CartProduct', 'cart_id = :cart_id', array(':cart_id' => $cart->id));
226 1
            foreach ((array)$allCartProducts as $cProduct) {
227 1
                $config = json_decode($cProduct->config, true);
228 1
                if (isset($config['parent_id']) && $config['parent_id'] == $cartProduct->product_id) {
229
                    $this->di['db']->trash($cProduct);
230
                    $this->di['logger']->info('Removed product addon from shopping cart');
231
                }
232 1
            }
233 1
        }
234
235 1
        $this->di['db']->trash($cartProduct);
236
237 1
        $this->di['logger']->info('Removed product from shopping cart');
238
239 1
        return true;
240
    }
241
242 1
    public function changeCartCurrency(\Model_Cart $cart, \Model_Currency $currency)
243
    {
244 1
        $cart->currency_id = $currency->id;
245 1
        $this->di['db']->store($cart);
246
247 1
        $this->di['logger']->info('Changed shopping cart #%s currency to %s', $cart->id, $currency->title);
248
249 1
        return true;
250
    }
251
252 1
    public function resetCart(\Model_Cart $cart)
253
    {
254 1
        $cartProducts = $this->di['db']->find('CartProduct', 'cart_id = :cart_id', array(':cart_id' => $cart->id));
255 1
        foreach ($cartProducts as $cartProduct) {
256 1
            $this->di['db']->trash($cartProduct);
257 1
        }
258 1
        $cart->promo_id   = NULL;
259 1
        $cart->updated_at = date('Y-m-d H:i:s');
260 1
        $this->di['db']->store($cart);
261
262 1
        return true;
263
    }
264
265 1
    public function removePromo(\Model_Cart $cart)
266
    {
267 1
        $cart->promo_id   = NULL;
268 1
        $cart->updated_at = date('Y-m-d H:i:s');
269 1
        $this->di['db']->store($cart);
270
271 1
        $this->di['logger']->info('Removed promo code from shopping cart #%s', $cart->id);
272
273 1
        return true;
274
    }
275
276 3
    public function applyPromo(\Model_Cart $cart, \Model_Promo $promo)
277
    {
278 3
        if ($cart->promo_id == $promo->id) {
279 1
            return true;
280
        }
281
282 2
        if ($this->isEmptyCart($cart)) {
283 1
            throw new \Box_Exception('Add products to cart before applying promo code');
284
        }
285
286 1
        $cart->promo_id = $promo->id;
287 1
        $this->di['db']->store($cart);
288
289 1
        $this->di['logger']->info('Applied promo code %s to shopping cart', $promo->code);
290
291 1
        return true;
292
    }
293
294 1
    protected function isEmptyCart(\Model_Cart $cart)
295
    {
296 1
        $cartProducts = $this->di['db']->find('CartProduct', 'cart_id = :cart_id', array(':cart_id' => $cart->id));
297
298 1
        return (count($cartProducts) == 0);
299
    }
300
301 1
    public function rm(\Model_Cart $cart)
302
    {
303 1
        $cartProducts = $this->di['db']->find('CartProduct', 'cart_id = :cart_id', array(':cart_id' => $cart->id));
304
305 1
        foreach ($cartProducts as $cartProduct) {
306 1
            $this->di['db']->trash($cartProduct);
307 1
        }
308
309 1
        $this->di['db']->trash($cart);
310
311 1
        return true;
312
    }
313
314 1
    public function toApiArray(\Model_Cart $model, $deep = false, $identity = null)
315
    {
316 1
        $products = $this->getCartProducts($model);
317
318 1
        $currency = $this->di['db']->getExistingModelById('Currency', $model->currency_id);
319
320 1
        $items          = array();
321 1
        $total          = 0;
322 1
        $cart_discount  = 0;
323 1
        $items_discount = 0;
324 1
        foreach ($products as $product) {
325 1
            $p = $this->cartProductToApiArray($product);
326 1
            $total += $p['total'] + $p['setup_price'];
327 1
            $items_discount += $p['discount'];
328 1
            $items[] = $p;
329 1
        }
330
331 1
        if ($model->promo_id) {
332
            $promo = $this->di['db']->getExistingModelById('Promo', $model->promo_id, 'Promo not found');
333
            $promocode = $promo->code;
334
        } else {
335 1
            $promocode = NULL;
336
        }
337
338 1
        $currencyService = $this->di['mod_service']('currency');
339
        $result          = array(
340 1
            'promocode' => $promocode,
341 1
            'discount'  => $items_discount,
342 1
            'subtotal'  => $total,
343 1
            'total'     => $total - $items_discount,
344 1
            'items'     => $items,
345 1
            'currency'  => $currencyService->toApiArray($currency),
346
        );
347 1
348
        return $result;
349
    }
350 4
351
    public function isClientAbleToUsePromo(\Model_Client $client, \Model_Promo $promo)
352 4
    {
353 1
        if (!$this->promoCanBeApplied($promo)) {
354
            return false;
355
        }
356 3
357 1
        if (!$promo->once_per_client) {
358
            return true;
359
        }
360 2
361
        return !$this->clientHadUsedPromo($client, $promo);
362
    }
363 5
364
    public function promoCanBeApplied(\Model_Promo $promo)
365 5
    {
366 1
        if (!$promo->active) {
367
            return false;
368
        }
369 4
370 1
        if ($promo->maxuses && $promo->maxuses <= $promo->used) {
371
            return false;
372
        }
373 3
374 1
        if ($promo->start_at && (strtotime($promo->start_at) - time() > 0)) {
375
            return false;
376
        }
377 2
378 1
        if ($promo->end_at && (strtotime($promo->end_at) - time() < 0)) {
379
            return false;
380
        }
381 1
382
        return true;
383
    }
384 6
385
    public function isPromoAvailableForClientGroup(\Model_Promo $promo)
386 6
    {
387
        $clientGroups = $this->di['tools']->decodeJ($promo->client_groups);
388 6
389 2
        if (empty($clientGroups)) {
390
            return true;
391
        }
392
393 4
        try {
394 4
            $client = $this->di['loggedin_client'];
395
        } catch (\Exception $e) {
396
            $client = null;
397
        }
398 4
399 1
        if (is_null($client)){
400
            return false;
401
        }
402 3
403 1
        if (!$client->client_group_id) {
404
            return false;
405
        }
406 2
407
        return in_array($client->client_group_id, $clientGroups);
408
    }
409 1
410
    protected function clientHadUsedPromo(\Model_Client $client, \Model_Promo $promo)
411 1
    {
412 1
        $sql     = "SELECT id FROM client_order WHERE promo_id = :promo AND client_id = :cid LIMIT 1";
413
        $promoId = $this->di['db']->getCell($sql, array(':promo' => $promo->id, ':cid' => $client->id));
414 1
415
        return ($promoId !== null);
416
    }
417 1
418
    public function getCartProducts(\Model_Cart $model)
419 1
    {
420
        return $this->di['db']->find('CartProduct', 'cart_id = :cart_id ORDER BY id ASC', array(':cart_id' => $model->id));
421
    }
422 2
423
    public function checkoutCart(\Model_Cart $cart, \Model_Client $client, $gateway_id = null)
424 2
    {
425 2
        if ($cart->promo_id) {
426 2
            $promo = $this->di['db']->getExistingModelById('Promo', $cart->promo_id, 'Promo not found');
427 1
            if (!$this->isClientAbleToUsePromo($client, $promo)) {
428
                throw new \Box_Exception('You have already used this promo code. Please remove promo code and checkout again.', null, 9874);
429 1
            }
430
        }
431 1
432
        $this->di['events_manager']->fire(
433 1
            array(
434
                'event'  => 'onBeforeClientCheckout',
435 1
                'params' => array(
436 1
                    'ip'        => $this->di['request']->getClientAddress(),
437 1
                    'client_id' => $client->id,
438 1
                    'cart_id'   => $cart->id)
439 1
            )
440
        );
441 1
442
        list($order, $invoice, $orders) = $this->createFromCart($client, $gateway_id);
443 1
444
        $this->rm($cart);
445 1
446
        $this->di['logger']->info('Checked out shopping cart');
447 1
448
        $this->di['events_manager']->fire(
449 1
            array(
450
                'event'  => 'onAfterClientOrderCreate',
451 1
                'params' => array(
452 1
                    'ip'        => $this->di['request']->getClientAddress(),
453 1
                    'client_id' => $client->id,
454 1
                    'id'        => $order->id
455 1
                )
456 1
            )
457
        );
458
459 1
        $result = array(
460 1
            'gateway_id'   => $gateway_id,
461 1
            'invoice_hash' => null,
462 1
            'order_id'     => $order->id,
463 1
            'orders'       => $orders,
464
        );
465
466 1
        // invoice may not be created if total is 0
467
        if ($invoice instanceof \Model_Invoice && $invoice->status == \Model_Invoice::STATUS_UNPAID) {
468
            $result['invoice_hash'] = $invoice->hash;
469
        }
470 1
471
        return $result;
472
    }
473
474
    public function createFromCart(\Model_Client $client, $gateway_id = null)
475
    {
476
        $cart = $this->getSessionCart();
477
        $ca = $this->toApiArray($cart);
478
        if (count($ca['items']) == 0) {
479
            throw new \Box_Exception('Can not checkout empty cart.');
480
        }
481
482
483
        $currency = $this->di['db']->getExistingModelById('Currency', $cart->currency_id, 'Currency not found.');
484
485
        //set default client currency
486
        if (!$client->currency) {
487
            $client->currency = $currency->code;
488
            $this->di['db']->store($client);
489
        }
490
491
        if ($client->currency != $currency->code) {
492
            throw new \Box_Exception('Selected currency :selected does not match your profile currency :code. Please change cart currency to continue.',
493
                array(':selected' => $currency->code, ':code' => $client->currency));
494
        }
495
496
        $clientService = $this->di['mod_service']('client');
497
        $taxed         = $clientService->isClientTaxable($client);
498
499
        $orders        = array();
500
        $invoice_items = array();
501
        $master_order  = null;
502
        $i             = 0;
503
504
        foreach ($this->getCartProducts($cart) as $p) {
505
            $item = $this->cartProductToApiArray($p);
506
507
            $order             = $this->di['db']->dispense('ClientOrder');
508
            $order->client_id  = $client->id;
509
            $order->promo_id   = $cart->promo_id;
510
            $order->product_id = $item['product_id'];
511
            $order->form_id    = $item['form_id'];
512
513
            $order->group_id       = $cart->id;
514
            $order->group_master   = ($i == 0);
515
            $order->invoice_option = 'issue-invoice';
516
            $order->title          = $item['title'];
517
            $order->currency       = $currency->code;
518
            $order->service_type   = $item['type'];
519
            $order->unit           = $this->di['array_get']($item, 'unit', NULL);
520
            $order->period         = $this->di['array_get']($item, 'period', NULL);
521
            $order->quantity       = $this->di['array_get']($item, 'quantity', NULL);
522
            $order->price          = $item['price'] * $currency->conversion_rate;
523
            $order->discount       = $item['discount_price'] * $currency->conversion_rate;
524
            $order->status         = \Model_ClientOrder::STATUS_PENDING_SETUP;
525
            $order->notes          = $this->di['array_get']($item, 'notes', NULL);
526
            $order->config         = json_encode($item);
527
            $order->created_at     = date('Y-m-d H:i:s');
528
            $order->updated_at     = date('Y-m-d H:i:s');
529
            $this->di['db']->store($order);
530
531
            $orders[] = $order;
532
533
            // mark promo as used
534
            if ($cart->promo_id) {
535
                $promo = $this->di['db']->getExistingModelById('Promo', $cart->promo_id, 'Promo not found.');
536
                $this->usePromo($promo);
537
538
                //set promo info for later use
539
                $order->promo_recurring = $promo->recurring;
540
                $order->promo_used      = 1;
541
                $this->di['db']->store($order);
542
            }
543
544
            $orderService = $this->di['mod_service']('order');
545
            $orderService->saveStatusChange($order, 'Order created');
546
547
            $invoice_items[] = array(
548
                'title'    => $order->title,
549
                'price'    => $order->price,
550
                'quantity' => $order->quantity,
551
                'unit'     => $order->unit,
552
                'period'   => $order->period,
553
                'taxed'    => $taxed,
554
                'type'     => \Model_InvoiceItem::TYPE_ORDER,
555
                'rel_id'   => $order->id,
556
                'task'     => \Model_InvoiceItem::TASK_ACTIVATE,
557
            );
558
559
            if($order->discount > 0){ 
560
                $invoice_items[] = array(
561
                    'title'    => __('Discount: :product', array(':product' => $order->title)),
562
                    'price'    => $order->discount * -1,
563
                    'quantity' => 1,
564
                    'unit'     => 'discount',
565
                    'rel_id'    => $order->id,
566
                    'taxed'    => $taxed,
567
                );
568
            }
569
570
            if ($item['setup_price'] > 0) {
571
                $setup_price     = ($item['setup_price'] * $currency->conversion_rate) - ($item['discount_setup'] * $currency->conversion_rate);
572
                $invoice_items[] = array(
573
                    'title'    => __(':product setup', array(':product' => $order->title)),
574
                    'price'    => $setup_price,
575
                    'quantity' => 1,
576
                    'unit'     => 'service',
577
                    'taxed'    => $taxed,
578
                );
579
            }
580
581
            //define master order to be returned
582
            if (null === $master_order) {
583
                $master_order = $order;
584
            }
585
586
            $i++;
587
        }
588
589
        if ($ca['total'] > 0) { //crete invoice if order total > 0
590
591
            $invoiceService =  $this->di['mod_service']('Invoice');
592
            $invoiceModel   = $invoiceService->prepareInvoice($client, array('client_id' => $client->id, 'items' => $invoice_items, 'gateway_id' => $gateway_id));
593
594
            $clientBalanceService = $this->di['mod_service']('Client', 'Balance');
595
            $balanceAmount = $clientBalanceService->getClientBalance($client);
596
            $useCredits = $balanceAmount >= $ca['total'];
597
598
            $invoiceService->approveInvoice($invoiceModel, array('id' => $invoiceModel->id, 'use_credits' => $useCredits));
599
600
            if ($invoiceModel->status == \Model_Invoice::STATUS_UNPAID) {
601
                foreach ($orders as $order) {
602
                    $order->unpaid_invoice_id = $invoiceModel->id;
603
                    $this->di['db']->store($order);
604
                }
605
            }
606
        }
607
608
        //activate orders if product is setup to be activated after order place or order total is $0
609
        $orderService = $this->di['mod_service']('Order');
610
        $ids = array();
611
        foreach ($orders as $order) {
612
            $ids[] = $order->id;
613
            $oa      = $orderService->toApiArray($order, false, $client);
614
            $product = $this->di['db']->getExistingModelById('Product', $oa['product_id']);
615
            try {
616
                if ($product->setup == \Model_ProductTable::SETUP_AFTER_ORDER){
617
                    $orderService->activateOrder($order);
618
                }
619
620
                if ($ca['total'] <= 0 && $product->setup == \Model_ProductTable::SETUP_AFTER_PAYMENT && $oa['total'] - $oa['discount'] <= 0){
621
                    $orderService->activateOrder($order);
622
                }
623
624
                if ($ca['total'] > 0 && $product->setup == \Model_ProductTable::SETUP_AFTER_PAYMENT && $invoiceModel->status == \Model_Invoice::STATUS_PAID ){
625
                    $orderService->activateOrder($order);
626
                }
627
            }
628
            catch (\Exception $e) {
629
                error_log($e->getMessage());
630
                $status = 'error';
631 1
                $notes  = 'Order could not be activated after checkout due to error: ' . $e->getMessage();
632
                $orderService->orderStatusAdd($order, $status, $notes);
633 1
            }
634 1
        }
635 1
636 1
        return array(
637
            $master_order,
638 1
            isset($invoiceModel) ? $invoiceModel : null,
639
            $ids,
640 1
        );
641
    }
642
643
    public function usePromo(\Model_Promo $promo)
644
    {
645
        $promo->used++;
646
        $promo->updated_at = date('Y-m-d H:i:s');
647
        $this->di['db']->store($promo);
648
    }
649
650
    public function findActivePromoByCode($code)
651
    {
652
        return $this->di['db']->findOne('Promo', 'code = :code AND active = 1 ORDER BY id ASC', array(':code' => $code));
653
    }
654
655
    private function getItemPrice(\Model_CartProduct $model)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
656
    {
657
        $product = $this->di['db']->load('Product', $model->product_id);
658
        $config = $this->getItemConfig($model);
659
        $repo = $product->getTable();
660
        return $repo->getProductPrice($product, $config);
661
    }
662
663
    private function getItemSetupPrice(\Model_CartProduct $model)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
664
    {
665
        $product = $this->di['db']->load('Product', $model->product_id);
666
        $config = $this->getItemConfig($model);
667
        $repo = $product->getTable();
668
        return $repo->getProductSetupPrice($product, $config);
669
    }
670
671
    /**
672
     * Function checks if product is related to other products in cart
673
     * If relation exists then count discount for this
674
     *
675
     * @param \Model_Cart $cart
676
     * @param \Model_CartProduct $model
677
     * @return number
678
     */
679
    protected function getRelatedItemsDiscount(\Model_Cart $cart, \Model_CartProduct $model)
680
    {
681
        $product = $this->di['db']->load('Product', $model->product_id);
682
        $repo = $product->getTable();
683
        $config = $this->getItemConfig($model);
684
685
        $discount = 0;
686
        if(method_exists($repo, 'getRelatedDiscount')) {
687
            $list = array();
688
            $products = $this->getCartProducts($cart);
689
            foreach($products as $p) {
690
                $item = $this->di['db']->toArray($p);
691
                $item['config'] = $this->getItemConfig($p);
692
                $list[] = $item;
693
            }
694
            $discount = $repo->getRelatedDiscount($list, $product, $config);
695
        }
696
        return $discount;
697
    }
698
699
    private function getItemTitle(\Model_CartProduct $model)
700
    {
701
        $product = $this->di['db']->load('Product', $model->product_id);
702
        $config = $this->getItemConfig($model);
703
        $service = $product->getService();
704
        if(method_exists($service, 'getCartProductTitle')) {
705
            return $service->getCartProductTitle($product, $config);
706
        } else {
707
            return __(':product_title', array(':product_title'=>$product->title));
708
        }
709
    }
710
711
    protected function getItemPromoDiscount(\Model_CartProduct $model, \Model_Promo $promo)
712
    {
713
        $product = $this->di['db']->load('Product', $model->product_id);
714
        $repo = $this->di['mod_service']('product');
715
        $config = $this->getItemConfig($model);
716
        return $repo->getProductDiscount($product, $promo, $config);
717
    }
718
719
    public function getItemConfig(\Model_CartProduct $model)
720
    {
721
        return $this->di['tools']->decodeJ($model->config);
722
    }
723
724
    public function cartProductToApiArray(\Model_CartProduct $model)
725
    {
726
        $product = $this->di['db']->load('Product', $model->product_id);
727
        $repo = $product->getTable();
728
        $config = $this->getItemConfig($model);
729
        $setup = $repo->getProductSetupPrice($product, $config);
730
        $price = $repo->getProductPrice($product, $config);
731
        $qty =  $this->di['array_get']($config, 'quantity', 1) ;
732
733
        list ($discount_price, $discount_setup) = $this->getProductDiscount($model, $setup);
734
735
        $discount_total = $discount_price + $discount_setup;
736
737
        $subtotal = ($price * $qty); 
738
        if(abs($discount_total) > ($subtotal + $setup) ) {
739
            $discount_total = $subtotal;
740
            $discount_price = $subtotal;
741
        }
742
743
        $data = array_merge($config, array(
744
            'id'            => $model->id,
745
            'product_id'    => $product->id,
746
            'form_id'       => $product->form_id,
747
            'title'         => $this->getItemTitle($model),
748
            'type'          => $product->type,
749 3
            'quantity'      => $qty,
750
            'unit'          => $repo->getUnit($product),
751 3
            'price'         => $price,
752 3
            'setup_price'   => $setup,
753 3
            'discount'      => $discount_total,
754 3
            'discount_price'=> $discount_price,
755 2
            'discount_setup'=> $discount_setup,
756 2
            'total'         => $subtotal,
757
        ));
758 2
        return $data;
759 1
    }
760 1
761 2
    public function getProductDiscount(\Model_CartProduct $cartProduct, $setup)
762 3
    {
763
        $cart = $this->di['db']->load('Cart', $cartProduct->cart_id);
764
        $discount_price = $this->getRelatedItemsDiscount($cart, $cartProduct);
765
        $discount_setup = 0; // discount for setup price
766
        if($cart->promo_id) {
767
            $promo = $this->di['db']->getExistingModelById('Promo', $cart->promo_id, 'Promo not found');
768
            //Promo discount should override related item discount
769
            $discount_price = $this->getItemPromoDiscount($cartProduct, $promo);
770
771
            if($promo->freesetup) {
772
                $discount_setup = $setup;
773
            }
774
        }
775
        return array($discount_price, $discount_setup);
776
    }
777
}