Test Setup Failed
Push — master ( 4e700f...c7183e )
by Julito
63:12
created

BuyCoursesPlugin::getCourses()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 48
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

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