Completed
Push — 1.11.x ( 30f47b...9fdd19 )
by José
24:40
created

BuyCoursesPlugin::create()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
1987
        return true;
1988
    }
1989
1990
    /**
1991
     * Complete service sale process. Update service sale status to completed
1992
     * @param int $serviceSaleId The service sale ID
1993
     * @return boolean
1994
     */
1995
    public function completeServiceSale($serviceSaleId)
1996
    {
1997
        $serviceSale = $this->getServiceSale($serviceSaleId);
1998
1999
        if ($serviceSale['status'] == self::SERVICE_STATUS_COMPLETED) {
2000
            return true;
2001
        }
2002
2003
        $this->updateServiceSaleStatus($serviceSaleId, self::SERVICE_STATUS_COMPLETED);
0 ignored issues
show
Bug introduced by
The method updateServiceSaleStatus() does not exist on BuyCoursesPlugin. Did you maybe mean updateService()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
2004
2005
        return true;
2006
    }
2007
2008
    /**
2009
     * Lists current service details
2010
     * @param string $name Optional. The name filter
2011
     * @param int $min Optional. The minimum price filter
2012
     * @param int $max Optional. The maximum price filter
2013
     * @param int $appliesTo Optional.
2014
     * @return array
2015
     */
2016
    public function getCatalogServiceList($name = null, $min = 0, $max = 0, $appliesTo = '')
2017
    {
2018
        $servicesTable = Database::get_main_table(BuyCoursesPlugin::TABLE_SERVICES);
2019
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
2020
2021
        $whereConditions = [
2022
            's.id <> ? ' => 0
2023
        ];
2024
2025
        if (!empty($name)) {
2026
            $whereConditions['AND s.name LIKE %?%'] = $name;
2027
        }
2028
2029
        if (!empty($min)) {
2030
            $whereConditions['AND s.price >= ?'] = $min;
2031
        }
2032
2033
        if (!empty($max)) {
2034
            $whereConditions['AND s.price <= ?'] = $max;
2035
        }
2036
2037
        if (!$appliesTo == '') {
2038
            $whereConditions['AND s.applies_to = ?'] = $appliesTo;
2039
        }
2040
2041
        $innerJoins = "INNER JOIN $userTable u ON s.owner_id = u.id";
2042
        $currency = $this->getSelectedCurrency();
2043
        $isoCode = $currency['iso_code'];
2044
        $return = Database::select(
2045
            "s.*, '$isoCode' as currency, u.firstname, u.lastname",
2046
            "$servicesTable s $innerJoins",
2047
            ['WHERE' => $whereConditions]
2048
        );
2049
2050
        $services = [];
2051
2052
        foreach ($return as $index => $service) {
2053
            $services[$index]['id'] = $service['id'];
2054
            $services[$index]['name'] = $service['name'];
2055
            $services[$index]['description'] = $service['description'];
2056
            $services[$index]['price'] = $service['price'];
2057
            $services[$index]['currency'] = $service['currency'];
2058
            $services[$index]['duration_days'] = $service['duration_days'];
2059
            $services[$index]['applies_to'] = $service['applies_to'];
2060
            $services[$index]['owner_id'] = $service['owner_id'];
2061
            $services[$index]['owner_name'] = api_get_person_name($service['firstname'], $service['lastname']);
2062
            $services[$index]['visibility'] = $service['visibility'];
2063
            $services[$index]['image'] = api_get_path(WEB_PLUGIN_PATH).'buycourses/uploads/services/images/'.$service['image'];
2064
            $services[$index]['video_url'] = $service['video_url'];
2065
            $services[$index]['service_information'] = $service['service_information'];
2066
        }
2067
2068
        return $services;
2069
2070
    }
2071
2072
}
2073