Completed
Push — master ( 067f55...e1cb48 )
by Julito
09:39
created

BuyCoursesPlugin::getSessionInfo()   C

Complexity

Conditions 12
Paths 56

Size

Total Lines 100
Code Lines 69

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 69
nc 56
nop 1
dl 0
loc 100
rs 6.2496
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

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