Test Setup Failed
Pull Request — 1.11.x (#1576)
by José
23:39
created

BuyCoursesPlugin::getCatalogSessionList()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 50
Code Lines 28

Duplication

Lines 20
Ratio 40 %

Importance

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