Passed
Push — master ( ea32e7...68af9c )
by Julito
09:25
created

BuyCoursesPlugin::saveCurrency()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 9
nc 1
nop 1
dl 0
loc 14
rs 9.9666
c 0
b 0
f 0
1
<?php
2
/* For license terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Entity\Course;
5
use Chamilo\CoreBundle\Entity\Session;
6
use Doctrine\ORM\Query\Expr\Join;
7
8
/**
9
 * Plugin class for the BuyCourses plugin.
10
 *
11
 * @package chamilo.plugin.buycourses
12
 *
13
 * @author  Jose Angel Ruiz <[email protected]>
14
 * @author  Imanol Losada <[email protected]>
15
 * @author  Alex Aragón <[email protected]>
16
 * @author  Angel Fernando Quiroz Campos <[email protected]>
17
 * @author  José Loguercio Silva  <[email protected]>
18
 * @author  Julio Montoya
19
 */
20
class BuyCoursesPlugin extends Plugin
21
{
22
    const TABLE_PAYPAL = 'plugin_buycourses_paypal_account';
23
    const TABLE_CURRENCY = 'plugin_buycourses_currency';
24
    const TABLE_ITEM = 'plugin_buycourses_item';
25
    const TABLE_ITEM_BENEFICIARY = 'plugin_buycourses_item_rel_beneficiary';
26
    const TABLE_SALE = 'plugin_buycourses_sale';
27
    const TABLE_TRANSFER = 'plugin_buycourses_transfer';
28
    const TABLE_COMMISSION = 'plugin_buycourses_commission';
29
    const TABLE_PAYPAL_PAYOUTS = 'plugin_buycourses_paypal_payouts';
30
    const TABLE_SERVICES = 'plugin_buycourses_services';
31
    const TABLE_SERVICES_SALE = 'plugin_buycourses_service_sale';
32
    const TABLE_CULQI = 'plugin_buycourses_culqi';
33
    const TABLE_GLOBAL_CONFIG = 'plugin_buycourses_global_config';
34
    const TABLE_INVOICE = 'plugin_buycourses_invoices';
35
    const PRODUCT_TYPE_COURSE = 1;
36
    const PRODUCT_TYPE_SESSION = 2;
37
    const PAYMENT_TYPE_PAYPAL = 1;
38
    const PAYMENT_TYPE_TRANSFER = 2;
39
    const PAYMENT_TYPE_CULQI = 3;
40
    const PAYOUT_STATUS_CANCELED = 2;
41
    const PAYOUT_STATUS_PENDING = 0;
42
    const PAYOUT_STATUS_COMPLETED = 1;
43
    const SALE_STATUS_CANCELED = -1;
44
    const SALE_STATUS_PENDING = 0;
45
    const SALE_STATUS_COMPLETED = 1;
46
    const SERVICE_STATUS_PENDING = 0;
47
    const SERVICE_STATUS_COMPLETED = 1;
48
    const SERVICE_STATUS_CANCELLED = -1;
49
    const SERVICE_TYPE_USER = 1;
50
    const SERVICE_TYPE_COURSE = 2;
51
    const SERVICE_TYPE_SESSION = 3;
52
    const SERVICE_TYPE_LP_FINAL_ITEM = 4;
53
    const CULQI_INTEGRATION_TYPE = 'INTEG';
54
    const CULQI_PRODUCTION_TYPE = 'PRODUC';
55
    const TAX_APPLIES_TO_ALL = 1;
56
    const TAX_APPLIES_TO_ONLY_COURSE = 2;
57
    const TAX_APPLIES_TO_ONLY_SESSION = 3;
58
    const TAX_APPLIES_TO_ONLY_SERVICES = 4;
59
    const PAGINATION_PAGE_SIZE = 5;
60
61
    public $isAdminPlugin = true;
62
63
    /**
64
     * BuyCoursesPlugin constructor.
65
     */
66
    public function __construct()
67
    {
68
        parent::__construct(
69
            '5.0',
70
            "
71
                Jose Angel Ruiz - NoSoloRed (original author) <br/>
72
                Francis Gonzales and Yannick Warnier - BeezNest (integration) <br/>
73
                Alex Aragón - BeezNest (Design icons and css styles) <br/>
74
                Imanol Losada - BeezNest (introduction of sessions purchase) <br/>
75
                Angel Fernando Quiroz Campos - BeezNest (cleanup and new reports) <br/>
76
                José Loguercio Silva - BeezNest (Payouts and buy Services) <br/>
77
                Julio Montoya
78
            ",
79
            [
80
                'show_main_menu_tab' => 'boolean',
81
                'public_main_menu_tab' => 'boolean',
82
                'include_sessions' => 'boolean',
83
                'include_services' => 'boolean',
84
                'paypal_enable' => 'boolean',
85
                'transfer_enable' => 'boolean',
86
                'culqi_enable' => 'boolean',
87
                'commissions_enable' => 'boolean',
88
                'unregistered_users_enable' => 'boolean',
89
                'hide_free_text' => 'boolean',
90
                'invoicing_enable' => 'boolean',
91
                'tax_enable' => 'boolean',
92
                'use_currency_symbol' => 'boolean',
93
            ]
94
        );
95
    }
96
97
    /**
98
     * @return BuyCoursesPlugin
99
     */
100
    public static function create()
101
    {
102
        static $result = null;
103
104
        return $result ? $result : $result = new self();
105
    }
106
107
    /**
108
     * Check if plugin is enabled.
109
     *
110
     * @return bool
111
     */
112
    public function isEnabled()
113
    {
114
        return $this->get('paypal_enable') || $this->get('transfer_enable') || $this->get('culqi_enable');
115
    }
116
117
    /**
118
     * This method creates the tables required to this plugin.
119
     */
120
    public function install()
121
    {
122
        $tablesToBeCompared = [
123
            self::TABLE_PAYPAL,
124
            self::TABLE_TRANSFER,
125
            self::TABLE_CULQI,
126
            self::TABLE_ITEM_BENEFICIARY,
127
            self::TABLE_ITEM,
128
            self::TABLE_SALE,
129
            self::TABLE_CURRENCY,
130
            self::TABLE_COMMISSION,
131
            self::TABLE_PAYPAL_PAYOUTS,
132
            self::TABLE_SERVICES,
133
            self::TABLE_SERVICES_SALE,
134
            self::TABLE_GLOBAL_CONFIG,
135
            self::TABLE_INVOICE,
136
        ];
137
        $em = Database::getManager();
138
        $cn = $em->getConnection();
139
        $sm = $cn->getSchemaManager();
140
        $tables = $sm->tablesExist($tablesToBeCompared);
141
142
        if ($tables) {
143
            return false;
144
        }
145
146
        require_once api_get_path(SYS_PLUGIN_PATH).'buycourses/database.php';
147
    }
148
149
    /**
150
     * This method drops the plugin tables.
151
     */
152
    public function uninstall()
153
    {
154
        $tablesToBeDeleted = [
155
            self::TABLE_PAYPAL,
156
            self::TABLE_TRANSFER,
157
            self::TABLE_CULQI,
158
            self::TABLE_ITEM_BENEFICIARY,
159
            self::TABLE_ITEM,
160
            self::TABLE_SALE,
161
            self::TABLE_CURRENCY,
162
            self::TABLE_COMMISSION,
163
            self::TABLE_PAYPAL_PAYOUTS,
164
            self::TABLE_SERVICES_SALE,
165
            self::TABLE_SERVICES,
166
            self::TABLE_GLOBAL_CONFIG,
167
            self::TABLE_INVOICE,
168
        ];
169
170
        foreach ($tablesToBeDeleted as $tableToBeDeleted) {
171
            $table = Database::get_main_table($tableToBeDeleted);
172
            $sql = "DROP TABLE IF EXISTS $table";
173
            Database::query($sql);
174
        }
175
        $this->manageTab(false);
176
    }
177
178
    public function update()
179
    {
180
        $table = self::TABLE_GLOBAL_CONFIG;
181
        $sql = "SHOW COLUMNS FROM $table WHERE Field = 'global_tax_perc'";
182
        $res = Database::query($sql);
183
184
        if (Database::num_rows($res) === 0) {
185
            $sql = "ALTER TABLE $table ADD (
186
                sale_email varchar(255) NOT NULL,
187
                global_tax_perc int unsigned NOT NULL,
188
                tax_applies_to int unsigned NOT NULL,
189
                tax_name varchar(255) NOT NULL,
190
                seller_name varchar(255) NOT NULL,
191
                seller_id varchar(255) NOT NULL,
192
                seller_address varchar(255) NOT NULL,
193
                seller_email varchar(255) NOT NULL,
194
                next_number_invoice int unsigned NOT NULL,
195
                invoice_series varchar(255) NOT NULL
196
            )";
197
            $res = Database::query($sql);
198
            if (!$res) {
0 ignored issues
show
introduced by
$res is of type Doctrine\DBAL\Driver\Statement, thus it always evaluated to true.
Loading history...
199
                echo Display::return_message($this->get_lang('ErrorUpdateFieldDB'), 'warning');
200
            }
201
        }
202
203
        $table = self::TABLE_ITEM;
204
        $sql = "SHOW COLUMNS FROM $table WHERE Field = 'tax_perc'";
205
        $res = Database::query($sql);
206
207
        if (Database::num_rows($res) === 0) {
208
            $sql = "ALTER TABLE $table ADD tax_perc int unsigned NULL";
209
            $res = Database::query($sql);
210
            if (!$res) {
0 ignored issues
show
introduced by
$res is of type Doctrine\DBAL\Driver\Statement, thus it always evaluated to true.
Loading history...
211
                echo Display::return_message($this->get_lang('ErrorUpdateFieldDB'), 'warning');
212
            }
213
        }
214
215
        $table = self::TABLE_SERVICES;
216
        $sql = "SHOW COLUMNS FROM $table WHERE Field = 'tax_perc'";
217
        $res = Database::query($sql);
218
219
        if (Database::num_rows($res) === 0) {
220
            $sql = "ALTER TABLE $table ADD tax_perc int unsigned NULL";
221
            $res = Database::query($sql);
222
            if (!$res) {
0 ignored issues
show
introduced by
$res is of type Doctrine\DBAL\Driver\Statement, thus it always evaluated to true.
Loading history...
223
                echo Display::return_message($this->get_lang('ErrorUpdateFieldDB'), 'warning');
224
            }
225
        }
226
227
        $table = self::TABLE_SALE;
228
        $sql = "SHOW COLUMNS FROM $table WHERE Field = 'tax_perc'";
229
        $res = Database::query($sql);
230
231
        if (Database::num_rows($res) === 0) {
232
            $sql = "ALTER TABLE $table ADD (
233
                price_without_tax decimal(10,2) NULL,
234
                tax_perc int unsigned NULL,
235
                tax_amount decimal(10,2) NULL,
236
                invoice int unsigned NULL
237
            )";
238
            $res = Database::query($sql);
239
            if (!$res) {
0 ignored issues
show
introduced by
$res is of type Doctrine\DBAL\Driver\Statement, thus it always evaluated to true.
Loading history...
240
                echo Display::return_message($this->get_lang('ErrorUpdateFieldDB'), 'warning');
241
            }
242
        }
243
244
        $table = self::TABLE_SERVICES_SALE;
245
        $sql = "SHOW COLUMNS FROM $table WHERE Field = 'tax_perc'";
246
        $res = Database::query($sql);
247
248
        if (Database::num_rows($res) === 0) {
249
            $sql = "ALTER TABLE $table ADD (
250
                price_without_tax decimal(10,2) NULL,
251
                tax_perc int unsigned NULL,
252
                tax_amount decimal(10,2) NULL,
253
                invoice int unsigned NULL
254
            )";
255
            $res = Database::query($sql);
256
            if (!$res) {
0 ignored issues
show
introduced by
$res is of type Doctrine\DBAL\Driver\Statement, thus it always evaluated to true.
Loading history...
257
                echo Display::return_message($this->get_lang('ErrorUpdateFieldDB'), 'warning');
258
            }
259
        }
260
261
        $table = self::TABLE_INVOICE;
262
        $sql = "CREATE TABLE IF NOT EXISTS $table (
263
            id int unsigned NOT NULL AUTO_INCREMENT,
264
            sale_id int unsigned NOT NULL,
265
            is_service int unsigned NOT NULL,
266
            num_invoice int unsigned NOT NULL,
267
            year int(4) unsigned NOT NULL,
268
            serie varchar(255) NOT NULL,
269
            date_invoice datetime NOT NULL,
270
            PRIMARY KEY (id)
271
        )";
272
        Database::query($sql);
273
274
        Display::addFlash(
275
            Display::return_message(
276
                $this->get_lang('Updated'),
277
                'info',
278
                false
279
            )
280
        );
281
282
        $fieldlabel = 'buycourses_company';
283
        $fieldtype = '1';
284
        $fieldtitle = $this->get_lang('Company');
285
        $fielddefault = '';
286
        UserManager::create_extra_field($fieldlabel, $fieldtype, $fieldtitle, $fielddefault);
287
288
        $fieldlabel = 'buycourses_vat';
289
        $fieldtype = '1';
290
        $fieldtitle = $this->get_lang('VAT');
291
        $fielddefault = '';
292
        UserManager::create_extra_field($fieldlabel, $fieldtype, $fieldtitle, $fielddefault);
293
294
        $fieldlabel = 'buycourses_address';
295
        $fieldtype = '1';
296
        $fieldtitle = $this->get_lang('Address');
297
        $fielddefault = '';
298
        UserManager::create_extra_field($fieldlabel, $fieldtype, $fieldtitle, $fielddefault);
299
300
        header('Location: '.api_get_path(WEB_PLUGIN_PATH).'buycourses');
301
        exit;
302
    }
303
304
    /**
305
     * This function verify if the plugin is enable and return the price info for a course or session in the new grid
306
     * catalog for 1.11.x , the main purpose is to show if a course or session is in sale it shows in the main platform
307
     * course catalog so the old buycourses plugin catalog can be deprecated.
308
     *
309
     * @param int $productId   course or session id
310
     * @param int $productType course or session type
311
     *
312
     * @return mixed bool|string html
313
     */
314
    public function buyCoursesForGridCatalogValidator($productId, $productType)
315
    {
316
        $return = [];
317
        $paypal = $this->get('paypal_enable') === 'true';
318
        $transfer = $this->get('transfer_enable') === 'true';
319
        $hideFree = $this->get('hide_free_text') === 'true';
320
321
        if ($paypal || $transfer) {
322
            $item = $this->getItemByProduct($productId, $productType);
323
            $html = '<div class="buycourses-price">';
324
            if ($item) {
325
                $html .= '<span class="label label-primary label-price">
326
                            <strong>'.$item['total_price_formatted'].'</strong>
327
                          </span>';
328
                $return['verificator'] = true;
329
            } else {
330
                if ($hideFree == false) {
331
                    $html .= '<span class="label label-primary label-free">
332
                                <strong>'.$this->get_lang('Free').'</strong>
333
                              </span>';
334
                }
335
                $return['verificator'] = false;
336
            }
337
            $html .= '</div>';
338
            $return['html'] = $html;
339
340
            return $return;
341
        }
342
343
        return false;
344
    }
345
346
    /**
347
     * Return the buyCourses plugin button to buy the course.
348
     *
349
     * @param int $productId
350
     * @param int $productType
351
     *
352
     * @return string $html
353
     */
354
    public function returnBuyCourseButton($productId, $productType)
355
    {
356
        $productId = (int) $productId;
357
        $productType = (int) $productType;
358
        $url = api_get_path(WEB_PLUGIN_PATH).'buycourses/src/process.php?i='.$productId.'&t='.$productType;
359
        $html = '<a class="btn btn-success btn-sm" title="'.$this->get_lang('Buy').'" href="'.$url.'">'.
360
            Display::returnFontAwesomeIcon('shopping-cart').'</a>';
361
362
        return $html;
363
    }
364
365
    /**
366
     * Get the currency for sales.
367
     *
368
     * @return array The selected currency. Otherwise return false
369
     */
370
    public function getSelectedCurrency()
371
    {
372
        return Database::select(
373
            '*',
374
            Database::get_main_table(self::TABLE_CURRENCY),
375
            [
376
                'where' => ['status = ?' => true],
377
            ],
378
            'first'
379
        );
380
    }
381
382
    /**
383
     * Get a list of currencies.
384
     *
385
     * @return array The currencies. Otherwise return false
386
     */
387
    public function getCurrencies()
388
    {
389
        return Database::select(
390
            '*',
391
            Database::get_main_table(self::TABLE_CURRENCY)
392
        );
393
    }
394
395
    /**
396
     * Save the selected currency.
397
     *
398
     * @param int $selectedId The currency Id
399
     */
400
    public function saveCurrency($selectedId)
401
    {
402
        $currencyTable = Database::get_main_table(
403
            self::TABLE_CURRENCY
404
        );
405
406
        Database::update(
407
            $currencyTable,
408
            ['status' => 0]
409
        );
410
        Database::update(
411
            $currencyTable,
412
            ['status' => 1],
413
            ['id = ?' => (int) $selectedId]
414
        );
415
    }
416
417
    /**
418
     * Save the PayPal configuration params.
419
     *
420
     * @param array $params
421
     *
422
     * @return int Rows affected. Otherwise return false
423
     */
424
    public function savePaypalParams($params)
425
    {
426
        return Database::update(
427
            Database::get_main_table(self::TABLE_PAYPAL),
428
            [
429
                'username' => $params['username'],
430
                'password' => $params['password'],
431
                'signature' => $params['signature'],
432
                'sandbox' => isset($params['sandbox']),
433
            ],
434
            ['id = ?' => 1]
435
        );
436
    }
437
438
    /**
439
     * Gets the stored PayPal params.
440
     *
441
     * @return array
442
     */
443
    public function getPaypalParams()
444
    {
445
        return Database::select(
446
            '*',
447
            Database::get_main_table(self::TABLE_PAYPAL),
448
            ['id = ?' => 1],
449
            'first'
450
        );
451
    }
452
453
    /**
454
     * Save a transfer account information.
455
     *
456
     * @param array $params The transfer account
457
     *
458
     * @return int Rows affected. Otherwise return false
459
     */
460
    public function saveTransferAccount($params)
461
    {
462
        return Database::insert(
463
            Database::get_main_table(self::TABLE_TRANSFER),
464
            [
465
                'name' => $params['tname'],
466
                'account' => $params['taccount'],
467
                'swift' => $params['tswift'],
468
            ]
469
        );
470
    }
471
472
    /**
473
     * Get a list of transfer accounts.
474
     *
475
     * @return array
476
     */
477
    public function getTransferAccounts()
478
    {
479
        return Database::select(
480
            '*',
481
            Database::get_main_table(self::TABLE_TRANSFER)
482
        );
483
    }
484
485
    /**
486
     * Remove a transfer account.
487
     *
488
     * @param int $id The transfer account ID
489
     *
490
     * @return int Rows affected. Otherwise return false
491
     */
492
    public function deleteTransferAccount($id)
493
    {
494
        return Database::delete(
495
            Database::get_main_table(self::TABLE_TRANSFER),
496
            ['id = ?' => (int) $id]
497
        );
498
    }
499
500
    /**
501
     * Get registered item data.
502
     *
503
     * @param int $itemId The item ID
504
     *
505
     * @return array
506
     */
507
    public function getItem($itemId)
508
    {
509
        return Database::select(
510
            '*',
511
            Database::get_main_table(self::TABLE_ITEM),
512
            [
513
                'where' => ['id = ?' => (int) $itemId],
514
            ],
515
            'first'
516
        );
517
    }
518
519
    /**
520
     * Get the item data.
521
     *
522
     * @param int $productId The item ID
523
     * @param int $itemType  The item type
524
     *
525
     * @return array
526
     */
527
    public function getItemByProduct($productId, $itemType)
528
    {
529
        $buyItemTable = Database::get_main_table(self::TABLE_ITEM);
530
        $buyCurrencyTable = Database::get_main_table(self::TABLE_CURRENCY);
531
532
        $fakeItemFrom = "
533
            $buyItemTable i
534
            INNER JOIN $buyCurrencyTable c
535
                ON i.currency_id = c.id
536
        ";
537
538
        $product = Database::select(
539
            ['i.*', 'c.iso_code'],
540
            $fakeItemFrom,
541
            [
542
                'where' => [
543
                    'i.product_id = ? AND i.product_type = ?' => [
544
                        (int) $productId,
545
                        (int) $itemType,
546
                    ],
547
                ],
548
            ],
549
            'first'
550
        );
551
552
        if (empty($product)) {
553
            return false;
554
        }
555
556
        $this->setPriceSettings($product, self::TAX_APPLIES_TO_ONLY_COURSE);
557
558
        return $product;
559
    }
560
561
    /**
562
     * List courses details from the configuration page.
563
     *
564
     * @return array
565
     */
566
    public function getCourseList($first, $maxResults)
567
    {
568
        return $this->getCourses($first, $maxResults);
569
    }
570
571
    /**
572
     * Lists current user session details, including each session course details.
573
     *
574
     * @param int    $start
575
     * @param int    $end
576
     * @param string $name Optional. The name filter
577
     * @param int    $min  Optional. The minimum price filter
578
     * @param int    $max  Optional. The maximum price filter
579
     *
580
     * @return array
581
     */
582
    public function getCatalogSessionList($start, $end, $name = null, $min = 0, $max = 0, $typeResult = 'all')
583
    {
584
        $sessions = $this->filterSessionList($start, $end, $name, $min, $max, $typeResult);
585
586
        if ($typeResult === 'count') {
587
            return $sessions;
588
        }
589
590
        $sessionCatalog = [];
591
        // loop through all sessions
592
        foreach ($sessions as $session) {
593
            $sessionCourses = $session->getCourses();
594
595
            if (empty($sessionCourses)) {
596
                continue;
597
            }
598
599
            $item = $this->getItemByProduct(
600
                $session->getId(),
601
                self::PRODUCT_TYPE_SESSION
602
            );
603
604
            if (empty($item)) {
605
                continue;
606
            }
607
608
            $sessionData = $this->getSessionInfo($session->getId());
609
            $sessionData['coach'] = $session->getGeneralCoach()->getCompleteName();
610
            $sessionData['enrolled'] = $this->getUserStatusForSession(
611
                api_get_user_id(),
612
                $session
613
            );
614
            $sessionData['courses'] = [];
615
616
            foreach ($sessionCourses as $sessionCourse) {
617
                $course = $sessionCourse->getCourse();
618
619
                $sessionCourseData = [
620
                    'title' => $course->getTitle(),
621
                    'coaches' => [],
622
                ];
623
624
                $userCourseSubscriptions = $session->getUserCourseSubscriptionsByStatus(
625
                    $course,
626
                    Chamilo\CoreBundle\Entity\Session::COACH
627
                );
628
629
                foreach ($userCourseSubscriptions as $userCourseSubscription) {
630
                    $user = $userCourseSubscription->getUser();
631
                    $sessionCourseData['coaches'][] = $user->getCompleteName();
632
                }
633
                $sessionData['courses'][] = $sessionCourseData;
634
            }
635
636
            $sessionCatalog[] = $sessionData;
637
        }
638
639
        return $sessionCatalog;
640
    }
641
642
    /**
643
     * Lists current user course details.
644
     *
645
     * @param string $name Optional. The name filter
646
     * @param int    $min  Optional. The minimum price filter
647
     * @param int    $max  Optional. The maximum price filter
648
     *
649
     * @return array
650
     */
651
    public function getCatalogCourseList($first, $pageSize, $name = null, $min = 0, $max = 0, $typeResult = 'all')
652
    {
653
        $courses = $this->filterCourseList($first, $pageSize, $name, $min, $max, $typeResult);
654
655
        if ($typeResult === 'count') {
656
            return $courses;
657
        }
658
659
        if (empty($courses)) {
660
            return [];
661
        }
662
663
        $courseCatalog = [];
664
        foreach ($courses as $course) {
665
            $item = $this->getItemByProduct(
666
                $course->getId(),
667
                self::PRODUCT_TYPE_COURSE
668
            );
669
670
            if (empty($item)) {
671
                continue;
672
            }
673
674
            $courseItem = [
675
                'id' => $course->getId(),
676
                'title' => $course->getTitle(),
677
                'code' => $course->getCode(),
678
                'course_img' => null,
679
                'item' => $item,
680
                'teachers' => [],
681
                'enrolled' => $this->getUserStatusForCourse(api_get_user_id(), $course),
682
            ];
683
684
            foreach ($course->getTeachers() as $courseUser) {
685
                $teacher = $courseUser->getUser();
686
                $courseItem['teachers'][] = $teacher->getCompleteName();
687
            }
688
689
            // Check images
690
            $possiblePath = api_get_path(SYS_COURSE_PATH);
691
            $possiblePath .= $course->getDirectory();
692
            $possiblePath .= '/course-pic.png';
693
694
            if (file_exists($possiblePath)) {
695
                $courseItem['course_img'] = api_get_path(WEB_COURSE_PATH).$course->getDirectory().'/course-pic.png';
696
            }
697
            $courseCatalog[] = $courseItem;
698
        }
699
700
        return $courseCatalog;
701
    }
702
703
    /**
704
     * @param $price
705
     * @param $isoCode
706
     *
707
     * @return string
708
     */
709
    public function getPriceWithCurrencyFromIsoCode($price, $isoCode)
710
    {
711
        $useSymbol = $this->get('use_currency_symbol') === 'true';
712
713
        $result = $isoCode.' '.$price;
714
        if ($useSymbol) {
715
            if ($isoCode === 'BRL') {
716
                $symbol = 'R$';
717
            } else {
718
                $symbol = Symfony\Component\Intl\Intl::getCurrencyBundle()->getCurrencySymbol($isoCode);
719
            }
720
            $result = $symbol.' '.$price;
721
        }
722
723
        return $result;
724
    }
725
726
    /**
727
     * Get course info.
728
     *
729
     * @param int $courseId The course ID
730
     *
731
     * @return array
732
     */
733
    public function getCourseInfo($courseId)
734
    {
735
        $entityManager = Database::getManager();
736
        $course = $entityManager->find('ChamiloCoreBundle:Course', $courseId);
737
738
        if (empty($course)) {
739
            return [];
740
        }
741
742
        $item = $this->getItemByProduct(
743
            $course->getId(),
744
            self::PRODUCT_TYPE_COURSE
745
        );
746
747
        if (empty($item)) {
748
            return [];
749
        }
750
751
        $courseDescription = $entityManager->getRepository('ChamiloCourseBundle:CCourseDescription')
752
            ->findOneBy(
753
                [
754
                    'cId' => $course->getId(),
755
                    'sessionId' => 0,
756
                ],
757
                [
758
                    'descriptionType' => 'ASC',
759
                ]
760
            );
761
762
        $globalParameters = $this->getGlobalParameters();
763
        $courseInfo = [
764
            'id' => $course->getId(),
765
            'title' => $course->getTitle(),
766
            'description' => $courseDescription ? $courseDescription->getContent() : null,
767
            'code' => $course->getCode(),
768
            'visual_code' => $course->getVisualCode(),
769
            'teachers' => [],
770
            'item' => $item,
771
            'tax_name' => $globalParameters['tax_name'],
772
            'tax_enable' => $this->checkTaxEnabledInProduct(self::TAX_APPLIES_TO_ONLY_COURSE),
773
            'course_img' => null,
774
        ];
775
776
        $courseTeachers = $course->getTeachers();
777
778
        foreach ($courseTeachers as $teachers) {
779
            $user = $teachers->getUser();
780
            $teacher['id'] = $user->getId();
781
            $teacher['name'] = $user->getCompleteName();
782
            $courseInfo['teachers'][] = $teacher;
783
        }
784
785
        $possiblePath = api_get_path(SYS_COURSE_PATH);
786
        $possiblePath .= $course->getDirectory();
787
        $possiblePath .= '/course-pic.png';
788
789
        if (file_exists($possiblePath)) {
790
            $courseInfo['course_img'] = api_get_path(WEB_COURSE_PATH).$course->getDirectory().'/course-pic.png';
791
        }
792
793
        return $courseInfo;
794
    }
795
796
    /**
797
     * Get session info.
798
     *
799
     * @param array $sessionId The session ID
800
     *
801
     * @return array
802
     */
803
    public function getSessionInfo($sessionId)
804
    {
805
        $entityManager = Database::getManager();
806
        $session = $entityManager->find('ChamiloCoreBundle:Session', $sessionId);
807
808
        if (empty($session)) {
809
            return [];
810
        }
811
812
        $item = $this->getItemByProduct(
813
            $session->getId(),
814
            self::PRODUCT_TYPE_SESSION
815
        );
816
817
        if (empty($item)) {
818
            return [];
819
        }
820
821
        $sessionDates = SessionManager::parseSessionDates(
822
            [
823
                'display_start_date' => $session->getDisplayStartDate(),
824
                'display_end_date' => $session->getDisplayEndDate(),
825
                'access_start_date' => $session->getAccessStartDate(),
826
                'access_end_date' => $session->getAccessEndDate(),
827
                'coach_access_start_date' => $session->getCoachAccessStartDate(),
828
                'coach_access_end_date' => $session->getCoachAccessEndDate(),
829
            ]
830
        );
831
832
        $globalParameters = $this->getGlobalParameters();
833
        $sessionInfo = [
834
            'id' => $session->getId(),
835
            'name' => $session->getName(),
836
            'description' => $session->getDescription(),
837
            'dates' => $sessionDates,
838
            'courses' => [],
839
            'tax_name' => $globalParameters['tax_name'],
840
            'tax_enable' => $this->checkTaxEnabledInProduct(self::TAX_APPLIES_TO_ONLY_SESSION),
841
            'image' => null,
842
            'nbrCourses' => $session->getNbrCourses(),
843
            'nbrUsers' => $session->getNbrUsers(),
844
            'item' => $item,
845
        ];
846
847
        $fieldValue = new ExtraFieldValue('session');
848
        $sessionImage = $fieldValue->get_values_by_handler_and_field_variable(
849
            $session->getId(),
850
            'image'
851
        );
852
853
        if (!empty($sessionImage)) {
854
            $sessionInfo['image'] = api_get_path(WEB_UPLOAD_PATH).$sessionImage['value'];
855
        }
856
857
        $sessionCourses = $session->getCourses();
858
        foreach ($sessionCourses as $sessionCourse) {
859
            $course = $sessionCourse->getCourse();
860
            $sessionCourseData = [
861
                'title' => $course->getTitle(),
862
                'coaches' => [],
863
            ];
864
865
            $userCourseSubscriptions = $session->getUserCourseSubscriptionsByStatus(
866
                $course,
867
                Chamilo\CoreBundle\Entity\Session::COACH
868
            );
869
870
            foreach ($userCourseSubscriptions as $userCourseSubscription) {
871
                $user = $userCourseSubscription->getUser();
872
                $coaches['id'] = $user->getUserId();
873
                $coaches['name'] = $user->getCompleteName();
874
                $sessionCourseData['coaches'][] = $coaches;
875
            }
876
877
            $sessionInfo['courses'][] = $sessionCourseData;
878
        }
879
880
        return $sessionInfo;
881
    }
882
883
    /**
884
     * Register a sale.
885
     *
886
     * @param int $itemId      The product ID
887
     * @param int $paymentType The payment type
888
     *
889
     * @return bool
890
     */
891
    public function registerSale($itemId, $paymentType)
892
    {
893
        if (!in_array(
894
            $paymentType,
895
            [self::PAYMENT_TYPE_PAYPAL, self::PAYMENT_TYPE_TRANSFER, self::PAYMENT_TYPE_CULQI]
896
        )
897
        ) {
898
            return false;
899
        }
900
901
        $entityManager = Database::getManager();
902
        $item = $this->getItem($itemId);
903
904
        if (empty($item)) {
905
            return false;
906
        }
907
908
        $productName = '';
909
        if ($item['product_type'] == self::PRODUCT_TYPE_COURSE) {
910
            $course = $entityManager->find('ChamiloCoreBundle:Course', $item['product_id']);
911
912
            if (empty($course)) {
913
                return false;
914
            }
915
916
            $productName = $course->getTitle();
917
        } elseif ($item['product_type'] == self::PRODUCT_TYPE_SESSION) {
918
            $session = $entityManager->find('ChamiloCoreBundle:Session', $item['product_id']);
919
920
            if (empty($session)) {
921
                return false;
922
            }
923
924
            $productName = $session->getName();
925
        }
926
927
        $price = $item['price'];
928
        $priceWithoutTax = null;
929
        $taxPerc = null;
930
        $taxAmount = 0;
931
        $taxEnable = $this->get('tax_enable') === 'true';
932
        $globalParameters = $this->getGlobalParameters();
933
        $taxAppliesTo = $globalParameters['tax_applies_to'];
934
935
        if ($taxEnable &&
936
            (
937
                $taxAppliesTo == self::TAX_APPLIES_TO_ALL ||
938
                ($taxAppliesTo == self::TAX_APPLIES_TO_ONLY_COURSE && $item['product_type'] == self::PRODUCT_TYPE_COURSE) ||
939
                ($taxAppliesTo == self::TAX_APPLIES_TO_ONLY_SESSION && $item['product_type'] == self::PRODUCT_TYPE_SESSION)
940
            )
941
        ) {
942
            $priceWithoutTax = $item['price'];
943
            $globalTaxPerc = $globalParameters['global_tax_perc'];
944
            $precision = 2;
945
            $taxPerc = is_null($item['tax_perc']) ? $globalTaxPerc : $item['tax_perc'];
946
            $taxAmount = round($priceWithoutTax * $taxPerc / 100, $precision);
947
            $price = $priceWithoutTax + $taxAmount;
948
        }
949
950
        $values = [
951
            'reference' => $this->generateReference(
952
                api_get_user_id(),
953
                $item['product_type'],
954
                $item['product_id']
955
            ),
956
            'currency_id' => $item['currency_id'],
957
            'date' => api_get_utc_datetime(),
958
            'user_id' => api_get_user_id(),
959
            'product_type' => $item['product_type'],
960
            'product_name' => $productName,
961
            'product_id' => $item['product_id'],
962
            'price' => $price,
963
            'price_without_tax' => $priceWithoutTax,
964
            'tax_perc' => $taxPerc,
965
            'tax_amount' => $taxAmount,
966
            'status' => self::SALE_STATUS_PENDING,
967
            'payment_type' => (int) $paymentType,
968
        ];
969
970
        return Database::insert(self::TABLE_SALE, $values);
971
    }
972
973
    /**
974
     * Get sale data by ID.
975
     *
976
     * @param int $saleId The sale ID
977
     *
978
     * @return array
979
     */
980
    public function getSale($saleId)
981
    {
982
        return Database::select(
983
            '*',
984
            Database::get_main_table(self::TABLE_SALE),
985
            [
986
                'where' => ['id = ?' => (int) $saleId],
987
            ],
988
            'first'
989
        );
990
    }
991
992
    /**
993
     * Get a list of sales by the payment type.
994
     *
995
     * @param int $paymentType The payment type to filter (default : Paypal)
996
     *
997
     * @return array The sale list. Otherwise return false
998
     */
999
    public function getSaleListByPaymentType($paymentType = self::PAYMENT_TYPE_PAYPAL)
1000
    {
1001
        $saleTable = Database::get_main_table(self::TABLE_SALE);
1002
        $currencyTable = Database::get_main_table(self::TABLE_CURRENCY);
1003
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
1004
1005
        $innerJoins = "
1006
            INNER JOIN $currencyTable c ON s.currency_id = c.id
1007
            INNER JOIN $userTable u ON s.user_id = u.id
1008
        ";
1009
1010
        return Database::select(
1011
            ['c.iso_code', 'u.firstname', 'u.lastname', 's.*'],
1012
            "$saleTable s $innerJoins",
1013
            [
1014
                'where' => [
1015
                    's.payment_type = ? AND s.status = ?' => [
1016
                        (int) $paymentType,
1017
                        self::SALE_STATUS_COMPLETED,
1018
                    ],
1019
                ],
1020
                'order' => 'id DESC',
1021
            ]
1022
        );
1023
    }
1024
1025
    /**
1026
     * Get data of sales.
1027
     *
1028
     * @param int $saleId    The sale id
1029
     * @param int $isService Check if a service
1030
     *
1031
     * @return array The sale data
1032
     */
1033
    public function getDataSaleInvoice($saleId, $isService)
1034
    {
1035
        if ($isService) {
1036
            $sale = $this->getServiceSale($saleId);
1037
            $sale['reference'] = $sale['reference'];
1038
            $sale['product_name'] = $sale['service']['name'];
1039
            $sale['payment_type'] = $sale['payment_type'];
1040
            $sale['user_id'] = $sale['buyer']['id'];
1041
            $sale['date'] = $sale['buy_date'];
1042
        } else {
1043
            $sale = $this->getSale($saleId);
1044
        }
1045
1046
        return $sale;
1047
    }
1048
1049
    /**
1050
     * Get data of invoice.
1051
     *
1052
     * @param int $saleId    The sale id
1053
     * @param int $isService Check if a service
1054
     *
1055
     * @return array The invoice data
1056
     */
1057
    public function getDataInvoice($saleId, $isService)
1058
    {
1059
        return Database::select(
1060
            '*',
1061
            Database::get_main_table(self::TABLE_INVOICE),
1062
            [
1063
                'where' => [
1064
                    'sale_id = ? AND ' => (int) $saleId,
1065
                    'is_service = ?' => (int) $isService,
1066
                ],
1067
            ],
1068
            'first'
1069
        );
1070
    }
1071
1072
    /**
1073
     * Get invoice numbering.
1074
     *
1075
     * @param int $saleId    The sale id
1076
     * @param int $isService Check if a service
1077
     *
1078
     * @return string
1079
     */
1080
    public function getNumInvoice($saleId, $isService)
1081
    {
1082
        $dataInvoice = $this->getDataInvoice($saleId, $isService);
1083
        if (empty($dataInvoice)) {
1084
            return '-';
1085
        }
1086
1087
        return $dataInvoice['serie'].$dataInvoice['year'].'/'.$dataInvoice['num_invoice'];
1088
    }
1089
1090
    /**
1091
     * Get currency data by ID.
1092
     *
1093
     * @param int $currencyId The currency ID
1094
     *
1095
     * @return array
1096
     */
1097
    public function getCurrency($currencyId)
1098
    {
1099
        return Database::select(
1100
            '*',
1101
            Database::get_main_table(self::TABLE_CURRENCY),
1102
            [
1103
                'where' => ['id = ?' => (int) $currencyId],
1104
            ],
1105
            'first'
1106
        );
1107
    }
1108
1109
    /**
1110
     * Complete sale process. Update sale status to completed.
1111
     *
1112
     * @param int $saleId The sale ID
1113
     *
1114
     * @return bool
1115
     */
1116
    public function completeSale($saleId)
1117
    {
1118
        $sale = $this->getSale($saleId);
1119
1120
        if ($sale['status'] == self::SALE_STATUS_COMPLETED) {
1121
            return true;
1122
        }
1123
1124
        $saleIsCompleted = false;
1125
        switch ($sale['product_type']) {
1126
            case self::PRODUCT_TYPE_COURSE:
1127
                $course = api_get_course_info_by_id($sale['product_id']);
1128
                $saleIsCompleted = CourseManager::subscribeUser($sale['user_id'], $course['code']);
1129
                break;
1130
            case self::PRODUCT_TYPE_SESSION:
1131
                SessionManager::subscribeUsersToSession(
1132
                    $sale['product_id'],
1133
                    [$sale['user_id']],
1134
                    api_get_session_visibility($sale['product_id']),
1135
                    false
1136
                );
1137
1138
                $saleIsCompleted = true;
1139
                break;
1140
        }
1141
1142
        if ($saleIsCompleted) {
1143
            $this->updateSaleStatus($sale['id'], self::SALE_STATUS_COMPLETED);
1144
            if ($this->get('invoicing_enable') === 'true') {
1145
                $this->setInvoice($sale['id']);
1146
            }
1147
        }
1148
1149
        return $saleIsCompleted;
1150
    }
1151
1152
    /**
1153
     * Update sale status to canceled.
1154
     *
1155
     * @param int $saleId The sale ID
1156
     */
1157
    public function cancelSale($saleId)
1158
    {
1159
        $this->updateSaleStatus($saleId, self::SALE_STATUS_CANCELED);
1160
    }
1161
1162
    /**
1163
     * Get payment types.
1164
     *
1165
     * @return array
1166
     */
1167
    public function getPaymentTypes()
1168
    {
1169
        return [
1170
            self::PAYMENT_TYPE_PAYPAL => 'PayPal',
1171
            self::PAYMENT_TYPE_TRANSFER => $this->get_lang('BankTransfer'),
1172
            self::PAYMENT_TYPE_CULQI => 'Culqi',
1173
        ];
1174
    }
1175
1176
    /**
1177
     * Register a invoice.
1178
     *
1179
     * @param int $saleId    The sale ID
1180
     * @param int $isService The service type to filter (default : 0)
1181
     */
1182
    public function setInvoice($saleId, $isService = 0)
1183
    {
1184
        $invoiceTable = Database::get_main_table(self::TABLE_INVOICE);
1185
        $year = date('Y');
1186
1187
        $globalParameters = $this->getGlobalParameters();
1188
        $numInvoice = $globalParameters['next_number_invoice'];
1189
        $serie = $globalParameters['invoice_series'];
1190
1191
        if (empty($numInvoice)) {
1192
            $item = Database::select(
1193
                ['MAX(num_invoice) AS num_invoice'],
1194
                $invoiceTable,
1195
                [
1196
                    'where' => ['year = ?' => $year],
1197
                ],
1198
                'first'
1199
            );
1200
1201
            $numInvoice = 1;
1202
            if ($item !== false) {
1203
                $numInvoice = (int) ($item['num_invoice'] + 1);
1204
            }
1205
        } else {
1206
            Database::update(
1207
                Database::get_main_table(self::TABLE_GLOBAL_CONFIG),
1208
                ['next_number_invoice' => 0],
1209
                ['id = ?' => 1]
1210
            );
1211
        }
1212
1213
        Database::insert(
1214
            $invoiceTable,
1215
            [
1216
                'sale_id' => $saleId,
1217
                'is_service' => $isService,
1218
                'num_invoice' => $numInvoice,
1219
                'year' => $year,
1220
                'serie' => $serie,
1221
                'date_invoice' => api_get_utc_datetime(),
1222
            ]
1223
        );
1224
1225
        // Record invoice in the sales table
1226
        $table = Database::get_main_table(self::TABLE_SALE);
1227
        if (!empty($isService)) {
1228
            $table = Database::get_main_table(self::TABLE_SERVICES_SALE);
1229
        }
1230
1231
        Database::update(
1232
            $table,
1233
            ['invoice' => 1],
1234
            ['id = ?' => $saleId]
1235
        );
1236
    }
1237
1238
    /**
1239
     * Get Tax's types.
1240
     *
1241
     * @return array
1242
     */
1243
    public function getTaxAppliesTo()
1244
    {
1245
        return [
1246
            self::TAX_APPLIES_TO_ALL => $this->get_lang('AllCoursesSessionsAndServices'),
1247
            self::TAX_APPLIES_TO_ONLY_COURSE => $this->get_lang('OnlyCourses'),
1248
            self::TAX_APPLIES_TO_ONLY_SESSION => $this->get_lang('OnlySessions'),
1249
            self::TAX_APPLIES_TO_ONLY_SERVICES => $this->get_lang('OnlyServices'),
1250
        ];
1251
    }
1252
1253
    /**
1254
     * Get a list of sales by the status.
1255
     *
1256
     * @param int $status The status to filter
1257
     *
1258
     * @return array The sale list. Otherwise return false
1259
     */
1260
    public function getSaleListByStatus($status = self::SALE_STATUS_PENDING)
1261
    {
1262
        $saleTable = Database::get_main_table(self::TABLE_SALE);
1263
        $currencyTable = Database::get_main_table(self::TABLE_CURRENCY);
1264
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
1265
1266
        $innerJoins = "
1267
            INNER JOIN $currencyTable c ON s.currency_id = c.id
1268
            INNER JOIN $userTable u ON s.user_id = u.id
1269
        ";
1270
1271
        return Database::select(
1272
            ['c.iso_code', 'u.firstname', 'u.lastname', 's.*'],
1273
            "$saleTable s $innerJoins",
1274
            [
1275
                'where' => ['s.status = ?' => (int) $status],
1276
                'order' => 'id DESC',
1277
            ]
1278
        );
1279
    }
1280
1281
    /**
1282
     * Get the statuses for sales.
1283
     *
1284
     * @return array
1285
     */
1286
    public function getSaleStatuses()
1287
    {
1288
        return [
1289
            self::SALE_STATUS_CANCELED => $this->get_lang('SaleStatusCanceled'),
1290
            self::SALE_STATUS_PENDING => $this->get_lang('SaleStatusPending'),
1291
            self::SALE_STATUS_COMPLETED => $this->get_lang('SaleStatusCompleted'),
1292
        ];
1293
    }
1294
1295
    /**
1296
     * Get the statuses for Payouts.
1297
     *
1298
     * @return array
1299
     */
1300
    public function getPayoutStatuses()
1301
    {
1302
        return [
1303
            self::PAYOUT_STATUS_CANCELED => $this->get_lang('PayoutStatusCanceled'),
1304
            self::PAYOUT_STATUS_PENDING => $this->get_lang('PayoutStatusPending'),
1305
            self::PAYOUT_STATUS_COMPLETED => $this->get_lang('PayoutStatusCompleted'),
1306
        ];
1307
    }
1308
1309
    /**
1310
     * Get the list of product types.
1311
     *
1312
     * @return array
1313
     */
1314
    public function getProductTypes()
1315
    {
1316
        return [
1317
            self::PRODUCT_TYPE_COURSE => get_lang('Course'),
1318
            self::PRODUCT_TYPE_SESSION => get_lang('Session'),
1319
        ];
1320
    }
1321
1322
    /**
1323
     * Get the list of service types.
1324
     *
1325
     * @return array
1326
     */
1327
    public function getServiceTypes()
1328
    {
1329
        return [
1330
            self::SERVICE_TYPE_USER => get_lang('User'),
1331
            self::SERVICE_TYPE_COURSE => get_lang('Course'),
1332
            self::SERVICE_TYPE_SESSION => get_lang('Session'),
1333
            self::SERVICE_TYPE_LP_FINAL_ITEM => get_lang('TemplateTitleCertificate'),
1334
        ];
1335
    }
1336
1337
    /**
1338
     * Generates a random text (used for order references).
1339
     *
1340
     * @param int  $length    Optional. Length of characters
1341
     * @param bool $lowercase Optional. Include lowercase characters
1342
     * @param bool $uppercase Optional. Include uppercase characters
1343
     * @param bool $numbers   Optional. Include numbers
1344
     *
1345
     * @return string
1346
     */
1347
    public static function randomText(
1348
        $length = 6,
1349
        $lowercase = true,
1350
        $uppercase = true,
1351
        $numbers = true
1352
    ) {
1353
        $salt = $lowercase ? 'abchefghknpqrstuvwxyz' : '';
1354
        $salt .= $uppercase ? 'ACDEFHKNPRSTUVWXYZ' : '';
1355
        $salt .= $numbers ? (strlen($salt) ? '2345679' : '0123456789') : '';
1356
1357
        if (strlen($salt) == 0) {
1358
            return '';
1359
        }
1360
1361
        $str = '';
1362
1363
        srand((float) microtime() * 1000000);
1364
1365
        for ($i = 0; $i < $length; $i++) {
1366
            $numbers = rand(0, strlen($salt) - 1);
1367
            $str .= substr($salt, $numbers, 1);
1368
        }
1369
1370
        return $str;
1371
    }
1372
1373
    /**
1374
     * Generates an order reference.
1375
     *
1376
     * @param int $userId      The user ID
1377
     * @param int $productType The course/session type
1378
     * @param int $productId   The course/session ID
1379
     *
1380
     * @return string
1381
     */
1382
    public function generateReference($userId, $productType, $productId)
1383
    {
1384
        return vsprintf(
1385
            '%d-%d-%d-%s',
1386
            [$userId, $productType, $productId, self::randomText()]
1387
        );
1388
    }
1389
1390
    /**
1391
     * Get a list of sales by the user.
1392
     *
1393
     * @param string $term The search term
1394
     *
1395
     * @return array The sale list. Otherwise return false
1396
     */
1397
    public function getSaleListByUser($term)
1398
    {
1399
        $term = trim($term);
1400
1401
        if (empty($term)) {
1402
            return [];
1403
        }
1404
1405
        $saleTable = Database::get_main_table(self::TABLE_SALE);
1406
        $currencyTable = Database::get_main_table(self::TABLE_CURRENCY);
1407
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
1408
        $innerJoins = "
1409
            INNER JOIN $currencyTable c ON s.currency_id = c.id
1410
            INNER JOIN $userTable u ON s.user_id = u.id
1411
        ";
1412
1413
        return Database::select(
1414
            ['c.iso_code', 'u.firstname', 'u.lastname', 's.*'],
1415
            "$saleTable s $innerJoins",
1416
            [
1417
                'where' => [
1418
                    'u.username LIKE %?% OR ' => $term,
1419
                    'u.lastname LIKE %?% OR ' => $term,
1420
                    'u.firstname LIKE %?%' => $term,
1421
                ],
1422
                'order' => 'id DESC',
1423
            ]
1424
        );
1425
    }
1426
1427
    /**
1428
     * Get a list of sales by the user id.
1429
     *
1430
     * @param int $id The user id
1431
     *
1432
     * @return array The sale list. Otherwise return false
1433
     */
1434
    public function getSaleListByUserId($id)
1435
    {
1436
        if (empty($id)) {
1437
            return [];
1438
        }
1439
1440
        $saleTable = Database::get_main_table(self::TABLE_SALE);
1441
        $currencyTable = Database::get_main_table(self::TABLE_CURRENCY);
1442
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
1443
1444
        $innerJoins = "
1445
            INNER JOIN $currencyTable c ON s.currency_id = c.id
1446
            INNER JOIN $userTable u ON s.user_id = u.id
1447
        ";
1448
1449
        return Database::select(
1450
            ['c.iso_code', 'u.firstname', 'u.lastname', 's.*'],
1451
            "$saleTable s $innerJoins",
1452
            [
1453
                'where' => [
1454
                    'u.id = ? AND s.status = ?' => [(int) $id, self::SALE_STATUS_COMPLETED],
1455
                ],
1456
                'order' => 'id DESC',
1457
            ]
1458
        );
1459
    }
1460
1461
    /**
1462
     * Convert the course info to array with necessary course data for save item.
1463
     *
1464
     * @param Course $course
1465
     * @param array  $defaultCurrency Optional. Currency data
1466
     *
1467
     * @return array
1468
     */
1469
    public function getCourseForConfiguration(Course $course, $defaultCurrency = null)
1470
    {
1471
        $courseItem = [
1472
            'item_id' => null,
1473
            'course_id' => $course->getId(),
1474
            'course_visual_code' => $course->getVisualCode(),
1475
            'course_code' => $course->getCode(),
1476
            'course_title' => $course->getTitle(),
1477
            'course_directory' => $course->getDirectory(),
1478
            'course_visibility' => $course->getVisibility(),
1479
            'visible' => false,
1480
            'currency' => empty($defaultCurrency) ? null : $defaultCurrency['iso_code'],
1481
            'price' => 0.00,
1482
            'tax_perc' => null,
1483
        ];
1484
1485
        $item = $this->getItemByProduct($course->getId(), self::PRODUCT_TYPE_COURSE);
1486
1487
        if ($item !== false) {
1488
            $courseItem['item_id'] = $item['id'];
1489
            $courseItem['visible'] = true;
1490
            $courseItem['currency'] = $item['iso_code'];
1491
            $courseItem['price'] = $item['price'];
1492
            $courseItem['tax_perc'] = $item['tax_perc'];
1493
        }
1494
1495
        return $courseItem;
1496
    }
1497
1498
    /**
1499
     * Convert the session info to array with necessary session data for save item.
1500
     *
1501
     * @param Session $session         The session data
1502
     * @param array   $defaultCurrency Optional. Currency data
1503
     *
1504
     * @return array
1505
     */
1506
    public function getSessionForConfiguration(Session $session, $defaultCurrency = null)
1507
    {
1508
        $buyItemTable = Database::get_main_table(self::TABLE_ITEM);
1509
        $buyCurrencyTable = Database::get_main_table(self::TABLE_CURRENCY);
1510
1511
        $fakeItemFrom = "
1512
            $buyItemTable i
1513
            INNER JOIN $buyCurrencyTable c ON i.currency_id = c.id
1514
        ";
1515
1516
        $sessionItem = [
1517
            'item_id' => null,
1518
            'session_id' => $session->getId(),
1519
            'session_name' => $session->getName(),
1520
            'session_visibility' => $session->getVisibility(),
1521
            'session_display_start_date' => null,
1522
            'session_display_end_date' => null,
1523
            'visible' => false,
1524
            'currency' => empty($defaultCurrency) ? null : $defaultCurrency['iso_code'],
1525
            'price' => 0.00,
1526
            'tax_perc' => null,
1527
        ];
1528
1529
        $displayStartDate = $session->getDisplayStartDate();
1530
1531
        if (!empty($displayStartDate)) {
1532
            $sessionItem['session_display_start_date'] = api_format_date(
1533
                $session->getDisplayStartDate()->format('Y-m-d h:i:s')
1534
            );
1535
        }
1536
1537
        $displayEndDate = $session->getDisplayEndDate();
1538
1539
        if (!empty($displayEndDate)) {
1540
            $sessionItem['session_display_end_date'] = api_format_date(
1541
                $session->getDisplayEndDate()->format('Y-m-d h:i:s'),
1542
                DATE_TIME_FORMAT_LONG_24H
1543
            );
1544
        }
1545
1546
        $item = Database::select(
1547
            ['i.*', 'c.iso_code'],
1548
            $fakeItemFrom,
1549
            [
1550
                'where' => [
1551
                    'i.product_id = ? AND ' => $session->getId(),
1552
                    'i.product_type = ?' => self::PRODUCT_TYPE_SESSION,
1553
                ],
1554
            ],
1555
            'first'
1556
        );
1557
1558
        if ($item !== false) {
1559
            $sessionItem['item_id'] = $item['id'];
1560
            $sessionItem['visible'] = true;
1561
            $sessionItem['currency'] = $item['iso_code'];
1562
            $sessionItem['price'] = $item['price'];
1563
            $sessionItem['tax_perc'] = $item['tax_perc'];
1564
        }
1565
1566
        return $sessionItem;
1567
    }
1568
1569
    /**
1570
     * Get all beneficiaries for a item.
1571
     *
1572
     * @param int $itemId The item ID
1573
     *
1574
     * @return array The beneficiaries. Otherwise return false
1575
     */
1576
    public function getItemBeneficiaries($itemId)
1577
    {
1578
        $beneficiaryTable = Database::get_main_table(self::TABLE_ITEM_BENEFICIARY);
1579
1580
        return Database::select(
1581
            '*',
1582
            $beneficiaryTable,
1583
            [
1584
                'where' => [
1585
                    'item_id = ?' => (int) $itemId,
1586
                ],
1587
            ]
1588
        );
1589
    }
1590
1591
    /**
1592
     * Delete a item with its beneficiaries.
1593
     *
1594
     * @param int $itemId The item ID
1595
     *
1596
     * @return int The number of affected rows. Otherwise return false
1597
     */
1598
    public function deleteItem($itemId)
1599
    {
1600
        $itemTable = Database::get_main_table(self::TABLE_ITEM);
1601
        $affectedRows = Database::delete(
1602
            $itemTable,
1603
            ['id = ?' => (int) $itemId]
1604
        );
1605
1606
        if (!$affectedRows) {
1607
            return false;
1608
        }
1609
1610
        return $this->deleteItemBeneficiaries($itemId);
1611
    }
1612
1613
    /**
1614
     * Register a item.
1615
     *
1616
     * @param array $itemData The item data
1617
     *
1618
     * @return int The item ID. Otherwise return false
1619
     */
1620
    public function registerItem(array $itemData)
1621
    {
1622
        $itemTable = Database::get_main_table(self::TABLE_ITEM);
1623
1624
        return Database::insert($itemTable, $itemData);
1625
    }
1626
1627
    /**
1628
     * Update the item data by product.
1629
     *
1630
     * @param array $itemData    The item data to be updated
1631
     * @param int   $productId   The product ID
1632
     * @param int   $productType The type of product
1633
     *
1634
     * @return int The number of affected rows. Otherwise return false
1635
     */
1636
    public function updateItem(array $itemData, $productId, $productType)
1637
    {
1638
        $itemTable = Database::get_main_table(self::TABLE_ITEM);
1639
1640
        return Database::update(
1641
            $itemTable,
1642
            $itemData,
1643
            [
1644
                'product_id = ? AND ' => (int) $productId,
1645
                'product_type' => $productType,
1646
            ]
1647
        );
1648
    }
1649
1650
    /**
1651
     * Remove all beneficiaries for a item.
1652
     *
1653
     * @param int $itemId The user ID
1654
     *
1655
     * @return int The number of affected rows. Otherwise return false
1656
     */
1657
    public function deleteItemBeneficiaries($itemId)
1658
    {
1659
        $beneficiaryTable = Database::get_main_table(self::TABLE_ITEM_BENEFICIARY);
1660
1661
        return Database::delete(
1662
            $beneficiaryTable,
1663
            ['item_id = ?' => (int) $itemId]
1664
        );
1665
    }
1666
1667
    /**
1668
     * Register the beneficiaries users with the sale of item.
1669
     *
1670
     * @param int   $itemId  The item ID
1671
     * @param array $userIds The beneficiary user ID and Teachers commissions if enabled
1672
     */
1673
    public function registerItemBeneficiaries($itemId, array $userIds)
1674
    {
1675
        $beneficiaryTable = Database::get_main_table(self::TABLE_ITEM_BENEFICIARY);
1676
1677
        $this->deleteItemBeneficiaries($itemId);
1678
1679
        foreach ($userIds as $userId => $commissions) {
1680
            Database::insert(
1681
                $beneficiaryTable,
1682
                [
1683
                    'item_id' => (int) $itemId,
1684
                    'user_id' => (int) $userId,
1685
                    'commissions' => (int) $commissions,
1686
                ]
1687
            );
1688
        }
1689
    }
1690
1691
    /**
1692
     * Check if a course is valid for sale.
1693
     *
1694
     * @param Course $course The course
1695
     *
1696
     * @return bool
1697
     */
1698
    public function isValidCourse(Course $course)
1699
    {
1700
        $courses = $this->getCourses();
1701
1702
        foreach ($courses as $_c) {
1703
            if ($_c->getCode() === $course->getCode()) {
1704
                return true;
1705
            }
1706
        }
1707
1708
        return false;
1709
    }
1710
1711
    /**
1712
     * Gets the beneficiaries with commissions and current paypal accounts by sale.
1713
     *
1714
     * @param int $saleId The sale ID
1715
     *
1716
     * @return array
1717
     */
1718
    public function getBeneficiariesBySale($saleId)
1719
    {
1720
        $sale = $this->getSale($saleId);
1721
        $item = $this->getItemByProduct($sale['product_id'], $sale['product_type']);
1722
        $itemBeneficiaries = $this->getItemBeneficiaries($item['id']);
1723
1724
        return $itemBeneficiaries;
1725
    }
1726
1727
    /**
1728
     * gets all payouts.
1729
     *
1730
     * @param int $status   - default 0 - pending
1731
     * @param int $payoutId - for get an individual payout if want all then false
1732
     * @param int $userId
1733
     *
1734
     * @return array
1735
     */
1736
    public function getPayouts(
1737
        $status = self::PAYOUT_STATUS_PENDING,
1738
        $payoutId = false,
1739
        $userId = false
1740
    ) {
1741
        $condition = ($payoutId) ? 'AND p.id = '.((int) $payoutId) : '';
1742
        $condition2 = ($userId) ? ' AND p.user_id = '.((int) $userId) : '';
1743
        $typeResult = ($condition) ? 'first' : 'all';
1744
        $payoutsTable = Database::get_main_table(self::TABLE_PAYPAL_PAYOUTS);
1745
        $saleTable = Database::get_main_table(self::TABLE_SALE);
1746
        $currencyTable = Database::get_main_table(self::TABLE_CURRENCY);
1747
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
1748
        $extraFieldTable = Database::get_main_table(TABLE_EXTRA_FIELD);
1749
        $extraFieldValues = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1750
1751
        $paypalExtraField = Database::select(
1752
            "*",
1753
            $extraFieldTable,
1754
            [
1755
                'where' => ['variable = ?' => 'paypal'],
1756
            ],
1757
            'first'
1758
        );
1759
1760
        if (!$paypalExtraField) {
1761
            return false;
1762
        }
1763
1764
        $innerJoins = "
1765
            INNER JOIN $userTable u ON p.user_id = u.id
1766
            INNER JOIN $saleTable s ON s.id = p.sale_id
1767
            INNER JOIN $currencyTable c ON s.currency_id = c.id
1768
            LEFT JOIN  $extraFieldValues efv ON p.user_id = efv.item_id 
1769
            AND field_id = ".((int) $paypalExtraField['id'])."
1770
        ";
1771
1772
        $payouts = Database::select(
1773
            "p.* , u.firstname, u.lastname, efv.value as paypal_account, s.reference as sale_reference, s.price as item_price, c.iso_code",
1774
            "$payoutsTable p $innerJoins",
1775
            [
1776
                'where' => ['p.status = ? '.$condition.' '.$condition2 => $status],
1777
            ],
1778
            $typeResult
1779
        );
1780
1781
        return $payouts;
1782
    }
1783
1784
    /**
1785
     * Verify if the beneficiary have a paypal account.
1786
     *
1787
     * @param int $userId
1788
     *
1789
     * @return true if the user have a paypal account, false if not
1790
     */
1791
    public function verifyPaypalAccountByBeneficiary($userId)
1792
    {
1793
        $extraFieldTable = Database::get_main_table(TABLE_EXTRA_FIELD);
1794
        $extraFieldValues = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1795
1796
        $paypalExtraField = Database::select(
1797
            '*',
1798
            $extraFieldTable,
1799
            [
1800
                'where' => ['variable = ?' => 'paypal'],
1801
            ],
1802
            'first'
1803
        );
1804
1805
        if (!$paypalExtraField) {
1806
            return false;
1807
        }
1808
1809
        $paypalFieldId = $paypalExtraField['id'];
1810
        $paypalAccount = Database::select(
1811
            'value',
1812
            $extraFieldValues,
1813
            [
1814
                'where' => ['field_id = ? AND item_id = ?' => [(int) $paypalFieldId, (int) $userId]],
1815
            ],
1816
            'first'
1817
        );
1818
1819
        if (!$paypalAccount) {
1820
            return false;
1821
        }
1822
1823
        if ($paypalAccount['value'] === '') {
1824
            return false;
1825
        }
1826
1827
        return true;
1828
    }
1829
1830
    /**
1831
     * Register the users payouts.
1832
     *
1833
     * @param int $saleId The sale ID
1834
     *
1835
     * @return array
1836
     */
1837
    public function storePayouts($saleId)
1838
    {
1839
        $payoutsTable = Database::get_main_table(self::TABLE_PAYPAL_PAYOUTS);
1840
        $platformCommission = $this->getPlatformCommission();
1841
1842
        $sale = $this->getSale($saleId);
1843
        $commission = (int) $platformCommission['commission'];
1844
        $teachersCommission = number_format(
1845
            (floatval($sale['price']) * $commission) / 100,
1846
            2
1847
        );
1848
1849
        $beneficiaries = $this->getBeneficiariesBySale($saleId);
1850
        foreach ($beneficiaries as $beneficiary) {
1851
            $beneficiaryCommission = (int) $beneficiary['commissions'];
1852
            Database::insert(
1853
                $payoutsTable,
1854
                [
1855
                    'date' => $sale['date'],
1856
                    'payout_date' => getdate(),
1857
                    'sale_id' => (int) $saleId,
1858
                    'user_id' => $beneficiary['user_id'],
1859
                    'commission' => number_format(
1860
                        (floatval($teachersCommission) * $beneficiaryCommission) / 100,
1861
                        2
1862
                    ),
1863
                    'status' => self::PAYOUT_STATUS_PENDING,
1864
                ]
1865
            );
1866
        }
1867
    }
1868
1869
    /**
1870
     * Register the users payouts.
1871
     *
1872
     * @param int $payoutId The payout ID
1873
     * @param int $status   The status to set (-1 to cancel, 0 to pending, 1 to completed)
1874
     *
1875
     * @return array
1876
     */
1877
    public function setStatusPayouts($payoutId, $status)
1878
    {
1879
        $payoutsTable = Database::get_main_table(self::TABLE_PAYPAL_PAYOUTS);
1880
1881
        Database::update(
1882
            $payoutsTable,
1883
            ['status' => (int) $status],
1884
            ['id = ?' => (int) $payoutId]
1885
        );
1886
    }
1887
1888
    /**
1889
     * Gets the stored platform commission params.
1890
     *
1891
     * @return array
1892
     */
1893
    public function getPlatformCommission()
1894
    {
1895
        return Database::select(
1896
            '*',
1897
            Database::get_main_table(self::TABLE_COMMISSION),
1898
            ['id = ?' => 1],
1899
            'first'
1900
        );
1901
    }
1902
1903
    /**
1904
     * Update the platform commission.
1905
     *
1906
     * @param int $params platform commission
1907
     *
1908
     * @return int The number of affected rows. Otherwise return false
1909
     */
1910
    public function updateCommission($params)
1911
    {
1912
        $commissionTable = Database::get_main_table(self::TABLE_COMMISSION);
1913
1914
        return Database::update(
1915
            $commissionTable,
1916
            ['commission' => (int) $params['commission']]
1917
        );
1918
    }
1919
1920
    /**
1921
     * Register additional service.
1922
     *
1923
     * @param array $service params
1924
     *
1925
     * @return mixed response
1926
     */
1927
    public function storeService($service)
1928
    {
1929
        $servicesTable = Database::get_main_table(self::TABLE_SERVICES);
1930
1931
        $return = Database::insert(
1932
            $servicesTable,
1933
            [
1934
                'name' => Security::remove_XSS($service['name']),
1935
                'description' => Security::remove_XSS($service['description']),
1936
                'price' => $service['price'],
1937
                'tax_perc' => $service['tax_perc'] != '' ? (int) $service['tax_perc'] : null,
1938
                'duration_days' => (int) $service['duration_days'],
1939
                'applies_to' => (int) $service['applies_to'],
1940
                'owner_id' => (int) $service['owner_id'],
1941
                'visibility' => (int) $service['visibility'],
1942
                'image' => '',
1943
                'video_url' => $service['video_url'],
1944
                'service_information' => $service['service_information'],
1945
            ]
1946
        );
1947
1948
        if ($return && !empty($service['picture_crop_image_base_64']) &&
1949
            !empty($service['picture_crop_result'])
1950
        ) {
1951
            $img = str_replace('data:image/png;base64,', '', $service['picture_crop_image_base_64']);
1952
            $img = str_replace(' ', '+', $img);
1953
            $data = base64_decode($img);
1954
            $file = api_get_path(SYS_PLUGIN_PATH).'buycourses/uploads/services/images/simg-'.$return.'.png';
1955
            file_put_contents($file, $data);
1956
1957
            Database::update(
1958
                $servicesTable,
1959
                ['image' => 'simg-'.$return.'.png'],
1960
                ['id = ?' => (int) $return]
1961
            );
1962
        }
1963
1964
        return $return;
1965
    }
1966
1967
    /**
1968
     * update a service.
1969
     *
1970
     * @param array $service
1971
     * @param int   $id
1972
     *
1973
     * @return mixed response
1974
     */
1975
    public function updateService($service, $id)
1976
    {
1977
        $servicesTable = Database::get_main_table(self::TABLE_SERVICES);
1978
        if (!empty($service['picture_crop_image_base_64'])) {
1979
            $img = str_replace('data:image/png;base64,', '', $service['picture_crop_image_base_64']);
1980
            $img = str_replace(' ', '+', $img);
1981
            $data = base64_decode($img);
1982
            $file = api_get_path(SYS_PLUGIN_PATH).'buycourses/uploads/services/images/simg-'.$id.'.png';
1983
            file_put_contents($file, $data);
1984
        }
1985
1986
        return Database::update(
1987
            $servicesTable,
1988
            [
1989
                'name' => Security::remove_XSS($service['name']),
1990
                'description' => Security::remove_XSS($service['description']),
1991
                'price' => $service['price'],
1992
                'tax_perc' => $service['tax_perc'] != '' ? (int) $service['tax_perc'] : null,
1993
                'duration_days' => (int) $service['duration_days'],
1994
                'applies_to' => (int) $service['applies_to'],
1995
                'owner_id' => (int) $service['owner_id'],
1996
                'visibility' => (int) $service['visibility'],
1997
                'image' => 'simg-'.$id.'.png',
1998
                'video_url' => $service['video_url'],
1999
                'service_information' => $service['service_information'],
2000
            ],
2001
            ['id = ?' => (int) $id]
2002
        );
2003
    }
2004
2005
    /**
2006
     * Remove a service.
2007
     *
2008
     * @param int $id The transfer account ID
2009
     *
2010
     * @return int Rows affected. Otherwise return false
2011
     */
2012
    public function deleteService($id)
2013
    {
2014
        Database::delete(
2015
            Database::get_main_table(self::TABLE_SERVICES_SALE),
2016
            ['service_id = ?' => (int) $id]
2017
        );
2018
2019
        return Database::delete(
2020
            Database::get_main_table(self::TABLE_SERVICES),
2021
            ['id = ?' => (int) $id]
2022
        );
2023
    }
2024
2025
    /**
2026
     * @param array $product
2027
     * @param int   $productType
2028
     *
2029
     * @return bool
2030
     */
2031
    public function setPriceSettings(&$product, $productType)
2032
    {
2033
        if (empty($product)) {
2034
            return false;
2035
        }
2036
2037
        $taxPerc = null;
2038
        $priceWithoutTax = $product['price'];
2039
        $product['total_price'] = $product['price'];
2040
        $product['tax_amount'] = 0;
2041
        $precision = 2;
2042
        if ($this->checkTaxEnabledInProduct($productType)) {
2043
            if (is_null($product['tax_perc'])) {
2044
                $globalParameters = $this->getGlobalParameters();
2045
                $globalTaxPerc = $globalParameters['global_tax_perc'];
2046
                $taxPerc = $globalTaxPerc;
2047
            } else {
2048
                $taxPerc = $product['tax_perc'];
2049
            }
2050
            //$taxPerc = is_null($product['tax_perc']) ? $globalTaxPerc : $product['tax_perc'];
2051
2052
            $taxAmount = round($priceWithoutTax * $taxPerc / 100, $precision);
2053
            $product['tax_amount'] = $taxAmount;
2054
            $priceWithTax = $priceWithoutTax + $taxAmount;
2055
            $product['total_price'] = $priceWithTax;
2056
        }
2057
2058
        $product['tax_perc_show'] = $taxPerc;
2059
        $product['price_formatted'] = $this->getPriceWithCurrencyFromIsoCode(
2060
            number_format($product['price'], $precision),
2061
            $product['iso_code']
2062
        );
2063
2064
        $product['tax_amount_formatted'] = number_format($product['tax_amount'], $precision);
2065
2066
        $product['total_price_formatted'] = $this->getPriceWithCurrencyFromIsoCode(
2067
            number_format($product['total_price'], $precision),
2068
            $product['iso_code']
2069
        );
2070
    }
2071
2072
    /**
2073
     * @param int $id
2074
     *
2075
     * @return array
2076
     */
2077
    public function getService($id)
2078
    {
2079
        $id = (int) $id;
2080
2081
        if (empty($id)) {
2082
            return [];
2083
        }
2084
2085
        $servicesTable = Database::get_main_table(self::TABLE_SERVICES);
2086
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
2087
        $conditions = ['WHERE' => ['s.id = ?' => $id]];
2088
        $showData = 'first';
2089
        $innerJoins = "INNER JOIN $userTable u ON s.owner_id = u.id";
2090
        $currency = $this->getSelectedCurrency();
2091
        $isoCode = $currency['iso_code'];
2092
        $service = Database::select(
2093
            "s.*, '$isoCode' as currency, u.firstname, u.lastname",
2094
            "$servicesTable s $innerJoins",
2095
            $conditions,
2096
            $showData
2097
        );
2098
2099
        $service['iso_code'] = $isoCode;
2100
        $globalParameters = $this->getGlobalParameters();
2101
2102
        $this->setPriceSettings($service, self::TAX_APPLIES_TO_ONLY_SERVICES);
2103
2104
        $service['tax_name'] = $globalParameters['tax_name'];
2105
        $service['tax_enable'] = $this->checkTaxEnabledInProduct(self::TAX_APPLIES_TO_ONLY_SERVICES);
2106
        $service['owner_name'] = api_get_person_name($service['firstname'], $service['lastname']);
2107
        $service['image'] = !empty($service['image']) ? api_get_path(WEB_PLUGIN_PATH).'buycourses/uploads/services/images/'.$service['image'] : null;
2108
2109
        return $service;
2110
    }
2111
2112
    /**
2113
     * List additional services.
2114
     *
2115
     * @return array
2116
     */
2117
    public function getServices($start, $end, $typeResult = 'all')
2118
    {
2119
        $servicesTable = Database::get_main_table(self::TABLE_SERVICES);
2120
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
2121
2122
        $start = (int) $start;
2123
        $end = (int) $end;
2124
2125
        $conditions = ['limit' => "$start, $end"];
2126
        $innerJoins = "INNER JOIN $userTable u ON s.owner_id = u.id";
2127
        $return = Database::select(
2128
            's.id',
2129
            "$servicesTable s $innerJoins",
2130
            $conditions,
2131
            $typeResult
2132
        );
2133
2134
        if ($typeResult === 'count') {
2135
            return $return;
2136
        }
2137
2138
        $services = [];
2139
        foreach ($return as $index => $service) {
2140
            $services[$index] = $this->getService($service['id']);
2141
        }
2142
2143
        return $services;
2144
    }
2145
2146
    /**
2147
     * Get the statuses for sales.
2148
     *
2149
     * @return array
2150
     */
2151
    public function getServiceSaleStatuses()
2152
    {
2153
        return [
2154
            self::SERVICE_STATUS_CANCELLED => $this->get_lang('SaleStatusCancelled'),
2155
            self::SERVICE_STATUS_PENDING => $this->get_lang('SaleStatusPending'),
2156
            self::SERVICE_STATUS_COMPLETED => $this->get_lang('SaleStatusCompleted'),
2157
        ];
2158
    }
2159
2160
    /**
2161
     * List services sales.
2162
     *
2163
     * @param int $buyerId  buyer id
2164
     * @param int $status   status
2165
     * @param int $nodeType The node Type ( User = 1 , Course = 2 , Session = 3 )
2166
     * @param int $nodeId   the nodeId
2167
     *
2168
     * @return array
2169
     */
2170
    public function getServiceSales(
2171
        $buyerId = 0,
2172
        $status = 0,
2173
        $nodeType = 0,
2174
        $nodeId = 0
2175
    ) {
2176
        $conditions = null;
2177
        $groupBy = '';
2178
        $buyerId = (int) $buyerId;
2179
        $status = (int) $status;
2180
        $nodeType = (int) $nodeType;
2181
        $nodeId = (int) $nodeId;
2182
2183
        $defaultOrder = 'ss.id ASC';
2184
2185
        if (!empty($buyerId)) {
2186
            $conditions = ['WHERE' => ['ss.buyer_id = ?' => $buyerId], 'ORDER' => $defaultOrder];
2187
        }
2188
2189
        if (is_numeric($status)) {
2190
            $conditions = ['WHERE' => ['ss.status = ?' => $status], 'ORDER' => $defaultOrder];
2191
        }
2192
2193
        if ($buyerId) {
2194
            $conditions = ['WHERE' => ['ss.buyer_id = ?' => [$buyerId]], 'ORDER' => $defaultOrder];
2195
        }
2196
2197
        if ($nodeType && $nodeId) {
2198
            $conditions = [
2199
                'WHERE' => ['ss.node_type = ? AND ss.node_id = ?' => [$nodeType, $nodeId]],
2200
                'ORDER' => $defaultOrder,
2201
            ];
2202
        }
2203
2204
        if ($nodeType && $nodeId && $buyerId && is_numeric($status)) {
2205
            $conditions = [
2206
                'WHERE' => [
2207
                    'ss.node_type = ? AND ss.node_id = ? AND ss.buyer_id = ? AND ss.status = ?' => [
2208
                        $nodeType,
2209
                        $nodeId,
2210
                        $buyerId,
2211
                        $status,
2212
                    ],
2213
                ],
2214
                'ORDER' => 'ss.service_id ASC',
2215
            ];
2216
        }
2217
2218
        $servicesTable = Database::get_main_table(self::TABLE_SERVICES);
2219
        $servicesSaleTable = Database::get_main_table(self::TABLE_SERVICES_SALE);
2220
2221
        $innerJoins = "INNER JOIN $servicesTable s ON ss.service_id = s.id $groupBy";
2222
        $return = Database::select(
2223
            'DISTINCT ss.id ',
2224
            "$servicesSaleTable ss $innerJoins",
2225
            $conditions
2226
            //, "all", null, true
2227
        );
2228
2229
        $list = [];
2230
        foreach ($return as $service) {
2231
            $list[] = $this->getServiceSale($service['id']);
2232
        }
2233
2234
        return $list;
2235
    }
2236
2237
    /**
2238
     * @param int $id service sale id
2239
     *
2240
     * @return array
2241
     */
2242
    public function getServiceSale($id)
2243
    {
2244
        $servicesTable = Database::get_main_table(self::TABLE_SERVICES);
2245
        $servicesSaleTable = Database::get_main_table(self::TABLE_SERVICES_SALE);
2246
2247
        if (empty($id)) {
2248
            return [];
2249
        }
2250
2251
        $conditions = ['WHERE' => ['ss.id = ?' => $id]];
2252
        $innerJoins = "INNER JOIN $servicesTable s ON ss.service_id = s.id ";
2253
        $currency = $this->getSelectedCurrency();
2254
        $isoCode = $currency['iso_code'];
2255
2256
        $servicesSale = Database::select(
2257
            'ss.*, s.name, s.description, s.price as service_price, s.duration_days, s.applies_to, s.owner_id, s.visibility, s.image',
2258
            "$servicesSaleTable ss $innerJoins",
2259
            $conditions,
2260
            'first'
2261
        );
2262
        $owner = api_get_user_info($servicesSale['owner_id']);
2263
        $buyer = api_get_user_info($servicesSale['buyer_id']);
2264
2265
        $servicesSale['service']['id'] = $servicesSale['service_id'];
2266
        $servicesSale['service']['name'] = $servicesSale['name'];
2267
        $servicesSale['service']['description'] = $servicesSale['description'];
2268
        $servicesSale['service']['price'] = $servicesSale['service_price'];
2269
        $servicesSale['service']['currency'] = $isoCode;
2270
2271
        $servicesSale['service']['total_price'] = $this->getPriceWithCurrencyFromIsoCode(
2272
            $servicesSale['price'],
2273
            $isoCode
2274
        );
2275
2276
        $servicesSale['service']['duration_days'] = $servicesSale['duration_days'];
2277
        $servicesSale['service']['applies_to'] = $servicesSale['applies_to'];
2278
        $servicesSale['service']['owner']['id'] = $servicesSale['owner_id'];
2279
        $servicesSale['service']['owner']['name'] = api_get_person_name($owner['firstname'], $owner['lastname']);
2280
        $servicesSale['service']['visibility'] = $servicesSale['visibility'];
2281
        $servicesSale['service']['image'] = $servicesSale['image'];
2282
        $servicesSale['item'] = $this->getService($servicesSale['service_id']);
2283
        $servicesSale['buyer']['id'] = $buyer['user_id'];
2284
        $servicesSale['buyer']['name'] = api_get_person_name($buyer['firstname'], $buyer['lastname']);
2285
        $servicesSale['buyer']['username'] = $buyer['username'];
2286
2287
        return $servicesSale;
2288
    }
2289
2290
    /**
2291
     * Update service sale status to cancelled.
2292
     *
2293
     * @param int $serviceSaleId The sale ID
2294
     *
2295
     * @return bool
2296
     */
2297
    public function cancelServiceSale($serviceSaleId)
2298
    {
2299
        $this->updateServiceSaleStatus(
2300
            $serviceSaleId,
2301
            self::SERVICE_STATUS_CANCELLED
2302
        );
2303
2304
        return true;
2305
    }
2306
2307
    /**
2308
     * Complete service sale process. Update service sale status to completed.
2309
     *
2310
     * @param int $serviceSaleId The service sale ID
2311
     *
2312
     * @return bool
2313
     */
2314
    public function completeServiceSale($serviceSaleId)
2315
    {
2316
        $serviceSale = $this->getServiceSale($serviceSaleId);
2317
        if ($serviceSale['status'] == self::SERVICE_STATUS_COMPLETED) {
2318
            return true;
2319
        }
2320
2321
        $this->updateServiceSaleStatus(
2322
            $serviceSaleId,
2323
            self::SERVICE_STATUS_COMPLETED
2324
        );
2325
2326
        if ($this->get('invoicing_enable') === 'true') {
2327
            $this->setInvoice($serviceSaleId, 1);
2328
        }
2329
2330
        return true;
2331
    }
2332
2333
    /**
2334
     * Lists current service details.
2335
     *
2336
     * @param string $name      Optional. The name filter
2337
     * @param int    $min       Optional. The minimum price filter
2338
     * @param int    $max       Optional. The maximum price filter
2339
     * @param mixed  $appliesTo optional
2340
     *
2341
     * @return array
2342
     */
2343
    public function getCatalogServiceList($start, $end, $name = null, $min = 0, $max = 0, $appliesTo = '', $typeResult = 'all')
2344
    {
2345
        $servicesTable = Database::get_main_table(self::TABLE_SERVICES);
2346
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
2347
2348
        $whereConditions = [
2349
            's.visibility <> ? ' => 0,
2350
        ];
2351
2352
        if (!empty($name)) {
2353
            $whereConditions['AND s.name LIKE %?%'] = $name;
2354
        }
2355
2356
        if (!empty($min)) {
2357
            $whereConditions['AND s.price >= ?'] = $min;
2358
        }
2359
2360
        if (!empty($max)) {
2361
            $whereConditions['AND s.price <= ?'] = $max;
2362
        }
2363
2364
        if (!$appliesTo == '') {
2365
            $whereConditions['AND s.applies_to = ?'] = $appliesTo;
2366
        }
2367
2368
        $start = (int) $start;
2369
        $end = (int) $end;
2370
2371
        $innerJoins = "INNER JOIN $userTable u ON s.owner_id = u.id";
2372
        $return = Database::select(
2373
            's.*',
2374
            "$servicesTable s $innerJoins",
2375
            ['WHERE' => $whereConditions, 'limit' => "$start, $end"],
2376
            $typeResult
2377
        );
2378
2379
        if ($typeResult === 'count') {
2380
            return $return;
2381
        }
2382
2383
        $services = [];
2384
        foreach ($return as $index => $service) {
2385
            $services[$index] = $this->getService($service['id']);
2386
        }
2387
2388
        return $services;
2389
    }
2390
2391
    /**
2392
     * Register a Service sale.
2393
     *
2394
     * @param int $serviceId   The service ID
2395
     * @param int $paymentType The payment type
2396
     * @param int $infoSelect  The ID for Service Type
2397
     *
2398
     * @return bool
2399
     */
2400
    public function registerServiceSale($serviceId, $paymentType, $infoSelect)
2401
    {
2402
        if (!in_array(
2403
            $paymentType,
2404
            [self::PAYMENT_TYPE_PAYPAL, self::PAYMENT_TYPE_TRANSFER, self::PAYMENT_TYPE_CULQI]
2405
        )
2406
        ) {
2407
            return false;
2408
        }
2409
2410
        $userId = api_get_user_id();
2411
        $service = $this->getService($serviceId);
2412
2413
        if (empty($service)) {
2414
            return false;
2415
        }
2416
2417
        $currency = $this->getSelectedCurrency();
2418
        $price = $service['price'];
2419
        $priceWithoutTax = null;
2420
        $taxPerc = null;
2421
        $taxEnable = $this->get('tax_enable') === 'true';
2422
        $globalParameters = $this->getGlobalParameters();
2423
        $taxAppliesTo = $globalParameters['tax_applies_to'];
2424
        $taxAmount = 0;
2425
2426
        if ($taxEnable &&
2427
            ($taxAppliesTo == self::TAX_APPLIES_TO_ALL || $taxAppliesTo == self::TAX_APPLIES_TO_ONLY_SERVICES)
2428
        ) {
2429
            $priceWithoutTax = $service['price'];
2430
            $globalTaxPerc = $globalParameters['global_tax_perc'];
2431
            $precision = 2;
2432
            $taxPerc = is_null($service['tax_perc']) ? $globalTaxPerc : $service['tax_perc'];
2433
            $taxAmount = round($priceWithoutTax * $taxPerc / 100, $precision);
2434
            $price = $priceWithoutTax + $taxAmount;
2435
        }
2436
2437
        $values = [
2438
            'service_id' => $serviceId,
2439
            'reference' => $this->generateReference(
2440
                $userId,
2441
                $service['applies_to'],
2442
                $infoSelect
2443
            ),
2444
            'currency_id' => $currency['id'],
2445
            'price' => $price,
2446
            'price_without_tax' => $priceWithoutTax,
2447
            'tax_perc' => $taxPerc,
2448
            'tax_amount' => $taxAmount,
2449
            'node_type' => $service['applies_to'],
2450
            'node_id' => (int) $infoSelect,
2451
            'buyer_id' => $userId,
2452
            'buy_date' => api_get_utc_datetime(),
2453
            'date_start' => api_get_utc_datetime(),
2454
            'date_end' => date_format(
2455
                date_add(
2456
                    date_create(api_get_utc_datetime()),
2457
                    date_interval_create_from_date_string($service['duration_days'].' days')
2458
                ),
2459
                'Y-m-d H:i:s'
2460
            ),
2461
            'status' => self::SERVICE_STATUS_PENDING,
2462
            'payment_type' => (int) $paymentType,
2463
        ];
2464
2465
        $returnedServiceSaleId = Database::insert(self::TABLE_SERVICES_SALE, $values);
2466
2467
        return $returnedServiceSaleId;
2468
    }
2469
2470
    /**
2471
     * Save Culqi configuration params.
2472
     *
2473
     * @param array $params
2474
     *
2475
     * @return int Rows affected. Otherwise return false
2476
     */
2477
    public function saveCulqiParameters($params)
2478
    {
2479
        return Database::update(
2480
            Database::get_main_table(self::TABLE_CULQI),
2481
            [
2482
                'commerce_code' => $params['commerce_code'],
2483
                'api_key' => $params['api_key'],
2484
                'integration' => $params['integration'],
2485
            ],
2486
            ['id = ?' => 1]
2487
        );
2488
    }
2489
2490
    /**
2491
     * Gets the stored Culqi params.
2492
     *
2493
     * @return array
2494
     */
2495
    public function getCulqiParams()
2496
    {
2497
        return Database::select(
2498
            '*',
2499
            Database::get_main_table(self::TABLE_CULQI),
2500
            ['id = ?' => 1],
2501
            'first'
2502
        );
2503
    }
2504
2505
    /**
2506
     * Save Global Parameters.
2507
     *
2508
     * @param array $params
2509
     *
2510
     * @return int Rows affected. Otherwise return false
2511
     */
2512
    public function saveGlobalParameters($params)
2513
    {
2514
        $sqlParams = [
2515
            'terms_and_conditions' => $params['terms_and_conditions'],
2516
            'sale_email' => $params['sale_email'],
2517
        ];
2518
2519
        if ($this->get('tax_enable') === 'true') {
2520
            $sqlParams['global_tax_perc'] = $params['global_tax_perc'];
2521
            $sqlParams['tax_applies_to'] = $params['tax_applies_to'];
2522
            $sqlParams['tax_name'] = $params['tax_name'];
2523
        }
2524
2525
        if ($this->get('invoicing_enable') === 'true') {
2526
            $sqlParams['seller_name'] = $params['seller_name'];
2527
            $sqlParams['seller_id'] = $params['seller_id'];
2528
            $sqlParams['seller_address'] = $params['seller_address'];
2529
            $sqlParams['seller_email'] = $params['seller_email'];
2530
            $sqlParams['next_number_invoice'] = $params['next_number_invoice'];
2531
            $sqlParams['invoice_series'] = $params['invoice_series'];
2532
        }
2533
2534
        return Database::update(
2535
            Database::get_main_table(self::TABLE_GLOBAL_CONFIG),
2536
            $sqlParams,
2537
            ['id = ?' => 1]
2538
        );
2539
    }
2540
2541
    /**
2542
     * get Global Parameters.
2543
     *
2544
     * @return array
2545
     */
2546
    public function getGlobalParameters()
2547
    {
2548
        return Database::select(
2549
            '*',
2550
            Database::get_main_table(self::TABLE_GLOBAL_CONFIG),
2551
            ['id = ?' => 1],
2552
            'first'
2553
        );
2554
    }
2555
2556
    /**
2557
     * @param int $productType
2558
     *
2559
     * @return bool
2560
     */
2561
    public function checkTaxEnabledInProduct($productType)
2562
    {
2563
        if (empty($this->get('tax_enable') === 'true')) {
2564
            return false;
2565
        }
2566
2567
        $globalParameters = $this->getGlobalParameters();
2568
        $taxAppliesTo = $globalParameters['tax_applies_to'];
2569
        if ($taxAppliesTo == self::TAX_APPLIES_TO_ALL) {
2570
            return true;
2571
        }
2572
2573
        if ($taxAppliesTo == $productType) {
2574
            return true;
2575
        }
2576
2577
        return false;
2578
    }
2579
2580
    /**
2581
     * Get the path.
2582
     *
2583
     * @param string $var path variable
2584
     *
2585
     * @return string path
2586
     */
2587
    public function getPath($var)
2588
    {
2589
        $pluginPath = api_get_path(WEB_PLUGIN_PATH).'buycourses/';
2590
        $paths = [
2591
            'SERVICE_IMAGES' => $pluginPath.'uploads/services/images/',
2592
            'SRC' => $pluginPath.'src/',
2593
            'VIEW' => $pluginPath.'view/',
2594
            'UPLOADS' => $pluginPath.'uploads/',
2595
            'LANGUAGES' => $pluginPath.'lang/',
2596
            'RESOURCES' => $pluginPath.'resources/',
2597
            'RESOURCES_IMG' => $pluginPath.'resources/img/',
2598
            'RESOURCES_CSS' => $pluginPath.'resources/css/',
2599
            'RESOURCES_JS' => $pluginPath.'resources/js/',
2600
        ];
2601
2602
        return $paths[$var];
2603
    }
2604
2605
    /**
2606
     * @param Session $session
2607
     *
2608
     * @return array
2609
     */
2610
    public function getBuyCoursePluginPrice(Session $session)
2611
    {
2612
        // start buycourse validation
2613
        // display the course price and buy button if the buycourses plugin is enabled and this course is configured
2614
        $isThisCourseInSale = $this->buyCoursesForGridCatalogValidator($session->getId(), self::PRODUCT_TYPE_SESSION);
2615
        $return = [];
2616
2617
        if ($isThisCourseInSale) {
2618
            // set the Price label
2619
            $return['html'] = $isThisCourseInSale['html'];
2620
            // set the Buy button instead register.
2621
            if ($isThisCourseInSale['verificator']) {
2622
                $return['buy_button'] = $this->returnBuyCourseButton($session->getId(), self::PRODUCT_TYPE_SESSION);
2623
            }
2624
        }
2625
        // end buycourse validation
2626
        return $return;
2627
    }
2628
2629
    /**
2630
     * @param array $saleInfo
2631
     *
2632
     * @return string
2633
     */
2634
    public function getSubscriptionSuccessMessage(array $saleInfo)
2635
    {
2636
        switch ($saleInfo['product_type']) {
2637
            case self::PRODUCT_TYPE_COURSE:
2638
                $courseInfo = api_get_course_info_by_id($saleInfo['product_id']);
2639
                $url = api_get_course_url($courseInfo['code']);
2640
                break;
2641
            case self::PRODUCT_TYPE_SESSION:
2642
                $sessionId = (int) $saleInfo['product_id'];
2643
                $url = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$sessionId;
2644
                break;
2645
            default:
2646
                $url = '#';
2647
        }
2648
2649
        return Display::return_message(
2650
            sprintf(
2651
                $this->get_lang('SubscriptionToCourseXSuccessful'),
2652
                $url,
2653
                $saleInfo['product_name']
2654
            ),
2655
            'success',
2656
            false
2657
        );
2658
    }
2659
2660
    /**
2661
     * Filter the registered courses for show in plugin catalog.
2662
     */
2663
    private function getCourses($first, $maxResults)
2664
    {
2665
        $em = Database::getManager();
2666
        $urlId = api_get_current_access_url_id();
2667
2668
        $qb = $em->createQueryBuilder();
2669
        $qb2 = $em->createQueryBuilder();
2670
        $qb3 = $em->createQueryBuilder();
2671
2672
        $qb = $qb
2673
            ->select('c')
2674
            ->from('ChamiloCoreBundle:Course', 'c')
2675
            ->where(
2676
                $qb->expr()->notIn(
2677
                    'c',
2678
                    $qb2
2679
                        ->select('course2')
2680
                        ->from('ChamiloCoreBundle:SessionRelCourse', 'sc')
2681
                        ->join('sc.course', 'course2')
2682
                        ->innerJoin(
2683
                            'ChamiloCoreBundle:AccessUrlRelSession',
2684
                            'us',
2685
                            Join::WITH,
2686
                            'us.sessionId = sc.session'
2687
                        )->where(
2688
                            $qb->expr()->eq('us.accessUrlId ', $urlId)
2689
                        )
2690
                        ->getDQL()
2691
                )
2692
            )->andWhere(
2693
                $qb->expr()->in(
2694
                    'c',
2695
                    $qb3
2696
                        ->select('course3')
2697
                        ->from('ChamiloCoreBundle:AccessUrlRelCourse', 'uc')
2698
                        ->join('uc.course', 'course3')
2699
                        ->where(
2700
                            $qb3->expr()->eq('uc.url ', $urlId)
2701
                        )
2702
                        ->getDQL()
2703
                )
2704
            )
2705
        ->setFirstResult($first)
2706
        ->setMaxResults($maxResults);
2707
2708
        return $qb;
2709
    }
2710
2711
    /**
2712
     * Get the user status for the session.
2713
     *
2714
     * @param int     $userId  The user ID
2715
     * @param Session $session The session
2716
     *
2717
     * @return string
2718
     */
2719
    private function getUserStatusForSession($userId, Session $session)
2720
    {
2721
        if (empty($userId)) {
2722
            return 'NO';
2723
        }
2724
2725
        $entityManager = Database::getManager();
2726
        $scuRepo = $entityManager->getRepository('ChamiloCoreBundle:SessionRelCourseRelUser');
2727
2728
        $buySaleTable = Database::get_main_table(self::TABLE_SALE);
2729
2730
        // Check if user bought the course
2731
        $sale = Database::select(
2732
            'COUNT(1) as qty',
2733
            $buySaleTable,
2734
            [
2735
                'where' => [
2736
                    'user_id = ? AND product_type = ? AND product_id = ? AND status = ?' => [
2737
                        $userId,
2738
                        self::PRODUCT_TYPE_SESSION,
2739
                        $session->getId(),
2740
                        self::SALE_STATUS_PENDING,
2741
                    ],
2742
                ],
2743
            ],
2744
            'first'
2745
        );
2746
2747
        if ($sale['qty'] > 0) {
2748
            return 'TMP';
2749
        }
2750
2751
        // Check if user is already subscribe to session
2752
        $userSubscription = $scuRepo->findBy([
2753
            'session' => $session,
2754
            'user' => $userId,
2755
        ]);
2756
2757
        if (!empty($userSubscription)) {
2758
            return 'YES';
2759
        }
2760
2761
        return 'NO';
2762
    }
2763
2764
    /**
2765
     * Get the user status for the course.
2766
     *
2767
     * @param int    $userId The user Id
2768
     * @param Course $course The course
2769
     *
2770
     * @return string
2771
     */
2772
    private function getUserStatusForCourse($userId, Course $course)
2773
    {
2774
        if (empty($userId)) {
2775
            return 'NO';
2776
        }
2777
2778
        $entityManager = Database::getManager();
2779
        $cuRepo = $entityManager->getRepository('ChamiloCoreBundle:CourseRelUser');
2780
        $buySaleTable = Database::get_main_table(self::TABLE_SALE);
2781
2782
        // Check if user bought the course
2783
        $sale = Database::select(
2784
            'COUNT(1) as qty',
2785
            $buySaleTable,
2786
            [
2787
                'where' => [
2788
                    'user_id = ? AND product_type = ? AND product_id = ? AND status = ?' => [
2789
                        $userId,
2790
                        self::PRODUCT_TYPE_COURSE,
2791
                        $course->getId(),
2792
                        self::SALE_STATUS_PENDING,
2793
                    ],
2794
                ],
2795
            ],
2796
            'first'
2797
        );
2798
2799
        if ($sale['qty'] > 0) {
2800
            return 'TMP';
2801
        }
2802
2803
        // Check if user is already subscribe to course
2804
        $userSubscription = $cuRepo->findBy([
2805
            'course' => $course,
2806
            'user' => $userId,
2807
        ]);
2808
2809
        if (!empty($userSubscription)) {
2810
            return 'YES';
2811
        }
2812
2813
        return 'NO';
2814
    }
2815
2816
    /**
2817
     * Update the sale status.
2818
     *
2819
     * @param int $saleId    The sale ID
2820
     * @param int $newStatus The new status
2821
     *
2822
     * @return bool
2823
     */
2824
    private function updateSaleStatus($saleId, $newStatus = self::SALE_STATUS_PENDING)
2825
    {
2826
        $saleTable = Database::get_main_table(self::TABLE_SALE);
2827
2828
        return Database::update(
2829
            $saleTable,
2830
            ['status' => (int) $newStatus],
2831
            ['id = ?' => (int) $saleId]
2832
        );
2833
    }
2834
2835
    /**
2836
     * Search filtered sessions by name, and range of price.
2837
     *
2838
     * @param int    $start
2839
     * @param int    $end
2840
     * @param string $name Optional. The name filter
2841
     * @param int    $min  Optional. The minimun price filter
2842
     * @param int    $max  Optional. The maximum price filter
2843
     *
2844
     * @return array
2845
     */
2846
    private function filterSessionList($start, $end, $name = null, $min = 0, $max = 0, $typeResult = 'all')
2847
    {
2848
        $itemTable = Database::get_main_table(self::TABLE_ITEM);
2849
        $sessionTable = Database::get_main_table(TABLE_MAIN_SESSION);
2850
2851
        $min = floatval($min);
2852
        $max = floatval($max);
2853
2854
        $innerJoin = "$itemTable i ON s.id = i.product_id";
2855
        $whereConditions = [
2856
            'i.product_type = ? ' => self::PRODUCT_TYPE_SESSION,
2857
        ];
2858
2859
        if (!empty($name)) {
2860
            $whereConditions['AND s.name LIKE %?%'] = $name;
2861
        }
2862
2863
        if (!empty($min)) {
2864
            $whereConditions['AND i.price >= ?'] = $min;
2865
        }
2866
2867
        if (!empty($max)) {
2868
            $whereConditions['AND i.price <= ?'] = $max;
2869
        }
2870
2871
        $start = (int) $start;
2872
        $end = (int) $end;
2873
2874
        $sessionIds = Database::select(
2875
            's.id',
2876
            "$sessionTable s INNER JOIN $innerJoin",
2877
            ['where' => $whereConditions, 'limit' => "$start, $end"],
2878
            $typeResult
2879
        );
2880
2881
        if ($typeResult === 'count') {
2882
            return $sessionIds;
2883
        }
2884
2885
        if (!$sessionIds) {
2886
            return [];
2887
        }
2888
2889
        $sessions = [];
2890
2891
        foreach ($sessionIds as $sessionId) {
2892
            $sessions[] = Database::getManager()->find(
2893
                'ChamiloCoreBundle:Session',
2894
                $sessionId
2895
            );
2896
        }
2897
2898
        return $sessions;
2899
    }
2900
2901
    /**
2902
     * Search filtered courses by name, and range of price.
2903
     *
2904
     * @param string $name Optional. The name filter
2905
     * @param int    $min  Optional. The minimun price filter
2906
     * @param int    $max  Optional. The maximum price filter
2907
     *
2908
     * @return array
2909
     */
2910
    private function filterCourseList($start, $end, $name = '', $min = 0, $max = 0, $typeResult = 'all')
2911
    {
2912
        $itemTable = Database::get_main_table(self::TABLE_ITEM);
2913
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
2914
        $urlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2915
2916
        $urlId = api_get_current_access_url_id();
2917
2918
        $min = floatval($min);
2919
        $max = floatval($max);
2920
2921
        $whereConditions = [
2922
            'i.product_type = ? ' => self::PRODUCT_TYPE_COURSE,
2923
        ];
2924
2925
        if (!empty($name)) {
2926
            $whereConditions['AND c.title LIKE %?%'] = $name;
2927
        }
2928
2929
        if (!empty($min)) {
2930
            $whereConditions['AND i.price >= ?'] = $min;
2931
        }
2932
2933
        if (!empty($max)) {
2934
            $whereConditions['AND i.price <= ?'] = $max;
2935
        }
2936
2937
        $whereConditions['AND url.access_url_id = ?'] = $urlId;
2938
        $start = (int) $start;
2939
        $end = (int) $end;
2940
2941
        $courseIds = Database::select(
2942
            'c.id',
2943
            "$courseTable c 
2944
            INNER JOIN $itemTable i 
2945
            ON c.id = i.product_id 
2946
            INNER JOIN $urlTable url 
2947
            ON c.id = url.c_id
2948
            ",
2949
            ['where' => $whereConditions, 'limit' => "$start, $end"],
2950
            $typeResult
2951
        );
2952
2953
        if ($typeResult === 'count') {
2954
            return $courseIds;
2955
        }
2956
2957
        if (!$courseIds) {
2958
            return [];
2959
        }
2960
2961
        $courses = [];
2962
        foreach ($courseIds as $courseId) {
2963
            $courses[] = Database::getManager()->find(
2964
                'ChamiloCoreBundle:Course',
2965
                $courseId
2966
            );
2967
        }
2968
2969
        return $courses;
2970
    }
2971
2972
    /**
2973
     * Update the service sale status.
2974
     *
2975
     * @param int $serviceSaleId The service sale ID
2976
     * @param int $newStatus     The new status
2977
     *
2978
     * @return bool
2979
     */
2980
    private function updateServiceSaleStatus(
2981
        $serviceSaleId,
2982
        $newStatus = self::SERVICE_STATUS_PENDING
2983
    ) {
2984
        $serviceSaleTable = Database::get_main_table(self::TABLE_SERVICES_SALE);
2985
2986
        return Database::update(
2987
            $serviceSaleTable,
2988
            ['status' => (int) $newStatus],
2989
            ['id = ?' => (int) $serviceSaleId]
2990
        );
2991
    }
2992
}
2993