Completed
Push — 1.11.x ( db9766...f61bdf )
by José
49:38 queued 25:09
created

BuyCoursesPlugin::getCourseForConfiguration()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 25
Code Lines 18

Duplication

Lines 6
Ratio 24 %

Importance

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