Passed
Pull Request — 1.10.x (#986)
by
unknown
65:04
created

BuyCoursesPlugin::updateServiceSaleStatus()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

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

This check looks for foreach loops that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

Consider removing the loop.

Loading history...
2095
                
2096
            }
2097
2098
            return $checked; 
2099
        }
2100
        
2101
        return false;
2102
    }
2103
    
2104
    /**
2105
     * Enable Recurring Payment in a Service
2106
     * @param int $serviceSaleId the service Sale Id
2107
     * @param int $recurringPaymentStatus The recurring Payment Status ID
2108
     * @return boolean true, false
2109
     */
2110
    public function updateRecurringPayments($serviceSaleId, $recurringPaymentStatus)
2111
    {
2112
        
2113
        $serviceSaleTable = Database::get_main_table(self::TABLE_SERVICES_NODE);
2114
2115
        return Database::update(
2116
            $serviceSaleTable,
2117
            ['recurring_payment' => intval($recurringPaymentStatus)],
2118
            ['id = ?' => intval($serviceSaleId)]
2119
        );
2120
    }
2121
    
2122
2123
}
2124