Completed
Pull Request — 1.11.x (#1688)
by José
28:44
created

BuyCoursesPlugin::getCourses()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 22
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 16
nc 1
nop 0
dl 0
loc 22
rs 9.2
c 0
b 0
f 0
1
<?php
2
/* For license terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Entity\Session;
5
use Chamilo\CoreBundle\Entity\Course;
6
7
/**
8
 * Plugin class for the BuyCourses plugin
9
 * @package chamilo.plugin.buycourses
10
 * @author Jose Angel Ruiz <[email protected]>
11
 * @author Imanol Losada <[email protected]>
12
 * @author Alex Aragón <[email protected]>
13
 * @author Angel Fernando Quiroz Campos <[email protected]>
14
 * @author José Loguercio Silva  <[email protected]>
15
 */
16
class BuyCoursesPlugin extends Plugin
17
{
18
    const TABLE_PAYPAL = 'plugin_buycourses_paypal_account';
19
    const TABLE_CURRENCY = 'plugin_buycourses_currency';
20
    const TABLE_ITEM = 'plugin_buycourses_item';
21
    const TABLE_ITEM_BENEFICIARY = 'plugin_buycourses_item_rel_beneficiary';
22
    const TABLE_SALE = 'plugin_buycourses_sale';
23
    const TABLE_TRANSFER = 'plugin_buycourses_transfer';
24
    const TABLE_COMMISSION = 'plugin_buycourses_commission';
25
    const TABLE_PAYPAL_PAYOUTS = 'plugin_buycourses_paypal_payouts';
26
    const TABLE_SERVICES = 'plugin_buycourses_services';
27
    const TABLE_SERVICES_SALE = 'plugin_buycourses_service_sale';
28
    const TABLE_CULQI = 'plugin_buycourses_culqi';
29
    const TABLE_GLOBAL_CONFIG = 'plugin_buycourses_global_config';
30
    const PRODUCT_TYPE_COURSE = 1;
31
    const PRODUCT_TYPE_SESSION = 2;
32
    const PAYMENT_TYPE_PAYPAL = 1;
33
    const PAYMENT_TYPE_TRANSFER = 2;
34
    const PAYMENT_TYPE_CULQI = 3;
35
    const PAYOUT_STATUS_CANCELED = 2;
36
    const PAYOUT_STATUS_PENDING = 0;
37
    const PAYOUT_STATUS_COMPLETED = 1;
38
    const SALE_STATUS_CANCELED = -1;
39
    const SALE_STATUS_PENDING = 0;
40
    const SALE_STATUS_COMPLETED = 1;
41
    const SERVICE_STATUS_PENDING = 0;
42
    const SERVICE_STATUS_COMPLETED = 1;
43
    const SERVICE_STATUS_CANCELLED = -1;
44
    const SERVICE_TYPE_USER = 1;
45
    const SERVICE_TYPE_COURSE = 2;
46
    const SERVICE_TYPE_SESSION = 3;
47
    const CULQI_INTEGRATION_TYPE = 'INTEG';
48
    const CULQI_PRODUCTION_TYPE = 'PRODUC';
49
50
    /**
51
     *
52
     * @return StaticPlugin
53
     */
54
    static function create()
55
    {
56
        static $result = null;
57
        return $result ? $result : $result = new self();
58
    }
59
60
    protected function __construct()
61
    {
62
        parent::__construct(
63
            '1.0',
64
            "
65
                Jose Angel Ruiz - NoSoloRed (original author) <br/>
66
                Francis Gonzales and Yannick Warnier - BeezNest (integration) <br/>
67
                Alex Aragón - BeezNest (Design icons and css styles) <br/>
68
                Imanol Losada - BeezNest (introduction of sessions purchase) <br/>
69
                Angel Fernando Quiroz Campos - BeezNest (cleanup and new reports) <br/>
70
                José Loguercio Silva - BeezNest (Payouts and buy Services)
71
            ",
72
            array(
73
                'show_main_menu_tab' => 'boolean',
74
                'include_sessions' => 'boolean',
75
                'include_services' => 'boolean',
76
                'paypal_enable' => 'boolean',
77
                'transfer_enable' => 'boolean',
78
                'culqi_enable' => 'boolean',
79
                'commissions_enable' => 'boolean',
80
                'unregistered_users_enable' => 'boolean'
81
            )
82
        );
83
    }
84
85
    /**
86
     * This method creates the tables required to this plugin
87
     */
88
    function install()
89
    {
90
        $tablesToBeCompared = array(
91
            self::TABLE_PAYPAL,
92
            self::TABLE_TRANSFER,
93
            self::TABLE_CULQI,
94
            self::TABLE_ITEM_BENEFICIARY,
95
            self::TABLE_ITEM,
96
            self::TABLE_SALE,
97
            self::TABLE_CURRENCY,
98
            self::TABLE_COMMISSION,
99
            self::TABLE_PAYPAL_PAYOUTS,
100
            self::TABLE_SERVICES,
101
            self::TABLE_SERVICES_SALE,
102
            self::TABLE_GLOBAL_CONFIG
103
        );
104
        $em = Database::getManager();
105
        $cn = $em->getConnection();
106
        $sm = $cn->getSchemaManager();
107
        $tables = $sm->tablesExist($tablesToBeCompared);
108
109
        if ($tables) {
110
            return false;
111
        }
112
113
        require_once api_get_path(SYS_PLUGIN_PATH) . 'buycourses/database.php';
114
    }
115
116
    /**
117
     * This method drops the plugin tables
118
     */
119
    function uninstall()
120
    {
121
        $tablesToBeDeleted = array(
122
            self::TABLE_PAYPAL,
123
            self::TABLE_TRANSFER,
124
            self::TABLE_CULQI,
125
            self::TABLE_ITEM_BENEFICIARY,
126
            self::TABLE_ITEM,
127
            self::TABLE_SALE,
128
            self::TABLE_CURRENCY,
129
            self::TABLE_COMMISSION,
130
            self::TABLE_PAYPAL_PAYOUTS,
131
            self::TABLE_SERVICES_SALE,
132
            self::TABLE_SERVICES,
133
            self::TABLE_GLOBAL_CONFIG
134
        );
135
136
        foreach ($tablesToBeDeleted as $tableToBeDeleted) {
137
            $table = Database::get_main_table($tableToBeDeleted);
138
            $sql = "DROP TABLE IF EXISTS $table";
139
            Database::query($sql);
140
        }
141
        $this->manageTab(false);
142
    }
143
144
    /**
145
     * This function verify if the plugin is enable and return the price info for a course or session in the new grid catalog
146
     * for 1.11.x , the main purpose is to show if a course or session is in sale it shows in the main platform course catalog
147
     * so the old buycourses plugin catalog can be deprecated.
148
     * @param int $productId course or session id
149
     * @param int $productType course or session type
150
     * @return mixed bool|string html
151
     */
152
    public function buyCoursesForGridCatalogVerificator($productId, $productType) {
153
        $return = [];
154
        $paypal = $this->get('paypal_enable') === 'true';
155
        $transfer = $this->get('transfer_enable') === 'true';
156
157
        if ($paypal || $transfer) {
158
            $item = $this->getItemByProduct(intval($productId), $productType);
159
            $return['html'] = '<div class="buycourses-price">';
160
            if ($item) {
161
                $return['html'] .= '<span class="label label-primary"><b>'. $item['iso_code'] .' ' . $item['price'] . '</b></span>';
162
                $return['verificator'] = true;
163
            } else {
164
                $return['html'] .= '<span class="label label-primary"><b>'. $this->get_lang('Free'). '</b></span>';
165
                $return['verificator'] = false;
166
            }
167
            $return['html'] .= '</div>';
168
        } else {
169
            return false;
170
        }
171
172
        return $return;
173
    }
174
175
    /**
176
     * Return the buyCourses plugin button to buy the course
177
     * @param int $productId
178
     * @param int $productType
179
     * @return string $html
180
     */
181
    public function returnBuyCourseButton($productId, $productType) {
182
        $url = api_get_path(WEB_PLUGIN_PATH) .
183
            'buycourses/src/process.php?i=' .
184
            intval($productId) .
185
            '&t=' .
186
            $productType
187
        ;
188
189
        $html = ' <a class="btn btn-success btn-sm" title="' . $this->get_lang('Buy') . '" href="' . $url . '">' .
190
            Display::returnFontAwesomeIcon('fa fa-shopping-cart') . '</a>';
191
192
        return $html;
193
    }
194
195
    /**
196
     * Get the currency for sales
197
     * @return array The selected currency. Otherwise return false
198
     */
199
    public function getSelectedCurrency()
200
    {
201
        return Database::select(
202
            '*',
203
            Database::get_main_table(BuyCoursesPlugin::TABLE_CURRENCY),
204
            [
205
                'where' => ['status = ?' => true]
206
            ],
207
            'first'
208
        );
209
    }
210
211
    /**
212
     * Get a list of currencies
213
     * @return array The currencies. Otherwise return false
214
     */
215
    public function getCurrencies()
216
    {
217
        return Database::select(
218
            '*',
219
            Database::get_main_table(BuyCoursesPlugin::TABLE_CURRENCY)
220
        );
221
    }
222
223
    /**
224
     * Save the selected currency
225
     * @param int $selectedId The currency Id
226
     */
227
    public function selectCurrency($selectedId)
228
    {
229
        $currencyTable = Database::get_main_table(
230
            BuyCoursesPlugin::TABLE_CURRENCY
231
        );
232
233
        Database::update(
234
            $currencyTable,
235
            ['status' => 0]
236
        );
237
        Database::update(
238
            $currencyTable,
239
            ['status' => 1],
240
            ['id = ?' => intval($selectedId)]
241
        );
242
    }
243
244
    /**
245
     * Save the PayPal configuration params
246
     * @param array $params
247
     * @return int Rows affected. Otherwise return false
248
     */
249
    public function savePaypalParams($params)
250
    {
251
        return Database::update(
252
            Database::get_main_table(BuyCoursesPlugin::TABLE_PAYPAL),
253
            [
254
                'username' => $params['username'],
255
                'password' => $params['password'],
256
                'signature' => $params['signature'],
257
                'sandbox' => isset($params['sandbox'])
258
            ],
259
            ['id = ?' => 1]
260
        );
261
    }
262
263
    /**
264
     * Gets the stored PayPal params
265
     * @return array
266
     */
267
    public function getPaypalParams()
268
    {
269
        return Database::select(
270
            '*',
271
            Database::get_main_table(BuyCoursesPlugin::TABLE_PAYPAL),
272
            ['id = ?' => 1],
273
            'first'
274
        );
275
    }
276
277
    /**
278
     * Save a transfer account information
279
     * @param array $params The transfer account
280
     * @return int Rows affected. Otherwise return false
281
     */
282
    public function saveTransferAccount($params)
283
    {
284
        return Database::insert(
285
            Database::get_main_table(self::TABLE_TRANSFER),
286
            [
287
                'name' => $params['tname'],
288
                'account' => $params['taccount'],
289
                'swift' => $params['tswift']
290
            ]
291
        );
292
    }
293
294
    /**
295
     * Get a list of transfer accounts
296
     * @return array
297
     */
298
    public function getTransferAccounts()
299
    {
300
        return Database::select(
301
            '*',
302
            Database::get_main_table(self::TABLE_TRANSFER)
303
        );
304
    }
305
306
    /**
307
     * Remove a transfer account
308
     * @param int $id The transfer account ID
309
     * @return int Rows affected. Otherwise return false
310
     */
311
    public function deleteTransferAccount($id)
312
    {
313
        return Database::delete(
314
            Database::get_main_table(self::TABLE_TRANSFER),
315
            ['id = ?' => intval($id)]
316
        );
317
    }
318
319
    /**
320
     * Filter the registered courses for show in plugin catalog
321
     * @return array
322
     */
323
    private function getCourses()
324
    {
325
        $entityManager = Database::getManager();
326
        $query = $entityManager->createQueryBuilder();
327
328
        $courses = $query
329
            ->select('c')
330
            ->from('ChamiloCoreBundle:Course', 'c')
331
            ->leftJoin(
332
                'ChamiloCoreBundle:SessionRelCourse',
333
                'sc',
334
                \Doctrine\ORM\Query\Expr\Join::WITH,
335
                'c = sc.course'
336
            )
337
            ->where(
338
                $query->expr()->isNull('sc.course')
339
            )
340
            ->getQuery()
341
            ->getResult();
342
343
        return $courses;
344
    }
345
346
    /**
347
     * Get the item data
348
     * @param int $productId The item ID
349
     * @param int $itemType The item type
350
     * @return array
351
     */
352
    public function getItemByProduct($productId, $itemType)
353
    {
354
        $buyItemTable = Database::get_main_table(BuyCoursesPlugin::TABLE_ITEM);
355
        $buyCurrencyTable = Database::get_main_table(BuyCoursesPlugin::TABLE_CURRENCY);
356
357
        $fakeItemFrom = "
358
            $buyItemTable i
359
            INNER JOIN $buyCurrencyTable c
360
                ON i.currency_id = c.id
361
        ";
362
363
        return Database::select(
364
            ['i.*', 'c.iso_code'],
365
            $fakeItemFrom,
366
            [
367
                'where' => [
368
                    'i.product_id = ? AND i.product_type = ?' => [
369
                        intval($productId),
370
                        intval($itemType)
371
                    ]
372
                ]
373
            ],
374
            'first'
375
        );
376
    }
377
378
    /**
379
     * List courses details from the configuration page
380
     * @return array
381
     */
382
    public function getCoursesForConfiguration()
383
    {
384
        $courses = $this->getCourses();
385
386
        if (empty($courses)) {
387
            return[];
388
        }
389
390
        $configurationCourses = [];
391
        $currency = $this->getSelectedCurrency();
392
393
        foreach ($courses as $course) {
394
            $configurationCourses[] = $this->getCourseForConfiguration($course, $currency);
395
        }
396
397
        return $configurationCourses;
398
    }
399
400
    /**
401
     * List sessions details from the buy-session table and the session table
402
     * @return array The sessions. Otherwise return false
403
     */
404
    public function getSessionsForConfiguration()
405
    {
406
        $auth = new Auth();
407
        $sessions = $auth->browseSessions();
408
409
        $currency = $this->getSelectedCurrency();
410
411
        $items = [];
412
413
        foreach ($sessions as $session) {
414
            $items[] = $this->getSessionForConfiguration($session, $currency);
415
        }
416
417
        return $items;
418
    }
419
420
    /**
421
     * Get the user status for the session
422
     * @param int $userId The user ID
423
     * @param Session $session The session
424
     * @return string
425
     */
426 View Code Duplication
    private function getUserStatusForSession($userId, Session $session)
427
    {
428
        if (empty($userId)) {
429
            return 'NO';
430
        }
431
432
        $entityManager = Database::getManager();
433
        $scuRepo = $entityManager->getRepository('ChamiloCoreBundle:SessionRelCourseRelUser');
434
435
        $buySaleTable = Database::get_main_table(self::TABLE_SALE);
436
437
        // Check if user bought the course
438
        $sale = Database::select(
439
            'COUNT(1) as qty',
440
            $buySaleTable,
441
            [
442
                'where' => [
443
                    'user_id = ? AND product_type = ? AND product_id = ? AND status = ?' => [
444
                        $userId,
445
                        self::PRODUCT_TYPE_SESSION,
446
                        $session->getId(),
447
                        self::SALE_STATUS_PENDING
448
                    ]
449
                ]
450
            ],
451
            'first'
452
        );
453
454
        if ($sale['qty'] > 0) {
455
            return "TMP";
456
        }
457
458
        // Check if user is already subscribe to session
459
        $userSubscription = $scuRepo->findBy([
460
            'session' => $session,
461
            'user' => $userId
462
        ]);
463
464
        if (!empty($userSubscription)) {
465
            return 'YES';
466
        }
467
468
        return 'NO';
469
    }
470
471
    /**
472
     * Lists current user session details, including each session course details
473
     * @param string $name Optional. The name filter
474
     * @param int $min Optional. The minimum price filter
475
     * @param int $max Optional. The maximum price filter
476
     * @return array
477
     */
478
    public function getCatalogSessionList($name = null, $min = 0, $max = 0)
479
    {
480
        $sessions = $this->filterSessionList($name, $min, $max);
481
482
        $sessionCatalog = array();
483
        // loop through all sessions
484
        foreach ($sessions as $session) {
485
            $sessionCourses = $session->getCourses();
486
487
            if (empty($sessionCourses)) {
488
                continue;
489
            }
490
491
            $item = $this->getItemByProduct($session->getId(), self::PRODUCT_TYPE_SESSION);
492
493
            if (empty($item)) {
494
                continue;
495
            }
496
497
            $sessionData = $this->getSessionInfo($session->getId());
498
            $sessionData['coach'] = $session->getGeneralCoach()->getCompleteName();
499
            $sessionData['enrolled'] = $this->getUserStatusForSession(api_get_user_id(), $session);
500
            $sessionData['courses'] = array();
501
502 View Code Duplication
            foreach ($sessionCourses as $sessionCourse) {
503
                $course = $sessionCourse->getCourse();
504
505
                $sessionCourseData = [
506
                    'title' => $course->getTitle(),
507
                    'coaches' => []
508
                ];
509
510
                $userCourseSubscriptions = $session->getUserCourseSubscriptionsByStatus(
511
                    $course,
512
                    Chamilo\CoreBundle\Entity\Session::COACH
513
                );
514
515
                foreach ($userCourseSubscriptions as $userCourseSubscription) {
516
                    $user = $userCourseSubscription->getUser();
517
                    $sessionCourseData['coaches'][] = $user->getCompleteName();
518
                }
519
520
                $sessionData['courses'][] = $sessionCourseData;
521
            }
522
523
            $sessionCatalog[] = $sessionData;
524
        }
525
526
        return $sessionCatalog;
527
    }
528
529
    /**
530
     * Get the user status for the course
531
     * @param int $userId The user Id
532
     * @param Course $course The course
533
     *
534
     * @return string
535
     */
536 View Code Duplication
    private function getUserStatusForCourse($userId, Course $course)
537
    {
538
        if (empty($userId)) {
539
            
540
            return 'NO';
541
        }
542
543
        $entityManager = Database::getManager();
544
        $cuRepo = $entityManager->getRepository('ChamiloCoreBundle:CourseRelUser');
545
546
        $buySaleTable = Database::get_main_table(self::TABLE_SALE);
547
548
        // Check if user bought the course
549
        $sale = Database::select(
550
            'COUNT(1) as qty',
551
            $buySaleTable,
552
            [
553
                'where' => [
554
                    'user_id = ? AND product_type = ? AND product_id = ? AND status = ?' => [
555
                        $userId,
556
                        self::PRODUCT_TYPE_COURSE,
557
                        $course->getId(),
558
                        self::SALE_STATUS_PENDING
559
                    ]
560
                ]
561
            ],
562
            'first'
563
        );
564
565
        if ($sale['qty'] > 0) {
566
            return "TMP";
567
        }
568
569
        // Check if user is already subscribe to course
570
        $userSubscription = $cuRepo->findBy([
571
            'course' => $course,
572
            'user' => $userId
573
        ]);
574
575
        if (!empty($userSubscription)) {
576
            return 'YES';
577
        }
578
579
        return 'NO';
580
    }
581
582
    /**
583
     * Lists current user course details
584
     * @param string $name Optional. The name filter
585
     * @param int $min Optional. The minimum price filter
586
     * @param int $max Optional. The maximum price filter
587
     * @return array
588
     */
589
    public function getCatalogCourseList($name = null, $min = 0, $max = 0)
590
    {
591
        $courses = $this->filterCourseList($name, $min, $max);
592
593
        if (empty($courses)) {
594
            return [];
595
        }
596
597
        $courseCatalog = [];
598
599
        foreach ($courses as $course) {
600
            $item = $this->getItemByProduct($course->getId(), self::PRODUCT_TYPE_COURSE);
601
602
            if (empty($item)) {
603
                continue;
604
            }
605
606
            $courseItem = [
607
                'id' => $course->getId(),
608
                'title' => $course->getTitle(),
609
                'code' => $course->getCode(),
610
                'course_img' => null,
611
                'price' => $item['price'],
612
                'currency' => $item['iso_code'],
613
                'teachers' => [],
614
                'enrolled' => $this->getUserStatusForCourse(api_get_user_id(), $course)
615
            ];
616
617
            foreach ($course->getTeachers() as $courseUser) {
618
                $teacher = $courseUser->getUser();
619
                $courseItem['teachers'][] = $teacher->getCompleteName();
620
            }
621
622
            //check images
623
            $possiblePath = api_get_path(SYS_COURSE_PATH);
624
            $possiblePath .= $course->getDirectory();
625
            $possiblePath .= '/course-pic.png';
626
627 View Code Duplication
            if (file_exists($possiblePath)) {
628
                $courseItem['course_img'] = api_get_path(WEB_COURSE_PATH)
629
                    . $course->getDirectory()
630
                    . '/course-pic.png';
631
            }
632
633
            $courseCatalog[] = $courseItem;
634
        }
635
636
        return $courseCatalog;
637
    }
638
639
    /**
640
     * Get course info
641
     * @param int $courseId The course ID
642
     * @return array
643
     */
644
    public function getCourseInfo($courseId)
645
    {
646
        $entityManager = Database::getManager();
647
        $course = $entityManager->find('ChamiloCoreBundle:Course', $courseId);
648
649
        if (empty($course)) {
650
            return [];
651
        }
652
653
        $item = $this->getItemByProduct($course->getId(), self::PRODUCT_TYPE_COURSE);
654
655
        if (empty($item)) {
656
            return [];
657
        }
658
659
        $courseInfo = [
660
            'id' => $course->getId(),
661
            'title' => $course->getTitle(),
662
            'description' => $course->getDescription(),
663
            'code' => $course->getCode(),
664
            'visual_code' => $course->getVisualCode(),
665
            'teachers' => [],
666
            'price' => $item['price'],
667
            'currency' => $item['iso_code'],
668
            'course_img' => null
669
        ];
670
671
        $courseTeachers = $course->getTeachers();
672
673
        foreach ($courseTeachers as $teacher) {
674
            $courseInfo['teachers'][] = $teacher->getUser()->getCompleteName();
675
        }
676
677
        $possiblePath = api_get_path(SYS_COURSE_PATH);
678
        $possiblePath .= $course->getDirectory();
679
        $possiblePath .= '/course-pic.png';
680
681 View Code Duplication
        if (file_exists($possiblePath)) {
682
            $courseInfo['course_img'] = api_get_path(WEB_COURSE_PATH)
683
                . $course->getDirectory()
684
                . '/course-pic.png';
685
        }
686
687
        return $courseInfo;
688
    }
689
690
    /**
691
     * Get session info
692
     * @param array $sessionId The session ID
693
     * @return array
694
     */
695
    public function getSessionInfo($sessionId)
696
    {
697
        $entityManager = Database::getManager();
698
        $session = $entityManager->find('ChamiloCoreBundle:Session', $sessionId);
699
700
        if (empty($session)) {
701
            return [];
702
        }
703
704
        $item = $this->getItemByProduct($session->getId(), self::PRODUCT_TYPE_SESSION);
705
706
        if (empty($item)) {
707
            return [];
708
        }
709
710
        $sessionDates = SessionManager::parseSessionDates([
711
            'display_start_date' => $session->getDisplayStartDate(),
712
            'display_end_date' => $session->getDisplayEndDate(),
713
            'access_start_date' => $session->getAccessStartDate(),
714
            'access_end_date' => $session->getAccessEndDate(),
715
            'coach_access_start_date' => $session->getCoachAccessStartDate(),
716
            'coach_access_end_date' => $session->getCoachAccessEndDate()
717
        ]);
718
719
        $sessionInfo = [
720
            'id' => $session->getId(),
721
            'name' => $session->getName(),
722
            'dates' => $sessionDates,
723
            'courses' => [],
724
            'price' => $item['price'],
725
            'currency' => $item['iso_code'],
726
            'image' => null
727
        ];
728
729
        $fieldValue = new ExtraFieldValue('session');
730
        $sessionImage = $fieldValue->get_values_by_handler_and_field_variable(
731
            $session->getId(),
732
            'image'
733
        );
734
735
        if (!empty($sessionImage)) {
736
            $sessionInfo['image'] = api_get_path(WEB_UPLOAD_PATH) . $sessionImage['value'];
737
        }
738
739
        $sessionCourses = $session->getCourses();
740
741 View Code Duplication
        foreach ($sessionCourses as $sessionCourse) {
742
            $course = $sessionCourse->getCourse();
743
744
            $sessionCourseData = [
745
                'title' => $course->getTitle(),
746
                'coaches' => []
747
            ];
748
749
            $userCourseSubscriptions = $session->getUserCourseSubscriptionsByStatus(
750
                $course,
751
                Chamilo\CoreBundle\Entity\Session::COACH
752
            );
753
754
            foreach ($userCourseSubscriptions as $userCourseSubscription) {
755
                $user = $userCourseSubscription->getUser();
756
                $sessionCourseData['coaches'][] = $user->getCompleteName();
757
            }
758
759
            $sessionInfo['courses'][] = $sessionCourseData;
760
        }
761
762
        return $sessionInfo;
763
    }
764
765
    /**
766
     * Get registered item data
767
     * @param int $itemId The item ID
768
     * @return array
769
     */
770
    public function getItem($itemId)
771
    {
772
        return Database::select(
773
            '*',
774
            Database::get_main_table(self::TABLE_ITEM),
775
            [
776
                'where' => ['id = ?' => intval($itemId)]
777
            ],
778
            'first'
779
        );
780
    }
781
782
    /**
783
     * Register a sale
784
     * @param int $itemId The product ID
785
     * @param int $paymentType The payment type
786
     * @return boolean
787
     */
788
    public function registerSale($itemId, $paymentType)
789
    {
790 View Code Duplication
        if (!in_array($paymentType, [self::PAYMENT_TYPE_PAYPAL, self::PAYMENT_TYPE_TRANSFER, self::PAYMENT_TYPE_CULQI])) {
791
            return false;
792
        }
793
794
        $entityManager = Database::getManager();
795
796
        $item = $this->getItem($itemId);
797
798
        if (empty($item)) {
799
            return false;
800
        }
801
802
        if ($item['product_type'] == self::PRODUCT_TYPE_COURSE) {
803
            $course = $entityManager->find('ChamiloCoreBundle:Course', $item['product_id']);
804
805
            if (empty($course)) {
806
                return false;
807
            }
808
809
            $productName = $course->getTitle();
810
        } elseif ($item['product_type'] == self::PRODUCT_TYPE_SESSION) {
811
            $session = $entityManager->find('ChamiloCoreBundle:Session', $item['product_id']);
812
813
            if (empty($session)) {
814
                return false;
815
            }
816
817
            $productName = $session->getName();
818
        }
819
820
        $values = [
821
            'reference' => $this->generateReference(
822
                api_get_user_id(),
823
                $item['product_type'],
824
                $item['product_id']
825
            ),
826
            'currency_id' => $item['currency_id'],
827
            'date' => api_get_utc_datetime(),
828
            'user_id' => api_get_user_id(),
829
            'product_type' => $item['product_type'],
830
            'product_name' => $productName,
831
            'product_id' => $item['product_id'],
832
            'price' => $item['price'],
833
            'status' => self::SALE_STATUS_PENDING,
834
            'payment_type' => intval($paymentType)
835
        ];
836
837
        return Database::insert(self::TABLE_SALE, $values);
838
    }
839
840
    /**
841
     * Get sale data by ID
842
     * @param int $saleId The sale ID
843
     * @return array
844
     */
845
    public function getSale($saleId)
846
    {
847
        return Database::select(
848
            '*',
849
            Database::get_main_table(self::TABLE_SALE),
850
            [
851
                'where' => ['id = ?' => intval($saleId)]
852
            ],
853
            'first'
854
        );
855
    }
856
857
    /**
858
     * Get a list of sales by the payment type
859
     * @param int $paymentType The payment type to filter (default : Paypal)
860
     * @return array The sale list. Otherwise return false
861
     */
862 View Code Duplication
    public function getSaleListByPaymentType($paymentType = self::PAYMENT_TYPE_PAYPAL)
863
    {
864
        $saleTable = Database::get_main_table(BuyCoursesPlugin::TABLE_SALE);
865
        $currencyTable = Database::get_main_table(BuyCoursesPlugin::TABLE_CURRENCY);
866
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
867
868
        $innerJoins = "
869
            INNER JOIN $currencyTable c ON s.currency_id = c.id
870
            INNER JOIN $userTable u ON s.user_id = u.id
871
        ";
872
873
        return Database::select(
874
            ['c.iso_code', 'u.firstname', 'u.lastname', 's.*'],
875
            "$saleTable s $innerJoins",
876
            [
877
                'where' => ['s.payment_type = ? AND s.status = ?' => [intval($paymentType), self::SALE_STATUS_COMPLETED]],
878
                'order' => 'id DESC'
879
            ]
880
        );
881
    }
882
883
    /**
884
     * Get currency data by ID
885
     * @param int $currencyId The currency ID
886
     * @return array
887
     */
888
    public function getCurrency($currencyId)
889
    {
890
        return Database::select(
891
            '*',
892
            Database::get_main_table(BuyCoursesPlugin::TABLE_CURRENCY),
893
            [
894
                'where' => ['id = ?' => intval($currencyId)]
895
            ],
896
            'first'
897
        );
898
    }
899
900
    /**
901
     * Update the sale status
902
     * @param int $saleId The sale ID
903
     * @param int $newStatus The new status
904
     * @return boolean
905
     */
906
    private function updateSaleStatus($saleId, $newStatus = self::SALE_STATUS_PENDING)
907
    {
908
        $saleTable = Database::get_main_table(self::TABLE_SALE);
909
910
        return Database::update(
911
            $saleTable,
912
            ['status' => intval($newStatus)],
913
            ['id = ?' => intval($saleId)]
914
        );
915
    }
916
917
    /**
918
     * Complete sale process. Update sale status to completed
919
     * @param int $saleId The sale ID
920
     * @return boolean
921
     */
922
    public function completeSale($saleId)
923
    {
924
        $sale = $this->getSale($saleId);
925
926
        if ($sale['status'] == self::SALE_STATUS_COMPLETED) {
927
            return true;
928
        }
929
930
        $saleIsCompleted = false;
931
932
        switch ($sale['product_type']) {
933
            case self::PRODUCT_TYPE_COURSE:
934
                $course = api_get_course_info_by_id($sale['product_id']);
935
936
                $saleIsCompleted = CourseManager::subscribe_user($sale['user_id'], $course['code']);
937
                break;
938
            case self::PRODUCT_TYPE_SESSION:
939
                SessionManager::subscribe_users_to_session(
940
                    $sale['product_id'],
941
                    [$sale['user_id']],
942
                    api_get_session_visibility($sale['product_id']),
943
                    false
944
                );
945
946
                $saleIsCompleted = true;
947
                break;
948
        }
949
950
        if ($saleIsCompleted) {
951
            $this->updateSaleStatus($sale['id'], self::SALE_STATUS_COMPLETED);
952
        }
953
954
        return $saleIsCompleted;
955
    }
956
957
    /**
958
     * Update sale status to canceled
959
     * @param int $saleId The sale ID
960
     */
961
    public function cancelSale($saleId)
962
    {
963
        $this->updateSaleStatus($saleId, self::SALE_STATUS_CANCELED);
964
    }
965
966
    /**
967
     * Get payment types
968
     * @return array
969
     */
970
    public function getPaymentTypes()
971
    {
972
        return [
973
            self::PAYMENT_TYPE_PAYPAL => 'PayPal',
974
            self::PAYMENT_TYPE_TRANSFER => $this->get_lang('BankTransfer'),
975
            self::PAYMENT_TYPE_CULQI => 'Culqi'
976
        ];
977
    }
978
979
    /**
980
     * Get a list of sales by the status
981
     * @param int $status The status to filter
982
     * @return array The sale list. Otherwise return false
983
     */
984 View Code Duplication
    public function getSaleListByStatus($status = self::SALE_STATUS_PENDING)
985
    {
986
        $saleTable = Database::get_main_table(BuyCoursesPlugin::TABLE_SALE);
987
        $currencyTable = Database::get_main_table(BuyCoursesPlugin::TABLE_CURRENCY);
988
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
989
990
        $innerJoins = "
991
            INNER JOIN $currencyTable c ON s.currency_id = c.id
992
            INNER JOIN $userTable u ON s.user_id = u.id
993
        ";
994
995
        return Database::select(
996
            ['c.iso_code', 'u.firstname', 'u.lastname', 's.*'],
997
            "$saleTable s $innerJoins",
998
            [
999
                'where' => ['s.status = ?' => intval($status)],
1000
                'order' => 'id DESC'
1001
            ]
1002
        );
1003
    }
1004
1005
    /**
1006
     * Get the statuses for sales
1007
     * @return array
1008
     */
1009
    public function getSaleStatuses()
1010
    {
1011
        return [
1012
            self::SALE_STATUS_CANCELED => $this->get_lang('SaleStatusCanceled'),
1013
            self::SALE_STATUS_PENDING => $this->get_lang('SaleStatusPending'),
1014
            self::SALE_STATUS_COMPLETED => $this->get_lang('SaleStatusCompleted')
1015
        ];
1016
    }
1017
1018
    /**
1019
     * Get the statuses for Payouts
1020
     * @return array
1021
     */
1022
    public function getPayoutStatuses()
1023
    {
1024
        return [
1025
            self::PAYOUT_STATUS_CANCELED => $this->get_lang('PayoutStatusCanceled'),
1026
            self::PAYOUT_STATUS_PENDING => $this->get_lang('PayoutStatusPending'),
1027
            self::PAYOUT_STATUS_COMPLETED => $this->get_lang('PayoutStatusCompleted')
1028
        ];
1029
    }
1030
1031
    /**
1032
     * Get the list of product types
1033
     * @return array
1034
     */
1035
    public function getProductTypes()
1036
    {
1037
        return [
1038
            self::PRODUCT_TYPE_COURSE => get_lang('Course'),
1039
            self::PRODUCT_TYPE_SESSION => get_lang('Session')
1040
        ];
1041
    }
1042
1043
    /**
1044
     * Get the list of service types
1045
     * @return array
1046
     */
1047
    public function getServiceTypes()
1048
    {
1049
        return [
1050
            self::SERVICE_TYPE_USER => get_lang('User'),
1051
            self::SERVICE_TYPE_COURSE => get_lang('Course'),
1052
            self::SERVICE_TYPE_SESSION => get_lang('Session')
1053
        ];
1054
    }
1055
1056
    /**
1057
     * Search filtered sessions by name, and range of price
1058
     * @param string $name Optional. The name filter
1059
     * @param int $min Optional. The minimun price filter
1060
     * @param int $max Optional. The maximum price filter
1061
     * @return array
1062
     */
1063 View Code Duplication
    private function filterSessionList($name = null, $min = 0, $max = 0)
1064
    {
1065
        if (empty($name) && empty($min) && empty($max)) {
1066
            $auth = new Auth();
1067
            return $auth->browseSessions();
1068
        }
1069
1070
        $itemTable = Database::get_main_table(self::TABLE_ITEM);
1071
        $sessionTable = Database::get_main_table(TABLE_MAIN_SESSION);
1072
1073
        $min = floatval($min);
1074
        $max = floatval($max);
1075
1076
        $innerJoin = "$itemTable i ON s.id = i.product_id";
1077
        $whereConditions = [
1078
            'i.product_type = ? ' => self::PRODUCT_TYPE_SESSION
1079
        ];
1080
1081
        if (!empty($name)) {
1082
            $whereConditions['AND s.name LIKE %?%'] = $name;
1083
        }
1084
1085
        if (!empty($min)) {
1086
            $whereConditions['AND i.price >= ?'] = $min;
1087
        }
1088
1089
        if (!empty($max)) {
1090
            $whereConditions['AND i.price <= ?'] = $max;
1091
        }
1092
1093
        $sessionIds = Database::select(
1094
            's.id',
1095
            "$sessionTable s INNER JOIN $innerJoin",
1096
            ['where' => $whereConditions]
1097
        );
1098
1099
        if (!$sessionIds) {
1100
            return [];
1101
        }
1102
1103
        $sessions = [];
1104
1105
        foreach ($sessionIds as $sessionId) {
1106
            $sessions[] = Database::getManager()->find('ChamiloCoreBundle:Session', $sessionId);
1107
        }
1108
1109
        return $sessions;
1110
    }
1111
1112
    /**
1113
     * Search filtered courses by name, and range of price
1114
     * @param string $name Optional. The name filter
1115
     * @param int $min Optional. The minimun price filter
1116
     * @param int $max Optional. The maximum price filter
1117
     * @return array
1118
     */
1119 View Code Duplication
    private function filterCourseList($name = null, $min = 0, $max = 0)
1120
    {
1121
        if (empty($name) && empty($min) && empty($max)) {
1122
            return $this->getCourses();
1123
        }
1124
1125
        $itemTable = Database::get_main_table(self::TABLE_ITEM);
1126
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
1127
1128
        $min = floatval($min);
1129
        $max = floatval($max);
1130
1131
        $innerJoin = "$itemTable i ON c.id = i.product_id";
1132
        $whereConditions = [
1133
            'i.product_type = ? ' => self::PRODUCT_TYPE_COURSE
1134
        ];
1135
1136
        if (!empty($name)) {
1137
            $whereConditions['AND c.title LIKE %?%'] = $name;
1138
        }
1139
1140
        if (!empty($min)) {
1141
            $whereConditions['AND i.price >= ?'] = $min;
1142
        }
1143
1144
        if (!empty($max)) {
1145
            $whereConditions['AND i.price <= ?'] = $max;
1146
        }
1147
1148
        $courseIds = Database::select(
1149
            'c.id',
1150
            "$courseTable c INNER JOIN $innerJoin",
1151
            ['where' => $whereConditions]
1152
        );
1153
1154
        if (!$courseIds) {
1155
            return [];
1156
        }
1157
1158
        $courses = [];
1159
1160
        foreach ($courseIds as $courseId) {
1161
            $courses[] = Database::getManager()->find('ChamiloCoreBundle:Course', $courseId);
1162
        }
1163
1164
        return $courses;
1165
    }
1166
1167
    /**
1168
     * Generates a random text (used for order references)
1169
     * @param int $length Optional. Length of characters
1170
     * @param boolean $lowercase Optional. Include lowercase characters
1171
     * @param boolean $uppercase Optional. Include uppercase characters
1172
     * @param boolean $numbers Optional. Include numbers
1173
     * @return string
1174
     */
1175
    public static function randomText(
1176
        $length = 6,
1177
        $lowercase = true,
1178
        $uppercase = true,
1179
        $numbers = true
1180
    )
1181
    {
1182
        $salt = $lowercase ? 'abchefghknpqrstuvwxyz' : '';
1183
        $salt .= $uppercase ? 'ACDEFHKNPRSTUVWXYZ' : '';
1184
        $salt .= $numbers ? (strlen($salt) ? '2345679' : '0123456789') : '';
1185
1186
        if (strlen($salt) == 0) {
1187
            return '';
1188
        }
1189
1190
        $str = '';
1191
1192
        srand((double)microtime() * 1000000);
1193
1194
        for ($i = 0; $i < $length; $i++) {
1195
            $numbers = rand(0, strlen($salt) - 1);
1196
            $str .= substr($salt, $numbers, 1);
1197
        }
1198
1199
        return $str;
1200
    }
1201
1202
    /**
1203
     * Generates an order reference
1204
     * @param int $userId The user ID
1205
     * @param int $productType The course/session type
1206
     * @param int $productId The course/session ID
1207
     * @return string
1208
     */
1209
    public function generateReference($userId, $productType, $productId)
1210
    {
1211
        return vsprintf(
1212
            "%d-%d-%d-%s",
1213
            [$userId, $productType, $productId, self::randomText()]
1214
        );
1215
    }
1216
1217
    /**
1218
     * Get a list of sales by the user
1219
     * @param string $term The search term
1220
     * @return array The sale list. Otherwise return false
1221
     */
1222
    public function getSaleListByUser($term)
1223
    {
1224
        $term = trim($term);
1225
1226
        if (empty($term)) {
1227
            return [];
1228
        }
1229
1230
        $saleTable = Database::get_main_table(BuyCoursesPlugin::TABLE_SALE);
1231
        $currencyTable = Database::get_main_table(BuyCoursesPlugin::TABLE_CURRENCY);
1232
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
1233
1234
        $innerJoins = "
1235
            INNER JOIN $currencyTable c ON s.currency_id = c.id
1236
            INNER JOIN $userTable u ON s.user_id = u.id
1237
        ";
1238
1239
        return Database::select(
1240
            ['c.iso_code', 'u.firstname', 'u.lastname', 's.*'],
1241
            "$saleTable s $innerJoins",
1242
            [
1243
                'where' => [
1244
                    'u.username LIKE %?% OR ' => $term,
1245
                    'u.lastname LIKE %?% OR ' => $term,
1246
                    'u.firstname LIKE %?%' => $term
1247
                ],
1248
                'order' => 'id DESC'
1249
            ]
1250
        );
1251
    }
1252
1253
    /**
1254
     * Get a list of sales by the user id
1255
     * @param int $id The user id
1256
     * @return array The sale list. Otherwise return false
1257
     */
1258 View Code Duplication
    public function getSaleListByUserId($id)
1259
    {
1260
1261
        if (empty($id)) {
1262
            return [];
1263
        }
1264
1265
        $saleTable = Database::get_main_table(BuyCoursesPlugin::TABLE_SALE);
1266
        $currencyTable = Database::get_main_table(BuyCoursesPlugin::TABLE_CURRENCY);
1267
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
1268
1269
        $innerJoins = "
1270
            INNER JOIN $currencyTable c ON s.currency_id = c.id
1271
            INNER JOIN $userTable u ON s.user_id = u.id
1272
        ";
1273
1274
        return Database::select(
1275
            ['c.iso_code', 'u.firstname', 'u.lastname', 's.*'],
1276
            "$saleTable s $innerJoins",
1277
            [
1278
                'where' => [
1279
                    'u.id = ? AND s.status = ?' => [intval($id), BuyCoursesPlugin::SALE_STATUS_COMPLETED]
1280
                ],
1281
                'order' => 'id DESC'
1282
            ]
1283
        );
1284
    }
1285
1286
    /**
1287
     * Convert the course info to array with necessary course data for save item
1288
     * @param Course $course
1289
     * @param array $defaultCurrency Optional. Currency data
1290
     * @return array
1291
     */
1292
    public function getCourseForConfiguration(Course $course, $defaultCurrency = null)
1293
    {
1294
        $courseItem = [
1295
            'item_id' => null,
1296
            'course_id' => $course->getId(),
1297
            'course_visual_code' => $course->getVisualCode(),
1298
            'course_code' => $course->getCode(),
1299
            'course_title' => $course->getTitle(),
1300
            'course_visibility' => $course->getVisibility(),
1301
            'visible' => false,
1302
            'currency' =>  empty($defaultCurrency) ? null : $defaultCurrency['iso_code'],
1303
            'price' => 0.00
1304
        ];
1305
1306
        $item = $this->getItemByProduct($course->getId(), self::PRODUCT_TYPE_COURSE);
1307
1308 View Code Duplication
        if ($item !== false) {
1309
            $courseItem['item_id'] = $item['id'];
1310
            $courseItem['visible'] = true;
1311
            $courseItem['currency'] = $item['iso_code'];
1312
            $courseItem['price'] = $item['price'];
1313
        }
1314
1315
        return $courseItem;
1316
    }
1317
1318
    /**
1319
     * Convert the session info to array with necessary session data for save item
1320
     * @param Session $session The session data
1321
     * @param array $defaultCurrency Optional. Currency data
1322
     * @return array
1323
     */
1324
    public function getSessionForConfiguration(Session $session, $defaultCurrency = null)
1325
    {
1326
        $buyItemTable = Database::get_main_table(BuyCoursesPlugin::TABLE_ITEM);
1327
        $buyCurrencyTable = Database::get_main_table(BuyCoursesPlugin::TABLE_CURRENCY);
1328
1329
        $fakeItemFrom = "
1330
            $buyItemTable i
1331
            INNER JOIN $buyCurrencyTable c ON i.currency_id = c.id
1332
        ";
1333
1334
        $sessionItem = [
1335
            'item_id' => null,
1336
            'session_id' => $session->getId(),
1337
            'session_name' => $session->getName(),
1338
            'session_visibility' => $session->getVisibility(),
1339
            'session_display_start_date' => null,
1340
            'session_display_end_date' => null,
1341
            'visible' => false,
1342
            'currency' =>  empty($defaultCurrency) ? null : $defaultCurrency['iso_code'],
1343
            'price' => 0.00
1344
        ];
1345
1346
        $displayStartDate = $session->getDisplayStartDate();
1347
1348
        if (!empty($displayStartDate)) {
1349
            $sessionItem['session_display_start_date'] = api_format_date(
1350
                $session->getDisplayStartDate()->format('Y-m-d h:i:s')
1351
            );
1352
        }
1353
1354
        $displayEndDate = $session->getDisplayEndDate();
1355
1356
        if (!empty($displayEndDate)) {
1357
            $sessionItem['session_display_end_date'] = api_format_date(
1358
                $session->getDisplayEndDate()->format('Y-m-d h:i:s'),
1359
                DATE_TIME_FORMAT_LONG_24H
1360
            );
1361
        }
1362
1363
        $item = Database::select(
1364
            ['i.*', 'c.iso_code'],
1365
            $fakeItemFrom,
1366
            [
1367
                'where' => [
1368
                    'i.product_id = ? AND ' => $session->getId(),
1369
                    'i.product_type = ?' => self::PRODUCT_TYPE_SESSION
1370
                ]
1371
            ],
1372
            'first'
1373
        );
1374
1375 View Code Duplication
        if ($item !== false) {
1376
            $sessionItem['item_id'] = $item['id'];
1377
            $sessionItem['visible'] = true;
1378
            $sessionItem['currency'] = $item['iso_code'];
1379
            $sessionItem['price'] = $item['price'];
1380
        }
1381
1382
        return $sessionItem;
1383
    }
1384
1385
    /**
1386
     * Get all beneficiaries for a item
1387
     * @param int $itemId The item ID
1388
     * @return array The beneficiries. Otherwise return false
1389
     */
1390 View Code Duplication
    public function getItemBeneficiaries($itemId)
1391
    {
1392
        $beneficiaryTable = Database::get_main_table(self::TABLE_ITEM_BENEFICIARY);
1393
1394
        return Database::select(
1395
            '*',
1396
            $beneficiaryTable,
1397
            ['where' => [
1398
                'item_id = ?' => intval($itemId)
1399
            ]]
1400
        );
1401
    }
1402
1403
    /**
1404
     * Delete a item with its beneficiaries
1405
     * @param int $itemId The item ID
1406
     * @return int The number of affected rows. Otherwise return false
1407
     */
1408
    public function deleteItem($itemId)
1409
    {
1410
        $itemTable = Database::get_main_table(BuyCoursesPlugin::TABLE_ITEM);
1411
1412
        $affectedRows = Database::delete(
1413
            $itemTable,
1414
            ['id = ?' => intval($itemId)]
1415
        );
1416
1417
        if (!$affectedRows) {
1418
            return false;
1419
        }
1420
1421
        return $this->deleteItemBeneficiaries($itemId);
1422
    }
1423
1424
    /**
1425
     * Register a item
1426
     * @param array $itemData The item data
1427
     * @return int The item ID. Otherwise return false
1428
     */
1429
    public function registerItem(array $itemData)
1430
    {
1431
        $itemTable = Database::get_main_table(BuyCoursesPlugin::TABLE_ITEM);
1432
1433
        return Database::insert($itemTable, $itemData);
1434
    }
1435
1436
    /**
1437
     * Update the item data by product
1438
     * @param array $itemData The item data to be updated
1439
     * @param int $productId The product ID
1440
     * @param int $productType The type of product
1441
     * @return int The number of affected rows. Otherwise return false
1442
     */
1443 View Code Duplication
    public function updateItem(array $itemData, $productId, $productType)
1444
    {
1445
        $itemTable = Database::get_main_table(BuyCoursesPlugin::TABLE_ITEM);
1446
1447
        return Database::update(
1448
            $itemTable,
1449
            $itemData,
1450
            [
1451
                'product_id = ? AND ' => intval($productId),
1452
                'product_type' => $productType
1453
            ]
1454
        );
1455
    }
1456
1457
    /**
1458
     * Remove all beneficiaries for a item
1459
     * @param int $itemId The user ID
1460
     * @return int The number of affected rows. Otherwise return false
1461
     */
1462 View Code Duplication
    public function deleteItemBeneficiaries($itemId)
1463
    {
1464
        $beneficiaryTable = Database::get_main_table(BuyCoursesPlugin::TABLE_ITEM_BENEFICIARY);
1465
1466
        return Database::delete(
1467
            $beneficiaryTable,
1468
            ['item_id = ?' => intval($itemId)]
1469
        );
1470
    }
1471
1472
    /**
1473
     * Register the beneficiaries users with the sale of item
1474
     * @param int $itemId The item ID
1475
     * @param array $userIds The beneficiary user ID and Teachers commissions if enabled
1476
     */
1477
    public function registerItemBeneficiaries($itemId, array $userIds)
1478
    {
1479
        $beneficiaryTable = Database::get_main_table(BuyCoursesPlugin::TABLE_ITEM_BENEFICIARY);
1480
1481
        $this->deleteItemBeneficiaries($itemId);
1482
1483 View Code Duplication
        foreach ($userIds as $userId => $commissions) {
1484
            Database::insert(
1485
                $beneficiaryTable,
1486
                [
1487
                    'item_id' => intval($itemId),
1488
                    'user_id' => intval($userId),
1489
                    'commissions' => intval($commissions)
1490
                ]
1491
            );
1492
        }
1493
    }
1494
1495
    /**
1496
     * Check if a course is valid for sale
1497
     * @param Course $course The course
1498
     * @return boolean
1499
     */
1500
    public function isValidCourse(Course $course)
1501
    {
1502
        $courses = $this->getCourses();
1503
1504
        foreach ($courses as $_c) {
1505
            if ($_c->getCode() === $course->getCode()) {
1506
                return true;
1507
            }
1508
        }
1509
1510
        return false;
1511
    }
1512
1513
    /**
1514
     * Gets the beneficiaries with commissions and current paypal accounts by sale
1515
     * @param int $saleId The sale ID
1516
     * @return array
1517
     */
1518
    public function getBeneficiariesBySale($saleId)
1519
    {
1520
1521
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
1522
1523
        $beneficiaries = [];
1524
        $sale = $this->getSale($saleId);
1525
        $item = $this->getItemByProduct($sale['product_id'], $sale['product_type']);
1526
        $itemBeneficiaries = $this->getItemBeneficiaries($item['id']);
1527
        return $itemBeneficiaries;
1528
1529
    }
1530
1531
    /**
1532
     * gets all payouts
1533
     * @param int $status - default 0 - pending
1534
     * @param int $payoutId - for get an individual payout if want all then false
1535
     * @return array
1536
     */
1537
    public function getPayouts($status = self::PAYOUT_STATUS_PENDING, $payoutId = false, $userId = false)
1538
    {
1539
        $condition = ($payoutId) ? 'AND p.id = '. intval($payoutId) : '';
1540
        $condition2 = ($userId) ? ' AND p.user_id = ' . intval($userId) : '';
1541
        $typeResult = ($condition) ? 'first' : 'all';
1542
        $payoutsTable = Database::get_main_table(BuyCoursesPlugin::TABLE_PAYPAL_PAYOUTS);
1543
        $saleTable = Database::get_main_table(BuyCoursesPlugin::TABLE_SALE);
1544
        $currencyTable = Database::get_main_table(BuyCoursesPlugin::TABLE_CURRENCY);
1545
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
1546
        $extraFieldTable = Database::get_main_table(TABLE_EXTRA_FIELD);
1547
        $extraFieldValues = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1548
1549
        $paypalExtraField = Database::select(
1550
            "*",
1551
            $extraFieldTable,
1552
            [
1553
                'where' => ['variable = ?' => 'paypal']
1554
            ],
1555
            'first'
1556
        );
1557
1558
        if (!$paypalExtraField) {
1559
            return false;
1560
        }
1561
1562
        $innerJoins = "
1563
            INNER JOIN $userTable u ON p.user_id = u.id
1564
            INNER JOIN $saleTable s ON s.id = p.sale_id
1565
            INNER JOIN $currencyTable c ON s.currency_id = c.id
1566
            LEFT JOIN  $extraFieldValues efv ON p.user_id = efv.item_id 
1567
            AND field_id = " . intval($paypalExtraField['id']) . "
1568
        ";
1569
1570
        $payouts = Database::select(
1571
            "p.* , u.firstname, u.lastname, efv.value as paypal_account, s.reference as sale_reference, s.price as item_price, c.iso_code",
1572
            "$payoutsTable p $innerJoins",
1573
            [
1574
                'where' => ['p.status = ? '.$condition . ' ' .$condition2 => $status]
1575
            ],
1576
            $typeResult
1577
        );
1578
1579
        return $payouts;
1580
    }
1581
1582
    /**
1583
     * Verify if the beneficiary have a paypal account
1584
     * @param int $userId
1585
     * @return true if the user have a paypal account, false if not
1586
     */
1587
    public function verifyPaypalAccountByBeneficiary($userId)
1588
    {
1589
        $extraFieldTable = Database::get_main_table(TABLE_EXTRA_FIELD);
1590
        $extraFieldValues = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1591
1592
        $paypalExtraField = Database::select(
1593
            "*",
1594
            $extraFieldTable,
1595
            [
1596
                'where' => ['variable = ?' => 'paypal']
1597
            ],
1598
            'first'
1599
        );
1600
1601
        if (!$paypalExtraField) {
1602
            return false;
1603
        }
1604
1605
        $paypalFieldId = $paypalExtraField['id'];
1606
1607
        $paypalAccount = Database::select(
1608
            "value",
1609
            $extraFieldValues,
1610
            [
1611
                'where' => ['field_id = ? AND item_id = ?' => [intval($paypalFieldId), intval($userId)]]
1612
            ],
1613
            'first'
1614
        );
1615
1616
        if (!$paypalAccount) {
1617
            return false;
1618
        }
1619
1620
        if ($paypalAccount['value'] === '') {
1621
            return false;
1622
        }
1623
1624
        return true;
1625
    }
1626
1627
    /**
1628
     * Register the users payouts
1629
     * @param int $saleId The sale ID
1630
     * @return array
1631
     */
1632
    public function storePayouts($saleId)
1633
    {
1634
        $payoutsTable = Database::get_main_table(BuyCoursesPlugin::TABLE_PAYPAL_PAYOUTS);
1635
        $platformCommission = $this->getPlatformCommission();
1636
1637
        $sale = $this->getSale($saleId);
1638
        $teachersCommission = number_format((floatval($sale['price']) * intval($platformCommission['commission']))/100, 2);
1639
1640
1641
        $beneficiaries = $this->getBeneficiariesBySale($saleId);
1642
        foreach ($beneficiaries as $beneficiary) {
1643
            Database::insert(
1644
                $payoutsTable,
1645
                [
1646
                    'date' => $sale['date'],
1647
                    'payout_date' => getdate(),
1648
                    'sale_id' => intval($saleId),
1649
                    'user_id' => $beneficiary['user_id'],
1650
                    'commission' => number_format((floatval($teachersCommission) * intval($beneficiary['commissions']))/100, 2),
1651
                    'status' => self::PAYOUT_STATUS_PENDING
1652
                ]
1653
            );
1654
        }
1655
    }
1656
1657
    /**
1658
     * Register the users payouts
1659
     * @param int $payoutId The payout ID
1660
     * @param int $status The status to set (-1 to cancel, 0 to pending, 1 to completed)
1661
     * @return array
1662
     */
1663 View Code Duplication
    public function setStatusPayouts($payoutId, $status)
1664
    {
1665
        $payoutsTable = Database::get_main_table(BuyCoursesPlugin::TABLE_PAYPAL_PAYOUTS);
1666
1667
        Database::update(
1668
            $payoutsTable,
1669
            ['status' => intval($status)],
1670
            ['id = ?' => intval($payoutId)]
1671
        );
1672
1673
    }
1674
1675
    /**
1676
     * Gets the stored platform commission params
1677
     * @return array
1678
     */
1679
    public function getPlatformCommission()
1680
    {
1681
        return Database::select(
1682
            '*',
1683
            Database::get_main_table(BuyCoursesPlugin::TABLE_COMMISSION),
1684
            ['id = ?' => 1],
1685
            'first'
1686
        );
1687
    }
1688
1689
    /**
1690
     * Update the platform commission
1691
     * @param int $params platform commission
1692
     * @return int The number of affected rows. Otherwise return false
1693
     */
1694 View Code Duplication
    public function updateCommission($params)
1695
    {
1696
        $commissionTable = Database::get_main_table(BuyCoursesPlugin::TABLE_COMMISSION);
1697
1698
        return Database::update(
1699
            $commissionTable,
1700
            ['commission' => intval($params['commission'])]
1701
        );
1702
    }
1703
1704
    /**
1705
     * Register addicional service
1706
     * @param array params $service
1707
     * @return mixed response
1708
     */
1709
    public function storeService($service)
1710
    {
1711
        $servicesTable = Database::get_main_table(BuyCoursesPlugin::TABLE_SERVICES);
1712
1713
        $return = Database::insert(
1714
            $servicesTable,
1715
            [
1716
                'name' => Security::remove_XSS($service['name']),
1717
                'description' => Security::remove_XSS($service['description']),
1718
                'price' => $service['price'],
1719
                'duration_days' => intval($service['duration_days']),
1720
                'applies_to' => intval($service['applies_to']),
1721
                'owner_id' => intval($service['owner_id']),
1722
                'visibility' => intval($service['visibility']),
1723
                'image' => 'simg.png',
1724
                'video_url' => $service['video_url'],
1725
                'service_information' => $service['service_information']
1726
            ]
1727
        );
1728
1729
        if ($return) {
1730
            $img = str_replace('data:image/png;base64,', '', $service['picture_crop_image_base_64']);
1731
            $img = str_replace(' ', '+', $img);
1732
            $data = base64_decode($img);
1733
            $file = api_get_path(SYS_PLUGIN_PATH).'buycourses/uploads/services/images/simg-'.$return.'.png';
1734
            file_put_contents($file, $data);
1735
1736
            Database::update(
1737
                $servicesTable,
1738
                ['image' => 'simg-'.$return.'.png'],
1739
                ['id = ?' => intval($return)]
1740
            );
1741
            return $return;
1742
        }
1743
1744
        return false;
1745
    }
1746
1747
    /**
1748
     * update a service
1749
     * @param array $service
1750
     * @param integer $id
1751
     * @return mixed response
1752
     */
1753
    public function updateService($service, $id)
1754
    {
1755
        $servicesTable = Database::get_main_table(BuyCoursesPlugin::TABLE_SERVICES);
1756
        if (!empty($service['picture_crop_image_base_64'])) {
1757
            $img = str_replace('data:image/png;base64,', '', $service['picture_crop_image_base_64']);
1758
            $img = str_replace(' ', '+', $img);
1759
            $data = base64_decode($img);
1760
            $file = api_get_path(SYS_PLUGIN_PATH).'buycourses/uploads/services/images/simg-'.$id.'.png';
1761
            file_put_contents($file, $data);
1762
        }
1763
1764
        return Database::update(
1765
            $servicesTable,
1766
            [
1767
                'name' => Security::remove_XSS($service['name']),
1768
                'description' => Security::remove_XSS($service['description']),
1769
                'price' => $service['price'],
1770
                'duration_days' => intval($service['duration_days']),
1771
                'applies_to' => intval($service['applies_to']),
1772
                'owner_id' => intval($service['owner_id']),
1773
                'visibility' => intval($service['visibility']),
1774
                'image' => 'simg-'.$id.'.png',
1775
                'video_url' => $service['video_url'],
1776
                'service_information' => $service['service_information']
1777
            ],
1778
            ['id = ?' => intval($id)]
1779
        );
1780
    }
1781
1782
    /**
1783
     * Remove a service
1784
     * @param int $id The transfer account ID
1785
     * @return int Rows affected. Otherwise return false
1786
     */
1787
    public function deleteService($id)
1788
    {
1789
        return Database::delete(
1790
            Database::get_main_table(self::TABLE_SERVICES),
1791
            ['id = ?' => intval($id)]
1792
        );
1793
    }
1794
1795
    /**
1796
     * List adicional services
1797
     * @param integer $id service id
1798
     * @return array
1799
     */
1800
    public function getServices($id = null)
1801
    {
1802
        $servicesTable = Database::get_main_table(BuyCoursesPlugin::TABLE_SERVICES);
1803
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
1804
1805
        $conditions = null;
1806
        $showData = "all";
1807
1808
        if ($id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1809
            $conditions = ['WHERE' => ['s.id = ?' => $id]];
1810
            $showData = "first";
1811
        }
1812
1813
        $innerJoins = "INNER JOIN $userTable u ON s.owner_id = u.id";
1814
        $currency = $this->getSelectedCurrency();
1815
        $isoCode = $currency['iso_code'];
1816
        $return = Database::select(
1817
            "s.*, '$isoCode' as currency, u.firstname, u.lastname",
1818
            "$servicesTable s $innerJoins",
1819
            $conditions,
0 ignored issues
show
Bug introduced by
It seems like $conditions defined by null on line 1805 can also be of type null; however, Database::select() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1820
            $showData
1821
        );
1822
1823
        $services = [];
1824
1825
        if ($id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1826
            $services['id'] = $return['id'];
1827
            $services['name'] = $return['name'];
1828
            $services['description'] = $return['description'];
1829
            $services['price'] = $return['price'];
1830
            $services['currency'] = $return['currency'];
1831
            $services['duration_days'] = $return['duration_days'];
1832
            $services['applies_to'] = $return['applies_to'];
1833
            $services['owner_id'] = $return['owner_id'];
1834
            $services['owner_name'] = api_get_person_name($return['firstname'], $return['lastname']);
1835
            $services['visibility'] = $return['visibility'];
1836
            $services['image'] = $return['image'];
1837
            $services['video_url'] = $return['video_url'];
1838
            $services['service_information'] = $return['service_information'];
1839
1840
            return $services;
1841
        }
1842
1843
        foreach ($return as $index => $service) {
1844
            $services[$index]['id'] = $service['id'];
1845
            $services[$index]['name'] = $service['name'];
1846
            $services[$index]['description'] = $service['description'];
1847
            $services[$index]['price'] = $service['price'];
1848
            $services[$index]['currency'] = $service['currency'];
1849
            $services[$index]['duration_days'] = $service['duration_days'];
1850
            $services[$index]['applies_to'] = $service['applies_to'];
1851
            $services[$index]['owner_id'] = $service['owner_id'];
1852
            $services[$index]['owner_name'] = api_get_person_name($service['firstname'], $service['lastname']);
1853
            $services[$index]['visibility'] = $service['visibility'];
1854
            $services[$index]['image'] = $service['image'];
1855
            $services[$index]['video_url'] = $service['video_url'];
1856
            $services[$index]['service_information'] = $service['service_information'];
1857
        }
1858
1859
        return $services;
1860
    }
1861
1862
    /**
1863
     * Get the statuses for sales
1864
     * @return array
1865
     */
1866
    public function getServiceSaleStatuses()
1867
    {
1868
        return [
1869
            self::SERVICE_STATUS_CANCELLED => $this->get_lang('SaleStatusCancelled'),
1870
            self::SERVICE_STATUS_PENDING => $this->get_lang('SaleStatusPending'),
1871
            self::SERVICE_STATUS_COMPLETED => $this->get_lang('SaleStatusCompleted')
1872
        ];
1873
    }
1874
1875
    /**
1876
     * List services sales
1877
     * @param integer $id service id
1878
     * @param integer $buyerId buyer id
1879
     * @param integer $status status
1880
     * @param integer $nodeType The node Type ( User = 1 , Course = 2 , Session = 3 )
1881
     * @param integer $nodeId the nodeId
1882
     * @param boolean $hot enable hot services
1883
     * @return array
1884
     */
1885
    public function getServiceSale($id = null, $buyerId = null, $status = null, $nodeType = null, $nodeId = null, $hot = false)
1886
    {
1887
        $servicesTable = Database::get_main_table(BuyCoursesPlugin::TABLE_SERVICES);
1888
        $servicesSaleTable = Database::get_main_table(BuyCoursesPlugin::TABLE_SERVICES_SALE);
1889
1890
        $conditions = null;
1891
        $showData = "all";
1892
        $groupBy = "";
1893
1894
        if ($id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1895
            $conditions = ['WHERE' => ['ss.id = ?' => $id]];
1896
            $showData = "first";
1897
        }
1898
1899
        if ($buyerId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $buyerId of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1900
            $conditions = ['WHERE' => ['ss.buyer_id = ?' => $buyerId], 'ORDER' => 'id ASC'];
1901
        }
1902
1903
        if (is_numeric($status)) {
1904
            $conditions = ['WHERE' => ['ss.status = ?' => $status], 'ORDER' => 'id ASC'];
1905
        }
1906
1907
        if ($id && $buyerId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Bug Best Practice introduced by
The expression $buyerId of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1908
            $conditions = ['WHERE' => ['ss.id = ? AND ss.buyer_id = ?' => [$id, $buyerId]], 'ORDER' => 'id ASC'];
1909
        }
1910
1911
        if ($nodeType && $nodeId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $nodeType of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Bug Best Practice introduced by
The expression $nodeId of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1912
            $conditions = ['WHERE' => ['ss.node_type = ? AND ss.node_id = ?' => [$nodeType, $nodeId]], 'ORDER' => 'id ASC'];
1913
        }
1914
1915
        if ($nodeType && $nodeId && $buyerId && is_numeric($status)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $nodeType of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Bug Best Practice introduced by
The expression $nodeId of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
Bug Best Practice introduced by
The expression $buyerId of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1916
            $conditions = ['WHERE' => ['ss.node_type = ? AND ss.node_id = ? AND ss.buyer_id = ? AND ss.status = ?' => [$nodeType, $nodeId, $buyerId, $status]], 'ORDER' => 'id ASC'];
1917
        }
1918
1919
        if ($hot) {
1920
            $hot = "count(ss.service_id) as hot, ";
1921
            $conditions = ['ORDER' => 'hot DESC', 'LIMIT' => '6'];
1922
            $groupBy = "GROUP BY ss.service_id";
1923
            "clean_teacher_files.php";
1924
        }
1925
1926
        $innerJoins = "INNER JOIN $servicesTable s ON ss.service_id = s.id $groupBy";
1927
        $currency = $this->getSelectedCurrency();
1928
        $isoCode = $currency['iso_code'];
1929
        $return = Database::select(
1930
            "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",
1931
            "$servicesSaleTable ss $innerJoins",
1932
            $conditions,
0 ignored issues
show
Bug introduced by
It seems like $conditions defined by null on line 1890 can also be of type null; however, Database::select() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1933
            $showData
1934
        );
1935
1936
        $servicesSale = [];
1937
1938
        if ($id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1939
1940
            $owner = api_get_user_info($return['owner_id']);
1941
            $buyer = api_get_user_info($return['buyer_id']);
1942
1943
            $servicesSale['id'] = $return['id'];
1944
            $servicesSale['service']['id'] = $return['service_id'];
1945
            $servicesSale['service']['name'] = $return['name'];
1946
            $servicesSale['service']['description'] = $return['description'];
1947
            $servicesSale['service']['price'] = $return['service_price'];
1948
            $servicesSale['service']['currency'] = $return['currency'];
1949
            $servicesSale['service']['duration_days'] = $return['duration_days'];
1950
            $servicesSale['service']['applies_to'] = $return['applies_to'];
1951
            $servicesSale['service']['owner']['id'] = $return['owner_id'];
1952
            $servicesSale['service']['owner']['name'] = api_get_person_name($owner['firstname'], $owner['lastname']);
1953
            $servicesSale['service']['visibility'] = $return['visibility'];
1954
            $servicesSale['service']['image'] = $return['image'];
1955
            $servicesSale['reference'] = $return['reference'];
1956
            $servicesSale['currency_id'] = $return['currency_id'];
1957
            $servicesSale['currency'] = $return['currency'];
1958
            $servicesSale['price'] = $return['price'];
1959
            $servicesSale['node_type'] = $return['node_type'];
1960
            $servicesSale['node_id'] = $return['node_id'];
1961
            $servicesSale['buyer']['id'] = $buyer['user_id'];
1962
            $servicesSale['buyer']['name'] = api_get_person_name($buyer['firstname'], $buyer['lastname']);
1963
            $servicesSale['buyer']['username'] = $buyer['username'];
1964
            $servicesSale['buy_date'] = $return['buy_date'];
1965
            $servicesSale['date_start'] = $return['date_start'];
1966
            $servicesSale['date_end'] = $return['date_end'];
1967
            $servicesSale['status'] = $return['status'];
1968
            $servicesSale['payment_type'] = $return['payment_type'];
1969
1970
            return $servicesSale;
1971
        }
1972
1973
1974
        foreach ($return as $index => $service) {
1975
1976
            $owner = api_get_user_info($service['owner_id']);
1977
            $buyer = api_get_user_info($service['buyer_id']);
1978
1979
            $servicesSale[$index]['id'] = $service['id'];
1980
            $servicesSale[$index]['service']['id'] = $service['service_id'];
1981
            $servicesSale[$index]['service']['name'] = $service['name'];
1982
            $servicesSale[$index]['service']['description'] = $service['description'];
1983
            $servicesSale[$index]['service']['price'] = $service['service_price'];
1984
            $servicesSale[$index]['service']['duration_days'] = $service['duration_days'];
1985
            $servicesSale[$index]['service']['applies_to'] = $service['applies_to'];
1986
            $servicesSale[$index]['service']['owner']['id'] = $service['owner_id'];
1987
            $servicesSale[$index]['service']['owner']['name'] = api_get_person_name($owner['firstname'], $owner['lastname']);
1988
            $servicesSale[$index]['service']['visibility'] = $service['visibility'];
1989
            $servicesSale[$index]['service']['image'] = $service['image'];
1990
            $servicesSale[$index]['reference'] = $service['reference'];
1991
            $servicesSale[$index]['currency_id'] = $service['currency_id'];
1992
            $servicesSale[$index]['currency'] = $service['currency'];
1993
            $servicesSale[$index]['price'] = $service['price'];
1994
            $servicesSale[$index]['node_type'] = $service['node_type'];
1995
            $servicesSale[$index]['node_id'] = $service['node_id'];
1996
            $servicesSale[$index]['buyer']['id'] = $service['buyer_id'];
1997
            $servicesSale[$index]['buyer']['name'] = api_get_person_name($buyer['firstname'], $buyer['lastname']);
1998
            $servicesSale[$index]['buyer']['username'] = $buyer['username'];
1999
            $servicesSale[$index]['buy_date'] = $service['buy_date'];
2000
            $servicesSale[$index]['date_start'] = $service['date_start'];
2001
            $servicesSale[$index]['date_end'] = $service['date_end'];
2002
            $servicesSale[$index]['status'] = $service['status'];
2003
            $servicesSale[$index]['payment_type'] = $service['payment_type'];
2004
        }
2005
2006
        return $servicesSale;
2007
    }
2008
2009
    /**
2010
     * Update service sale status to cancelled
2011
     * @param int $serviceSaleId The sale ID
2012
     * @return boolean
2013
     */
2014
    public function cancelServiceSale($serviceSaleId)
2015
    {
2016
        $this->updateServiceSaleStatus($serviceSaleId, self::SERVICE_STATUS_CANCELLED);
2017
        return true;
2018
    }
2019
2020
    /**
2021
     * Complete service sale process. Update service sale status to completed
2022
     * @param int $serviceSaleId The service sale ID
2023
     * @return boolean
2024
     */
2025
    public function completeServiceSale($serviceSaleId)
2026
    {
2027
        $serviceSale = $this->getServiceSale($serviceSaleId);
2028
2029
        if ($serviceSale['status'] == self::SERVICE_STATUS_COMPLETED) {
2030
            return true;
2031
        }
2032
2033
        $this->updateServiceSaleStatus($serviceSaleId, self::SERVICE_STATUS_COMPLETED);
2034
2035
        return true;
2036
    }
2037
2038
    /**
2039
     * Lists current service details
2040
     * @param string $name Optional. The name filter
2041
     * @param int $min Optional. The minimum price filter
2042
     * @param int $max Optional. The maximum price filter
2043
     * @param mixed $appliesTo Optional.
2044
     * @return array
2045
     */
2046
    public function getCatalogServiceList($name = null, $min = 0, $max = 0, $appliesTo = '')
2047
    {
2048
        $servicesTable = Database::get_main_table(BuyCoursesPlugin::TABLE_SERVICES);
2049
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
2050
2051
        $whereConditions = [
2052
            's.id <> ? ' => 0
2053
        ];
2054
2055
        if (!empty($name)) {
2056
            $whereConditions['AND s.name LIKE %?%'] = $name;
2057
        }
2058
2059
        if (!empty($min)) {
2060
            $whereConditions['AND s.price >= ?'] = $min;
2061
        }
2062
2063
        if (!empty($max)) {
2064
            $whereConditions['AND s.price <= ?'] = $max;
2065
        }
2066
2067
        if (!$appliesTo == '') {
2068
            $whereConditions['AND s.applies_to = ?'] = $appliesTo;
2069
        }
2070
2071
        $innerJoins = "INNER JOIN $userTable u ON s.owner_id = u.id";
2072
        $currency = $this->getSelectedCurrency();
2073
        $isoCode = $currency['iso_code'];
2074
        $return = Database::select(
2075
            "s.*, '$isoCode' as currency, u.firstname, u.lastname",
2076
            "$servicesTable s $innerJoins",
2077
            ['WHERE' => $whereConditions]
2078
        );
2079
2080
        $services = [];
2081
2082
        foreach ($return as $index => $service) {
2083
            $services[$index]['id'] = $service['id'];
2084
            $services[$index]['name'] = $service['name'];
2085
            $services[$index]['description'] = $service['description'];
2086
            $services[$index]['price'] = $service['price'];
2087
            $services[$index]['currency'] = $service['currency'];
2088
            $services[$index]['duration_days'] = $service['duration_days'];
2089
            $services[$index]['applies_to'] = $service['applies_to'];
2090
            $services[$index]['owner_id'] = $service['owner_id'];
2091
            $services[$index]['owner_name'] = api_get_person_name($service['firstname'], $service['lastname']);
2092
            $services[$index]['visibility'] = $service['visibility'];
2093
            $services[$index]['image'] = api_get_path(WEB_PLUGIN_PATH).'buycourses/uploads/services/images/'.$service['image'];
2094
            $services[$index]['video_url'] = $service['video_url'];
2095
            $services[$index]['service_information'] = $service['service_information'];
2096
        }
2097
2098
        return $services;
2099
2100
    }
2101
2102
    /**
2103
     * Update the service sale status
2104
     * @param int $serviceSaleId The service sale ID
2105
     * @param int $newStatus The new status
2106
     * @return boolean
2107
     */
2108 View Code Duplication
    private function updateServiceSaleStatus($serviceSaleId, $newStatus = self::SERVICE_STATUS_PENDING)
2109
    {
2110
        $serviceSaleTable = Database::get_main_table(self::TABLE_SERVICES_SALE);
2111
2112
        return Database::update(
2113
            $serviceSaleTable,
2114
            ['status' => intval($newStatus)],
2115
            ['id = ?' => intval($serviceSaleId)]
2116
        );
2117
    }
2118
2119
    /**
2120
     * Register a Service sale
2121
     * @param int $serviceId The service ID
2122
     * @param int $paymentType The payment type
2123
     * @param int $infoSelect The ID for Service Type
2124
     * @param int $trial trial mode
2125
     * @return boolean
2126
     */
2127
    public function registerServiceSale($serviceId, $paymentType, $infoSelect, $trial = null)
2128
    {
2129 View Code Duplication
        if (!in_array($paymentType, [self::PAYMENT_TYPE_PAYPAL, self::PAYMENT_TYPE_TRANSFER, self::PAYMENT_TYPE_CULQI])) {
2130
            return false;
2131
        }
2132
2133
        $userId = api_get_user_id();
2134
2135
        $service = $this->getServices($serviceId);
2136
2137
        if (empty($service)) {
2138
            return false;
2139
        }
2140
2141
        $currency = $this->getSelectedCurrency();
2142
2143
        $values = [
2144
            'service_id' => $serviceId,
2145
            'reference' => $this->generateReference(
2146
                $userId,
2147
                $service['applies_to'],
2148
                $infoSelect
2149
            ),
2150
            'currency_id' => $currency['id'],
2151
            'price' => $service['price'],
2152
            'node_type' => $service['applies_to'],
2153
            'node_id' => intval($infoSelect),
2154
            'buyer_id' => $userId,
2155
            'buy_date' => api_get_utc_datetime(),
2156
            'date_start' => api_get_utc_datetime(),
2157
            'date_end' => date_format(date_add(date_create(api_get_utc_datetime()), date_interval_create_from_date_string($service['duration_days'].' days')), 'Y-m-d H:i:s'),
2158
            'status' => self::SERVICE_STATUS_PENDING,
2159
            'payment_type' => intval($paymentType)
2160
        ];
2161
2162
        $returnedServiceSaleId = Database::insert(self::TABLE_SERVICES_SALE, $values);
2163
2164
        return $returnedServiceSaleId;
2165
    }
2166
2167
    /**
2168
     * Save Culqi configuration params
2169
     * @param array $params
2170
     * @return int Rows affected. Otherwise return false
2171
     */
2172
    public function saveCulqiParameters($params)
2173
    {
2174
        return Database::update(
2175
            Database::get_main_table(BuyCoursesPlugin::TABLE_CULQI),
2176
            [
2177
                'commerce_code' => $params['commerce_code'],
2178
                'api_key' => $params['api_key'],
2179
                'integration' => $params['integration']
2180
            ],
2181
            ['id = ?' => 1]
2182
        );
2183
    }
2184
2185
    /**
2186
     * Gets the stored Culqi params
2187
     * @return array
2188
     */
2189
    public function getCulqiParams()
2190
    {
2191
        return Database::select(
2192
            '*',
2193
            Database::get_main_table(BuyCoursesPlugin::TABLE_CULQI),
2194
            ['id = ?' => 1],
2195
            'first'
2196
        );
2197
    }
2198
2199
    /**
2200
     * Save Global Parameters
2201
     * @param array $params
2202
     * @return int Rows affected. Otherwise return false
2203
     */
2204
    public function saveGlobalParameters($params)
2205
    {
2206
        return Database::update(
2207
            Database::get_main_table(BuyCoursesPlugin::TABLE_GLOBAL_CONFIG),
2208
            [
2209
                'terms_and_conditions' => $params['terms_and_conditions']
2210
            ],
2211
            ['id = ?' => 1]
2212
        );
2213
    }
2214
2215
    /**
2216
     * get Global Parameters
2217
     * @return array
2218
     */
2219
    public function getGlobalParameters()
2220
    {
2221
        return Database::select(
2222
            '*',
2223
            Database::get_main_table(BuyCoursesPlugin::TABLE_GLOBAL_CONFIG),
2224
            ['id = ?' => 1],
2225
            'first'
2226
        );
2227
    }
2228
2229
    /**
2230
     * Get the path
2231
     * @param string $var path variable
2232
     * @return string path
2233
     */
2234
    public function getPath($var)
2235
    {
2236
        $pluginPath = api_get_path(WEB_PLUGIN_PATH) . 'buycourses/';
2237
        $paths = [
2238
            'SERVICE_IMAGES' => $pluginPath . 'uploads/services/images/',
2239
            'SRC' => $pluginPath . 'src/',
2240
            'VIEW' => $pluginPath . 'view/',
2241
            'UPLOADS' => $pluginPath . 'uploads/',
2242
            'LANGUAGES' => $pluginPath . 'lang/',
2243
            'RESOURCES' => $pluginPath . 'resources/',
2244
            'RESOURCES_IMG' => $pluginPath . 'resources/img/',
2245
            'RESOURCES_CSS' => $pluginPath . 'resources/css/',
2246
            'RESOURCES_JS' => $pluginPath . 'resources/js/',
2247
        ];
2248
2249
        return $paths[$var];
2250
    }
2251
2252
}
2253