Test Setup Failed
Push — master ( f71949...6c6bd7 )
by Julito
55:21
created

BuyCoursesPlugin::getCatalogServiceList()   B

Complexity

Conditions 7
Paths 48

Size

Total Lines 54
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 36
nc 48
nop 4
dl 0
loc 54
rs 7.8331
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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