BuyCoursesPlugin   F
last analyzed

Complexity

Total Complexity 499

Size/Duplication

Total Lines 6124
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 1
Metric Value
wmc 499
eloc 2779
c 3
b 0
f 1
dl 0
loc 6124
rs 0.8

177 Methods

Rating   Name   Duplication   Size   Complexity  
A saveTpvRedsysParams() 0 14 1
A updateServiceSaleStatus() 0 10 1
A getPath() 0 16 1
B completeSubscriptionSale() 0 34 6
A getSubscriptionSaleListByDate() 0 27 3
A getSubscriptionSale() 0 9 1
A getItemByProduct() 0 32 2
A deleteService() 0 10 1
A registerItem() 0 5 1
A getDataCoupons() 0 21 2
A saveCecabankParameters() 0 15 1
A setStatusPayouts() 0 8 1
A getPayoutStatuses() 0 6 1
A getSubscription() 0 12 1
A saveCulqiParameters() 0 10 1
A checkItemSubscriptionActive() 0 16 1
A registerCoupon() 0 26 2
A cancelSubscriptionSale() 0 3 1
A registerCouponItem() 0 22 2
A getItemsCoupons() 0 24 3
A storeService() 0 38 5
A getStripeParams() 0 7 1
B getCatalogSessionList() 0 58 7
A getProductTypes() 0 5 1
A isEnabled() 0 3 5
D registerSubscriptionSale() 0 112 18
A getSaleListByPaymentType() 0 22 1
A getServiceSaleCouponCode() 0 23 1
A getServicesCoupons() 0 17 1
B getSubscriptionSaleListReport() 0 84 8
A getTpvRedsysParams() 0 7 1
A getItemBeneficiaries() 0 10 1
A getUserStatusForCourse() 0 42 4
A getSaleCouponCode() 0 23 1
A getSubscriptionSaleListByStatus() 0 17 1
A registerSubscription() 0 14 1
A getBeneficiariesBySale() 0 7 1
A getCurrencies() 0 5 1
A deleteCouponItemsByCoupon() 0 7 1
B filterSubscriptionSessionList() 0 48 6
A getSubscriptionsItemsByDuration() 0 8 1
A uninstall() 0 35 2
A checkTaxEnabledInProduct() 0 17 4
A getTransferInfoExtra() 0 7 1
B buyCoursesForGridCatalogValidator() 0 34 9
A getSaleFromReference() 0 9 1
A getNumInvoice() 0 8 2
B getServiceSales() 0 61 11
A getCouponServiceByCode() 0 5 1
A returnPagination() 0 16 1
A getCulqiParams() 0 7 1
A storePayouts() 0 27 2
A getTaxAppliesTo() 0 7 1
A getCecabankSignature() 0 22 1
A updateSubscriptionSaleStatus() 0 8 1
B filterCourseList() 0 64 7
A getFrequencies() 0 16 2
A getUserStatusForSession() 0 43 4
A getDataInvoice() 0 12 1
A getCouponStatuses() 0 5 1
B getSaleListReport() 0 84 8
A deleteItemBeneficiaries() 0 7 1
B getSalesReportScript() 0 92 9
A getSubscriptionItemByProduct() 0 32 2
A saveCurrency() 0 14 1
A setInvoice() 0 53 4
A verifyPaypalAccountByBeneficiary() 0 37 4
A getSaleStatuses() 0 6 1
A saveTransferInfoEmail() 0 6 1
A getUserStatusForSubscriptionCourse() 0 43 4
A getUserStatusForSubscriptionSession() 0 44 4
A updateItem() 0 10 1
B getCatalogServiceList() 0 50 7
B updateCouponData() 0 26 7
A returnBuyCourseButton() 0 13 2
A registerCouponSubscriptionSale() 0 14 2
A getDataCouponByCode() 0 37 3
A generateReference() 0 5 1
A getSaleListByDate() 0 27 3
B getPaymentTypes() 0 42 9
A getCoupon() 0 5 1
A updateCoupon() 0 25 2
A updateSubscription() 0 16 1
A getSubscriptionSuccessMessage() 0 23 3
A storeSubscriptionPayouts() 0 27 2
A getServiceSaleStatuses() 0 6 1
A updateSubscriptions() 0 3 1
A updateSaleStatus() 0 8 1
A getSubscriptionSaleListByEmail() 0 22 2
B getSubscriptionSessionInfo() 0 80 6
A getCouponByCode() 0 5 1
A savePaypalParams() 0 11 1
A getPriceWithCurrencyFromIsoCode() 0 15 3
A registerItemBeneficiaries() 0 13 2
A deleteCouponServicesByCoupon() 0 6 1
F update() 0 326 19
A deleteTransferAccount() 0 5 1
A getSaleListByStatus() 0 17 1
A updateSubscriptionSaleExpirationStatus() 0 8 1
A getService() 0 31 3
A deleteFrequency() 0 6 1
A getSubscriptionSaleListByUser() 0 26 2
C registerServiceSale() 0 85 11
B getCatalogCourseList() 0 50 7
B getSessionInfo() 0 80 6
A deleteItem() 0 13 2
A updateCouponDelivered() 0 9 1
B filterSessionList() 0 58 8
B getSessionForConfiguration() 0 61 5
B completeSale() 0 34 6
B getSubscriptionCourseInfo() 0 62 6
A getSaleListByUserId() 0 23 2
A getTransferAccounts() 0 5 1
A getServices() 0 24 3
A getCouponInfo() 0 13 1
A registerCouponServiceSale() 0 14 2
A updateCommission() 0 7 1
A getCouponsListByStatus() 0 5 1
A getServiceSale() 0 46 2
A getGlobalParameters() 0 7 1
A getSubscriptionItem() 0 13 1
A filterSubscriptionCourseList() 0 51 5
B getCatalogSubscriptionCourseList() 0 50 7
A install() 0 39 2
A updateService() 0 27 3
B getCatalogSubscriptionSessionList() 0 58 7
A getSelectedCurrency() 0 9 1
A updateFrequency() 0 8 1
A getSubscriptionSaleListByUserId() 0 23 2
B getCourseInfo() 0 62 6
A saveStripeParameters() 0 10 1
A getCourseList() 0 3 1
A getCecabankParams() 0 7 1
A create() 0 5 2
D registerSale() 0 104 18
A getSaleListByUser() 0 26 2
A getBuyCoursePluginPrice() 0 17 3
A getCurrency() 0 9 1
A getCourseForConfiguration() 0 27 3
A getDataCouponService() 0 24 1
A getDataSubscriptions() 0 13 1
A updateSaleReference() 0 8 1
A getDataCoupon() 0 38 3
A getSaleListByEmail() 0 22 2
A getCourses() 0 46 1
A addFrequency() 0 8 1
A selectFrequency() 0 13 1
A getSubscriptionsDue() 0 14 1
A deleteSubscription() 0 8 1
A registerCouponSale() 0 14 2
B addNewSubscription() 0 48 6
A getServiceTypes() 0 7 1
A getAllServices() 0 19 2
A getDataSubscription() 0 15 1
A getPaypalParams() 0 7 1
A completeServiceSale() 0 17 3
A getDataCouponServiceByCode() 0 24 1
A getSubscriptions() 0 5 1
A saveGlobalParameters() 0 26 3
A getItem() 0 9 1
A getSubscriptionsItemsByProduct() 0 33 3
A __construct() 0 31 1
A getFrequenciesList() 0 6 1
A registerCouponService() 0 21 2
A isValidCourse() 0 11 3
B randomText() 0 24 7
A saveTransferAccount() 0 8 1
A getCouponDiscountTypes() 0 5 1
A getSale() 0 9 1
A cancelServiceSale() 0 8 1
A getPlatformCommission() 0 7 1
A cancelSale() 0 3 1
A getDataSaleInvoice() 0 14 2
A getCouponService() 0 5 1
A getPayouts() 0 46 5
B setPriceSettings() 0 65 9
B addNewCoupon() 0 33 8

How to fix   Complexity   

Complex Class

Complex classes like BuyCoursesPlugin often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use BuyCoursesPlugin, and based on these observations, apply Extract Interface, too.

1
<?php
2
/* For license terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Entity\Course;
5
use Chamilo\CoreBundle\Entity\Session;
6
use Doctrine\ORM\Query\Expr\Join;
7
use Symfony\Component\HttpFoundation\Request as HttpRequest;
8
9
/**
10
 * Plugin class for the BuyCourses plugin.
11
 *
12
 * @package chamilo.plugin.buycourses
13
 *
14
 * @author  Jose Angel Ruiz <[email protected]>
15
 * @author  Imanol Losada <[email protected]>
16
 * @author  Alex Aragón <[email protected]>
17
 * @author  Angel Fernando Quiroz Campos <[email protected]>
18
 * @author  José Loguercio Silva  <[email protected]>
19
 * @author  Julio Montoya
20
 */
21
class BuyCoursesPlugin extends Plugin
22
{
23
    public const TABLE_PAYPAL = 'plugin_buycourses_paypal_account';
24
    public const TABLE_CURRENCY = 'plugin_buycourses_currency';
25
    public const TABLE_ITEM = 'plugin_buycourses_item';
26
    public const TABLE_ITEM_BENEFICIARY = 'plugin_buycourses_item_rel_beneficiary';
27
    public const TABLE_SALE = 'plugin_buycourses_sale';
28
    public const TABLE_TRANSFER = 'plugin_buycourses_transfer';
29
    public const TABLE_COMMISSION = 'plugin_buycourses_commission';
30
    public const TABLE_PAYPAL_PAYOUTS = 'plugin_buycourses_paypal_payouts';
31
    public const TABLE_SERVICES = 'plugin_buycourses_services';
32
    public const TABLE_SERVICES_SALE = 'plugin_buycourses_service_sale';
33
    public const TABLE_CULQI = 'plugin_buycourses_culqi';
34
    public const TABLE_GLOBAL_CONFIG = 'plugin_buycourses_global_config';
35
    public const TABLE_INVOICE = 'plugin_buycourses_invoices';
36
    public const TABLE_TPV_REDSYS = 'plugin_buycourses_tpvredsys_account';
37
    public const TABLE_COUPON = 'plugin_buycourses_coupon';
38
    public const TABLE_COUPON_ITEM = 'plugin_buycourses_coupon_rel_item';
39
    public const TABLE_COUPON_SERVICE = 'plugin_buycourses_coupon_rel_service';
40
    public const TABLE_SUBSCRIPTION = 'plugin_buycourses_subscription';
41
    public const TABLE_SUBSCRIPTION_SALE = 'plugin_buycourses_subscription_rel_sale';
42
    public const TABLE_SUBSCRIPTION_PERIOD = 'plugin_buycourses_subscription_period';
43
    public const TABLE_COUPON_SALE = 'plugin_buycourses_coupon_rel_sale';
44
    public const TABLE_COUPON_SERVICE_SALE = 'plugin_buycourses_coupon_rel_service_sale';
45
    public const TABLE_COUPON_SUBSCRIPTION_SALE = 'plugin_buycourses_coupon_rel_subscription_sale';
46
    public const TABLE_STRIPE = 'plugin_buycourses_stripe_account';
47
    public const TABLE_TPV_CECABANK = 'plugin_buycourses_cecabank_account';
48
    public const PRODUCT_TYPE_COURSE = 1;
49
    public const PRODUCT_TYPE_SESSION = 2;
50
    public const PRODUCT_TYPE_SERVICE = 3;
51
    public const PAYMENT_TYPE_PAYPAL = 1;
52
    public const PAYMENT_TYPE_TRANSFER = 2;
53
    public const PAYMENT_TYPE_CULQI = 3;
54
    public const PAYMENT_TYPE_TPV_REDSYS = 4;
55
    public const PAYMENT_TYPE_STRIPE = 5;
56
    public const PAYMENT_TYPE_TPV_CECABANK = 6;
57
    public const PAYOUT_STATUS_CANCELED = 2;
58
    public const PAYOUT_STATUS_PENDING = 0;
59
    public const PAYOUT_STATUS_COMPLETED = 1;
60
    public const SALE_STATUS_CANCELED = -1;
61
    public const SALE_STATUS_PENDING = 0;
62
    public const SALE_STATUS_COMPLETED = 1;
63
    public const SERVICE_STATUS_PENDING = 0;
64
    public const SERVICE_STATUS_COMPLETED = 1;
65
    public const SERVICE_STATUS_CANCELLED = -1;
66
    public const SERVICE_TYPE_USER = 1;
67
    public const SERVICE_TYPE_COURSE = 2;
68
    public const SERVICE_TYPE_SESSION = 3;
69
    public const SERVICE_TYPE_LP_FINAL_ITEM = 4;
70
    public const CULQI_INTEGRATION_TYPE = 'INTEG';
71
    public const CULQI_PRODUCTION_TYPE = 'PRODUC';
72
    public const TAX_APPLIES_TO_ALL = 1;
73
    public const TAX_APPLIES_TO_ONLY_COURSE = 2;
74
    public const TAX_APPLIES_TO_ONLY_SESSION = 3;
75
    public const TAX_APPLIES_TO_ONLY_SERVICES = 4;
76
    public const PAGINATION_PAGE_SIZE = 6;
77
    public const COUPON_DISCOUNT_TYPE_PERCENTAGE = 1;
78
    public const COUPON_DISCOUNT_TYPE_AMOUNT = 2;
79
    public const COUPON_STATUS_ACTIVE = 1;
80
    public const COUPON_STATUS_DISABLE = 0;
81
82
    public $isAdminPlugin = false;
83
84
    /**
85
     * BuyCoursesPlugin constructor.
86
     */
87
    public function __construct()
88
    {
89
        parent::__construct(
90
            '7.1',
91
            "
92
                Jose Angel Ruiz - NoSoloRed (original author) <br/>
93
                Francis Gonzales and Yannick Warnier - BeezNest (integration) <br/>
94
                Alex Aragón - BeezNest (Design icons and css styles) <br/>
95
                Imanol Losada - BeezNest (introduction of sessions purchase) <br/>
96
                Angel Fernando Quiroz Campos - BeezNest (cleanup and new reports) <br/>
97
                José Loguercio Silva - BeezNest (Payouts and buy Services) <br/>
98
                Julio Montoya
99
            ",
100
            [
101
                'show_main_menu_tab' => 'boolean',
102
                'public_main_menu_tab' => 'boolean',
103
                'include_sessions' => 'boolean',
104
                'include_services' => 'boolean',
105
                'paypal_enable' => 'boolean',
106
                'transfer_enable' => 'boolean',
107
                'culqi_enable' => 'boolean',
108
                'commissions_enable' => 'boolean',
109
                'unregistered_users_enable' => 'boolean',
110
                'hide_free_text' => 'boolean',
111
                'hide_shopping_cart_from_course_catalogue' => 'boolean',
112
                'invoicing_enable' => 'boolean',
113
                'tax_enable' => 'boolean',
114
                'use_currency_symbol' => 'boolean',
115
                'tpv_redsys_enable' => 'boolean',
116
                'stripe_enable' => 'boolean',
117
                'cecabank_enable' => 'boolean',
118
            ]
119
        );
120
    }
121
122
    /**
123
     * @return BuyCoursesPlugin
124
     */
125
    public static function create()
126
    {
127
        static $result = null;
128
129
        return $result ? $result : $result = new self();
130
    }
131
132
    /**
133
     * Check if plugin is enabled.
134
     *
135
     * @param bool $checkEnabled Check if, additionnally to being installed, the plugin is enabled
136
     */
137
    public function isEnabled(bool $checkEnabled = false): bool
138
    {
139
        return $this->get('paypal_enable') || $this->get('transfer_enable') || $this->get('culqi_enable') || $this->get('stripe_enable') || $this->get('cecabank_enable');
140
    }
141
142
    /**
143
     * This method creates the tables required to this plugin.
144
     */
145
    public function install()
146
    {
147
        $tablesToBeCompared = [
148
            self::TABLE_PAYPAL,
149
            self::TABLE_TRANSFER,
150
            self::TABLE_CULQI,
151
            self::TABLE_ITEM_BENEFICIARY,
152
            self::TABLE_ITEM,
153
            self::TABLE_SALE,
154
            self::TABLE_CURRENCY,
155
            self::TABLE_COMMISSION,
156
            self::TABLE_PAYPAL_PAYOUTS,
157
            self::TABLE_SERVICES,
158
            self::TABLE_SERVICES_SALE,
159
            self::TABLE_GLOBAL_CONFIG,
160
            self::TABLE_INVOICE,
161
            self::TABLE_TPV_REDSYS,
162
            self::TABLE_COUPON,
163
            self::TABLE_COUPON_ITEM,
164
            self::TABLE_COUPON_SERVICE,
165
            self::TABLE_SUBSCRIPTION,
166
            self::TABLE_SUBSCRIPTION_SALE,
167
            self::TABLE_SUBSCRIPTION_PERIOD,
168
            self::TABLE_COUPON_SALE,
169
            self::TABLE_COUPON_SERVICE_SALE,
170
            self::TABLE_COUPON_SUBSCRIPTION_SALE,
171
            self::TABLE_STRIPE,
172
            self::TABLE_TPV_CECABANK,
173
        ];
174
        $em = Database::getManager();
175
        $cn = $em->getConnection();
176
        $sm = $cn->getSchemaManager();
177
        $tables = $sm->tablesExist($tablesToBeCompared);
178
179
        if ($tables) {
180
            return false;
181
        }
182
183
        require_once api_get_path(SYS_PLUGIN_PATH).'buycourses/database.php';
184
    }
185
186
    /**
187
     * This method drops the plugin tables.
188
     */
189
    public function uninstall()
190
    {
191
        $tablesToBeDeleted = [
192
            self::TABLE_PAYPAL,
193
            self::TABLE_TRANSFER,
194
            self::TABLE_CULQI,
195
            self::TABLE_ITEM_BENEFICIARY,
196
            self::TABLE_ITEM,
197
            self::TABLE_SALE,
198
            self::TABLE_CURRENCY,
199
            self::TABLE_COMMISSION,
200
            self::TABLE_PAYPAL_PAYOUTS,
201
            self::TABLE_SERVICES_SALE,
202
            self::TABLE_SERVICES,
203
            self::TABLE_GLOBAL_CONFIG,
204
            self::TABLE_INVOICE,
205
            self::TABLE_TPV_REDSYS,
206
            self::TABLE_COUPON,
207
            self::TABLE_COUPON_ITEM,
208
            self::TABLE_COUPON_SERVICE,
209
            self::TABLE_SUBSCRIPTION,
210
            self::TABLE_SUBSCRIPTION_SALE,
211
            self::TABLE_SUBSCRIPTION_PERIOD,
212
            self::TABLE_COUPON_SALE,
213
            self::TABLE_COUPON_SERVICE_SALE,
214
            self::TABLE_COUPON_SUBSCRIPTION_SALE,
215
            self::TABLE_STRIPE,
216
        ];
217
218
        foreach ($tablesToBeDeleted as $tableToBeDeleted) {
219
            $table = Database::get_main_table($tableToBeDeleted);
220
            $sql = "DROP TABLE IF EXISTS $table";
221
            Database::query($sql);
222
        }
223
        $this->manageTab(false);
224
    }
225
226
    public function update()
227
    {
228
        $table = self::TABLE_GLOBAL_CONFIG;
229
        $sql = "SHOW COLUMNS FROM $table WHERE Field = 'global_tax_perc'";
230
        $res = Database::query($sql);
231
232
        if (Database::num_rows($res) === 0) {
233
            $sql = "ALTER TABLE $table ADD (
234
                sale_email varchar(255) NOT NULL,
235
                global_tax_perc int unsigned NOT NULL,
236
                tax_applies_to int unsigned NOT NULL,
237
                tax_name varchar(255) NOT NULL,
238
                seller_name varchar(255) NOT NULL,
239
                seller_id varchar(255) NOT NULL,
240
                seller_address varchar(255) NOT NULL,
241
                seller_email varchar(255) NOT NULL,
242
                next_number_invoice int unsigned NOT NULL,
243
                invoice_series varchar(255) NOT NULL
244
            )";
245
            $res = Database::query($sql);
246
            if (!$res) {
0 ignored issues
show
introduced by
$res is of type Doctrine\DBAL\Driver\Statement, thus it always evaluated to true.
Loading history...
247
                echo Display::return_message($this->get_lang('ErrorUpdateFieldDB'), 'warning');
248
            }
249
        }
250
251
        $sql = "SHOW COLUMNS FROM $table WHERE Field = 'info_email_extra'";
252
        $res = Database::query($sql);
253
254
        if (Database::num_rows($res) === 0) {
255
            $sql = "ALTER TABLE $table ADD (info_email_extra TEXT NOT NULL)";
256
            $res = Database::query($sql);
257
            if (!$res) {
0 ignored issues
show
introduced by
$res is of type Doctrine\DBAL\Driver\Statement, thus it always evaluated to true.
Loading history...
258
                echo Display::return_message($this->get_lang('ErrorUpdateFieldDB'), 'warning');
259
            }
260
        }
261
262
        $table = self::TABLE_ITEM;
263
        $sql = "SHOW COLUMNS FROM $table WHERE Field = 'tax_perc'";
264
        $res = Database::query($sql);
265
266
        if (Database::num_rows($res) === 0) {
267
            $sql = "ALTER TABLE $table ADD tax_perc int unsigned NULL";
268
            $res = Database::query($sql);
269
            if (!$res) {
0 ignored issues
show
introduced by
$res is of type Doctrine\DBAL\Driver\Statement, thus it always evaluated to true.
Loading history...
270
                echo Display::return_message($this->get_lang('ErrorUpdateFieldDB'), 'warning');
271
            }
272
        }
273
274
        $table = self::TABLE_SERVICES;
275
        $sql = "SHOW COLUMNS FROM $table WHERE Field = 'tax_perc'";
276
        $res = Database::query($sql);
277
278
        if (Database::num_rows($res) === 0) {
279
            $sql = "ALTER TABLE $table ADD tax_perc int unsigned NULL";
280
            $res = Database::query($sql);
281
            if (!$res) {
0 ignored issues
show
introduced by
$res is of type Doctrine\DBAL\Driver\Statement, thus it always evaluated to true.
Loading history...
282
                echo Display::return_message($this->get_lang('ErrorUpdateFieldDB'), 'warning');
283
            }
284
        }
285
286
        $table = self::TABLE_SALE;
287
        $sql = "SHOW COLUMNS FROM $table WHERE Field = 'tax_perc'";
288
        $res = Database::query($sql);
289
290
        if (Database::num_rows($res) === 0) {
291
            $sql = "ALTER TABLE $table ADD (
292
                price_without_tax decimal(10,2) NULL,
293
                tax_perc int unsigned NULL,
294
                tax_amount decimal(10,2) NULL,
295
                invoice int unsigned NULL
296
            )";
297
            $res = Database::query($sql);
298
            if (!$res) {
0 ignored issues
show
introduced by
$res is of type Doctrine\DBAL\Driver\Statement, thus it always evaluated to true.
Loading history...
299
                echo Display::return_message($this->get_lang('ErrorUpdateFieldDB'), 'warning');
300
            }
301
        }
302
303
        $sql = "SHOW COLUMNS FROM $table WHERE Field = 'price_without_discount'";
304
        $res = Database::query($sql);
305
306
        if (Database::num_rows($res) === 0) {
307
            $sql = "ALTER TABLE $table ADD (
308
                price_without_discount decimal(10,2) NULL,
309
                discount_amount decimal(10,2) NULL
310
            )";
311
            $res = Database::query($sql);
312
            if (!$res) {
0 ignored issues
show
introduced by
$res is of type Doctrine\DBAL\Driver\Statement, thus it always evaluated to true.
Loading history...
313
                echo Display::return_message($this->get_lang('ErrorUpdateFieldDB'), 'warning');
314
            }
315
        }
316
317
        $table = self::TABLE_SERVICES_SALE;
318
        $sql = "SHOW COLUMNS FROM $table WHERE Field = 'tax_perc'";
319
        $res = Database::query($sql);
320
321
        if (Database::num_rows($res) === 0) {
322
            $sql = "ALTER TABLE $table ADD (
323
                price_without_tax decimal(10,2) NULL,
324
                tax_perc int unsigned NULL,
325
                tax_amount decimal(10,2) NULL,
326
                invoice int unsigned NULL
327
            )";
328
            $res = Database::query($sql);
329
            if (!$res) {
0 ignored issues
show
introduced by
$res is of type Doctrine\DBAL\Driver\Statement, thus it always evaluated to true.
Loading history...
330
                echo Display::return_message($this->get_lang('ErrorUpdateFieldDB'), 'warning');
331
            }
332
        }
333
334
        $sql = "SHOW COLUMNS FROM $table WHERE Field = 'price_without_discount'";
335
        $res = Database::query($sql);
336
337
        if (Database::num_rows($res) === 0) {
338
            $sql = "ALTER TABLE $table ADD (
339
                price_without_discount decimal(10,2) NULL,
340
                discount_amount decimal(10,2) NULL
341
            )";
342
            $res = Database::query($sql);
343
            if (!$res) {
0 ignored issues
show
introduced by
$res is of type Doctrine\DBAL\Driver\Statement, thus it always evaluated to true.
Loading history...
344
                echo Display::return_message($this->get_lang('ErrorUpdateFieldDB'), 'warning');
345
            }
346
        }
347
348
        $table = self::TABLE_INVOICE;
349
        $sql = "CREATE TABLE IF NOT EXISTS $table (
350
            id int unsigned NOT NULL AUTO_INCREMENT,
351
            sale_id int unsigned NOT NULL,
352
            is_service int unsigned NOT NULL,
353
            num_invoice int unsigned NOT NULL,
354
            year int(4) unsigned NOT NULL,
355
            serie varchar(255) NOT NULL,
356
            date_invoice datetime NOT NULL,
357
            PRIMARY KEY (id)
358
        )";
359
        Database::query($sql);
360
361
        $table = self::TABLE_TPV_REDSYS;
362
        $sql = "CREATE TABLE IF NOT EXISTS $table (
363
            id int unsigned NOT NULL AUTO_INCREMENT,
364
            merchantcode varchar(255) NOT NULL,
365
            terminal varchar(255) NOT NULL,
366
            currency varchar(255) NOT NULL,
367
            kc varchar(255) NOT NULL,
368
            url_redsys varchar(255) NOT NULL,
369
            url_redsys_sandbox varchar(255) NOT NULL,
370
            sandbox int unsigned NULL,
371
            PRIMARY KEY (id)
372
        )";
373
        Database::query($sql);
374
375
        $sql = "SELECT * FROM $table";
376
        $res = Database::query($sql);
377
        if (Database::num_rows($res) == 0) {
378
            Database::insert($table, [
379
                'url_redsys' => 'https://sis.redsys.es/sis/realizarPago',
380
                'url_redsys_sandbox' => 'https://sis-t.redsys.es:25443/sis/realizarPago',
381
            ]);
382
        }
383
384
        $table = self::TABLE_COUPON;
385
        $sql = "CREATE TABLE IF NOT EXISTS $table (
386
            id int unsigned NOT NULL AUTO_INCREMENT,
387
            code varchar(255) NOT NULL,
388
            discount_type int unsigned NOT NULL,
389
            discount_amount decimal(10, 2) NOT NULL,
390
            valid_start datetime NOT NULL,
391
            valid_end datetime NOT NULL,
392
            delivered varchar(255) NOT NULL,
393
            active tinyint NOT NULL,
394
            PRIMARY KEY (id)
395
        )";
396
        Database::query($sql);
397
398
        $table = self::TABLE_COUPON_ITEM;
399
        $sql = "CREATE TABLE IF NOT EXISTS $table (
400
            id int unsigned NOT NULL AUTO_INCREMENT,
401
            coupon_id int unsigned NOT NULL,
402
            product_type int unsigned NOT NULL,
403
            product_id int unsigned NOT NULL,
404
            PRIMARY KEY (id)
405
        )";
406
        Database::query($sql);
407
408
        $table = self::TABLE_COUPON_SERVICE;
409
        $sql = "CREATE TABLE IF NOT EXISTS $table (
410
            id int unsigned NOT NULL AUTO_INCREMENT,
411
            coupon_id int unsigned NOT NULL,
412
            service_id int unsigned NOT NULL,
413
            PRIMARY KEY (id)
414
        )";
415
        Database::query($sql);
416
417
        $table = self::TABLE_SUBSCRIPTION;
418
        $sql = "CREATE TABLE IF NOT EXISTS $table (
419
            product_type int unsigned NOT NULL,
420
            product_id int unsigned NOT NULL,
421
            duration int unsigned NOT NULL,
422
            currency_id int unsigned NOT NULL,
423
            price decimal(10, 2) NOT NULL,
424
            tax_perc int unsigned,
425
            PRIMARY KEY (product_type, product_id, duration)
426
        )";
427
        Database::query($sql);
428
429
        $table = self::TABLE_SUBSCRIPTION_SALE;
430
        $sql = "CREATE TABLE IF NOT EXISTS $table (
431
            id int unsigned NOT NULL AUTO_INCREMENT,
432
            currency_id int unsigned NOT NULL,
433
            reference varchar(255) NOT NULL,
434
            date datetime NOT NULL,
435
            user_id int unsigned NOT NULL,
436
            product_type int NOT NULL,
437
            product_name varchar(255) NOT NULL,
438
            product_id int unsigned NOT NULL,
439
            price decimal(10,2) NOT NULL,
440
            price_without_tax decimal(10,2) NULL,
441
            tax_perc int unsigned NULL,
442
            tax_amount decimal(10,2) NULL,
443
            status int NOT NULL,
444
            payment_type int NOT NULL,
445
            invoice int NOT NULL,
446
            price_without_discount decimal(10,2),
447
            discount_amount decimal(10,2),
448
            subscription_end datetime NOT NULL,
449
            expired tinyint NULL,
450
            PRIMARY KEY (id)
451
        )";
452
        Database::query($sql);
453
454
        $table = self::TABLE_SUBSCRIPTION_PERIOD;
455
        $sql = "CREATE TABLE IF NOT EXISTS $table (
456
            duration int unsigned NOT NULL,
457
            name varchar(50) NOT NULL,
458
            PRIMARY KEY (duration)
459
        )";
460
        Database::query($sql);
461
462
        $table = self::TABLE_COUPON_SALE;
463
        $sql = "CREATE TABLE IF NOT EXISTS $table (
464
            id int unsigned NOT NULL AUTO_INCREMENT,
465
            coupon_id int unsigned NOT NULL,
466
            sale_id int unsigned NOT NULL,
467
            PRIMARY KEY (id)
468
        )";
469
        Database::query($sql);
470
471
        $table = self::TABLE_COUPON_SERVICE_SALE;
472
        $sql = "CREATE TABLE IF NOT EXISTS $table (
473
            id int unsigned NOT NULL AUTO_INCREMENT,
474
            coupon_id int unsigned NOT NULL,
475
            service_sale_id int unsigned NOT NULL,
476
            PRIMARY KEY (id)
477
        )";
478
        Database::query($sql);
479
480
        $table = self::TABLE_COUPON_SUBSCRIPTION_SALE;
481
        $sql = "CREATE TABLE IF NOT EXISTS $table (
482
            id int unsigned NOT NULL AUTO_INCREMENT,
483
            coupon_id int unsigned NOT NULL,
484
            sale_id int unsigned NOT NULL,
485
            PRIMARY KEY (id)
486
        )";
487
        Database::query($sql);
488
489
        $table = self::TABLE_STRIPE;
490
        $sql = "CREATE TABLE IF NOT EXISTS $table (
491
            id int unsigned NOT NULL AUTO_INCREMENT,
492
            account_id varchar(255) NOT NULL,
493
            secret_key varchar(255) NOT NULL,
494
            endpoint_secret varchar(255) NOT NULL,
495
            PRIMARY KEY (id)
496
        )";
497
        Database::query($sql);
498
499
        $sql = "SELECT * FROM $table";
500
        $res = Database::query($sql);
501
        if (Database::num_rows($res) == 0) {
502
            Database::insert($table, [
503
                'account_id' => '',
504
                'secret_key' => '',
505
                'endpoint_secret' => '',
506
            ]);
507
        }
508
509
        $table = self::TABLE_TPV_CECABANK;
510
        $sql = "CREATE TABLE IF NOT EXISTS $table (
511
            id int unsigned NOT NULL AUTO_INCREMENT,
512
            crypto_key varchar(255) NOT NULL,
513
            merchant_id varchar(255) NOT NULL,
514
            acquirer_bin varchar(255) NOT NULL,
515
            terminal_id varchar(255) NOT NULL,
516
            cypher varchar(255) NOT NULL,
517
            exponent varchar(255) NOT NULL,
518
            supported_payment varchar(255) NOT NULL,
519
            url varchar(255) NOT NULL,
520
            PRIMARY KEY (id)
521
        )";
522
        Database::query($sql);
523
524
        Display::addFlash(
525
            Display::return_message(
526
                $this->get_lang('Updated'),
527
                'info',
528
                false
529
            )
530
        );
531
532
        $fieldlabel = 'buycourses_company';
533
        $fieldtype = '1';
534
        $fieldtitle = $this->get_lang('Company');
535
        $fielddefault = '';
536
        UserManager::create_extra_field($fieldlabel, $fieldtype, $fieldtitle, $fielddefault);
537
538
        $fieldlabel = 'buycourses_vat';
539
        $fieldtype = '1';
540
        $fieldtitle = $this->get_lang('VAT');
541
        $fielddefault = '';
542
        UserManager::create_extra_field($fieldlabel, $fieldtype, $fieldtitle, $fielddefault);
543
544
        $fieldlabel = 'buycourses_address';
545
        $fieldtype = '1';
546
        $fieldtitle = $this->get_lang('Address');
547
        $fielddefault = '';
548
        UserManager::create_extra_field($fieldlabel, $fieldtype, $fieldtitle, $fielddefault);
549
550
        header('Location: '.api_get_path(WEB_PLUGIN_PATH).'buycourses');
551
        exit;
552
    }
553
554
    /**
555
     * This function verify if the plugin is enable and return the price info for a course or session in the new grid
556
     * catalog for 1.11.x , the main purpose is to show if a course or session is in sale it shows in the main platform
557
     * course catalog so the old buycourses plugin catalog can be deprecated.
558
     *
559
     * @param int $productId   course or session id
560
     * @param int $productType course or session type
561
     *
562
     * @return mixed bool|string html
563
     */
564
    public function buyCoursesForGridCatalogValidator(int $productId, int $productType)
565
    {
566
        $return = [];
567
        $paypal = $this->get('paypal_enable') === 'true';
568
        $transfer = $this->get('transfer_enable') === 'true';
569
        $stripe = $this->get('stripe_enable') === 'true';
570
        $culqi = $this->get('culqi_enable') === 'true';
571
        $cecabank = $this->get('cecabank_enable') === 'true';
572
        $tpv_redsys = $this->get('tpv_redsys_enable') === 'true';
573
        $hideFree = $this->get('hide_free_text') === 'true';
574
575
        if ($paypal || $transfer || $stripe || $culqi || $cecabank || $tpv_redsys) {
576
            $item = $this->getItemByProduct($productId, $productType);
577
            $html = '<div class="buycourses-price">';
578
            if ($item) {
579
                $html .= '<span class="label label-primary label-price">
580
                            <strong>'.$item['total_price_formatted'].'</strong>
581
                          </span>';
582
                $return['verificator'] = true;
583
            } else {
584
                if ($hideFree == false) {
585
                    $html .= '<span class="label label-primary label-free">
586
                                <strong>'.$this->get_lang('Free').'</strong>
587
                              </span>';
588
                }
589
                $return['verificator'] = false;
590
            }
591
            $html .= '</div>';
592
            $return['html'] = $html;
593
594
            return $return;
595
        }
596
597
        return false;
598
    }
599
600
    /**
601
     * Return the buyCourses plugin button to buy the course.
602
     *
603
     * @return string $html
604
     */
605
    public function returnBuyCourseButton(int $productId, int $productType)
606
    {
607
        $productId = $productId;
608
        $productType = $productType;
609
        $url = api_get_path(WEB_PLUGIN_PATH).'buycourses/src/process.php?i='.$productId.'&t='.$productType;
610
        $buyButton = Display::returnFontAwesomeIcon('shopping-cart');
611
        if ($this->get('hide_shopping_cart_from_course_catalogue') === 'true') {
612
            $buyButton = Display::returnFontAwesomeIcon('check').PHP_EOL.get_lang('Subscribe');
613
        }
614
        $html = '<a class="btn btn-success btn-sm" title="'.$this->get_lang('Buy').'" href="'.$url.'">'.
615
            $buyButton.'</a>';
616
617
        return $html;
618
    }
619
620
    /**
621
     * Get the currency for sales.
622
     *
623
     * @return array The selected currency. Otherwise return false
624
     */
625
    public function getSelectedCurrency()
626
    {
627
        return Database::select(
628
            '*',
629
            Database::get_main_table(self::TABLE_CURRENCY),
630
            [
631
                'where' => ['status = ?' => true],
632
            ],
633
            'first'
634
        );
635
    }
636
637
    /**
638
     * Get a list of currencies.
639
     *
640
     * @return array The currencies. Otherwise return false
641
     */
642
    public function getCurrencies()
643
    {
644
        return Database::select(
645
            '*',
646
            Database::get_main_table(self::TABLE_CURRENCY)
647
        );
648
    }
649
650
    /**
651
     * Save the selected currency.
652
     *
653
     * @param int $selectedId The currency Id
654
     */
655
    public function saveCurrency(int $selectedId)
656
    {
657
        $currencyTable = Database::get_main_table(
658
            self::TABLE_CURRENCY
659
        );
660
661
        Database::update(
662
            $currencyTable,
663
            ['status' => 0]
664
        );
665
        Database::update(
666
            $currencyTable,
667
            ['status' => 1],
668
            ['id = ?' => $selectedId]
669
        );
670
    }
671
672
    /**
673
     * Save the PayPal configuration params.
674
     *
675
     * @return int Rows affected. Otherwise return false
676
     */
677
    public function savePaypalParams(array $params)
678
    {
679
        return Database::update(
680
            Database::get_main_table(self::TABLE_PAYPAL),
681
            [
682
                'username' => $params['username'],
683
                'password' => $params['password'],
684
                'signature' => $params['signature'],
685
                'sandbox' => isset($params['sandbox']),
686
            ],
687
            ['id = ?' => 1]
688
        );
689
    }
690
691
    /**
692
     * Gets the stored PayPal params.
693
     *
694
     * @return array
695
     */
696
    public function getPaypalParams()
697
    {
698
        return Database::select(
699
            '*',
700
            Database::get_main_table(self::TABLE_PAYPAL),
701
            ['id = ?' => 1],
702
            'first'
703
        );
704
    }
705
706
    /**
707
     * Gets the stored TPV Redsys params.
708
     *
709
     * @return array
710
     */
711
    public function getTpvRedsysParams()
712
    {
713
        return Database::select(
714
            '*',
715
            Database::get_main_table(self::TABLE_TPV_REDSYS),
716
            ['id = ?' => 1],
717
            'first'
718
        );
719
    }
720
721
    /**
722
     * Save the tpv Redsys configuration params.
723
     *
724
     * @return int Rows affected. Otherwise return false
725
     */
726
    public function saveTpvRedsysParams(array $params)
727
    {
728
        return Database::update(
729
            Database::get_main_table(self::TABLE_TPV_REDSYS),
730
            [
731
                'merchantcode' => $params['merchantcode'],
732
                'terminal' => $params['terminal'],
733
                'currency' => $params['currency'],
734
                'kc' => $params['kc'],
735
                'url_redsys' => $params['url_redsys'],
736
                'url_redsys_sandbox' => $params['url_redsys_sandbox'],
737
                'sandbox' => isset($params['sandbox']),
738
            ],
739
            ['id = ?' => 1]
740
        );
741
    }
742
743
    /**
744
     * Save Stripe configuration params.
745
     *
746
     * @return int Rows affected. Otherwise return false
747
     */
748
    public function saveStripeParameters(array $params)
749
    {
750
        return Database::update(
751
            Database::get_main_table(self::TABLE_STRIPE),
752
            [
753
                'account_id' => $params['account_id'],
754
                'secret_key' => $params['secret_key'],
755
                'endpoint_secret' => $params['endpoint_secret'],
756
            ],
757
            ['id = ?' => 1]
758
        );
759
    }
760
761
    /**
762
     * Gets the stored Stripe params.
763
     *
764
     * @return array
765
     */
766
    public function getStripeParams()
767
    {
768
        return Database::select(
769
            '*',
770
            Database::get_main_table(self::TABLE_STRIPE),
771
            ['id = ?' => 1],
772
            'first'
773
        );
774
    }
775
776
    /**
777
     * Save a transfer account information.
778
     *
779
     * @param array $params The transfer account
780
     *
781
     * @return int Rows affected. Otherwise, return false
782
     */
783
    public function saveTransferAccount(array $params)
784
    {
785
        return Database::insert(
786
            Database::get_main_table(self::TABLE_TRANSFER),
787
            [
788
                'name' => $params['tname'],
789
                'account' => $params['taccount'],
790
                'swift' => $params['tswift'],
791
            ]
792
        );
793
    }
794
795
    /**
796
     * Save email message information in transfer.
797
     *
798
     * @param array $params The transfer message
799
     *
800
     * @return int Rows affected. Otherwise return false
801
     */
802
    public function saveTransferInfoEmail(array $params)
803
    {
804
        return Database::update(
805
            Database::get_main_table(self::TABLE_GLOBAL_CONFIG),
806
            ['info_email_extra' => $params['tinfo_email_extra']],
807
            ['id = ?' => 1]
808
        );
809
    }
810
811
    /**
812
     * Gets message information for transfer email.
813
     *
814
     * @return array
815
     */
816
    public function getTransferInfoExtra()
817
    {
818
        return Database::select(
819
            'info_email_extra AS tinfo_email_extra',
820
            Database::get_main_table(self::TABLE_GLOBAL_CONFIG),
821
            ['id = ?' => 1],
822
            'first'
823
        );
824
    }
825
826
    /**
827
     * Get a list of transfer accounts.
828
     *
829
     * @return array
830
     */
831
    public function getTransferAccounts()
832
    {
833
        return Database::select(
834
            '*',
835
            Database::get_main_table(self::TABLE_TRANSFER)
836
        );
837
    }
838
839
    /**
840
     * Remove a transfer account.
841
     *
842
     * @param int $id The transfer account ID
843
     *
844
     * @return int Rows affected. Otherwise return false
845
     */
846
    public function deleteTransferAccount(int $id)
847
    {
848
        return Database::delete(
849
            Database::get_main_table(self::TABLE_TRANSFER),
850
            ['id = ?' => $id]
851
        );
852
    }
853
854
    /**
855
     * Get registered item data.
856
     *
857
     * @param int $itemId The item ID
858
     *
859
     * @return array
860
     */
861
    public function getItem(int $itemId)
862
    {
863
        return Database::select(
864
            '*',
865
            Database::get_main_table(self::TABLE_ITEM),
866
            [
867
                'where' => ['id = ?' => $itemId],
868
            ],
869
            'first'
870
        );
871
    }
872
873
    /**
874
     * Get the item data.
875
     *
876
     * @param int $productId The item ID
877
     * @param int $itemType  The item type
878
     *
879
     * @return array
880
     */
881
    public function getItemByProduct(int $productId, int $itemType, array $coupon = null)
882
    {
883
        $buyItemTable = Database::get_main_table(self::TABLE_ITEM);
884
        $buyCurrencyTable = Database::get_main_table(self::TABLE_CURRENCY);
885
886
        $fakeItemFrom = "
887
            $buyItemTable i
888
            INNER JOIN $buyCurrencyTable c
889
                ON i.currency_id = c.id
890
        ";
891
892
        $product = Database::select(
893
            ['i.*', 'c.iso_code'],
894
            $fakeItemFrom,
895
            [
896
                'where' => [
897
                    'i.product_id = ? AND i.product_type = ?' => [
898
                        $productId,
899
                        $itemType,
900
                    ],
901
                ],
902
            ],
903
            'first'
904
        );
905
906
        if (empty($product)) {
907
            return false;
908
        }
909
910
        $this->setPriceSettings($product, self::TAX_APPLIES_TO_ONLY_COURSE, $coupon);
911
912
        return $product;
913
    }
914
915
    /**
916
     * Get registered item data.
917
     *
918
     * @param int $itemId      The product ID
919
     * @param int $productType The product type
920
     *
921
     * @return array
922
     */
923
    public function getSubscriptionItem(int $itemId, int $productType)
924
    {
925
        return Database::select(
926
            '*',
927
            Database::get_main_table(self::TABLE_SUBSCRIPTION),
928
            [
929
                'where' => ['product_id = ? AND product_type = ?' => [
930
                        $itemId,
931
                        $productType,
932
                    ],
933
                ],
934
            ],
935
            'first'
936
        );
937
    }
938
939
    /**
940
     * Get the item data.
941
     *
942
     * @param int   $productId The item ID
943
     * @param int   $itemType  The item type
944
     * @param array $coupon    Array with at least 'discount_type' and 'discount_amount' elements
945
     *
946
     * @return array
947
     */
948
    public function getSubscriptionItemByProduct(int $productId, int $itemType, array $coupon = null)
949
    {
950
        $buySubscriptionItemTable = Database::get_main_table(self::TABLE_SUBSCRIPTION);
951
        $buyCurrencyTable = Database::get_main_table(self::TABLE_CURRENCY);
952
953
        $fakeItemFrom = "
954
            $buySubscriptionItemTable s
955
            INNER JOIN $buyCurrencyTable c
956
                ON s.currency_id = c.id
957
        ";
958
959
        $item = Database::select(
960
            ['s.*', 'c.iso_code'],
961
            $fakeItemFrom,
962
            [
963
                'where' => [
964
                    's.product_id = ? AND s.product_type = ?' => [
965
                        $productId,
966
                        $itemType,
967
                    ],
968
                ],
969
            ],
970
            'first'
971
        );
972
973
        if (empty($item)) {
974
            return false;
975
        }
976
977
        $this->setPriceSettings($item, self::TAX_APPLIES_TO_ONLY_COURSE, $coupon);
978
979
        return $item;
980
    }
981
982
    /**
983
     * Get the item data.
984
     *
985
     * @param int $productId The item ID
986
     * @param int $itemType  The item type
987
     *
988
     * @return array
989
     */
990
    public function getSubscriptionsItemsByProduct(int $productId, int $itemType)
991
    {
992
        $buySubscriptionItemTable = Database::get_main_table(self::TABLE_SUBSCRIPTION);
993
        $buyCurrencyTable = Database::get_main_table(self::TABLE_CURRENCY);
994
995
        $fakeItemFrom = "
996
            $buySubscriptionItemTable s
997
            INNER JOIN $buyCurrencyTable c
998
                ON s.currency_id = c.id
999
        ";
1000
1001
        $items = Database::select(
1002
            ['s.*', 'c.iso_code'],
1003
            $fakeItemFrom,
1004
            [
1005
                'where' => [
1006
                    's.product_id = ? AND s.product_type = ?' => [
1007
                        $productId,
1008
                        $itemType,
1009
                    ],
1010
                ],
1011
            ]
1012
        );
1013
1014
        for ($i = 0; $i < count($items); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
1015
            $this->setPriceSettings($items[$i], self::TAX_APPLIES_TO_ONLY_COURSE);
1016
        }
1017
1018
        if (empty($items)) {
1019
            return false;
1020
        }
1021
1022
        return $items;
1023
    }
1024
1025
    /**
1026
     * Get registered item data by duration.
1027
     *
1028
     * @param int $duration The subscription duration
1029
     *
1030
     * @return array
1031
     */
1032
    public function getSubscriptionsItemsByDuration(int $duration)
1033
    {
1034
        return Database::select(
1035
            '*',
1036
            Database::get_main_table(self::TABLE_SUBSCRIPTION),
1037
            [
1038
                'where' => [
1039
                    'duration = ?' => [$duration],
1040
                ],
1041
            ]
1042
        );
1043
    }
1044
1045
    /**
1046
     * List courses details from the configuration page.
1047
     *
1048
     * @return array
1049
     */
1050
    public function getCourseList(int $first, int $maxResults)
1051
    {
1052
        return $this->getCourses($first, $maxResults);
1053
    }
1054
1055
    /**
1056
     * Lists current user session details, including each session course details.
1057
     *
1058
     * It can return the number of rows when $typeResult is 'count'.
1059
     *
1060
     * @param string $name       Optional. The name filter.
1061
     * @param int    $min        Optional. The minimum price filter.
1062
     * @param int    $max        Optional. The maximum price filter.
1063
     * @param string $typeResult Optional. 'all', 'first' or 'count'.
1064
     *
1065
     * @return array|int
1066
     */
1067
    public function getCatalogSessionList(int $start, int $end, string $name = null, int $min = 0, int $max = 0, string $typeResult = 'all', $sessionCategory = 0)
1068
    {
1069
        $sessions = $this->filterSessionList($start, $end, $name, $min, $max, $typeResult, $sessionCategory);
1070
1071
        if ($typeResult === 'count') {
1072
            return $sessions;
1073
        }
1074
1075
        $sessionCatalog = [];
1076
        // loop through all sessions
1077
        foreach ($sessions as $session) {
1078
            $sessionCourses = $session->getCourses();
1079
1080
            if (empty($sessionCourses)) {
1081
                continue;
1082
            }
1083
1084
            $item = $this->getItemByProduct(
1085
                $session->getId(),
1086
                self::PRODUCT_TYPE_SESSION
1087
            );
1088
1089
            if (empty($item)) {
1090
                continue;
1091
            }
1092
1093
            $sessionData = $this->getSessionInfo($session->getId());
1094
            $sessionData['coach'] = $session->getGeneralCoach()->getCompleteName();
1095
            $sessionData['enrolled'] = $this->getUserStatusForSession(
1096
                api_get_user_id(),
1097
                $session
1098
            );
1099
            $sessionData['courses'] = [];
1100
1101
            foreach ($sessionCourses as $sessionCourse) {
1102
                $course = $sessionCourse->getCourse();
1103
1104
                $sessionCourseData = [
1105
                    'title' => $course->getTitle(),
1106
                    'coaches' => [],
1107
                ];
1108
1109
                $userCourseSubscriptions = $session->getUserCourseSubscriptionsByStatus(
1110
                    $course,
1111
                    Chamilo\CoreBundle\Entity\Session::COACH
1112
                );
1113
1114
                foreach ($userCourseSubscriptions as $userCourseSubscription) {
1115
                    $user = $userCourseSubscription->getUser();
1116
                    $sessionCourseData['coaches'][] = $user->getCompleteName();
1117
                }
1118
                $sessionData['courses'][] = $sessionCourseData;
1119
            }
1120
1121
            $sessionCatalog[] = $sessionData;
1122
        }
1123
1124
        return $sessionCatalog;
1125
    }
1126
1127
    /**
1128
     * Lists current user course details.
1129
     *
1130
     * @param string $name Optional. The name filter
1131
     * @param int    $min  Optional. The minimum price filter
1132
     * @param int    $max  Optional. The maximum price filter
1133
     *
1134
     * @return array|int
1135
     */
1136
    public function getCatalogCourseList(int $first, int $pageSize, string $name = null, int $min = 0, int $max = 0, string $typeResult = 'all')
1137
    {
1138
        $courses = $this->filterCourseList($first, $pageSize, $name, $min, $max, $typeResult);
1139
1140
        if ($typeResult === 'count') {
1141
            return $courses;
1142
        }
1143
1144
        if (empty($courses)) {
1145
            return [];
1146
        }
1147
1148
        $courseCatalog = [];
1149
        foreach ($courses as $course) {
1150
            $item = $this->getItemByProduct(
1151
                $course->getId(),
1152
                self::PRODUCT_TYPE_COURSE
1153
            );
1154
1155
            if (empty($item)) {
1156
                continue;
1157
            }
1158
1159
            $courseItem = [
1160
                'id' => $course->getId(),
1161
                'title' => $course->getTitle(),
1162
                'code' => $course->getCode(),
1163
                'course_img' => null,
1164
                'item' => $item,
1165
                'teachers' => [],
1166
                'enrolled' => $this->getUserStatusForCourse(api_get_user_id(), $course),
1167
            ];
1168
1169
            foreach ($course->getTeachers() as $courseUser) {
1170
                $teacher = $courseUser->getUser();
1171
                $courseItem['teachers'][] = $teacher->getCompleteName();
1172
            }
1173
1174
            // Check images
1175
            $possiblePath = api_get_path(SYS_COURSE_PATH);
1176
            $possiblePath .= $course->getDirectory();
1177
            $possiblePath .= '/course-pic.png';
1178
1179
            if (file_exists($possiblePath)) {
1180
                $courseItem['course_img'] = api_get_path(WEB_COURSE_PATH).$course->getDirectory().'/course-pic.png';
1181
            }
1182
            $courseCatalog[] = $courseItem;
1183
        }
1184
1185
        return $courseCatalog;
1186
    }
1187
1188
    /**
1189
     * Lists current user subscription session details, including each session course details.
1190
     *
1191
     * It can return the number of rows when $typeResult is 'count'.
1192
     *
1193
     * @param int    $start           Pagination start.
1194
     * @param int    $end             Pagination end.
1195
     * @param string $name            Optional. The name filter.
1196
     * @param string $typeResult      Optional. 'all', 'first' or 'count'.
1197
     * @param int    $sessionCategory Optional. Session category id
1198
     *
1199
     * @return array|int
1200
     */
1201
    public function getCatalogSubscriptionSessionList(int $start, int $end, string $name = null, string $typeResult = 'all', int $sessionCategory = 0)
1202
    {
1203
        $sessions = $this->filterSubscriptionSessionList($start, $end, $name, $typeResult, $sessionCategory);
1204
1205
        if ($typeResult === 'count') {
1206
            return $sessions;
1207
        }
1208
1209
        $sessionCatalog = [];
1210
        // loop through all sessions
1211
        foreach ($sessions as $session) {
1212
            $sessionCourses = $session->getCourses();
1213
1214
            if (empty($sessionCourses)) {
1215
                continue;
1216
            }
1217
1218
            $item = $this->getSubscriptionItemByProduct(
1219
                $session->getId(),
1220
                self::PRODUCT_TYPE_SESSION
1221
            );
1222
1223
            if (empty($item)) {
1224
                continue;
1225
            }
1226
1227
            $sessionData = $this->getSubscriptionSessionInfo($session->getId());
1228
            $sessionData['coach'] = $session->getGeneralCoach()->getCompleteName();
1229
            $sessionData['enrolled'] = $this->getUserStatusForSubscriptionSession(
1230
                api_get_user_id(),
1231
                $session
1232
            );
1233
            $sessionData['courses'] = [];
1234
1235
            foreach ($sessionCourses as $sessionCourse) {
1236
                $course = $sessionCourse->getCourse();
1237
1238
                $sessionCourseData = [
1239
                    'title' => $course->getTitle(),
1240
                    'coaches' => [],
1241
                ];
1242
1243
                $userCourseSubscriptions = $session->getUserCourseSubscriptionsByStatus(
1244
                    $course,
1245
                    Chamilo\CoreBundle\Entity\Session::COACH
1246
                );
1247
1248
                foreach ($userCourseSubscriptions as $userCourseSubscription) {
1249
                    $user = $userCourseSubscription->getUser();
1250
                    $sessionCourseData['coaches'][] = $user->getCompleteName();
1251
                }
1252
                $sessionData['courses'][] = $sessionCourseData;
1253
            }
1254
1255
            $sessionCatalog[] = $sessionData;
1256
        }
1257
1258
        return $sessionCatalog;
1259
    }
1260
1261
    /**
1262
     * Lists current user subscription course details.
1263
     *
1264
     * @param string $typeResult Optional. 'all', 'first' or 'count'.
1265
     *
1266
     * @return array|int
1267
     */
1268
    public function getCatalogSubscriptionCourseList(int $first, int $pageSize, string $name = null, string $typeResult = 'all')
1269
    {
1270
        $courses = $this->filterSubscriptionCourseList($first, $pageSize, $name, $typeResult);
1271
1272
        if ($typeResult === 'count') {
1273
            return $courses;
1274
        }
1275
1276
        if (empty($courses)) {
1277
            return [];
1278
        }
1279
1280
        $courseCatalog = [];
1281
        foreach ($courses as $course) {
1282
            $item = $this->getSubscriptionItemByProduct(
1283
                $course->getId(),
1284
                self::PRODUCT_TYPE_COURSE
1285
            );
1286
1287
            if (empty($item)) {
1288
                continue;
1289
            }
1290
1291
            $courseItem = [
1292
                'id' => $course->getId(),
1293
                'title' => $course->getTitle(),
1294
                'code' => $course->getCode(),
1295
                'course_img' => null,
1296
                'item' => $item,
1297
                'teachers' => [],
1298
                'enrolled' => $this->getUserStatusForSubscriptionCourse(api_get_user_id(), $course),
1299
            ];
1300
1301
            foreach ($course->getTeachers() as $courseUser) {
1302
                $teacher = $courseUser->getUser();
1303
                $courseItem['teachers'][] = $teacher->getCompleteName();
1304
            }
1305
1306
            // Check images
1307
            $possiblePath = api_get_path(SYS_COURSE_PATH);
1308
            $possiblePath .= $course->getDirectory();
1309
            $possiblePath .= '/course-pic.png';
1310
1311
            if (file_exists($possiblePath)) {
1312
                $courseItem['course_img'] = api_get_path(WEB_COURSE_PATH).$course->getDirectory().'/course-pic.png';
1313
            }
1314
            $courseCatalog[] = $courseItem;
1315
        }
1316
1317
        return $courseCatalog;
1318
    }
1319
1320
    public function getPriceWithCurrencyFromIsoCode(float $price, string $isoCode): string
1321
    {
1322
        $useSymbol = $this->get('use_currency_symbol') === 'true';
1323
1324
        $result = $isoCode.' '.$price;
1325
        if ($useSymbol) {
1326
            if ($isoCode === 'BRL') {
1327
                $symbol = 'R$';
1328
            } else {
1329
                $symbol = Symfony\Component\Intl\Intl::getCurrencyBundle()->getCurrencySymbol($isoCode);
1330
            }
1331
            $result = $symbol.' '.$price;
1332
        }
1333
1334
        return $result;
1335
    }
1336
1337
    /**
1338
     * Get course info.
1339
     *
1340
     * @return array
1341
     */
1342
    public function getCourseInfo(int $courseId, array $coupon = null)
1343
    {
1344
        $entityManager = Database::getManager();
1345
        $course = $entityManager->find('ChamiloCoreBundle:Course', $courseId);
1346
1347
        if (empty($course)) {
1348
            return [];
1349
        }
1350
1351
        $item = $this->getItemByProduct(
1352
            $course->getId(),
1353
            self::PRODUCT_TYPE_COURSE,
1354
            $coupon
1355
        );
1356
1357
        if (empty($item)) {
1358
            return [];
1359
        }
1360
1361
        $courseDescription = $entityManager->getRepository('ChamiloCourseBundle:CCourseDescription')
1362
            ->findOneBy(
1363
                [
1364
                    'cId' => $course->getId(),
1365
                    'sessionId' => 0,
1366
                ],
1367
                [
1368
                    'descriptionType' => 'ASC',
1369
                ]
1370
            );
1371
1372
        $globalParameters = $this->getGlobalParameters();
1373
        $courseInfo = [
1374
            'id' => $course->getId(),
1375
            'title' => $course->getTitle(),
1376
            'description' => $courseDescription ? $courseDescription->getContent() : null,
1377
            'code' => $course->getCode(),
1378
            'visual_code' => $course->getVisualCode(),
1379
            'teachers' => [],
1380
            'item' => $item,
1381
            'tax_name' => $globalParameters['tax_name'],
1382
            'tax_enable' => $this->checkTaxEnabledInProduct(self::TAX_APPLIES_TO_ONLY_COURSE),
1383
            'course_img' => null,
1384
        ];
1385
1386
        $courseTeachers = $course->getTeachers();
1387
1388
        foreach ($courseTeachers as $teachers) {
1389
            $user = $teachers->getUser();
1390
            $teacher['id'] = $user->getId();
1391
            $teacher['name'] = $user->getCompleteName();
1392
            $courseInfo['teachers'][] = $teacher;
1393
        }
1394
1395
        $possiblePath = api_get_path(SYS_COURSE_PATH);
1396
        $possiblePath .= $course->getDirectory();
1397
        $possiblePath .= '/course-pic.png';
1398
1399
        if (file_exists($possiblePath)) {
1400
            $courseInfo['course_img'] = api_get_path(WEB_COURSE_PATH).$course->getDirectory().'/course-pic.png';
1401
        }
1402
1403
        return $courseInfo;
1404
    }
1405
1406
    /**
1407
     * Get session info.
1408
     *
1409
     * @return array
1410
     */
1411
    public function getSessionInfo(int $sessionId, array $coupon = null)
1412
    {
1413
        $entityManager = Database::getManager();
1414
        $session = $entityManager->find('ChamiloCoreBundle:Session', $sessionId);
1415
1416
        if (empty($session)) {
1417
            return [];
1418
        }
1419
1420
        $item = $this->getItemByProduct(
1421
            $session->getId(),
1422
            self::PRODUCT_TYPE_SESSION,
1423
            $coupon
1424
        );
1425
1426
        if (empty($item)) {
1427
            return [];
1428
        }
1429
1430
        $sessionDates = SessionManager::parseSessionDates(
1431
            [
1432
                'display_start_date' => $session->getDisplayStartDate(),
1433
                'display_end_date' => $session->getDisplayEndDate(),
1434
                'access_start_date' => $session->getAccessStartDate(),
1435
                'access_end_date' => $session->getAccessEndDate(),
1436
                'coach_access_start_date' => $session->getCoachAccessStartDate(),
1437
                'coach_access_end_date' => $session->getCoachAccessEndDate(),
1438
            ]
1439
        );
1440
1441
        $globalParameters = $this->getGlobalParameters();
1442
        $sessionInfo = [
1443
            'id' => $session->getId(),
1444
            'name' => $session->getName(),
1445
            'description' => $session->getDescription(),
1446
            'dates' => $sessionDates,
1447
            'courses' => [],
1448
            'tax_name' => $globalParameters['tax_name'],
1449
            'tax_enable' => $this->checkTaxEnabledInProduct(self::TAX_APPLIES_TO_ONLY_SESSION),
1450
            'image' => null,
1451
            'nbrCourses' => $session->getNbrCourses(),
1452
            'nbrUsers' => $session->getNbrUsers(),
1453
            'item' => $item,
1454
            'duration' => $session->getDuration(),
1455
        ];
1456
1457
        $fieldValue = new ExtraFieldValue('session');
1458
        $sessionImage = $fieldValue->get_values_by_handler_and_field_variable(
1459
            $session->getId(),
1460
            'image'
1461
        );
1462
1463
        if (!empty($sessionImage)) {
1464
            $sessionInfo['image'] = api_get_path(WEB_UPLOAD_PATH).$sessionImage['value'];
1465
        }
1466
1467
        $sessionCourses = $session->getCourses();
1468
        foreach ($sessionCourses as $sessionCourse) {
1469
            $course = $sessionCourse->getCourse();
1470
            $sessionCourseData = [
1471
                'title' => $course->getTitle(),
1472
                'coaches' => [],
1473
            ];
1474
1475
            $userCourseSubscriptions = $session->getUserCourseSubscriptionsByStatus(
1476
                $course,
1477
                Chamilo\CoreBundle\Entity\Session::COACH
1478
            );
1479
1480
            foreach ($userCourseSubscriptions as $userCourseSubscription) {
1481
                $user = $userCourseSubscription->getUser();
1482
                $coaches['id'] = $user->getUserId();
1483
                $coaches['name'] = $user->getCompleteName();
1484
                $sessionCourseData['coaches'][] = $coaches;
1485
            }
1486
1487
            $sessionInfo['courses'][] = $sessionCourseData;
1488
        }
1489
1490
        return $sessionInfo;
1491
    }
1492
1493
    /**
1494
     * Get course info.
1495
     *
1496
     * @return array
1497
     */
1498
    public function getSubscriptionCourseInfo(int $courseId, array $coupon = null)
1499
    {
1500
        $entityManager = Database::getManager();
1501
        $course = $entityManager->find('ChamiloCoreBundle:Course', $courseId);
1502
1503
        if (empty($course)) {
1504
            return [];
1505
        }
1506
1507
        $item = $this->getSubscriptionItemByProduct(
1508
            $course->getId(),
1509
            self::PRODUCT_TYPE_COURSE,
1510
            $coupon
1511
        );
1512
1513
        if (empty($item)) {
1514
            return [];
1515
        }
1516
1517
        $courseDescription = $entityManager->getRepository('ChamiloCourseBundle:CCourseDescription')
1518
            ->findOneBy(
1519
                [
1520
                    'cId' => $course->getId(),
1521
                    'sessionId' => 0,
1522
                ],
1523
                [
1524
                    'descriptionType' => 'ASC',
1525
                ]
1526
            );
1527
1528
        $globalParameters = $this->getGlobalParameters();
1529
        $courseInfo = [
1530
            'id' => $course->getId(),
1531
            'title' => $course->getTitle(),
1532
            'description' => $courseDescription ? $courseDescription->getContent() : null,
1533
            'code' => $course->getCode(),
1534
            'visual_code' => $course->getVisualCode(),
1535
            'teachers' => [],
1536
            'item' => $item,
1537
            'tax_name' => $globalParameters['tax_name'],
1538
            'tax_enable' => $this->checkTaxEnabledInProduct(self::TAX_APPLIES_TO_ONLY_COURSE),
1539
            'course_img' => null,
1540
        ];
1541
1542
        $courseTeachers = $course->getTeachers();
1543
1544
        foreach ($courseTeachers as $teachers) {
1545
            $user = $teachers->getUser();
1546
            $teacher['id'] = $user->getId();
1547
            $teacher['name'] = $user->getCompleteName();
1548
            $courseInfo['teachers'][] = $teacher;
1549
        }
1550
1551
        $possiblePath = api_get_path(SYS_COURSE_PATH);
1552
        $possiblePath .= $course->getDirectory();
1553
        $possiblePath .= '/course-pic.png';
1554
1555
        if (file_exists($possiblePath)) {
1556
            $courseInfo['course_img'] = api_get_path(WEB_COURSE_PATH).$course->getDirectory().'/course-pic.png';
1557
        }
1558
1559
        return $courseInfo;
1560
    }
1561
1562
    /**
1563
     * Get session info.
1564
     *
1565
     * @param array $sessionId The session ID
1566
     *
1567
     * @return array
1568
     */
1569
    public function getSubscriptionSessionInfo(int $sessionId, array $coupon = null)
1570
    {
1571
        $entityManager = Database::getManager();
1572
        $session = $entityManager->find('ChamiloCoreBundle:Session', $sessionId);
1573
1574
        if (empty($session)) {
1575
            return [];
1576
        }
1577
1578
        $item = $this->getSubscriptionItemByProduct(
1579
            $session->getId(),
1580
            self::PRODUCT_TYPE_SESSION,
1581
            $coupon
1582
        );
1583
1584
        if (empty($item)) {
1585
            return [];
1586
        }
1587
1588
        $sessionDates = SessionManager::parseSessionDates(
1589
            [
1590
                'display_start_date' => $session->getDisplayStartDate(),
1591
                'display_end_date' => $session->getDisplayEndDate(),
1592
                'access_start_date' => $session->getAccessStartDate(),
1593
                'access_end_date' => $session->getAccessEndDate(),
1594
                'coach_access_start_date' => $session->getCoachAccessStartDate(),
1595
                'coach_access_end_date' => $session->getCoachAccessEndDate(),
1596
            ]
1597
        );
1598
1599
        $globalParameters = $this->getGlobalParameters();
1600
        $sessionInfo = [
1601
            'id' => $session->getId(),
1602
            'name' => $session->getName(),
1603
            'description' => $session->getDescription(),
1604
            'dates' => $sessionDates,
1605
            'courses' => [],
1606
            'tax_name' => $globalParameters['tax_name'],
1607
            'tax_enable' => $this->checkTaxEnabledInProduct(self::TAX_APPLIES_TO_ONLY_SESSION),
1608
            'image' => null,
1609
            'nbrCourses' => $session->getNbrCourses(),
1610
            'nbrUsers' => $session->getNbrUsers(),
1611
            'item' => $item,
1612
            'duration' => $session->getDuration(),
1613
        ];
1614
1615
        $fieldValue = new ExtraFieldValue('session');
1616
        $sessionImage = $fieldValue->get_values_by_handler_and_field_variable(
1617
            $session->getId(),
1618
            'image'
1619
        );
1620
1621
        if (!empty($sessionImage)) {
1622
            $sessionInfo['image'] = api_get_path(WEB_UPLOAD_PATH).$sessionImage['value'];
1623
        }
1624
1625
        $sessionCourses = $session->getCourses();
1626
        foreach ($sessionCourses as $sessionCourse) {
1627
            $course = $sessionCourse->getCourse();
1628
            $sessionCourseData = [
1629
                'title' => $course->getTitle(),
1630
                'coaches' => [],
1631
            ];
1632
1633
            $userCourseSubscriptions = $session->getUserCourseSubscriptionsByStatus(
1634
                $course,
1635
                Chamilo\CoreBundle\Entity\Session::COACH
1636
            );
1637
1638
            foreach ($userCourseSubscriptions as $userCourseSubscription) {
1639
                $user = $userCourseSubscription->getUser();
1640
                $coaches['id'] = $user->getUserId();
1641
                $coaches['name'] = $user->getCompleteName();
1642
                $sessionCourseData['coaches'][] = $coaches;
1643
            }
1644
1645
            $sessionInfo['courses'][] = $sessionCourseData;
1646
        }
1647
1648
        return $sessionInfo;
1649
    }
1650
1651
    /**
1652
     * Register a sale.
1653
     *
1654
     * @param int    $itemId      The product ID
1655
     * @param int    $paymentType The payment type
1656
     * @param string $couponId    The coupon ID
1657
     *
1658
     * @return bool
1659
     */
1660
    public function registerSale(int $itemId, int $paymentType, string $couponId = null)
1661
    {
1662
        if (!in_array(
1663
                $paymentType,
1664
                [
1665
                    self::PAYMENT_TYPE_PAYPAL,
1666
                    self::PAYMENT_TYPE_TRANSFER,
1667
                    self::PAYMENT_TYPE_CULQI,
1668
                    self::PAYMENT_TYPE_TPV_REDSYS,
1669
                    self::PAYMENT_TYPE_STRIPE,
1670
                    self::PAYMENT_TYPE_TPV_CECABANK,
1671
                ]
1672
            )
1673
        ) {
1674
            return false;
1675
        }
1676
1677
        $entityManager = Database::getManager();
1678
        $item = $this->getItem($itemId);
1679
1680
        if (empty($item)) {
1681
            return false;
1682
        }
1683
1684
        $productName = '';
1685
        if ($item['product_type'] == self::PRODUCT_TYPE_COURSE) {
1686
            $course = $entityManager->find('ChamiloCoreBundle:Course', $item['product_id']);
1687
1688
            if (empty($course)) {
1689
                return false;
1690
            }
1691
1692
            $productName = $course->getTitle();
1693
        } elseif ($item['product_type'] == self::PRODUCT_TYPE_SESSION) {
1694
            $session = $entityManager->find('ChamiloCoreBundle:Session', $item['product_id']);
1695
1696
            if (empty($session)) {
1697
                return false;
1698
            }
1699
1700
            $productName = $session->getName();
1701
        }
1702
1703
        if ($couponId != null) {
1704
            $coupon = $this->getCoupon($couponId, $item['product_type'], $item['product_id']);
1705
        }
1706
1707
        $couponDiscount = 0;
1708
        $priceWithoutDiscount = 0;
1709
        if ($coupon != null) {
1710
            if ($coupon['discount_type'] == self::COUPON_DISCOUNT_TYPE_AMOUNT) {
1711
                $couponDiscount = $coupon['discount_amount'];
1712
            } elseif ($coupon['discount_type'] == self::COUPON_DISCOUNT_TYPE_PERCENTAGE) {
1713
                $couponDiscount = ($item['price'] * $coupon['discount_amount']) / 100;
1714
            }
1715
            $priceWithoutDiscount = $item['price'];
1716
        }
1717
        $item['price'] = $item['price'] - $couponDiscount;
1718
        $price = $item['price'];
1719
        $priceWithoutTax = null;
1720
        $taxPerc = null;
1721
        $taxAmount = 0;
1722
        $taxEnable = $this->get('tax_enable') === 'true';
1723
        $globalParameters = $this->getGlobalParameters();
1724
        $taxAppliesTo = $globalParameters['tax_applies_to'];
1725
1726
        if ($taxEnable &&
1727
            (
1728
                $taxAppliesTo == self::TAX_APPLIES_TO_ALL ||
1729
                ($taxAppliesTo == self::TAX_APPLIES_TO_ONLY_COURSE && $item['product_type'] == self::PRODUCT_TYPE_COURSE) ||
1730
                ($taxAppliesTo == self::TAX_APPLIES_TO_ONLY_SESSION && $item['product_type'] == self::PRODUCT_TYPE_SESSION)
1731
            )
1732
        ) {
1733
            $priceWithoutTax = $item['price'];
1734
            $globalTaxPerc = $globalParameters['global_tax_perc'];
1735
            $precision = 2;
1736
            $taxPerc = is_null($item['tax_perc']) ? $globalTaxPerc : $item['tax_perc'];
1737
            $taxAmount = round($priceWithoutTax * $taxPerc / 100, $precision);
1738
            $price = $priceWithoutTax + $taxAmount;
1739
        }
1740
1741
        $values = [
1742
            'reference' => $this->generateReference(
1743
                api_get_user_id(),
1744
                $item['product_type'],
1745
                $item['product_id']
1746
            ),
1747
            'currency_id' => $item['currency_id'],
1748
            'date' => api_get_utc_datetime(),
1749
            'user_id' => api_get_user_id(),
1750
            'product_type' => $item['product_type'],
1751
            'product_name' => $productName,
1752
            'product_id' => $item['product_id'],
1753
            'price' => $price,
1754
            'price_without_tax' => $priceWithoutTax,
1755
            'tax_perc' => $taxPerc,
1756
            'tax_amount' => $taxAmount,
1757
            'status' => self::SALE_STATUS_PENDING,
1758
            'payment_type' => $paymentType,
1759
            'price_without_discount' => $priceWithoutDiscount,
1760
            'discount_amount' => $couponDiscount,
1761
        ];
1762
1763
        return Database::insert(self::TABLE_SALE, $values);
1764
    }
1765
1766
    /**
1767
     * Update the sale reference.
1768
     *
1769
     * @return bool
1770
     */
1771
    public function updateSaleReference(int $saleId, string $saleReference)
1772
    {
1773
        $saleTable = Database::get_main_table(self::TABLE_SALE);
1774
1775
        return Database::update(
1776
            $saleTable,
1777
            ['reference' => $saleReference],
1778
            ['id = ?' => $saleId]
1779
        );
1780
    }
1781
1782
    /**
1783
     * Get sale data by ID.
1784
     *
1785
     * @return array
1786
     */
1787
    public function getSale(int $saleId)
1788
    {
1789
        return Database::select(
1790
            '*',
1791
            Database::get_main_table(self::TABLE_SALE),
1792
            [
1793
                'where' => ['id = ?' => (int) $saleId],
1794
            ],
1795
            'first'
1796
        );
1797
    }
1798
1799
    /**
1800
     * Get sale data by reference.
1801
     *
1802
     * @return array
1803
     */
1804
    public function getSaleFromReference(string $reference)
1805
    {
1806
        return Database::select(
1807
            '*',
1808
            Database::get_main_table(self::TABLE_SALE),
1809
            [
1810
                'where' => ['reference = ?' => $reference],
1811
            ],
1812
            'first'
1813
        );
1814
    }
1815
1816
    /**
1817
     * Get a list of sales by the payment type.
1818
     *
1819
     * @param int $paymentType The payment type to filter (default : Paypal)
1820
     *
1821
     * @return array The sale list. Otherwise return false
1822
     */
1823
    public function getSaleListByPaymentType(int $paymentType = self::PAYMENT_TYPE_PAYPAL)
1824
    {
1825
        $saleTable = Database::get_main_table(self::TABLE_SALE);
1826
        $currencyTable = Database::get_main_table(self::TABLE_CURRENCY);
1827
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
1828
1829
        $innerJoins = "
1830
            INNER JOIN $currencyTable c ON s.currency_id = c.id
1831
            INNER JOIN $userTable u ON s.user_id = u.id
1832
        ";
1833
1834
        return Database::select(
1835
            ['c.iso_code', 'u.firstname', 'u.lastname', 's.*'],
1836
            "$saleTable s $innerJoins",
1837
            [
1838
                'where' => [
1839
                    's.payment_type = ? AND s.status = ?' => [
1840
                        $paymentType,
1841
                        self::SALE_STATUS_COMPLETED,
1842
                    ],
1843
                ],
1844
                'order' => 'id DESC',
1845
            ]
1846
        );
1847
    }
1848
1849
    /**
1850
     * Get data of sales.
1851
     *
1852
     * @param int $saleId    The sale id
1853
     * @param int $isService Check if a service
1854
     *
1855
     * @return array The sale data
1856
     */
1857
    public function getDataSaleInvoice(int $saleId, int $isService)
1858
    {
1859
        if ($isService) {
1860
            $sale = $this->getServiceSale($saleId);
1861
            $sale['reference'] = $sale['reference'];
1862
            $sale['product_name'] = $sale['service']['name'];
1863
            $sale['payment_type'] = $sale['payment_type'];
1864
            $sale['user_id'] = $sale['buyer']['id'];
1865
            $sale['date'] = $sale['buy_date'];
1866
        } else {
1867
            $sale = $this->getSale($saleId);
1868
        }
1869
1870
        return $sale;
1871
    }
1872
1873
    /**
1874
     * Get data of invoice.
1875
     *
1876
     * @param int $saleId    The sale id
1877
     * @param int $isService Check if a service
1878
     *
1879
     * @return array The invoice data
1880
     */
1881
    public function getDataInvoice(int $saleId, int $isService)
1882
    {
1883
        return Database::select(
1884
            '*',
1885
            Database::get_main_table(self::TABLE_INVOICE),
1886
            [
1887
                'where' => [
1888
                    'sale_id = ? AND ' => (int) $saleId,
1889
                    'is_service = ?' => (int) $isService,
1890
                ],
1891
            ],
1892
            'first'
1893
        );
1894
    }
1895
1896
    /**
1897
     * Get invoice numbering.
1898
     *
1899
     * @param int $saleId    The sale id
1900
     * @param int $isService Check if a service
1901
     *
1902
     * @return string
1903
     */
1904
    public function getNumInvoice(int $saleId, int $isService)
1905
    {
1906
        $dataInvoice = $this->getDataInvoice($saleId, $isService);
1907
        if (empty($dataInvoice)) {
1908
            return '-';
1909
        }
1910
1911
        return $dataInvoice['serie'].$dataInvoice['year'].'/'.$dataInvoice['num_invoice'];
1912
    }
1913
1914
    /**
1915
     * Get currency data by ID.
1916
     *
1917
     * @param int $currencyId The currency ID
1918
     *
1919
     * @return array
1920
     */
1921
    public function getCurrency(int $currencyId)
1922
    {
1923
        return Database::select(
1924
            '*',
1925
            Database::get_main_table(self::TABLE_CURRENCY),
1926
            [
1927
                'where' => ['id = ?' => $currencyId],
1928
            ],
1929
            'first'
1930
        );
1931
    }
1932
1933
    /**
1934
     * Complete sale process. Update sale status to completed.
1935
     *
1936
     * @return bool
1937
     */
1938
    public function completeSale(int $saleId)
1939
    {
1940
        $sale = $this->getSale($saleId);
1941
1942
        if ($sale['status'] == self::SALE_STATUS_COMPLETED) {
1943
            return true;
1944
        }
1945
1946
        $saleIsCompleted = false;
1947
        switch ($sale['product_type']) {
1948
            case self::PRODUCT_TYPE_COURSE:
1949
                $course = api_get_course_info_by_id($sale['product_id']);
1950
                $saleIsCompleted = CourseManager::subscribeUser($sale['user_id'], $course['code']);
1951
                break;
1952
            case self::PRODUCT_TYPE_SESSION:
1953
                SessionManager::subscribeUsersToSession(
1954
                    $sale['product_id'],
1955
                    [$sale['user_id']],
1956
                    api_get_session_visibility($sale['product_id']),
1957
                    false
1958
                );
1959
1960
                $saleIsCompleted = true;
1961
                break;
1962
        }
1963
1964
        if ($saleIsCompleted) {
1965
            $this->updateSaleStatus($sale['id'], self::SALE_STATUS_COMPLETED);
1966
            if ($this->get('invoicing_enable') === 'true') {
1967
                $this->setInvoice($sale['id']);
1968
            }
1969
        }
1970
1971
        return $saleIsCompleted;
1972
    }
1973
1974
    /**
1975
     * Update sale status to canceled.
1976
     *
1977
     * @param int $saleId The sale ID
1978
     */
1979
    public function cancelSale(int $saleId)
1980
    {
1981
        $this->updateSaleStatus($saleId, self::SALE_STATUS_CANCELED);
1982
    }
1983
1984
    /**
1985
     * Get payment types.
1986
     */
1987
    public function getPaymentTypes(bool $onlyActive = false): array
1988
    {
1989
        $types = [
1990
            self::PAYMENT_TYPE_PAYPAL => 'PayPal',
1991
            self::PAYMENT_TYPE_TRANSFER => $this->get_lang('BankTransfer'),
1992
            self::PAYMENT_TYPE_CULQI => 'Culqi',
1993
            self::PAYMENT_TYPE_TPV_REDSYS => $this->get_lang('TpvPayment'),
1994
            self::PAYMENT_TYPE_STRIPE => 'Stripe',
1995
            self::PAYMENT_TYPE_TPV_CECABANK => $this->get_lang('TpvCecabank'),
1996
        ];
1997
1998
        if (!$onlyActive) {
1999
            return $types;
2000
        }
2001
2002
        if ($this->get('paypal_enable') !== 'true') {
2003
            unset($types[BuyCoursesPlugin::PAYMENT_TYPE_PAYPAL]);
2004
        }
2005
2006
        if ($this->get('transfer_enable') !== 'true') {
2007
            unset($types[BuyCoursesPlugin::PAYMENT_TYPE_TRANSFER]);
2008
        }
2009
2010
        if ($this->get('culqi_enable') !== 'true') {
2011
            unset($types[BuyCoursesPlugin::PAYMENT_TYPE_CULQI]);
2012
        }
2013
2014
        if ($this->get('tpv_redsys_enable') !== 'true'
2015
            || !file_exists(api_get_path(SYS_PLUGIN_PATH).'buycourses/resources/apiRedsys.php')
2016
        ) {
2017
            unset($types[BuyCoursesPlugin::PAYMENT_TYPE_TPV_REDSYS]);
2018
        }
2019
2020
        if ($this->get('stripe_enable') !== 'true') {
2021
            unset($types[BuyCoursesPlugin::PAYMENT_TYPE_STRIPE]);
2022
        }
2023
2024
        if ($this->get('cecabank_enable') !== 'true') {
2025
            unset($types[BuyCoursesPlugin::PAYMENT_TYPE_TPV_CECABANK]);
2026
        }
2027
2028
        return $types;
2029
    }
2030
2031
    /**
2032
     * Register a invoice.
2033
     *
2034
     * @param int $saleId    The sale ID
2035
     * @param int $isService The service type to filter (default : 0)
2036
     */
2037
    public function setInvoice(int $saleId, int $isService = 0)
2038
    {
2039
        $invoiceTable = Database::get_main_table(self::TABLE_INVOICE);
2040
        $year = date('Y');
2041
2042
        $globalParameters = $this->getGlobalParameters();
2043
        $numInvoice = $globalParameters['next_number_invoice'];
2044
        $serie = $globalParameters['invoice_series'];
2045
2046
        if (empty($numInvoice)) {
2047
            $item = Database::select(
2048
                ['MAX(num_invoice) AS num_invoice'],
2049
                $invoiceTable,
2050
                [
2051
                    'where' => ['year = ?' => $year],
2052
                ],
2053
                'first'
2054
            );
2055
2056
            $numInvoice = 1;
2057
            if ($item !== false) {
2058
                $numInvoice = (int) ($item['num_invoice'] + 1);
2059
            }
2060
        } else {
2061
            Database::update(
2062
                Database::get_main_table(self::TABLE_GLOBAL_CONFIG),
2063
                ['next_number_invoice' => 0],
2064
                ['id = ?' => 1]
2065
            );
2066
        }
2067
2068
        Database::insert(
2069
            $invoiceTable,
2070
            [
2071
                'sale_id' => $saleId,
2072
                'is_service' => $isService,
2073
                'num_invoice' => $numInvoice,
2074
                'year' => $year,
2075
                'serie' => $serie,
2076
                'date_invoice' => api_get_utc_datetime(),
2077
            ]
2078
        );
2079
2080
        // Record invoice in the sales table
2081
        $table = Database::get_main_table(self::TABLE_SALE);
2082
        if (!empty($isService)) {
2083
            $table = Database::get_main_table(self::TABLE_SERVICES_SALE);
2084
        }
2085
2086
        Database::update(
2087
            $table,
2088
            ['invoice' => 1],
2089
            ['id = ?' => $saleId]
2090
        );
2091
    }
2092
2093
    /**
2094
     * Get Tax's types.
2095
     *
2096
     * @return array
2097
     */
2098
    public function getTaxAppliesTo()
2099
    {
2100
        return [
2101
            self::TAX_APPLIES_TO_ALL => $this->get_lang('AllCoursesSessionsAndServices'),
2102
            self::TAX_APPLIES_TO_ONLY_COURSE => $this->get_lang('OnlyCourses'),
2103
            self::TAX_APPLIES_TO_ONLY_SESSION => $this->get_lang('OnlySessions'),
2104
            self::TAX_APPLIES_TO_ONLY_SERVICES => $this->get_lang('OnlyServices'),
2105
        ];
2106
    }
2107
2108
    /**
2109
     * Get a list of sales by the status.
2110
     *
2111
     * @param int $status The status to filter
2112
     *
2113
     * @return array The sale list. Otherwise return false
2114
     */
2115
    public function getSaleListByStatus(int $status = self::SALE_STATUS_PENDING)
2116
    {
2117
        $saleTable = Database::get_main_table(self::TABLE_SALE);
2118
        $currencyTable = Database::get_main_table(self::TABLE_CURRENCY);
2119
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
2120
2121
        $innerJoins = "
2122
            INNER JOIN $currencyTable c ON s.currency_id = c.id
2123
            INNER JOIN $userTable u ON s.user_id = u.id
2124
        ";
2125
2126
        return Database::select(
2127
            ['c.iso_code', 'u.firstname', 'u.lastname', 'u.email', 's.*'],
2128
            "$saleTable s $innerJoins",
2129
            [
2130
                'where' => ['s.status = ?' => $status],
2131
                'order' => 'id DESC',
2132
            ]
2133
        );
2134
    }
2135
2136
    /**
2137
     * Get the list statuses for sales.
2138
     *
2139
     * @throws Exception
2140
     *
2141
     * @return array
2142
     */
2143
    public function getSaleListReport(string $dateStart = null, string $dateEnd = null)
2144
    {
2145
        $saleTable = Database::get_main_table(self::TABLE_SALE);
2146
        $currencyTable = Database::get_main_table(self::TABLE_CURRENCY);
2147
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
2148
        $innerJoins = "
2149
            INNER JOIN $currencyTable c ON s.currency_id = c.id
2150
            INNER JOIN $userTable u ON s.user_id = u.id
2151
        ";
2152
        $list = Database::select(
2153
            ['c.iso_code', 'u.firstname', 'u.lastname', 'u.email', 's.*'],
2154
            "$saleTable s $innerJoins",
2155
            [
2156
                'order' => 'id DESC',
2157
            ]
2158
        );
2159
        $listExportTemp = [];
2160
        $listExport = [];
2161
        $textStatus = null;
2162
        $paymentTypes = $this->getPaymentTypes();
2163
        $productTypes = $this->getProductTypes();
2164
        foreach ($list as $item) {
2165
            $statusSaleOrder = $item['status'];
2166
            switch ($statusSaleOrder) {
2167
                case 0:
2168
                    $textStatus = $this->get_lang('SaleStatusPending');
2169
                    break;
2170
                case 1:
2171
                    $textStatus = $this->get_lang('SaleStatusCompleted');
2172
                    break;
2173
                case -1:
2174
                    $textStatus = $this->get_lang('SaleStatusCanceled');
2175
                    break;
2176
            }
2177
            $dateFilter = new DateTime($item['date']);
2178
            $listExportTemp[] = [
2179
                'id' => $item['id'],
2180
                'reference' => $item['reference'],
2181
                'status' => $textStatus,
2182
                'status_filter' => $item['status'],
2183
                'date' => $dateFilter->format('Y-m-d'),
2184
                'order_time' => $dateFilter->format('H:i:s'),
2185
                'price' => $item['iso_code'].' '.$item['price'],
2186
                'product_type' => $productTypes[$item['product_type']],
2187
                'product_name' => $item['product_name'],
2188
                'payment_type' => $paymentTypes[$item['payment_type']],
2189
                'complete_user_name' => api_get_person_name($item['firstname'], $item['lastname']),
2190
                'email' => $item['email'],
2191
            ];
2192
        }
2193
        $listExport[] = [
2194
            get_lang('Number'),
2195
            $this->get_lang('OrderStatus'),
2196
            $this->get_lang('OrderDate'),
2197
            $this->get_lang('OrderTime'),
2198
            $this->get_lang('PaymentMethod'),
2199
            $this->get_lang('SalePrice'),
2200
            $this->get_lang('ProductType'),
2201
            $this->get_lang('ProductName'),
2202
            $this->get_lang('UserName'),
2203
            get_lang('Email'),
2204
        ];
2205
        //Validation Export
2206
        $dateStart = strtotime($dateStart);
2207
        $dateEnd = strtotime($dateEnd);
2208
        foreach ($listExportTemp as $item) {
2209
            $dateFilter = strtotime($item['date']);
2210
            if (($dateFilter >= $dateStart) && ($dateFilter <= $dateEnd)) {
2211
                $listExport[] = [
2212
                    'id' => $item['id'],
2213
                    'status' => $item['status'],
2214
                    'date' => $item['date'],
2215
                    'order_time' => $item['order_time'],
2216
                    'payment_type' => $item['payment_type'],
2217
                    'price' => $item['price'],
2218
                    'product_type' => $item['product_type'],
2219
                    'product_name' => $item['product_name'],
2220
                    'complete_user_name' => $item['complete_user_name'],
2221
                    'email' => $item['email'],
2222
                ];
2223
            }
2224
        }
2225
2226
        return $listExport;
2227
    }
2228
2229
    /**
2230
     * Get the statuses for sales.
2231
     *
2232
     * @return array
2233
     */
2234
    public function getSaleStatuses()
2235
    {
2236
        return [
2237
            self::SALE_STATUS_CANCELED => $this->get_lang('SaleStatusCanceled'),
2238
            self::SALE_STATUS_PENDING => $this->get_lang('SaleStatusPending'),
2239
            self::SALE_STATUS_COMPLETED => $this->get_lang('SaleStatusCompleted'),
2240
        ];
2241
    }
2242
2243
    /**
2244
     * Get the statuses for Payouts.
2245
     *
2246
     * @return array
2247
     */
2248
    public function getPayoutStatuses()
2249
    {
2250
        return [
2251
            self::PAYOUT_STATUS_CANCELED => $this->get_lang('PayoutStatusCanceled'),
2252
            self::PAYOUT_STATUS_PENDING => $this->get_lang('PayoutStatusPending'),
2253
            self::PAYOUT_STATUS_COMPLETED => $this->get_lang('PayoutStatusCompleted'),
2254
        ];
2255
    }
2256
2257
    /**
2258
     * Get the list of product types.
2259
     *
2260
     * @return array
2261
     */
2262
    public function getProductTypes()
2263
    {
2264
        return [
2265
            self::PRODUCT_TYPE_COURSE => get_lang('Course'),
2266
            self::PRODUCT_TYPE_SESSION => get_lang('Session'),
2267
        ];
2268
    }
2269
2270
    /**
2271
     * Get the list of service types.
2272
     *
2273
     * @return array
2274
     */
2275
    public function getServiceTypes()
2276
    {
2277
        return [
2278
            self::SERVICE_TYPE_USER => get_lang('User'),
2279
            self::SERVICE_TYPE_COURSE => get_lang('Course'),
2280
            self::SERVICE_TYPE_SESSION => get_lang('Session'),
2281
            self::SERVICE_TYPE_LP_FINAL_ITEM => get_lang('TemplateTitleCertificate'),
2282
        ];
2283
    }
2284
2285
    /**
2286
     * Get the list of coupon status.
2287
     *
2288
     * @return array
2289
     */
2290
    public function getCouponStatuses()
2291
    {
2292
        return [
2293
            self::COUPON_STATUS_ACTIVE => $this->get_lang('CouponActive'),
2294
            self::COUPON_STATUS_DISABLE => $this->get_lang('CouponDisabled'),
2295
        ];
2296
    }
2297
2298
    /**
2299
     * Get the list of coupon discount types.
2300
     *
2301
     * @return array
2302
     */
2303
    public function getCouponDiscountTypes()
2304
    {
2305
        return [
2306
            self::COUPON_DISCOUNT_TYPE_PERCENTAGE => $this->get_lang('CouponPercentage'),
2307
            self::COUPON_DISCOUNT_TYPE_AMOUNT => $this->get_lang('CouponAmount'),
2308
        ];
2309
    }
2310
2311
    /**
2312
     * Generates a random text (used for order references).
2313
     *
2314
     * @param int  $length    Optional. Length of characters (defaults to 6)
2315
     * @param bool $lowercase Optional. Include lowercase characters
2316
     * @param bool $uppercase Optional. Include uppercase characters
2317
     * @param bool $numbers   Optional. Include numbers
2318
     */
2319
    public static function randomText(
2320
        int $length = 6,
2321
        bool $lowercase = true,
2322
        bool $uppercase = true,
2323
        bool $numbers = true
2324
    ): string {
2325
        $salt = $lowercase ? 'abchefghknpqrstuvwxyz' : '';
2326
        $salt .= $uppercase ? 'ACDEFHKNPRSTUVWXYZ' : '';
2327
        $salt .= $numbers ? (strlen($salt) ? '2345679' : '0123456789') : '';
2328
2329
        if (strlen($salt) == 0) {
2330
            return '';
2331
        }
2332
2333
        $str = '';
2334
2335
        srand((float) microtime() * 1000000);
2336
2337
        for ($i = 0; $i < $length; $i++) {
2338
            $numbers = rand(0, strlen($salt) - 1);
2339
            $str .= substr($salt, $numbers, 1);
2340
        }
2341
2342
        return $str;
2343
    }
2344
2345
    /**
2346
     * Generates an order reference.
2347
     *
2348
     * @param int $userId      The user ID
2349
     * @param int $productType The course/session type
2350
     * @param int $productId   The course/session ID
2351
     */
2352
    public function generateReference(int $userId, int $productType, int $productId): string
2353
    {
2354
        return vsprintf(
2355
            '%d-%d-%d-%s',
2356
            [$userId, $productType, $productId, self::randomText()]
2357
        );
2358
    }
2359
2360
    /**
2361
     * Get a list of sales by the user.
2362
     *
2363
     * @param string $term The search term
2364
     *
2365
     * @return array The sale list. Otherwise return false
2366
     */
2367
    public function getSaleListByUser(string $term)
2368
    {
2369
        $term = trim($term);
2370
2371
        if (empty($term)) {
2372
            return [];
2373
        }
2374
2375
        $saleTable = Database::get_main_table(self::TABLE_SALE);
2376
        $currencyTable = Database::get_main_table(self::TABLE_CURRENCY);
2377
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
2378
        $innerJoins = "
2379
            INNER JOIN $currencyTable c ON s.currency_id = c.id
2380
            INNER JOIN $userTable u ON s.user_id = u.id
2381
        ";
2382
2383
        return Database::select(
2384
            ['c.iso_code', 'u.firstname', 'u.lastname', 'u.email', 's.*'],
2385
            "$saleTable s $innerJoins",
2386
            [
2387
                'where' => [
2388
                    'u.username LIKE %?% OR ' => $term,
2389
                    'u.lastname LIKE %?% OR ' => $term,
2390
                    'u.firstname LIKE %?%' => $term,
2391
                ],
2392
                'order' => 'id DESC',
2393
            ]
2394
        );
2395
    }
2396
2397
    /**
2398
     * Get a list of sales by the user id.
2399
     *
2400
     * @param int $id The user id
2401
     *
2402
     * @return array The sale list. Otherwise return false
2403
     */
2404
    public function getSaleListByUserId(int $id)
2405
    {
2406
        if (empty($id)) {
2407
            return [];
2408
        }
2409
2410
        $saleTable = Database::get_main_table(self::TABLE_SALE);
2411
        $currencyTable = Database::get_main_table(self::TABLE_CURRENCY);
2412
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
2413
2414
        $innerJoins = "
2415
            INNER JOIN $currencyTable c ON s.currency_id = c.id
2416
            INNER JOIN $userTable u ON s.user_id = u.id
2417
        ";
2418
2419
        return Database::select(
2420
            ['c.iso_code', 'u.firstname', 'u.lastname', 's.*'],
2421
            "$saleTable s $innerJoins",
2422
            [
2423
                'where' => [
2424
                    'u.id = ? AND s.status = ?' => [(int) $id, self::SALE_STATUS_COMPLETED],
2425
                ],
2426
                'order' => 'id DESC',
2427
            ]
2428
        );
2429
    }
2430
2431
    /**
2432
     * Get a list of sales by date range.
2433
     *
2434
     * @return array The sale list. Otherwise return false
2435
     */
2436
    public function getSaleListByDate(string $dateStart, string $dateEnd)
2437
    {
2438
        $dateStart = trim($dateStart);
2439
        $dateEnd = trim($dateEnd);
2440
        if (empty($dateStart)) {
2441
            return [];
2442
        }
2443
        if (empty($dateEnd)) {
2444
            return [];
2445
        }
2446
        $saleTable = Database::get_main_table(self::TABLE_SALE);
2447
        $currencyTable = Database::get_main_table(self::TABLE_CURRENCY);
2448
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
2449
        $innerJoins = "
2450
            INNER JOIN $currencyTable c ON s.currency_id = c.id
2451
            INNER JOIN $userTable u ON s.user_id = u.id
2452
        ";
2453
2454
        return Database::select(
2455
            ['c.iso_code', 'u.firstname', 'u.lastname', 'u.email', 's.*'],
2456
            "$saleTable s $innerJoins",
2457
            [
2458
                'where' => [
2459
                    's.date BETWEEN ? AND ' => $dateStart,
2460
                    ' ? ' => $dateEnd,
2461
                ],
2462
                'order' => 'id DESC',
2463
            ]
2464
        );
2465
    }
2466
2467
    /**
2468
     * Get a list of sales by the user Email.
2469
     *
2470
     * @param string $term The search term
2471
     *
2472
     * @return array The sale list. Otherwise return false
2473
     */
2474
    public function getSaleListByEmail(string $term)
2475
    {
2476
        $term = trim($term);
2477
        if (empty($term)) {
2478
            return [];
2479
        }
2480
        $saleTable = Database::get_main_table(self::TABLE_SALE);
2481
        $currencyTable = Database::get_main_table(self::TABLE_CURRENCY);
2482
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
2483
        $innerJoins = "
2484
            INNER JOIN $currencyTable c ON s.currency_id = c.id
2485
            INNER JOIN $userTable u ON s.user_id = u.id
2486
        ";
2487
2488
        return Database::select(
2489
            ['c.iso_code', 'u.firstname', 'u.lastname', 'u.email', 's.*'],
2490
            "$saleTable s $innerJoins",
2491
            [
2492
                'where' => [
2493
                    'u.email LIKE %?% ' => $term,
2494
                ],
2495
                'order' => 'id DESC',
2496
            ]
2497
        );
2498
    }
2499
2500
    /**
2501
     * Convert the course info to array with necessary course data for save item.
2502
     *
2503
     * @param array $defaultCurrency Optional. Currency data
2504
     *
2505
     * @return array
2506
     */
2507
    public function getCourseForConfiguration(Course $course, array $defaultCurrency = null)
2508
    {
2509
        $courseItem = [
2510
            'item_id' => null,
2511
            'course_id' => $course->getId(),
2512
            'course_visual_code' => $course->getVisualCode(),
2513
            'course_code' => $course->getCode(),
2514
            'course_title' => $course->getTitle(),
2515
            'course_directory' => $course->getDirectory(),
2516
            'course_visibility' => $course->getVisibility(),
2517
            'visible' => false,
2518
            'currency' => empty($defaultCurrency) ? null : $defaultCurrency['iso_code'],
2519
            'price' => 0.00,
2520
            'tax_perc' => null,
2521
        ];
2522
2523
        $item = $this->getItemByProduct($course->getId(), self::PRODUCT_TYPE_COURSE);
2524
2525
        if ($item !== false) {
2526
            $courseItem['item_id'] = $item['id'];
2527
            $courseItem['visible'] = true;
2528
            $courseItem['currency'] = $item['iso_code'];
2529
            $courseItem['price'] = $item['price'];
2530
            $courseItem['tax_perc'] = $item['tax_perc'];
2531
        }
2532
2533
        return $courseItem;
2534
    }
2535
2536
    /**
2537
     * Convert the session info to array with necessary session data for save item.
2538
     *
2539
     * @param Session $session         The session data
2540
     * @param array   $defaultCurrency Optional. Currency data
2541
     *
2542
     * @return array
2543
     */
2544
    public function getSessionForConfiguration(Session $session, array $defaultCurrency = null)
2545
    {
2546
        $buyItemTable = Database::get_main_table(self::TABLE_ITEM);
2547
        $buyCurrencyTable = Database::get_main_table(self::TABLE_CURRENCY);
2548
2549
        $fakeItemFrom = "
2550
            $buyItemTable i
2551
            INNER JOIN $buyCurrencyTable c ON i.currency_id = c.id
2552
        ";
2553
2554
        $sessionItem = [
2555
            'item_id' => null,
2556
            'session_id' => $session->getId(),
2557
            'session_name' => $session->getName(),
2558
            'session_visibility' => $session->getVisibility(),
2559
            'session_display_start_date' => null,
2560
            'session_display_end_date' => null,
2561
            'visible' => false,
2562
            'currency' => empty($defaultCurrency) ? null : $defaultCurrency['iso_code'],
2563
            'price' => 0.00,
2564
            'tax_perc' => null,
2565
        ];
2566
2567
        $displayStartDate = $session->getDisplayStartDate();
2568
2569
        if (!empty($displayStartDate)) {
2570
            $sessionItem['session_display_start_date'] = api_format_date(
2571
                $session->getDisplayStartDate()->format('Y-m-d h:i:s')
2572
            );
2573
        }
2574
2575
        $displayEndDate = $session->getDisplayEndDate();
2576
2577
        if (!empty($displayEndDate)) {
2578
            $sessionItem['session_display_end_date'] = api_format_date(
2579
                $session->getDisplayEndDate()->format('Y-m-d h:i:s'),
2580
                DATE_TIME_FORMAT_LONG_24H
2581
            );
2582
        }
2583
2584
        $item = Database::select(
2585
            ['i.*', 'c.iso_code'],
2586
            $fakeItemFrom,
2587
            [
2588
                'where' => [
2589
                    'i.product_id = ? AND ' => $session->getId(),
2590
                    'i.product_type = ?' => self::PRODUCT_TYPE_SESSION,
2591
                ],
2592
            ],
2593
            'first'
2594
        );
2595
2596
        if ($item !== false) {
2597
            $sessionItem['item_id'] = $item['id'];
2598
            $sessionItem['visible'] = true;
2599
            $sessionItem['currency'] = $item['iso_code'];
2600
            $sessionItem['price'] = $item['price'];
2601
            $sessionItem['tax_perc'] = $item['tax_perc'];
2602
        }
2603
2604
        return $sessionItem;
2605
    }
2606
2607
    /**
2608
     * Get all beneficiaries for a item.
2609
     *
2610
     * @param int $itemId The item ID
2611
     *
2612
     * @return array The beneficiaries. Otherwise return false
2613
     */
2614
    public function getItemBeneficiaries(int $itemId)
2615
    {
2616
        $beneficiaryTable = Database::get_main_table(self::TABLE_ITEM_BENEFICIARY);
2617
2618
        return Database::select(
2619
            '*',
2620
            $beneficiaryTable,
2621
            [
2622
                'where' => [
2623
                    'item_id = ?' => $itemId,
2624
                ],
2625
            ]
2626
        );
2627
    }
2628
2629
    /**
2630
     * Delete a item with its beneficiaries.
2631
     *
2632
     * @param int $itemId The item ID
2633
     *
2634
     * @return int The number of affected rows. Otherwise return false
2635
     */
2636
    public function deleteItem(int $itemId)
2637
    {
2638
        $itemTable = Database::get_main_table(self::TABLE_ITEM);
2639
        $affectedRows = Database::delete(
2640
            $itemTable,
2641
            ['id = ?' => $itemId]
2642
        );
2643
2644
        if (!$affectedRows) {
2645
            return false;
2646
        }
2647
2648
        return $this->deleteItemBeneficiaries($itemId);
2649
    }
2650
2651
    /**
2652
     * Register a item.
2653
     *
2654
     * @param array $itemData The item data
2655
     *
2656
     * @return int The item ID. Otherwise return false
2657
     */
2658
    public function registerItem(array $itemData)
2659
    {
2660
        $itemTable = Database::get_main_table(self::TABLE_ITEM);
2661
2662
        return Database::insert($itemTable, $itemData);
2663
    }
2664
2665
    /**
2666
     * Update the item data by product.
2667
     *
2668
     * @param array $itemData    The item data to be updated
2669
     * @param int   $productId   The product ID
2670
     * @param int   $productType The type of product
2671
     *
2672
     * @return int The number of affected rows. Otherwise return false
2673
     */
2674
    public function updateItem(array $itemData, int $productId, int $productType)
2675
    {
2676
        $itemTable = Database::get_main_table(self::TABLE_ITEM);
2677
2678
        return Database::update(
2679
            $itemTable,
2680
            $itemData,
2681
            [
2682
                'product_id = ? AND ' => $productId,
2683
                'product_type' => $productType,
2684
            ]
2685
        );
2686
    }
2687
2688
    /**
2689
     * Remove all beneficiaries for a item.
2690
     *
2691
     * @param int $itemId The user ID
2692
     *
2693
     * @return int The number of affected rows. Otherwise return false
2694
     */
2695
    public function deleteItemBeneficiaries(int $itemId)
2696
    {
2697
        $beneficiaryTable = Database::get_main_table(self::TABLE_ITEM_BENEFICIARY);
2698
2699
        return Database::delete(
2700
            $beneficiaryTable,
2701
            ['item_id = ?' => $itemId]
2702
        );
2703
    }
2704
2705
    /**
2706
     * Register the beneficiaries users with the sale of item.
2707
     *
2708
     * @param int   $itemId  The item ID
2709
     * @param array $userIds The beneficiary user ID and Teachers commissions if enabled
2710
     */
2711
    public function registerItemBeneficiaries(int $itemId, array $userIds)
2712
    {
2713
        $beneficiaryTable = Database::get_main_table(self::TABLE_ITEM_BENEFICIARY);
2714
2715
        $this->deleteItemBeneficiaries($itemId);
2716
2717
        foreach ($userIds as $userId => $commissions) {
2718
            Database::insert(
2719
                $beneficiaryTable,
2720
                [
2721
                    'item_id' => $itemId,
2722
                    'user_id' => (int) $userId,
2723
                    'commissions' => (int) $commissions,
2724
                ]
2725
            );
2726
        }
2727
    }
2728
2729
    /**
2730
     * Check if a course is valid for sale.
2731
     *
2732
     * @param Course $course The course
2733
     *
2734
     * @return bool
2735
     */
2736
    public function isValidCourse(Course $course)
2737
    {
2738
        $courses = $this->getCourses();
2739
2740
        foreach ($courses as $_c) {
2741
            if ($_c->getCode() === $course->getCode()) {
2742
                return true;
2743
            }
2744
        }
2745
2746
        return false;
2747
    }
2748
2749
    /**
2750
     * Gets the beneficiaries with commissions and current paypal accounts by sale.
2751
     *
2752
     * @param int $saleId The sale ID
2753
     *
2754
     * @return array
2755
     */
2756
    public function getBeneficiariesBySale(int $saleId)
2757
    {
2758
        $sale = $this->getSale($saleId);
2759
        $item = $this->getItemByProduct($sale['product_id'], $sale['product_type']);
2760
        $itemBeneficiaries = $this->getItemBeneficiaries($item['id']);
2761
2762
        return $itemBeneficiaries;
2763
    }
2764
2765
    /**
2766
     * gets all payouts.
2767
     *
2768
     * @param int $status   - default 0 - pending
2769
     * @param int $payoutId - for get an individual payout if want all then false
2770
     *
2771
     * @return array
2772
     */
2773
    public function getPayouts(
2774
        int $status = self::PAYOUT_STATUS_PENDING,
2775
        int $payoutId = 0,
2776
        int $userId = 0
2777
    ) {
2778
        $condition = ($payoutId) ? 'AND p.id = '.($payoutId) : '';
2779
        $condition2 = ($userId) ? ' AND p.user_id = '.($userId) : '';
2780
        $typeResult = ($condition) ? 'first' : 'all';
2781
        $payoutsTable = Database::get_main_table(self::TABLE_PAYPAL_PAYOUTS);
2782
        $saleTable = Database::get_main_table(self::TABLE_SALE);
2783
        $currencyTable = Database::get_main_table(self::TABLE_CURRENCY);
2784
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
2785
        $extraFieldTable = Database::get_main_table(TABLE_EXTRA_FIELD);
2786
        $extraFieldValues = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
2787
2788
        $paypalExtraField = Database::select(
2789
            "*",
2790
            $extraFieldTable,
2791
            [
2792
                'where' => ['variable = ?' => 'paypal'],
2793
            ],
2794
            'first'
2795
        );
2796
2797
        if (!$paypalExtraField) {
2798
            return false;
2799
        }
2800
2801
        $innerJoins = "
2802
            INNER JOIN $userTable u ON p.user_id = u.id
2803
            INNER JOIN $saleTable s ON s.id = p.sale_id
2804
            INNER JOIN $currencyTable c ON s.currency_id = c.id
2805
            LEFT JOIN  $extraFieldValues efv ON p.user_id = efv.item_id
2806
            AND field_id = ".((int) $paypalExtraField['id'])."
2807
        ";
2808
2809
        $payouts = Database::select(
2810
            "p.* , u.firstname, u.lastname, efv.value as paypal_account, s.reference as sale_reference, s.price as item_price, c.iso_code",
2811
            "$payoutsTable p $innerJoins",
2812
            [
2813
                'where' => ['p.status = ? '.$condition.' '.$condition2 => $status],
2814
            ],
2815
            $typeResult
2816
        );
2817
2818
        return $payouts;
2819
    }
2820
2821
    /**
2822
     * Verify if the beneficiary have a paypal account.
2823
     *
2824
     * @return true if the user have a paypal account, false if not
2825
     */
2826
    public function verifyPaypalAccountByBeneficiary(int $userId)
2827
    {
2828
        $extraFieldTable = Database::get_main_table(TABLE_EXTRA_FIELD);
2829
        $extraFieldValues = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
2830
2831
        $paypalExtraField = Database::select(
2832
            '*',
2833
            $extraFieldTable,
2834
            [
2835
                'where' => ['variable = ?' => 'paypal'],
2836
            ],
2837
            'first'
2838
        );
2839
2840
        if (!$paypalExtraField) {
2841
            return false;
2842
        }
2843
2844
        $paypalFieldId = $paypalExtraField['id'];
2845
        $paypalAccount = Database::select(
2846
            'value',
2847
            $extraFieldValues,
2848
            [
2849
                'where' => ['field_id = ? AND item_id = ?' => [(int) $paypalFieldId, $userId]],
2850
            ],
2851
            'first'
2852
        );
2853
2854
        if (!$paypalAccount) {
2855
            return false;
2856
        }
2857
2858
        if ($paypalAccount['value'] === '') {
2859
            return false;
2860
        }
2861
2862
        return true;
2863
    }
2864
2865
    /**
2866
     * Register the users payouts.
2867
     *
2868
     * @return array
2869
     */
2870
    public function storePayouts(int $saleId)
2871
    {
2872
        $payoutsTable = Database::get_main_table(self::TABLE_PAYPAL_PAYOUTS);
2873
        $platformCommission = $this->getPlatformCommission();
2874
2875
        $sale = $this->getSale($saleId);
2876
        $commission = (int) $platformCommission['commission'];
2877
        $teachersCommission = number_format(
2878
            (floatval($sale['price']) * $commission) / 100,
2879
            2
2880
        );
2881
2882
        $beneficiaries = $this->getBeneficiariesBySale($saleId);
2883
        foreach ($beneficiaries as $beneficiary) {
2884
            $beneficiaryCommission = (int) $beneficiary['commissions'];
2885
            Database::insert(
2886
                $payoutsTable,
2887
                [
2888
                    'date' => $sale['date'],
2889
                    'payout_date' => api_get_utc_datetime(),
2890
                    'sale_id' => $saleId,
2891
                    'user_id' => $beneficiary['user_id'],
2892
                    'commission' => number_format(
2893
                        (floatval($teachersCommission) * $beneficiaryCommission) / 100,
2894
                        2
2895
                    ),
2896
                    'status' => self::PAYOUT_STATUS_PENDING,
2897
                ]
2898
            );
2899
        }
2900
    }
2901
2902
    /**
2903
     * Register the users payouts.
2904
     *
2905
     * @param int $saleId The subscription sale ID
2906
     *
2907
     * @return array
2908
     */
2909
    public function storeSubscriptionPayouts(int $saleId)
2910
    {
2911
        $payoutsTable = Database::get_main_table(self::TABLE_PAYPAL_PAYOUTS);
2912
        $platformCommission = $this->getPlatformCommission();
2913
2914
        $sale = $this->getSubscriptionSale($saleId);
2915
        $commission = (int) $platformCommission['commission'];
2916
        $teachersCommission = number_format(
2917
            (floatval($sale['price']) * $commission) / 100,
2918
            2
2919
        );
2920
2921
        $beneficiaries = $this->getBeneficiariesBySale($saleId);
2922
        foreach ($beneficiaries as $beneficiary) {
2923
            $beneficiaryCommission = (int) $beneficiary['commissions'];
2924
            Database::insert(
2925
                $payoutsTable,
2926
                [
2927
                    'date' => $sale['date'],
2928
                    'payout_date' => api_get_utc_datetime(),
2929
                    'sale_id' => $saleId,
2930
                    'user_id' => $beneficiary['user_id'],
2931
                    'commission' => number_format(
2932
                        (floatval($teachersCommission) * $beneficiaryCommission) / 100,
2933
                        2
2934
                    ),
2935
                    'status' => self::PAYOUT_STATUS_PENDING,
2936
                ]
2937
            );
2938
        }
2939
    }
2940
2941
    /**
2942
     * Register the users payouts.
2943
     *
2944
     * @param int $payoutId The payout ID
2945
     * @param int $status   The status to set (-1 to cancel, 0 to pending, 1 to completed)
2946
     *
2947
     * @return array
2948
     */
2949
    public function setStatusPayouts(int $payoutId, int $status)
2950
    {
2951
        $payoutsTable = Database::get_main_table(self::TABLE_PAYPAL_PAYOUTS);
2952
2953
        Database::update(
2954
            $payoutsTable,
2955
            ['status' => (int) $status],
2956
            ['id = ?' => (int) $payoutId]
2957
        );
2958
    }
2959
2960
    /**
2961
     * Gets the stored platform commission params.
2962
     *
2963
     * @return array
2964
     */
2965
    public function getPlatformCommission()
2966
    {
2967
        return Database::select(
2968
            '*',
2969
            Database::get_main_table(self::TABLE_COMMISSION),
2970
            ['id = ?' => 1],
2971
            'first'
2972
        );
2973
    }
2974
2975
    /**
2976
     * Update the platform commission.
2977
     *
2978
     * @param array $params platform commission
2979
     *
2980
     * @return int The number of affected rows. Otherwise return false
2981
     */
2982
    public function updateCommission(array $params)
2983
    {
2984
        $commissionTable = Database::get_main_table(self::TABLE_COMMISSION);
2985
2986
        return Database::update(
2987
            $commissionTable,
2988
            ['commission' => (int) $params['commission']]
2989
        );
2990
    }
2991
2992
    /**
2993
     * Register additional service.
2994
     *
2995
     * @param array $service params
2996
     *
2997
     * @return mixed response
2998
     */
2999
    public function storeService(array $service)
3000
    {
3001
        $servicesTable = Database::get_main_table(self::TABLE_SERVICES);
3002
3003
        $return = Database::insert(
3004
            $servicesTable,
3005
            [
3006
                'name' => Security::remove_XSS($service['name']),
3007
                'description' => Security::remove_XSS($service['description']),
3008
                'price' => $service['price'],
3009
                'tax_perc' => $service['tax_perc'] != '' ? (int) $service['tax_perc'] : null,
3010
                'duration_days' => (int) $service['duration_days'],
3011
                'applies_to' => (int) $service['applies_to'],
3012
                'owner_id' => (int) $service['owner_id'],
3013
                'visibility' => (int) $service['visibility'],
3014
                'image' => '',
3015
                'video_url' => $service['video_url'],
3016
                'service_information' => $service['service_information'],
3017
            ]
3018
        );
3019
3020
        if ($return && !empty($service['picture_crop_image_base_64']) &&
3021
            !empty($service['picture_crop_result'])
3022
        ) {
3023
            $img = str_replace('data:image/png;base64,', '', $service['picture_crop_image_base_64']);
3024
            $img = str_replace(' ', '+', $img);
3025
            $data = base64_decode($img);
3026
            $file = api_get_path(SYS_PLUGIN_PATH).'buycourses/uploads/services/images/simg-'.$return.'.png';
3027
            file_put_contents($file, $data);
3028
3029
            Database::update(
3030
                $servicesTable,
3031
                ['image' => 'simg-'.$return.'.png'],
3032
                ['id = ?' => $return]
3033
            );
3034
        }
3035
3036
        return $return;
3037
    }
3038
3039
    /**
3040
     * update a service.
3041
     *
3042
     * @return mixed response
3043
     */
3044
    public function updateService(array $service, int $id)
3045
    {
3046
        $servicesTable = Database::get_main_table(self::TABLE_SERVICES);
3047
        if (!empty($service['picture_crop_image_base_64'])) {
3048
            $img = str_replace('data:image/png;base64,', '', $service['picture_crop_image_base_64']);
3049
            $img = str_replace(' ', '+', $img);
3050
            $data = base64_decode($img);
3051
            $file = api_get_path(SYS_PLUGIN_PATH).'buycourses/uploads/services/images/simg-'.$id.'.png';
3052
            file_put_contents($file, $data);
3053
        }
3054
3055
        return Database::update(
3056
            $servicesTable,
3057
            [
3058
                'name' => Security::remove_XSS($service['name']),
3059
                'description' => Security::remove_XSS($service['description']),
3060
                'price' => $service['price'],
3061
                'tax_perc' => $service['tax_perc'] != '' ? (int) $service['tax_perc'] : null,
3062
                'duration_days' => (int) $service['duration_days'],
3063
                'applies_to' => (int) $service['applies_to'],
3064
                'owner_id' => (int) $service['owner_id'],
3065
                'visibility' => (int) $service['visibility'],
3066
                'image' => 'simg-'.$id.'.png',
3067
                'video_url' => $service['video_url'],
3068
                'service_information' => $service['service_information'],
3069
            ],
3070
            ['id = ?' => $id]
3071
        );
3072
    }
3073
3074
    /**
3075
     * Remove a service.
3076
     *
3077
     * @param int $id The transfer account ID
3078
     *
3079
     * @return int Rows affected. Otherwise return false
3080
     */
3081
    public function deleteService(int $id)
3082
    {
3083
        Database::delete(
3084
            Database::get_main_table(self::TABLE_SERVICES_SALE),
3085
            ['service_id = ?' => $id]
3086
        );
3087
3088
        return Database::delete(
3089
            Database::get_main_table(self::TABLE_SERVICES),
3090
            ['id = ?' => $id]
3091
        );
3092
    }
3093
3094
    /**
3095
     * @param array|null $coupon Array with at least 'discount_type' and 'discount_amount' elements
3096
     */
3097
    public function setPriceSettings(array &$product, int $productType, array $coupon = null): bool
3098
    {
3099
        if (empty($product)) {
3100
            return false;
3101
        }
3102
3103
        $taxPerc = null;
3104
        $product['has_coupon'] = $coupon != null ? true : false;
3105
        $couponDiscount = 0;
3106
        if ($coupon != null) {
3107
            if ($coupon['discount_type'] == self::COUPON_DISCOUNT_TYPE_AMOUNT) {
3108
                $couponDiscount = $coupon['discount_amount'];
3109
            } elseif ($coupon['discount_type'] == self::COUPON_DISCOUNT_TYPE_PERCENTAGE) {
3110
                $couponDiscount = ($product['price'] * $coupon['discount_amount']) / 100;
3111
            }
3112
            $product['price_without_discount'] = $product['price'];
3113
        }
3114
        $product['discount_amount'] = $couponDiscount;
3115
        $product['price'] = $product['price'] - $couponDiscount;
3116
        $priceWithoutTax = $product['price'];
3117
        $product['total_price'] = $product['price'];
3118
        $product['tax_amount'] = 0;
3119
3120
        if ($this->checkTaxEnabledInProduct($productType)) {
3121
            if (is_null($product['tax_perc'])) {
3122
                $globalParameters = $this->getGlobalParameters();
3123
                $globalTaxPerc = $globalParameters['global_tax_perc'];
3124
                $taxPerc = $globalTaxPerc;
3125
            } else {
3126
                $taxPerc = $product['tax_perc'];
3127
            }
3128
            //$taxPerc = is_null($product['tax_perc']) ? $globalTaxPerc : $product['tax_perc'];
3129
3130
            $taxAmount = round($priceWithoutTax * $taxPerc / 100, 2);
3131
            $product['tax_amount'] = $taxAmount;
3132
            $priceWithTax = $priceWithoutTax + $taxAmount;
3133
            $product['total_price'] = $priceWithTax;
3134
        }
3135
3136
        $product['tax_perc_show'] = $taxPerc;
3137
        $product['price_formatted'] = $this->getPriceWithCurrencyFromIsoCode(
3138
            $product['price'],
3139
            $product['iso_code']
3140
        );
3141
3142
        $product['tax_amount_formatted'] = number_format($product['tax_amount'], 2);
3143
3144
        $product['total_price_formatted'] = $this->getPriceWithCurrencyFromIsoCode(
3145
            $product['total_price'],
3146
            $product['iso_code']
3147
        );
3148
3149
        if ($coupon != null) {
3150
            $product['discount_amount_formatted'] = $this->getPriceWithCurrencyFromIsoCode(
3151
                $product['discount_amount'],
3152
                $product['iso_code']
3153
            );
3154
3155
            $product['price_without_discount_formatted'] = $this->getPriceWithCurrencyFromIsoCode(
3156
                $product['price_without_discount'],
3157
                $product['iso_code']
3158
            );
3159
        }
3160
3161
        return true;
3162
    }
3163
3164
    /**
3165
     * @param array $coupon
3166
     *
3167
     * @return array
3168
     */
3169
    public function getService(int $id, array $coupon = null)
3170
    {
3171
        if (empty($id)) {
3172
            return [];
3173
        }
3174
3175
        $servicesTable = Database::get_main_table(self::TABLE_SERVICES);
3176
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
3177
        $conditions = ['WHERE' => ['s.id = ?' => $id]];
3178
        $showData = 'first';
3179
        $innerJoins = "INNER JOIN $userTable u ON s.owner_id = u.id";
3180
        $currency = $this->getSelectedCurrency();
3181
        $isoCode = $currency['iso_code'];
3182
        $service = Database::select(
3183
            "s.*, '$isoCode' as currency, u.firstname, u.lastname",
3184
            "$servicesTable s $innerJoins",
3185
            $conditions,
3186
            $showData
3187
        );
3188
3189
        $service['iso_code'] = $isoCode;
3190
        $globalParameters = $this->getGlobalParameters();
3191
3192
        $this->setPriceSettings($service, self::TAX_APPLIES_TO_ONLY_SERVICES, $coupon);
3193
3194
        $service['tax_name'] = $globalParameters['tax_name'];
3195
        $service['tax_enable'] = $this->checkTaxEnabledInProduct(self::TAX_APPLIES_TO_ONLY_SERVICES);
3196
        $service['owner_name'] = api_get_person_name($service['firstname'], $service['lastname']);
3197
        $service['image'] = !empty($service['image']) ? api_get_path(WEB_PLUGIN_PATH).'buycourses/uploads/services/images/'.$service['image'] : null;
3198
3199
        return $service;
3200
    }
3201
3202
    /**
3203
     * List additional services.
3204
     *
3205
     * @return array
3206
     */
3207
    public function getAllServices()
3208
    {
3209
        $servicesTable = Database::get_main_table(self::TABLE_SERVICES);
3210
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
3211
3212
        $innerJoins = "INNER JOIN $userTable u ON s.owner_id = u.id";
3213
        $return = Database::select(
3214
            's.id',
3215
            "$servicesTable s $innerJoins",
3216
            [],
3217
            'all'
3218
        );
3219
3220
        $services = [];
3221
        foreach ($return as $index => $service) {
3222
            $services[$index] = $this->getService($service['id']);
3223
        }
3224
3225
        return $services;
3226
    }
3227
3228
    /**
3229
     * List additional services.
3230
     *
3231
     * @return array|int
3232
     */
3233
    public function getServices(int $start, int $end, string $typeResult = 'all')
3234
    {
3235
        $servicesTable = Database::get_main_table(self::TABLE_SERVICES);
3236
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
3237
3238
        $conditions = ['limit' => "$start, $end"];
3239
        $innerJoins = "INNER JOIN $userTable u ON s.owner_id = u.id";
3240
        $return = Database::select(
3241
            's.id',
3242
            "$servicesTable s $innerJoins",
3243
            $conditions,
3244
            $typeResult
3245
        );
3246
3247
        if ($typeResult === 'count') {
3248
            return $return;
3249
        }
3250
3251
        $services = [];
3252
        foreach ($return as $index => $service) {
3253
            $services[$index] = $this->getService($service['id']);
3254
        }
3255
3256
        return $services;
3257
    }
3258
3259
    /**
3260
     * Get the statuses for sales.
3261
     *
3262
     * @return array
3263
     */
3264
    public function getServiceSaleStatuses()
3265
    {
3266
        return [
3267
            self::SERVICE_STATUS_CANCELLED => $this->get_lang('SaleStatusCancelled'),
3268
            self::SERVICE_STATUS_PENDING => $this->get_lang('SaleStatusPending'),
3269
            self::SERVICE_STATUS_COMPLETED => $this->get_lang('SaleStatusCompleted'),
3270
        ];
3271
    }
3272
3273
    /**
3274
     * List services sales.
3275
     *
3276
     * @param int $buyerId  buyer id
3277
     * @param int $status   status
3278
     * @param int $nodeType The node Type ( User = 1 , Course = 2 , Session = 3 )
3279
     * @param int $nodeId   the nodeId
3280
     *
3281
     * @return array
3282
     */
3283
    public function getServiceSales(
3284
        int $buyerId = 0,
3285
        int $status = 0,
3286
        int $nodeType = 0,
3287
        int $nodeId = 0
3288
    ) {
3289
        $conditions = null;
3290
        $groupBy = '';
3291
3292
        $servicesTable = Database::get_main_table(self::TABLE_SERVICES);
3293
        $servicesSaleTable = Database::get_main_table(self::TABLE_SERVICES_SALE);
3294
3295
        $defaultOrder = 'id ASC';
3296
3297
        if (!empty($buyerId)) {
3298
            $conditions = ['WHERE' => ['ss.buyer_id = ?' => $buyerId], 'ORDER' => $defaultOrder];
3299
        }
3300
3301
        if (is_numeric($status)) {
3302
            $conditions = ['WHERE' => ['ss.status = ?' => $status], 'ORDER' => $defaultOrder];
3303
        }
3304
3305
        if ($buyerId) {
3306
            $conditions = ['WHERE' => ['ss.buyer_id = ?' => [$buyerId]], 'ORDER' => $defaultOrder];
3307
        }
3308
3309
        if ($nodeType && $nodeId) {
3310
            $conditions = [
3311
                'WHERE' => ['ss.node_type = ? AND ss.node_id = ?' => [$nodeType, $nodeId]],
3312
                'ORDER' => $defaultOrder,
3313
            ];
3314
        }
3315
3316
        if ($nodeType && $nodeId && $buyerId && is_numeric($status)) {
3317
            $conditions = [
3318
                'WHERE' => [
3319
                    'ss.node_type = ? AND ss.node_id = ? AND ss.buyer_id = ? AND ss.status = ?' => [
3320
                        $nodeType,
3321
                        $nodeId,
3322
                        $buyerId,
3323
                        $status,
3324
                    ],
3325
                ],
3326
                'ORDER' => 'ss.service_id ASC',
3327
            ];
3328
        }
3329
3330
        $innerJoins = "INNER JOIN $servicesTable s ON ss.service_id = s.id $groupBy";
3331
        $return = Database::select(
3332
            'DISTINCT ss.id ',
3333
            "$servicesSaleTable ss $innerJoins",
3334
            $conditions
3335
            //, "all", null, true
3336
        );
3337
3338
        $list = [];
3339
        foreach ($return as $service) {
3340
            $list[] = $this->getServiceSale($service['id']);
3341
        }
3342
3343
        return $list;
3344
    }
3345
3346
    /**
3347
     * @param int $id service sale id
3348
     *
3349
     * @return array
3350
     */
3351
    public function getServiceSale(int $id)
3352
    {
3353
        $servicesTable = Database::get_main_table(self::TABLE_SERVICES);
3354
        $servicesSaleTable = Database::get_main_table(self::TABLE_SERVICES_SALE);
3355
3356
        if (empty($id)) {
3357
            return [];
3358
        }
3359
3360
        $conditions = ['WHERE' => ['ss.id = ?' => $id]];
3361
        $innerJoins = "INNER JOIN $servicesTable s ON ss.service_id = s.id ";
3362
        $currency = $this->getSelectedCurrency();
3363
        $isoCode = $currency['iso_code'];
3364
3365
        $servicesSale = Database::select(
3366
            'ss.*, s.name, s.description, s.price as service_price, s.duration_days, s.applies_to, s.owner_id, s.visibility, s.image',
3367
            "$servicesSaleTable ss $innerJoins",
3368
            $conditions,
3369
            'first'
3370
        );
3371
        $owner = api_get_user_info($servicesSale['owner_id']);
3372
        $buyer = api_get_user_info($servicesSale['buyer_id']);
3373
3374
        $servicesSale['service']['id'] = $servicesSale['service_id'];
3375
        $servicesSale['service']['name'] = $servicesSale['name'];
3376
        $servicesSale['service']['description'] = $servicesSale['description'];
3377
        $servicesSale['service']['price'] = $servicesSale['service_price'];
3378
        $servicesSale['service']['currency'] = $isoCode;
3379
3380
        $servicesSale['service']['total_price'] = $this->getPriceWithCurrencyFromIsoCode(
3381
            $servicesSale['price'],
3382
            $isoCode
3383
        );
3384
3385
        $servicesSale['service']['duration_days'] = $servicesSale['duration_days'];
3386
        $servicesSale['service']['applies_to'] = $servicesSale['applies_to'];
3387
        $servicesSale['service']['owner']['id'] = $servicesSale['owner_id'];
3388
        $servicesSale['service']['owner']['name'] = api_get_person_name($owner['firstname'], $owner['lastname']);
3389
        $servicesSale['service']['visibility'] = $servicesSale['visibility'];
3390
        $servicesSale['service']['image'] = $servicesSale['image'];
3391
        $servicesSale['item'] = $this->getService($servicesSale['service_id']);
3392
        $servicesSale['buyer']['id'] = $buyer['user_id'];
3393
        $servicesSale['buyer']['name'] = api_get_person_name($buyer['firstname'], $buyer['lastname']);
3394
        $servicesSale['buyer']['username'] = $buyer['username'];
3395
3396
        return $servicesSale;
3397
    }
3398
3399
    /**
3400
     * Update service sale status to cancelled.
3401
     *
3402
     * @param int $serviceSaleId The sale ID
3403
     *
3404
     * @return bool
3405
     */
3406
    public function cancelServiceSale(int $serviceSaleId)
3407
    {
3408
        $this->updateServiceSaleStatus(
3409
            $serviceSaleId,
3410
            self::SERVICE_STATUS_CANCELLED
3411
        );
3412
3413
        return true;
3414
    }
3415
3416
    /**
3417
     * Complete service sale process. Update service sale status to completed.
3418
     *
3419
     * @param int $serviceSaleId The service sale ID
3420
     *
3421
     * @return bool
3422
     */
3423
    public function completeServiceSale(int $serviceSaleId)
3424
    {
3425
        $serviceSale = $this->getServiceSale($serviceSaleId);
3426
        if ($serviceSale['status'] == self::SERVICE_STATUS_COMPLETED) {
3427
            return true;
3428
        }
3429
3430
        $this->updateServiceSaleStatus(
3431
            $serviceSaleId,
3432
            self::SERVICE_STATUS_COMPLETED
3433
        );
3434
3435
        if ($this->get('invoicing_enable') === 'true') {
3436
            $this->setInvoice($serviceSaleId, 1);
3437
        }
3438
3439
        return true;
3440
    }
3441
3442
    /**
3443
     * Lists current service details.
3444
     *
3445
     * @return array|int
3446
     */
3447
    public function getCatalogServiceList(
3448
        int $start,
3449
        int $end,
3450
        string $name = null,
3451
        int $min = 0,
3452
        int $max = 0,
3453
        $appliesTo = '',
3454
        string $typeResult = 'all'
3455
    ) {
3456
        $servicesTable = Database::get_main_table(self::TABLE_SERVICES);
3457
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
3458
3459
        $whereConditions = [
3460
            's.visibility <> ? ' => 0,
3461
        ];
3462
3463
        if (!empty($name)) {
3464
            $whereConditions['AND s.name LIKE %?%'] = $name;
3465
        }
3466
3467
        if (!empty($min)) {
3468
            $whereConditions['AND s.price >= ?'] = $min;
3469
        }
3470
3471
        if (!empty($max)) {
3472
            $whereConditions['AND s.price <= ?'] = $max;
3473
        }
3474
3475
        if (!$appliesTo == '') {
3476
            $whereConditions['AND s.applies_to = ?'] = $appliesTo;
3477
        }
3478
3479
        $innerJoins = "INNER JOIN $userTable u ON s.owner_id = u.id";
3480
        $return = Database::select(
3481
            's.*',
3482
            "$servicesTable s $innerJoins",
3483
            ['WHERE' => $whereConditions, 'limit' => "$start, $end"],
3484
            $typeResult
3485
        );
3486
3487
        if ($typeResult === 'count') {
3488
            return $return;
3489
        }
3490
3491
        $services = [];
3492
        foreach ($return as $index => $service) {
3493
            $services[$index] = $this->getService($service['id']);
3494
        }
3495
3496
        return $services;
3497
    }
3498
3499
    /**
3500
     * Register a Service sale.
3501
     *
3502
     * @param int $serviceId   The service ID
3503
     * @param int $paymentType The payment type
3504
     * @param int $infoSelect  The ID for Service Type
3505
     *
3506
     * @return bool
3507
     */
3508
    public function registerServiceSale(int $serviceId, int $paymentType, int $infoSelect, int $couponId = null)
3509
    {
3510
        if (!in_array(
3511
            $paymentType,
3512
            [self::PAYMENT_TYPE_PAYPAL, self::PAYMENT_TYPE_TRANSFER, self::PAYMENT_TYPE_CULQI]
3513
        )
3514
        ) {
3515
            return false;
3516
        }
3517
3518
        $userId = api_get_user_id();
3519
        $service = $this->getService($serviceId);
3520
3521
        if (empty($service)) {
3522
            return false;
3523
        }
3524
3525
        if ($couponId != null) {
3526
            $coupon = $this->getCouponService($couponId, $serviceId);
3527
        }
3528
3529
        $couponDiscount = 0;
3530
        $priceWithoutDiscount = 0;
3531
        if ($coupon != null) {
3532
            if ($coupon['discount_type'] == self::COUPON_DISCOUNT_TYPE_AMOUNT) {
3533
                $couponDiscount = $coupon['discount_amount'];
3534
            } elseif ($coupon['discount_type'] == self::COUPON_DISCOUNT_TYPE_PERCENTAGE) {
3535
                $couponDiscount = ($service['price'] * $coupon['discount_amount']) / 100;
3536
            }
3537
            $priceWithoutDiscount = $service['price'];
3538
        }
3539
        $service['price'] = $service['price'] - $couponDiscount;
3540
        $currency = $this->getSelectedCurrency();
3541
        $price = $service['price'];
3542
        $priceWithoutTax = null;
3543
        $taxPerc = null;
3544
        $taxEnable = $this->get('tax_enable') === 'true';
3545
        $globalParameters = $this->getGlobalParameters();
3546
        $taxAppliesTo = $globalParameters['tax_applies_to'];
3547
        $taxAmount = 0;
3548
3549
        if ($taxEnable &&
3550
            ($taxAppliesTo == self::TAX_APPLIES_TO_ALL || $taxAppliesTo == self::TAX_APPLIES_TO_ONLY_SERVICES)
3551
        ) {
3552
            $priceWithoutTax = $service['price'];
3553
            $globalTaxPerc = $globalParameters['global_tax_perc'];
3554
            $precision = 2;
3555
            $taxPerc = is_null($service['tax_perc']) ? $globalTaxPerc : $service['tax_perc'];
3556
            $taxAmount = round($priceWithoutTax * $taxPerc / 100, $precision);
3557
            $price = $priceWithoutTax + $taxAmount;
3558
        }
3559
3560
        $values = [
3561
            'service_id' => $serviceId,
3562
            'reference' => $this->generateReference(
3563
                $userId,
3564
                $service['applies_to'],
3565
                $infoSelect
3566
            ),
3567
            'currency_id' => $currency['id'],
3568
            'price' => $price,
3569
            'price_without_tax' => $priceWithoutTax,
3570
            'tax_perc' => $taxPerc,
3571
            'tax_amount' => $taxAmount,
3572
            'node_type' => $service['applies_to'],
3573
            'node_id' => $infoSelect,
3574
            'buyer_id' => $userId,
3575
            'buy_date' => api_get_utc_datetime(),
3576
            'date_start' => api_get_utc_datetime(),
3577
            'date_end' => date_format(
3578
                date_add(
3579
                    date_create(api_get_utc_datetime()),
3580
                    date_interval_create_from_date_string($service['duration_days'].' days')
3581
                ),
3582
                'Y-m-d H:i:s'
3583
            ),
3584
            'status' => self::SERVICE_STATUS_PENDING,
3585
            'payment_type' => $paymentType,
3586
            'price_without_discount' => $priceWithoutDiscount,
3587
            'discount_amount' => $couponDiscount,
3588
        ];
3589
3590
        $returnedServiceSaleId = Database::insert(self::TABLE_SERVICES_SALE, $values);
3591
3592
        return $returnedServiceSaleId;
3593
    }
3594
3595
    /**
3596
     * Save Culqi configuration params.
3597
     *
3598
     * @return int Rows affected. Otherwise return false
3599
     */
3600
    public function saveCulqiParameters(array $params)
3601
    {
3602
        return Database::update(
3603
            Database::get_main_table(self::TABLE_CULQI),
3604
            [
3605
                'commerce_code' => $params['commerce_code'],
3606
                'api_key' => $params['api_key'],
3607
                'integration' => $params['integration'],
3608
            ],
3609
            ['id = ?' => 1]
3610
        );
3611
    }
3612
3613
    /**
3614
     * Gets the stored Culqi params.
3615
     *
3616
     * @return array
3617
     */
3618
    public function getCulqiParams()
3619
    {
3620
        return Database::select(
3621
            '*',
3622
            Database::get_main_table(self::TABLE_CULQI),
3623
            ['id = ?' => 1],
3624
            'first'
3625
        );
3626
    }
3627
3628
    /**
3629
     * Save Cecabank configuration params.
3630
     *
3631
     * @return array
3632
     */
3633
    public function saveCecabankParameters(array $params)
3634
    {
3635
        return Database::update(
3636
            Database::get_main_table(self::TABLE_TPV_CECABANK),
3637
            [
3638
                'crypto_key' => $params['crypto_key'],
3639
                'merchant_id' => $params['merchart_id'],
3640
                'acquirer_bin' => $params['acquirer_bin'],
3641
                'terminal_id' => $params['terminal_id'],
3642
                'cypher' => $params['cypher'],
3643
                'exponent' => $params['exponent'],
3644
                'supported_payment' => $params['supported_payment'],
3645
                'url' => $params['url'],
3646
            ],
3647
            ['id = ?' => 1]
3648
        );
3649
    }
3650
3651
    /**
3652
     * Gets the stored Cecabank params.
3653
     *
3654
     * @return array
3655
     */
3656
    public function getCecabankParams()
3657
    {
3658
        return Database::select(
3659
            '*',
3660
            Database::get_main_table(self::TABLE_TPV_CECABANK),
3661
            ['id = ?' => 1],
3662
            'first'
3663
        );
3664
    }
3665
3666
    /**
3667
     * Save Global Parameters.
3668
     *
3669
     * @return int Rows affected. Otherwise return false
3670
     */
3671
    public function saveGlobalParameters(array $params)
3672
    {
3673
        $sqlParams = [
3674
            'terms_and_conditions' => $params['terms_and_conditions'],
3675
            'sale_email' => $params['sale_email'],
3676
        ];
3677
3678
        if ($this->get('tax_enable') === 'true') {
3679
            $sqlParams['global_tax_perc'] = $params['global_tax_perc'];
3680
            $sqlParams['tax_applies_to'] = $params['tax_applies_to'];
3681
            $sqlParams['tax_name'] = $params['tax_name'];
3682
        }
3683
3684
        if ($this->get('invoicing_enable') === 'true') {
3685
            $sqlParams['seller_name'] = $params['seller_name'];
3686
            $sqlParams['seller_id'] = $params['seller_id'];
3687
            $sqlParams['seller_address'] = $params['seller_address'];
3688
            $sqlParams['seller_email'] = $params['seller_email'];
3689
            $sqlParams['next_number_invoice'] = $params['next_number_invoice'];
3690
            $sqlParams['invoice_series'] = $params['invoice_series'];
3691
        }
3692
3693
        return Database::update(
3694
            Database::get_main_table(self::TABLE_GLOBAL_CONFIG),
3695
            $sqlParams,
3696
            ['id = ?' => 1]
3697
        );
3698
    }
3699
3700
    /**
3701
     * get Global Parameters.
3702
     *
3703
     * @return array
3704
     */
3705
    public function getGlobalParameters()
3706
    {
3707
        return Database::select(
3708
            '*',
3709
            Database::get_main_table(self::TABLE_GLOBAL_CONFIG),
3710
            ['id = ?' => 1],
3711
            'first'
3712
        );
3713
    }
3714
3715
    /**
3716
     * @return bool
3717
     */
3718
    public function checkTaxEnabledInProduct(int $productType)
3719
    {
3720
        if (empty($this->get('tax_enable') === 'true')) {
3721
            return false;
3722
        }
3723
3724
        $globalParameters = $this->getGlobalParameters();
3725
        $taxAppliesTo = $globalParameters['tax_applies_to'];
3726
        if ($taxAppliesTo == self::TAX_APPLIES_TO_ALL) {
3727
            return true;
3728
        }
3729
3730
        if ($taxAppliesTo == $productType) {
3731
            return true;
3732
        }
3733
3734
        return false;
3735
    }
3736
3737
    /**
3738
     * Get the path.
3739
     *
3740
     * @param string $var path variable
3741
     *
3742
     * @return string path
3743
     */
3744
    public function getPath($var)
3745
    {
3746
        $pluginPath = api_get_path(WEB_PLUGIN_PATH).'buycourses/';
3747
        $paths = [
3748
            'SERVICE_IMAGES' => $pluginPath.'uploads/services/images/',
3749
            'SRC' => $pluginPath.'src/',
3750
            'VIEW' => $pluginPath.'view/',
3751
            'UPLOADS' => $pluginPath.'uploads/',
3752
            'LANGUAGES' => $pluginPath.'lang/',
3753
            'RESOURCES' => $pluginPath.'resources/',
3754
            'RESOURCES_IMG' => $pluginPath.'resources/img/',
3755
            'RESOURCES_CSS' => $pluginPath.'resources/css/',
3756
            'RESOURCES_JS' => $pluginPath.'resources/js/',
3757
        ];
3758
3759
        return $paths[$var];
3760
    }
3761
3762
    /**
3763
     * @return array
3764
     */
3765
    public function getBuyCoursePluginPrice(Session $session)
3766
    {
3767
        // start buycourse validation
3768
        // display the course price and buy button if the buycourses plugin is enabled and this course is configured
3769
        $isThisCourseInSale = $this->buyCoursesForGridCatalogValidator($session->getId(), self::PRODUCT_TYPE_SESSION);
3770
        $return = [];
3771
3772
        if ($isThisCourseInSale) {
3773
            // set the Price label
3774
            $return['html'] = $isThisCourseInSale['html'];
3775
            // set the Buy button instead register.
3776
            if ($isThisCourseInSale['verificator']) {
3777
                $return['buy_button'] = $this->returnBuyCourseButton($session->getId(), self::PRODUCT_TYPE_SESSION);
3778
            }
3779
        }
3780
        // end buycourse validation
3781
        return $return;
3782
    }
3783
3784
    /**
3785
     * Register a coupon sale.
3786
     *
3787
     * @param int $saleId   The sale ID
3788
     * @param int $couponId The coupon ID
3789
     *
3790
     * @return int
3791
     */
3792
    public function registerCouponSale(int $saleId, int $couponId)
3793
    {
3794
        $sale = $this->getSale($saleId);
3795
3796
        if (empty($sale)) {
3797
            return false;
3798
        }
3799
3800
        $values = [
3801
            'coupon_id' => $couponId,
3802
            'sale_id' => $saleId,
3803
        ];
3804
3805
        return Database::insert(self::TABLE_COUPON_SALE, $values);
3806
    }
3807
3808
    /**
3809
     * Register a coupon service sale.
3810
     *
3811
     * @param int $saleId   The sale ID
3812
     * @param int $couponId The coupon ID
3813
     *
3814
     * @return int
3815
     */
3816
    public function registerCouponServiceSale(int $saleId, int $couponId)
3817
    {
3818
        $sale = $this->getSale($saleId);
3819
3820
        if (empty($sale)) {
3821
            return false;
3822
        }
3823
3824
        $values = [
3825
            'coupon_id' => $couponId,
3826
            'service_sale_id' => $saleId,
3827
        ];
3828
3829
        return Database::insert(self::TABLE_COUPON_SERVICE_SALE, $values);
3830
    }
3831
3832
    /**
3833
     * Register a coupon sale.
3834
     *
3835
     * @param int $saleId   The sale ID
3836
     * @param int $couponId The coupon ID
3837
     *
3838
     * @return int
3839
     */
3840
    public function registerCouponSubscriptionSale(int $saleId, int $couponId)
3841
    {
3842
        $sale = $this->getSubscriptionSale($saleId);
3843
3844
        if (empty($sale)) {
3845
            return false;
3846
        }
3847
3848
        $values = [
3849
            'coupon_id' => (int) $couponId,
3850
            'sale_id' => (int) $saleId,
3851
        ];
3852
3853
        return Database::insert(self::TABLE_COUPON_SUBSCRIPTION_SALE, $values);
3854
    }
3855
3856
    /**
3857
     * Add a new coupon.
3858
     */
3859
    public function addNewCoupon(array $coupon): bool
3860
    {
3861
        $couponId = $this->registerCoupon($coupon);
3862
        if ($couponId) {
3863
            if (isset($coupon['courses'])) {
3864
                foreach ($coupon['courses'] as $course) {
3865
                    $this->registerCouponItem($couponId, self::PRODUCT_TYPE_COURSE, $course);
3866
                }
3867
            }
3868
3869
            if (isset($coupon['sessions'])) {
3870
                foreach ($coupon['sessions'] as $session) {
3871
                    $this->registerCouponItem($couponId, self::PRODUCT_TYPE_SESSION, $session);
3872
                }
3873
            }
3874
3875
            if (isset($coupon['services'])) {
3876
                foreach ($coupon['services'] as $service) {
3877
                    $this->registerCouponService($couponId, $service);
3878
                }
3879
            }
3880
3881
            return true;
3882
        } else {
3883
            Display::addFlash(
3884
                Display::return_message(
3885
                    $this->get_lang('CouponErrorInsert'),
3886
                    'error',
3887
                    false
3888
                )
3889
            );
3890
3891
            return false;
3892
        }
3893
    }
3894
3895
    /**
3896
     * Add a new coupon.
3897
     *
3898
     * @return bool
3899
     */
3900
    public function updateCouponData(array $coupon)
3901
    {
3902
        $this->updateCoupon($coupon);
3903
        $this->deleteCouponItemsByCoupon(self::PRODUCT_TYPE_COURSE, $coupon['id']);
3904
        $this->deleteCouponItemsByCoupon(self::PRODUCT_TYPE_SESSION, $coupon['id']);
3905
        $this->deleteCouponServicesByCoupon($coupon['id']);
3906
3907
        if (isset($coupon['courses'])) {
3908
            foreach ($coupon['courses'] as $course) {
3909
                $this->registerCouponItem($coupon['id'], self::PRODUCT_TYPE_COURSE, $course);
3910
            }
3911
        }
3912
3913
        if (isset($coupon['sessions'])) {
3914
            foreach ($coupon['sessions'] as $session) {
3915
                $this->registerCouponItem($coupon['id'], self::PRODUCT_TYPE_SESSION, $session);
3916
            }
3917
        }
3918
3919
        if (isset($coupon['services'])) {
3920
            foreach ($coupon['services'] as $service) {
3921
                $this->registerCouponService($coupon['id'], $service);
3922
            }
3923
        }
3924
3925
        return true;
3926
    }
3927
3928
    /**
3929
     * Update coupons delivered.
3930
     *
3931
     * @param int $couponId The coupon ID
3932
     *
3933
     * @return bool
3934
     */
3935
    public function updateCouponDelivered(int $couponId)
3936
    {
3937
        $couponTable = Database::get_main_table(self::TABLE_COUPON);
3938
3939
        $sql = "UPDATE $couponTable
3940
        SET delivered = delivered+1
3941
        WHERE id = $couponId";
3942
3943
        Database::query($sql);
3944
    }
3945
3946
    /**
3947
     * Get coupon info.
3948
     *
3949
     * @param int $couponId The coupon ID
3950
     *
3951
     * @return array The coupon data
3952
     */
3953
    public function getCouponInfo(int $couponId)
3954
    {
3955
        $coupon = $this->getDataCoupon($couponId);
3956
3957
        $couponRelCourses = $this->getItemsCoupons($couponId, self::PRODUCT_TYPE_COURSE);
3958
        $couponRelSessions = $this->getItemsCoupons($couponId, self::PRODUCT_TYPE_SESSION);
3959
        $couponRelServices = $this->getServicesCoupons($couponId);
3960
3961
        $coupon['courses'] = $couponRelCourses;
3962
        $coupon['sessions'] = $couponRelSessions;
3963
        $coupon['services'] = $couponRelServices;
3964
3965
        return $coupon;
3966
    }
3967
3968
    /**
3969
     * Get a list of coupons.
3970
     *
3971
     * @param int $status The coupons activation status
3972
     *
3973
     * @return array Coupons data
3974
     */
3975
    public function getCouponsListByStatus(int $status)
3976
    {
3977
        $coupons = $this->getDataCoupons($status);
3978
3979
        return $coupons;
3980
    }
3981
3982
    /**
3983
     * Get the coupon data.
3984
     *
3985
     * @return array The coupon data
3986
     */
3987
    public function getCoupon(int $couponId, int $productType, int $productId)
3988
    {
3989
        $coupon = $this->getDataCoupon($couponId, $productType, $productId);
3990
3991
        return $coupon;
3992
    }
3993
3994
    /**
3995
     * Get data of the coupon code.
3996
     *
3997
     * @param string $couponCode  The coupon code
3998
     * @param int    $productId   The product ID
3999
     * @param int    $productType The product type
4000
     *
4001
     * @return array The coupon data
4002
     */
4003
    public function getCouponByCode(string $couponCode, int $productType = null, int $productId = null)
4004
    {
4005
        $coupon = $this->getDataCouponByCode($couponCode, $productType, $productId);
4006
4007
        return $coupon;
4008
    }
4009
4010
    /**
4011
     * Get data of the coupon code for a service.
4012
     *
4013
     * @param int $couponId  The coupon ID
4014
     * @param int $serviceId The product ID
4015
     *
4016
     * @return array The coupon data
4017
     */
4018
    public function getCouponService(int $couponId, int $serviceId)
4019
    {
4020
        $coupon = $this->getDataCouponService($couponId, $serviceId);
4021
4022
        return $coupon;
4023
    }
4024
4025
    /**
4026
     * Get data of the coupon code for a service.
4027
     *
4028
     * @param string $couponCode The coupon code code
4029
     * @param int    $serviceId  The product id
4030
     *
4031
     * @return array The coupon data
4032
     */
4033
    public function getCouponServiceByCode(string $couponCode, int $serviceId)
4034
    {
4035
        $coupon = $this->getDataCouponServiceByCode($couponCode, $serviceId);
4036
4037
        return $coupon;
4038
    }
4039
4040
    /**
4041
     * Get the coupon code of a item sale.
4042
     *
4043
     * @param int $saleId The sale ID
4044
     *
4045
     * @return string The coupon code
4046
     */
4047
    public function getSaleCouponCode(int $saleId)
4048
    {
4049
        $couponTable = Database::get_main_table(self::TABLE_COUPON);
4050
        $couponSaleTable = Database::get_main_table(self::TABLE_COUPON_SALE);
4051
4052
        $couponFrom = "
4053
            $couponTable c
4054
            INNER JOIN $couponSaleTable s
4055
                on c.id = s.coupon_id
4056
        ";
4057
4058
        $couponCode = Database::select(
4059
            ['c.code'],
4060
            $couponFrom,
4061
            [
4062
                'where' => [
4063
                    's.sale_id = ? ' => $saleId,
4064
                ],
4065
            ],
4066
            'first'
4067
        );
4068
4069
        return $couponCode['code'];
4070
    }
4071
4072
    /**
4073
     * Get the coupon code of a service sale.
4074
     *
4075
     * @param int $serviceSaleId The service sale ID
4076
     *
4077
     * @return string The coupon code
4078
     */
4079
    public function getServiceSaleCouponCode(int $serviceSaleId)
4080
    {
4081
        $couponTable = Database::get_main_table(self::TABLE_COUPON);
4082
        $couponServiceSaleTable = Database::get_main_table(self::TABLE_COUPON_SERVICE_SALE);
4083
4084
        $couponFrom = "
4085
            $couponTable c
4086
            INNER JOIN $couponServiceSaleTable s
4087
                on c.id = s.coupon_id
4088
        ";
4089
4090
        $couponCode = Database::select(
4091
            ['c.code'],
4092
            $couponFrom,
4093
            [
4094
                'where' => [
4095
                    's.service_sale_id = ? ' => $serviceSaleId,
4096
                ],
4097
            ],
4098
            'first'
4099
        );
4100
4101
        return $couponCode['code'];
4102
    }
4103
4104
    /**
4105
     * @return array
4106
     */
4107
    public function getCecabankSignature(string $saleReference, float $price)
4108
    {
4109
        $urlOk = api_get_path(WEB_PLUGIN_PATH).'buycourses/src/cecabank_success.php';
4110
        $urlKo = api_get_path(WEB_PLUGIN_PATH).'buycourses/src/cecabank_cancel.php';
4111
4112
        $cecabankParams = $this->getCecabankParams();
4113
        $signature = $cecabankParams['crypto_key']
4114
        .$cecabankParams['merchant_id']
4115
        .$cecabankParams['acquirer_bin']
4116
        .$cecabankParams['terminal_id']
4117
        .$saleReference
4118
        .$price * 100
4119
        .'978'
4120
        .$cecabankParams['exponent']
4121
        .$cecabankParams['cypher']
4122
        .$urlOk
4123
        .$urlKo;
4124
4125
        $sha256 = hash('sha256', $signature);
4126
        $signature = strtolower($sha256);
4127
4128
        return $signature;
4129
    }
4130
4131
    /**
4132
     * Register a subscription sale.
4133
     *
4134
     * @param int $productId   The product ID
4135
     * @param int $productType The product type
4136
     * @param int $paymentType The payment type
4137
     * @param int $duration    The subscription duration
4138
     * @param int $couponId    The coupon ID
4139
     *
4140
     * @return int
4141
     */
4142
    public function registerSubscriptionSale(
4143
        int $productId,
4144
        int $productType,
4145
        int $paymentType,
4146
        int $duration,
4147
        int $couponId = null
4148
    ) {
4149
        if (!in_array(
4150
            $paymentType,
4151
            [
4152
                self::PAYMENT_TYPE_PAYPAL,
4153
                self::PAYMENT_TYPE_TRANSFER,
4154
                self::PAYMENT_TYPE_CULQI,
4155
                self::PAYMENT_TYPE_TPV_REDSYS,
4156
                self::PAYMENT_TYPE_STRIPE,
4157
                self::PAYMENT_TYPE_TPV_CECABANK,
4158
            ]
4159
        )
4160
        ) {
4161
            return false;
4162
        }
4163
4164
        $entityManager = Database::getManager();
4165
        $item = $this->getSubscriptionItem($productId, $productType);
4166
4167
        if (empty($item)) {
4168
            return false;
4169
        }
4170
4171
        $productName = '';
4172
        if ($item['product_type'] == self::PRODUCT_TYPE_COURSE) {
4173
            $course = $entityManager->find('ChamiloCoreBundle:Course', $item['product_id']);
4174
4175
            if (empty($course)) {
4176
                return false;
4177
            }
4178
4179
            $productName = $course->getTitle();
4180
        } elseif ($item['product_type'] == self::PRODUCT_TYPE_SESSION) {
4181
            $session = $entityManager->find('ChamiloCoreBundle:Session', $item['product_id']);
4182
4183
            if (empty($session)) {
4184
                return false;
4185
            }
4186
4187
            $productName = $session->getName();
4188
        }
4189
4190
        if ($couponId != null) {
4191
            $coupon = $this->getCoupon($couponId, $item['product_type'], $item['product_id']);
4192
        }
4193
4194
        $couponDiscount = 0;
4195
        $priceWithoutDiscount = 0;
4196
        if ($coupon != null) {
4197
            if ($coupon['discount_type'] == self::COUPON_DISCOUNT_TYPE_AMOUNT) {
4198
                $couponDiscount = $coupon['discount_amount'];
4199
            } elseif ($coupon['discount_type'] == self::COUPON_DISCOUNT_TYPE_PERCENTAGE) {
4200
                $couponDiscount = ($item['price'] * $coupon['discount_amount']) / 100;
4201
            }
4202
            $priceWithoutDiscount = $item['price'];
4203
        }
4204
        $item['price'] = $item['price'] - $couponDiscount;
4205
        $price = $item['price'];
4206
        $priceWithoutTax = null;
4207
        $taxPerc = null;
4208
        $taxAmount = 0;
4209
        $taxEnable = $this->get('tax_enable') === 'true';
4210
        $globalParameters = $this->getGlobalParameters();
4211
        $taxAppliesTo = $globalParameters['tax_applies_to'];
4212
4213
        if ($taxEnable &&
4214
            (
4215
                $taxAppliesTo == self::TAX_APPLIES_TO_ALL ||
4216
                ($taxAppliesTo == self::TAX_APPLIES_TO_ONLY_COURSE && $item['product_type'] == self::PRODUCT_TYPE_COURSE) ||
4217
                ($taxAppliesTo == self::TAX_APPLIES_TO_ONLY_SESSION && $item['product_type'] == self::PRODUCT_TYPE_SESSION)
4218
            )
4219
        ) {
4220
            $priceWithoutTax = $item['price'];
4221
            $globalTaxPerc = $globalParameters['global_tax_perc'];
4222
            $precision = 2;
4223
            $taxPerc = is_null($item['tax_perc']) ? $globalTaxPerc : $item['tax_perc'];
4224
            $taxAmount = round($priceWithoutTax * $taxPerc / 100, $precision);
4225
            $price = $priceWithoutTax + $taxAmount;
4226
        }
4227
4228
        $subscriptionEnd = date('y:m:d', strtotime('+'.$duration.' days'));
4229
4230
        $values = [
4231
            'reference' => $this->generateReference(
4232
                api_get_user_id(),
4233
                $item['product_type'],
4234
                $item['product_id']
4235
            ),
4236
            'currency_id' => $item['currency_id'],
4237
            'date' => api_get_utc_datetime(),
4238
            'user_id' => api_get_user_id(),
4239
            'product_type' => $item['product_type'],
4240
            'product_name' => $productName,
4241
            'product_id' => $item['product_id'],
4242
            'price' => $price,
4243
            'price_without_tax' => $priceWithoutTax,
4244
            'tax_perc' => $taxPerc,
4245
            'tax_amount' => $taxAmount,
4246
            'status' => self::SALE_STATUS_PENDING,
4247
            'payment_type' => $paymentType,
4248
            'price_without_discount' => $priceWithoutDiscount,
4249
            'discount_amount' => $couponDiscount,
4250
            'subscription_end' => $subscriptionEnd,
4251
        ];
4252
4253
        return Database::insert(self::TABLE_SUBSCRIPTION_SALE, $values);
4254
    }
4255
4256
    /**
4257
     * Add a new subscription.
4258
     *
4259
     * @return bool
4260
     */
4261
    public function addNewSubscription(array $subscription)
4262
    {
4263
        $result = false;
4264
4265
        if (isset($subscription['frequencies'])) {
4266
            foreach ($subscription['frequencies'] as $frequency) {
4267
                $subscriptionDb = $this->getSubscription($subscription['product_type'], $subscription['product_id'], $frequency['duration']);
4268
4269
                if (!isset($subscriptionDb) || empty($subscription)) {
4270
                    Display::addFlash(
4271
                        Display::return_message(
4272
                            $this->get_lang('SubscriptionAlreadyExists').' ('.$frequency['duration'].')',
4273
                            'error',
4274
                            false
4275
                        )
4276
                    );
4277
4278
                    return false;
4279
                } else {
4280
                    $subscriptionId = $this->registerSubscription($subscription, $frequency);
4281
                    if ($subscriptionId) {
4282
                        $result = true;
4283
                    } else {
4284
                        Display::addFlash(
4285
                            Display::return_message(
4286
                                $this->get_lang('SubscriptionErrorInsert'),
4287
                                'error',
4288
                                false
4289
                            )
4290
                        );
4291
4292
                        return false;
4293
                    }
4294
                }
4295
            }
4296
        } else {
4297
            Display::addFlash(
4298
                Display::return_message(
4299
                    $this->get_lang('FrequenciesNotSetError'),
4300
                    'error',
4301
                    false
4302
                )
4303
            );
4304
4305
            return false;
4306
        }
4307
4308
        return $result;
4309
    }
4310
4311
    /**
4312
     * Add a new subscription.
4313
     *
4314
     * @return bool
4315
     */
4316
    public function updateSubscriptions(int $productType, int $productId, int $taxPerc)
4317
    {
4318
        $this->updateSubscription($productType, $productId, $taxPerc);
4319
    }
4320
4321
    /**
4322
     * Delete a subscription.
4323
     *
4324
     * @return int
4325
     */
4326
    public function deleteSubscription(int $productType, int $productId, int $duration)
4327
    {
4328
        return Database::delete(
4329
            Database::get_main_table(self::TABLE_SUBSCRIPTION),
4330
            [
4331
                'product_type = ? AND ' => (int) $productType,
4332
                'product_id = ? AND ' => (int) $productId,
4333
                'duration = ? ' => (int) $duration,
4334
            ]
4335
        );
4336
    }
4337
4338
    /**
4339
     * Get a list of subscriptions by product ID and type.
4340
     *
4341
     * @param string $productId   The product ID
4342
     * @param int    $productType The product type
4343
     *
4344
     * @return array Subscriptions data
4345
     */
4346
    public function getSubscriptions($productType, $productId)
4347
    {
4348
        $subscriptions = $this->getDataSubscriptions($productType, $productId);
4349
4350
        return $subscriptions;
4351
    }
4352
4353
    /**
4354
     * Get data of the subscription.
4355
     *
4356
     * @return array The subscription data
4357
     */
4358
    public function getSubscription(int $productType, int $productId, int $duration, array $coupon = null)
4359
    {
4360
        $subscription = $this->getDataSubscription($productType, $productId, $duration);
4361
4362
        $currency = $this->getSelectedCurrency();
4363
        $isoCode = $currency['iso_code'];
4364
4365
        $subscription['iso_code'] = $isoCode;
4366
4367
        $this->setPriceSettings($subscription, self::TAX_APPLIES_TO_ONLY_COURSE, $coupon);
4368
4369
        return $subscription;
4370
    }
4371
4372
    /**
4373
     * Get subscription sale data by ID.
4374
     *
4375
     * @param int $saleId The sale ID
4376
     *
4377
     * @return array
4378
     */
4379
    public function getSubscriptionSale(int $saleId)
4380
    {
4381
        return Database::select(
4382
            '*',
4383
            Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE),
4384
            [
4385
                'where' => ['id = ?' => $saleId],
4386
            ],
4387
            'first'
4388
        );
4389
    }
4390
4391
    /**
4392
     * Complete subscription sale process. Update sale status to completed.
4393
     *
4394
     * @param int $saleId The subscription sale ID
4395
     *
4396
     * @return bool
4397
     */
4398
    public function completeSubscriptionSale(int $saleId)
4399
    {
4400
        $sale = $this->getSubscriptionSale($saleId);
4401
4402
        if ($sale['status'] == self::SALE_STATUS_COMPLETED) {
4403
            return true;
4404
        }
4405
4406
        $saleIsCompleted = false;
4407
        switch ($sale['product_type']) {
4408
            case self::PRODUCT_TYPE_COURSE:
4409
                $course = api_get_course_info_by_id($sale['product_id']);
4410
                $saleIsCompleted = CourseManager::subscribeUser($sale['user_id'], $course['code']);
4411
                break;
4412
            case self::PRODUCT_TYPE_SESSION:
4413
                SessionManager::subscribeUsersToSession(
4414
                    $sale['product_id'],
4415
                    [$sale['user_id']],
4416
                    api_get_session_visibility($sale['product_id']),
4417
                    false
4418
                );
4419
4420
                $saleIsCompleted = true;
4421
                break;
4422
        }
4423
4424
        if ($saleIsCompleted) {
4425
            $this->updateSubscriptionSaleStatus($sale['id'], self::SALE_STATUS_COMPLETED);
4426
            if ($this->get('invoicing_enable') === 'true') {
4427
                $this->setInvoice($sale['id']);
4428
            }
4429
        }
4430
4431
        return $saleIsCompleted;
4432
    }
4433
4434
    /**
4435
     * Update subscription sale status to canceled.
4436
     *
4437
     * @param int $saleId The subscription sale ID
4438
     */
4439
    public function cancelSubscriptionSale(int $saleId)
4440
    {
4441
        $this->updateSubscriptionSaleStatus($saleId, self::SALE_STATUS_CANCELED);
4442
    }
4443
4444
    /**
4445
     * Get a list of subscription sales by the status.
4446
     *
4447
     * @param int $status The status to filter
4448
     *
4449
     * @return array The sale list. Otherwise return false
4450
     */
4451
    public function getSubscriptionSaleListByStatus(int $status = self::SALE_STATUS_PENDING)
4452
    {
4453
        $saleTable = Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE);
4454
        $currencyTable = Database::get_main_table(self::TABLE_CURRENCY);
4455
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
4456
4457
        $innerJoins = "
4458
            INNER JOIN $currencyTable c ON s.currency_id = c.id
4459
            INNER JOIN $userTable u ON s.user_id = u.id
4460
        ";
4461
4462
        return Database::select(
4463
            ['c.iso_code', 'u.firstname', 'u.lastname', 'u.email', 's.*'],
4464
            "$saleTable s $innerJoins",
4465
            [
4466
                'where' => ['s.status = ?' => $status],
4467
                'order' => 'id DESC',
4468
            ]
4469
        );
4470
    }
4471
4472
    /**
4473
     * Get the list statuses for subscriptions sales.
4474
     *
4475
     * @param string $dateStart
4476
     * @param string $dateEnd
4477
     *
4478
     * @throws Exception
4479
     *
4480
     * @return array
4481
     */
4482
    public function getSubscriptionSaleListReport(string $dateStart = null, string $dateEnd = null)
4483
    {
4484
        $saleTable = Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE);
4485
        $currencyTable = Database::get_main_table(self::TABLE_CURRENCY);
4486
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
4487
        $innerJoins = "
4488
            INNER JOIN $currencyTable c ON s.currency_id = c.id
4489
            INNER JOIN $userTable u ON s.user_id = u.id
4490
        ";
4491
        $list = Database::select(
4492
            ['c.iso_code', 'u.firstname', 'u.lastname', 'u.email', 's.*'],
4493
            "$saleTable s $innerJoins",
4494
            [
4495
                'order' => 'id DESC',
4496
            ]
4497
        );
4498
        $listExportTemp = [];
4499
        $listExport = [];
4500
        $textStatus = null;
4501
        $paymentTypes = $this->getPaymentTypes();
4502
        $productTypes = $this->getProductTypes();
4503
        foreach ($list as $item) {
4504
            $statusSaleOrder = $item['status'];
4505
            switch ($statusSaleOrder) {
4506
                case 0:
4507
                    $textStatus = $this->get_lang('SaleStatusPending');
4508
                    break;
4509
                case 1:
4510
                    $textStatus = $this->get_lang('SaleStatusCompleted');
4511
                    break;
4512
                case -1:
4513
                    $textStatus = $this->get_lang('SaleStatusCanceled');
4514
                    break;
4515
            }
4516
            $dateFilter = new DateTime($item['date']);
4517
            $listExportTemp[] = [
4518
                'id' => $item['id'],
4519
                'reference' => $item['reference'],
4520
                'status' => $textStatus,
4521
                'status_filter' => $item['status'],
4522
                'date' => $dateFilter->format('Y-m-d'),
4523
                'order_time' => $dateFilter->format('H:i:s'),
4524
                'price' => $item['iso_code'].' '.$item['price'],
4525
                'product_type' => $productTypes[$item['product_type']],
4526
                'product_name' => $item['product_name'],
4527
                'payment_type' => $paymentTypes[$item['payment_type']],
4528
                'complete_user_name' => api_get_person_name($item['firstname'], $item['lastname']),
4529
                'email' => $item['email'],
4530
            ];
4531
        }
4532
        $listExport[] = [
4533
            get_lang('Number'),
4534
            $this->get_lang('OrderStatus'),
4535
            $this->get_lang('OrderDate'),
4536
            $this->get_lang('OrderTime'),
4537
            $this->get_lang('PaymentMethod'),
4538
            $this->get_lang('SalePrice'),
4539
            $this->get_lang('ProductType'),
4540
            $this->get_lang('ProductName'),
4541
            $this->get_lang('UserName'),
4542
            get_lang('Email'),
4543
        ];
4544
        //Validation Export
4545
        $dateStart = strtotime($dateStart);
4546
        $dateEnd = strtotime($dateEnd);
4547
        foreach ($listExportTemp as $item) {
4548
            $dateFilter = strtotime($item['date']);
4549
            if (($dateFilter >= $dateStart) && ($dateFilter <= $dateEnd)) {
4550
                $listExport[] = [
4551
                    'id' => $item['id'],
4552
                    'status' => $item['status'],
4553
                    'date' => $item['date'],
4554
                    'order_time' => $item['order_time'],
4555
                    'payment_type' => $item['payment_type'],
4556
                    'price' => $item['price'],
4557
                    'product_type' => $item['product_type'],
4558
                    'product_name' => $item['product_name'],
4559
                    'complete_user_name' => $item['complete_user_name'],
4560
                    'email' => $item['email'],
4561
                ];
4562
            }
4563
        }
4564
4565
        return $listExport;
4566
    }
4567
4568
    /**
4569
     * Get a list of subscription sales by the user.
4570
     *
4571
     * @param string $term The search term
4572
     *
4573
     * @return array The sale list. Otherwise return false
4574
     */
4575
    public function getSubscriptionSaleListByUser(string $term)
4576
    {
4577
        $term = trim($term);
4578
4579
        if (empty($term)) {
4580
            return [];
4581
        }
4582
4583
        $saleTable = Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE);
4584
        $currencyTable = Database::get_main_table(self::TABLE_CURRENCY);
4585
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
4586
        $innerJoins = "
4587
            INNER JOIN $currencyTable c ON s.currency_id = c.id
4588
            INNER JOIN $userTable u ON s.user_id = u.id
4589
        ";
4590
4591
        return Database::select(
4592
            ['c.iso_code', 'u.firstname', 'u.lastname', 'u.email', 's.*'],
4593
            "$saleTable s $innerJoins",
4594
            [
4595
                'where' => [
4596
                    'u.username LIKE %?% OR ' => $term,
4597
                    'u.lastname LIKE %?% OR ' => $term,
4598
                    'u.firstname LIKE %?%' => $term,
4599
                ],
4600
                'order' => 'id DESC',
4601
            ]
4602
        );
4603
    }
4604
4605
    /**
4606
     * Get a list of subscription sales by the user id.
4607
     *
4608
     * @param int $id The user id
4609
     *
4610
     * @return array The sale list. Otherwise return false
4611
     */
4612
    public function getSubscriptionSaleListByUserId(int $id)
4613
    {
4614
        if (empty($id)) {
4615
            return [];
4616
        }
4617
4618
        $saleTable = Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE);
4619
        $currencyTable = Database::get_main_table(self::TABLE_CURRENCY);
4620
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
4621
4622
        $innerJoins = "
4623
            INNER JOIN $currencyTable c ON s.currency_id = c.id
4624
            INNER JOIN $userTable u ON s.user_id = u.id
4625
        ";
4626
4627
        return Database::select(
4628
            ['c.iso_code', 'u.firstname', 'u.lastname', 's.*'],
4629
            "$saleTable s $innerJoins",
4630
            [
4631
                'where' => [
4632
                    'u.id = ? AND s.status = ?' => [$id, self::SALE_STATUS_COMPLETED],
4633
                ],
4634
                'order' => 'id DESC',
4635
            ]
4636
        );
4637
    }
4638
4639
    /**
4640
     * Get a list of subscription sales by date range.
4641
     *
4642
     * @return array The sale list. Otherwise return false
4643
     */
4644
    public function getSubscriptionSaleListByDate(string $dateStart, string $dateEnd)
4645
    {
4646
        $dateStart = trim($dateStart);
4647
        $dateEnd = trim($dateEnd);
4648
        if (empty($dateStart)) {
4649
            return [];
4650
        }
4651
        if (empty($dateEnd)) {
4652
            return [];
4653
        }
4654
        $saleTable = Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE);
4655
        $currencyTable = Database::get_main_table(self::TABLE_CURRENCY);
4656
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
4657
        $innerJoins = "
4658
            INNER JOIN $currencyTable c ON s.currency_id = c.id
4659
            INNER JOIN $userTable u ON s.user_id = u.id
4660
        ";
4661
4662
        return Database::select(
4663
            ['c.iso_code', 'u.firstname', 'u.lastname', 'u.email', 's.*'],
4664
            "$saleTable s $innerJoins",
4665
            [
4666
                'where' => [
4667
                    's.date BETWEEN ? AND ' => $dateStart,
4668
                    ' ? ' => $dateEnd,
4669
                ],
4670
                'order' => 'id DESC',
4671
            ]
4672
        );
4673
    }
4674
4675
    /**
4676
     * Get a list of subscription sales by the user Email.
4677
     *
4678
     * @param string $term The search term
4679
     *
4680
     * @return array The sale list. Otherwise return false
4681
     */
4682
    public function getSubscriptionSaleListByEmail(string $term)
4683
    {
4684
        $term = trim($term);
4685
        if (empty($term)) {
4686
            return [];
4687
        }
4688
        $saleTable = Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE);
4689
        $currencyTable = Database::get_main_table(self::TABLE_CURRENCY);
4690
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
4691
        $innerJoins = "
4692
            INNER JOIN $currencyTable c ON s.currency_id = c.id
4693
            INNER JOIN $userTable u ON s.user_id = u.id
4694
        ";
4695
4696
        return Database::select(
4697
            ['c.iso_code', 'u.firstname', 'u.lastname', 'u.email', 's.*'],
4698
            "$saleTable s $innerJoins",
4699
            [
4700
                'where' => [
4701
                    'u.email LIKE %?% ' => $term,
4702
                ],
4703
                'order' => 'id DESC',
4704
            ]
4705
        );
4706
    }
4707
4708
    /**
4709
     * Get subscription sale data by ID.
4710
     *
4711
     * @param string $date The date
4712
     *
4713
     * @return array
4714
     */
4715
    public function getSubscriptionsDue(string $date)
4716
    {
4717
        return Database::select(
4718
            'id, user_id, product_id, product_type',
4719
            Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE),
4720
            [
4721
                'where' => ['subscription_end < ? AND status <> ? AND (expired is NULL OR expired <> ?)' => [
4722
                    $date,
4723
                    self::SALE_STATUS_COMPLETED,
4724
                    1,
4725
                    ],
4726
                ],
4727
            ],
4728
            'first'
4729
        );
4730
    }
4731
4732
    /**
4733
     * Get subscription sale data by ID.
4734
     *
4735
     * @param int $userId      The user ID
4736
     * @param int $productId   The product ID
4737
     * @param int $productType The product type
4738
     *
4739
     * @return array
4740
     */
4741
    public function checkItemSubscriptionActive(int $userId, int $productId, int $productType)
4742
    {
4743
        return Database::select(
4744
            '*',
4745
            Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE),
4746
            [
4747
                'where' => ['subscription_end >= ? AND userId = ? AND productId = ? AND productType = ? AND status <> ?' => [
4748
                    api_get_utc_datetime(),
4749
                    $userId,
4750
                    $productId,
4751
                    $productType,
4752
                    self::SALE_STATUS_COMPLETED,
4753
                    ],
4754
                ],
4755
            ],
4756
            'first'
4757
        );
4758
    }
4759
4760
    /**
4761
     * Get subscription sale data by ID.
4762
     *
4763
     * @return array
4764
     */
4765
    public function updateSubscriptionSaleExpirationStatus(int $id)
4766
    {
4767
        $saleTable = Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE);
4768
4769
        return Database::update(
4770
            $saleTable,
4771
            ['expired' => 1],
4772
            ['id = ?' => $id]
4773
        );
4774
    }
4775
4776
    /**
4777
     * Get the list of frequencies discount types.
4778
     *
4779
     * @return array
4780
     */
4781
    public function getFrequencies()
4782
    {
4783
        $data = Database::select(
4784
            '*',
4785
            Database::get_main_table(self::TABLE_SUBSCRIPTION_PERIOD),
4786
            []
4787
        );
4788
4789
        $frequenciesList = $this->getFrequenciesList();
4790
        $frequencies = [];
4791
4792
        foreach ($data as $key => $items) {
4793
            $frequencies[$items['duration']] = $items['name'];
4794
        }
4795
4796
        return $frequencies;
4797
    }
4798
4799
    /**
4800
     * Get the list of frequencies discount types.
4801
     *
4802
     * @return array
4803
     */
4804
    public function getFrequenciesList()
4805
    {
4806
        return Database::select(
4807
            '*',
4808
            Database::get_main_table(self::TABLE_SUBSCRIPTION_PERIOD),
4809
            []
4810
        );
4811
    }
4812
4813
    /**
4814
     * Get the a frequency.
4815
     *
4816
     * @param int $duration The duration of the frequency value
4817
     *
4818
     * @return array
4819
     */
4820
    public function selectFrequency(int $duration)
4821
    {
4822
        return Database::select(
4823
            '*',
4824
            Database::get_main_table(self::TABLE_SUBSCRIPTION_PERIOD),
4825
            [
4826
                'where' => [
4827
                    'duration = ?' => [
4828
                        (int) $duration,
4829
                    ],
4830
                ],
4831
            ],
4832
            'first'
4833
        );
4834
    }
4835
4836
    /**
4837
     * Add a new subscription frequency.
4838
     *
4839
     * @return array
4840
     */
4841
    public function addFrequency(int $duration, string $name)
4842
    {
4843
        $values = [
4844
            'duration' => $duration,
4845
            'name' => $name,
4846
        ];
4847
4848
        return Database::insert(self::TABLE_SUBSCRIPTION_PERIOD, $values);
4849
    }
4850
4851
    /**
4852
     * Update a subscription frequency.
4853
     *
4854
     * @return array
4855
     */
4856
    public function updateFrequency(int $duration, string $name)
4857
    {
4858
        $periodTable = Database::get_main_table(self::TABLE_SUBSCRIPTION_PERIOD);
4859
4860
        return Database::update(
4861
            $periodTable,
4862
            ['name' => $name],
4863
            ['duration = ?' => $duration]
4864
        );
4865
    }
4866
4867
    /**
4868
     * Delete a subscription frequency.
4869
     *
4870
     * @return array
4871
     */
4872
    public function deleteFrequency(int $duration)
4873
    {
4874
        return Database::delete(
4875
            Database::get_main_table(self::TABLE_SUBSCRIPTION_PERIOD),
4876
            [
4877
                'duration = ?' => $duration,
4878
            ]
4879
        );
4880
    }
4881
4882
    /**
4883
     * @return string
4884
     */
4885
    public function getSubscriptionSuccessMessage(array $saleInfo)
4886
    {
4887
        switch ($saleInfo['product_type']) {
4888
            case self::PRODUCT_TYPE_COURSE:
4889
                $courseInfo = api_get_course_info_by_id($saleInfo['product_id']);
4890
                $url = api_get_course_url($courseInfo['code']);
4891
                break;
4892
            case self::PRODUCT_TYPE_SESSION:
4893
                $sessionId = (int) $saleInfo['product_id'];
4894
                $url = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$sessionId;
4895
                break;
4896
            default:
4897
                $url = '#';
4898
        }
4899
4900
        return Display::return_message(
4901
            sprintf(
4902
                $this->get_lang('SubscriptionToCourseXSuccessful'),
4903
                $url,
4904
                $saleInfo['product_name']
4905
            ),
4906
            'success',
4907
            false
4908
        );
4909
    }
4910
4911
    /**
4912
     * @return string
4913
     */
4914
    public static function returnPagination(
4915
        string $baseUrl,
4916
        string $currentPage,
4917
        string $pagesCount,
4918
        string $totalItems,
4919
        array $extraQueryParams = []
4920
    ) {
4921
        $queryParams = HttpRequest::createFromGlobals()->query->all();
4922
4923
        unset($queryParams['page']);
4924
4925
        $url = $baseUrl.'?'.http_build_query(
4926
            array_merge($queryParams, $extraQueryParams)
4927
        );
4928
4929
        return Display::getPagination($url, $currentPage, $pagesCount, $totalItems);
4930
    }
4931
4932
    /**
4933
     * Returns the javascript to set the sales report table for courses.
4934
     */
4935
    public static function getSalesReportScript(array $sales = [], bool $invoicingEnable = false)
4936
    {
4937
        $cols = "
4938
    '".preg_replace("/'/", "\\'", get_plugin_lang('OrderReference', 'BuyCoursesPlugin'))."',
4939
    '".preg_replace("/'/", "\\'", get_plugin_lang('OrderStatus', 'BuyCoursesPlugin'))."',
4940
    '".preg_replace("/'/", "\\'", get_plugin_lang('OrderDate', 'BuyCoursesPlugin'))."',
4941
    '".preg_replace("/'/", "\\'", get_plugin_lang('PaymentMethod', 'BuyCoursesPlugin'))."',
4942
    '".preg_replace("/'/", "\\'", get_plugin_lang('Price', 'BuyCoursesPlugin'))."',
4943
    '".preg_replace("/'/", "\\'", get_plugin_lang('CouponDiscount', 'BuyCoursesPlugin'))."',
4944
    '".preg_replace("/'/", "\\'", get_plugin_lang('Coupon', 'BuyCoursesPlugin'))."',
4945
    '".preg_replace("/'/", "\\'", get_plugin_lang('ProductType', 'BuyCoursesPlugin'))."',
4946
    '".preg_replace("/'/", "\\'", get_plugin_lang('Name', 'BuyCoursesPlugin'))."',
4947
    '".preg_replace("/'/", "\\'", get_lang('UserName'))."',
4948
    '".preg_replace("/'/", "\\'", get_lang('Email'))."',";
4949
        $model = "
4950
        {name:'reference', index:'reference', height:'auto', width:70, sorttype:'string', align:'center'},
4951
        {name:'status', index:'status', height:'auto', width:70, sorttype:'string', align:'center'},
4952
        {name:'date', index:'date', height:'auto', width:70, sorttype:'date', align:'center'},
4953
        {name:'payment_type', index:'payment_type', height:'auto', width:70, sorttype:'string', align:'center'},
4954
        {name:'total_price', index:'total_price', height:'auto', width:70, sorttype:'string', align:'center'},
4955
        {name:'coupon_discount', index:'coupon_discount', height:'auto', width:40, sorttype:'string', align: 'center'},
4956
        {name:'coupon', index:'coupon', height:'auto', width:60, sorttype:'string', align:'center'},
4957
        {name:'product_type', index:'product_type', height:'auto', width:40, sorttype:'string'},
4958
        {name:'product_name', index:'product_name', height:'auto', /*width:60,*/ sorttype:'string'},
4959
        {name:'complete_user_name', index:'complete_user_name', height:'auto', width:70, sorttype:'string'},
4960
        {name:'email', index:'email', height:'auto', /*width:60,*/ sorttype:'string'}, ";
4961
        if ($invoicingEnable) {
4962
            $model .= "{name:'invoice', index:'invoice', height:'auto', width:70, sorttype:'string'},";
4963
            $cols .= "'".get_plugin_lang('Invoice', 'BuyCoursesPlugin')."',";
4964
        }
4965
        $cols .= "'".get_lang('Options')."',";
4966
        $model .= "
4967
        {name:'options', index:'options', height:'auto', width:60, sortable:false},";
4968
        $data = '';
4969
        foreach ($sales as $item) {
4970
            $option = '';
4971
            if (!isset($item['complete_user_name'])) {
4972
                $item['complete_user_name'] = api_get_person_name($item['firstname'], $item['lastname']);
4973
            }
4974
            if ($item['invoice'] == 1) {
4975
                if ($invoicingEnable) {
4976
                    $item['invoice'] = "<a href='".api_get_path(WEB_PLUGIN_PATH).'buycourses/src/invoice.php?invoice='.$item['id']."&is_service=0"
4977
                        ."' title='".get_plugin_lang('InvoiceView', 'BuyCoursesPlugin')."'>".
4978
                        Display::return_icon('default.png', get_plugin_lang('InvoiceView', 'BuyCoursesPlugin'), '', ICON_SIZE_MEDIUM).
4979
                        "<br/>".$item['num_invoice'].
4980
                        "</a>";
4981
                }
4982
            } else {
4983
                $item['invoice'] = null;
4984
            }
4985
            if ($item['status'] == BuyCoursesPlugin::SALE_STATUS_CANCELED) {
4986
                $item['status'] = get_plugin_lang('SaleStatusCanceled', 'BuyCoursesPlugin');
4987
            } elseif ($item['status'] == BuyCoursesPlugin::SALE_STATUS_PENDING) {
4988
                $item['status'] = get_plugin_lang('SaleStatusPending', 'BuyCoursesPlugin');
4989
                $option = "<div class='btn-group btn-group-xs' role='group'>".
4990
                    "<a title='".get_plugin_lang('SubscribeUser', 'BuyCoursesPlugin')."'".
4991
                    " href='".api_get_self()."?order=".$item['id']."&action=confirm'".
4992
                    " class='btn btn-default'>".
4993
                    Display::return_icon('user_subscribe_session.png', get_plugin_lang('SubscribeUser', 'BuyCoursesPlugin'), '', ICON_SIZE_SMALL)
4994
                    ."</a>".
4995
                    "<a title='".get_plugin_lang('DeleteOrder', 'BuyCoursesPlugin')."'".
4996
                    " href='".api_get_self()."?order=".$item['id']."&action=cancel'".
4997
                    " class='btn btn-default'>".
4998
                    Display::return_icon('delete.png', get_plugin_lang('DeleteOrder', 'BuyCoursesPlugin'), '', ICON_SIZE_SMALL)
4999
                    ."</a>".
5000
                    "</div>";
5001
            } elseif ($item['status'] == BuyCoursesPlugin::SALE_STATUS_COMPLETED) {
5002
                $item['status'] = get_plugin_lang('SaleStatusCompleted', 'BuyCoursesPlugin');
5003
            }
5004
            $item['options'] = $option;
5005
            $item['date'] = api_get_local_time($item['date']);
5006
            $data .= json_encode($item).",";
5007
        }
5008
5009
        return "
5010
<script>
5011
    $(window).load( function () {
5012
        $('#table_report').jqGrid({
5013
            height: '100%',
5014
            autowidth: true,
5015
            LoadOnce: true,
5016
            rowNum:10,
5017
            rowList: [10, 25, 50, 100],
5018
            pager: 'tblGridPager',
5019
            datatype: 'local',
5020
            viewrecords: true,
5021
            gridview: true,
5022
            colNames:[ $cols ],
5023
            colModel:[ $model ],
5024
            caption: '".get_plugin_lang('SalesReport', 'BuyCoursesPlugin')."'
5025
        });
5026
        var mydata = [ $data ];
5027
        for(var i=0;i<=mydata.length;i++){
5028
            $('#table_report').jqGrid('addRowData',i+1,mydata[i]);
5029
            if(i==mydata.length){
5030
                $('#table_report').trigger('reloadGrid',[{page:1}])
5031
            }
5032
        }
5033
    });
5034
</script>";
5035
    }
5036
5037
    /**
5038
     * Filter the registered courses for show in plugin catalog.
5039
     */
5040
    private function getCourses(int $first, int $maxResults)
5041
    {
5042
        $em = Database::getManager();
5043
        $urlId = api_get_current_access_url_id();
5044
5045
        $qb = $em->createQueryBuilder();
5046
        $qb2 = $em->createQueryBuilder();
5047
        $qb3 = $em->createQueryBuilder();
5048
5049
        $qb = $qb
5050
            ->select('c')
5051
            ->from('ChamiloCoreBundle:Course', 'c')
5052
            ->where(
5053
                $qb->expr()->notIn(
5054
                    'c',
5055
                    $qb2
5056
                        ->select('course2')
5057
                        ->from('ChamiloCoreBundle:SessionRelCourse', 'sc')
5058
                        ->join('sc.course', 'course2')
5059
                        ->innerJoin(
5060
                            'ChamiloCoreBundle:AccessUrlRelSession',
5061
                            'us',
5062
                            Join::WITH,
5063
                            'us.sessionId = sc.session'
5064
                        )->where(
5065
                            $qb->expr()->eq('us.accessUrlId ', $urlId)
5066
                        )
5067
                        ->getDQL()
5068
                )
5069
            )->andWhere(
5070
                $qb->expr()->in(
5071
                    'c',
5072
                    $qb3
5073
                        ->select('course3')
5074
                        ->from('ChamiloCoreBundle:AccessUrlRelCourse', 'uc')
5075
                        ->join('uc.course', 'course3')
5076
                        ->where(
5077
                            $qb3->expr()->eq('uc.url ', $urlId)
5078
                        )
5079
                        ->getDQL()
5080
                )
5081
            )
5082
        ->setFirstResult($first)
5083
        ->setMaxResults($maxResults);
5084
5085
        return $qb;
5086
    }
5087
5088
    /**
5089
     * Get the user status for the session.
5090
     *
5091
     * @param int     $userId  The user ID
5092
     * @param Session $session The session
5093
     *
5094
     * @return string
5095
     */
5096
    private function getUserStatusForSession(int $userId, Session $session)
5097
    {
5098
        if (empty($userId)) {
5099
            return 'NO';
5100
        }
5101
5102
        $entityManager = Database::getManager();
5103
        $scuRepo = $entityManager->getRepository('ChamiloCoreBundle:SessionRelCourseRelUser');
5104
5105
        $buySaleTable = Database::get_main_table(self::TABLE_SALE);
5106
5107
        // Check if user bought the course
5108
        $sale = Database::select(
5109
            'COUNT(1) as qty',
5110
            $buySaleTable,
5111
            [
5112
                'where' => [
5113
                    'user_id = ? AND product_type = ? AND product_id = ? AND status = ?' => [
5114
                        $userId,
5115
                        self::PRODUCT_TYPE_SESSION,
5116
                        $session->getId(),
5117
                        self::SALE_STATUS_PENDING,
5118
                    ],
5119
                ],
5120
            ],
5121
            'first'
5122
        );
5123
5124
        if ($sale['qty'] > 0) {
5125
            return 'TMP';
5126
        }
5127
5128
        // Check if user is already subscribe to session
5129
        $userSubscription = $scuRepo->findBy([
5130
            'session' => $session,
5131
            'user' => $userId,
5132
        ]);
5133
5134
        if (!empty($userSubscription)) {
5135
            return 'YES';
5136
        }
5137
5138
        return 'NO';
5139
    }
5140
5141
    /**
5142
     * Get the user status for the course.
5143
     *
5144
     * @param int    $userId The user Id
5145
     * @param Course $course The course
5146
     *
5147
     * @return string
5148
     */
5149
    private function getUserStatusForCourse(int $userId, Course $course)
5150
    {
5151
        if (empty($userId)) {
5152
            return 'NO';
5153
        }
5154
5155
        $entityManager = Database::getManager();
5156
        $cuRepo = $entityManager->getRepository('ChamiloCoreBundle:CourseRelUser');
5157
        $buySaleTable = Database::get_main_table(self::TABLE_SALE);
5158
5159
        // Check if user bought the course
5160
        $sale = Database::select(
5161
            'COUNT(1) as qty',
5162
            $buySaleTable,
5163
            [
5164
                'where' => [
5165
                    'user_id = ? AND product_type = ? AND product_id = ? AND status = ?' => [
5166
                        $userId,
5167
                        self::PRODUCT_TYPE_COURSE,
5168
                        $course->getId(),
5169
                        self::SALE_STATUS_PENDING,
5170
                    ],
5171
                ],
5172
            ],
5173
            'first'
5174
        );
5175
5176
        if ($sale['qty'] > 0) {
5177
            return 'TMP';
5178
        }
5179
5180
        // Check if user is already subscribe to course
5181
        $userSubscription = $cuRepo->findBy([
5182
            'course' => $course,
5183
            'user' => $userId,
5184
        ]);
5185
5186
        if (!empty($userSubscription)) {
5187
            return 'YES';
5188
        }
5189
5190
        return 'NO';
5191
    }
5192
5193
    /**
5194
     * Update the sale status.
5195
     *
5196
     * @param int $saleId    The sale ID
5197
     * @param int $newStatus The new status
5198
     *
5199
     * @return bool
5200
     */
5201
    private function updateSaleStatus(int $saleId, int $newStatus = self::SALE_STATUS_PENDING)
5202
    {
5203
        $saleTable = Database::get_main_table(self::TABLE_SALE);
5204
5205
        return Database::update(
5206
            $saleTable,
5207
            ['status' => (int) $newStatus],
5208
            ['id = ?' => (int) $saleId]
5209
        );
5210
    }
5211
5212
    /**
5213
     * Search filtered sessions by name, and range of price.
5214
     *
5215
     * @param string $name            Optional. The name filter
5216
     * @param int    $min             Optional. The minimum price filter
5217
     * @param int    $max             Optional. The maximum price filter
5218
     * @param string $typeResult      Optional. 'all' and 'count'
5219
     * @param int    $sessionCategory Optional. Session category id
5220
     *
5221
     * @return array
5222
     */
5223
    private function filterSessionList(
5224
        int $start,
5225
        int $end,
5226
        string $name = null,
5227
        int $min = 0,
5228
        int $max = 0,
5229
        string $typeResult = 'all',
5230
        int $sessionCategory = 0
5231
    ) {
5232
        $itemTable = Database::get_main_table(self::TABLE_ITEM);
5233
        $sessionTable = Database::get_main_table(TABLE_MAIN_SESSION);
5234
5235
        $innerJoin = "$itemTable i ON s.id = i.product_id";
5236
        $whereConditions = [
5237
            'i.product_type = ? ' => self::PRODUCT_TYPE_SESSION,
5238
        ];
5239
5240
        if (!empty($name)) {
5241
            $whereConditions['AND s.name LIKE %?%'] = $name;
5242
        }
5243
5244
        if (!empty($min)) {
5245
            $whereConditions['AND i.price >= ?'] = $min;
5246
        }
5247
5248
        if (!empty($max)) {
5249
            $whereConditions['AND i.price <= ?'] = $max;
5250
        }
5251
5252
        if ($sessionCategory != 0) {
5253
            $whereConditions['AND s.session_category_id = ?'] = $sessionCategory;
5254
        }
5255
5256
        $sessionIds = Database::select(
5257
            's.id',
5258
            "$sessionTable s INNER JOIN $innerJoin",
5259
            ['where' => $whereConditions, 'limit' => "$start, $end"],
5260
            $typeResult
5261
        );
5262
5263
        if ($typeResult === 'count') {
5264
            return $sessionIds;
5265
        }
5266
5267
        if (!$sessionIds) {
5268
            return [];
5269
        }
5270
5271
        $sessions = [];
5272
5273
        foreach ($sessionIds as $sessionId) {
5274
            $sessions[] = Database::getManager()->find(
5275
                'ChamiloCoreBundle:Session',
5276
                $sessionId
5277
            );
5278
        }
5279
5280
        return $sessions;
5281
    }
5282
5283
    /**
5284
     * Search filtered courses by name, and range of price.
5285
     *
5286
     * @param string $name Optional. The name filter
5287
     * @param int    $min  Optional. The minimun price filter
5288
     * @param int    $max  Optional. The maximum price filter
5289
     *
5290
     * @return array
5291
     */
5292
    private function filterCourseList(
5293
        int $start,
5294
        int $end,
5295
        string $name = null,
5296
        int $min = 0,
5297
        int $max = 0,
5298
        string $typeResult = 'all'
5299
    ) {
5300
        $itemTable = Database::get_main_table(self::TABLE_ITEM);
5301
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
5302
        $urlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
5303
5304
        $urlId = api_get_current_access_url_id();
5305
5306
        $min = floatval($min);
5307
        $max = floatval($max);
5308
5309
        $whereConditions = [
5310
            'i.product_type = ? ' => self::PRODUCT_TYPE_COURSE,
5311
        ];
5312
5313
        if (!empty($name)) {
5314
            $whereConditions['AND c.title LIKE %?%'] = $name;
5315
        }
5316
5317
        if (!empty($min)) {
5318
            $whereConditions['AND i.price >= ?'] = $min;
5319
        }
5320
5321
        if (!empty($max)) {
5322
            $whereConditions['AND i.price <= ?'] = $max;
5323
        }
5324
5325
        $whereConditions['AND url.access_url_id = ?'] = $urlId;
5326
5327
        $courseIds = Database::select(
5328
            'c.id',
5329
            "$courseTable c
5330
            INNER JOIN $itemTable i
5331
            ON c.id = i.product_id
5332
            INNER JOIN $urlTable url
5333
            ON c.id = url.c_id
5334
            ",
5335
            ['where' => $whereConditions, 'limit' => "$start, $end"],
5336
            $typeResult
5337
        );
5338
5339
        if ($typeResult === 'count') {
5340
            return $courseIds;
5341
        }
5342
5343
        if (!$courseIds) {
5344
            return [];
5345
        }
5346
5347
        $courses = [];
5348
        foreach ($courseIds as $courseId) {
5349
            $courses[] = Database::getManager()->find(
5350
                'ChamiloCoreBundle:Course',
5351
                $courseId
5352
            );
5353
        }
5354
5355
        return $courses;
5356
    }
5357
5358
    /**
5359
     * Search filtered sessions by name, and range of price.
5360
     *
5361
     * @param string $name            Optional. The name filter
5362
     * @param int    $sessionCategory Optional. Session category id
5363
     *
5364
     * @return array
5365
     */
5366
    private function filterSubscriptionSessionList(
5367
        int $start,
5368
        int $end,
5369
        string $name = null,
5370
        string $typeResult = 'all',
5371
        int $sessionCategory = 0
5372
    ) {
5373
        $subscriptionTable = Database::get_main_table(self::TABLE_SUBSCRIPTION);
5374
        $sessionTable = Database::get_main_table(TABLE_MAIN_SESSION);
5375
5376
        $innerJoin = "$subscriptionTable st ON s.id = st.product_id";
5377
        $whereConditions = [
5378
            'st.product_type = ? ' => self::PRODUCT_TYPE_SESSION,
5379
        ];
5380
5381
        if (!empty($name)) {
5382
            $whereConditions['AND s.name LIKE %?%'] = $name;
5383
        }
5384
5385
        if ($sessionCategory != 0) {
5386
            $whereConditions['AND s.session_category_id = ?'] = $sessionCategory;
5387
        }
5388
5389
        $sessionIds = Database::select(
5390
            'DISTINCT s.id',
5391
            "$sessionTable s INNER JOIN $innerJoin",
5392
            ['where' => $whereConditions, 'limit' => "$start, $end"],
5393
            $typeResult
5394
        );
5395
5396
        if ($typeResult === 'count') {
5397
            return $sessionIds;
5398
        }
5399
5400
        if (!$sessionIds) {
5401
            return [];
5402
        }
5403
5404
        $sessions = [];
5405
5406
        foreach ($sessionIds as $sessionId) {
5407
            $sessions[] = Database::getManager()->find(
5408
                'ChamiloCoreBundle:Session',
5409
                $sessionId
5410
            );
5411
        }
5412
5413
        return $sessions;
5414
    }
5415
5416
    /**
5417
     * Search filtered subscriptions courses by name, and range of price.
5418
     *
5419
     * @param string $name Optional. The name filter
5420
     *
5421
     * @return array
5422
     */
5423
    private function filterSubscriptionCourseList(
5424
        int $start,
5425
        int $end,
5426
        string $name = '',
5427
        string $typeResult = 'all'
5428
    ) {
5429
        $subscriptionTable = Database::get_main_table(self::TABLE_SUBSCRIPTION);
5430
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
5431
        $urlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
5432
5433
        $urlId = api_get_current_access_url_id();
5434
5435
        $whereConditions = [
5436
            'st.product_type = ? ' => self::PRODUCT_TYPE_COURSE,
5437
        ];
5438
5439
        if (!empty($name)) {
5440
            $whereConditions['AND c.title LIKE %?%'] = $name;
5441
        }
5442
5443
        $whereConditions['AND url.access_url_id = ?'] = $urlId;
5444
5445
        $courseIds = Database::select(
5446
            'DISTINCT c.id',
5447
            "$courseTable c
5448
            INNER JOIN $subscriptionTable st
5449
            ON c.id = st.product_id
5450
            INNER JOIN $urlTable url
5451
            ON c.id = url.c_id
5452
            ",
5453
            ['where' => $whereConditions, 'limit' => "$start, $end"],
5454
            $typeResult
5455
        );
5456
5457
        if ($typeResult === 'count') {
5458
            return $courseIds;
5459
        }
5460
5461
        if (!$courseIds) {
5462
            return [];
5463
        }
5464
5465
        $courses = [];
5466
        foreach ($courseIds as $courseId) {
5467
            $courses[] = Database::getManager()->find(
5468
                'ChamiloCoreBundle:Course',
5469
                $courseId
5470
            );
5471
        }
5472
5473
        return $courses;
5474
    }
5475
5476
    /**
5477
     * Update the service sale status.
5478
     *
5479
     * @param int $serviceSaleId The service sale ID
5480
     * @param int $newStatus     The new status
5481
     *
5482
     * @return bool
5483
     */
5484
    private function updateServiceSaleStatus(
5485
        int $serviceSaleId,
5486
        int $newStatus = self::SERVICE_STATUS_PENDING
5487
    ) {
5488
        $serviceSaleTable = Database::get_main_table(self::TABLE_SERVICES_SALE);
5489
5490
        return Database::update(
5491
            $serviceSaleTable,
5492
            ['status' => $newStatus],
5493
            ['id = ?' => $serviceSaleId]
5494
        );
5495
    }
5496
5497
    /**
5498
     * Get the items (courses or sessions) of a coupon.
5499
     *
5500
     * @return array The item data
5501
     */
5502
    private function getItemsCoupons(int $couponId, int $productType)
5503
    {
5504
        $couponItemTable = Database::get_main_table(self::TABLE_COUPON_ITEM);
5505
5506
        if ($productType == self::PRODUCT_TYPE_COURSE) {
5507
            $itemTable = Database::get_main_table(TABLE_MAIN_COURSE);
5508
            $select = ['ci.product_id as id', 'it.title'];
5509
        } elseif ($productType == self::PRODUCT_TYPE_SESSION) {
5510
            $itemTable = Database::get_main_table(TABLE_MAIN_SESSION);
5511
            $select = ['ci.product_id as id', 'it.name'];
5512
        }
5513
5514
        $couponFrom = "
5515
            $couponItemTable ci
5516
            INNER JOIN $itemTable it
5517
                on it.id = ci.product_id and ci.product_type = $productType
5518
        ";
5519
5520
        return Database::select(
5521
            $select,
5522
            $couponFrom,
5523
            [
5524
                'where' => [
5525
                    'ci.coupon_id = ? ' => $couponId,
5526
                ],
5527
            ]
5528
        );
5529
    }
5530
5531
    /**
5532
     * Get the services of a coupon.
5533
     *
5534
     * @param int $couponId The coupon ID
5535
     *
5536
     * @return array The service data
5537
     */
5538
    private function getServicesCoupons(int $couponId)
5539
    {
5540
        $couponServiceTable = Database::get_main_table(self::TABLE_COUPON_SERVICE);
5541
        $serviceTable = Database::get_main_table(self::TABLE_SERVICES);
5542
5543
        $couponFrom = "
5544
            $couponServiceTable cs
5545
            INNER JOIN $serviceTable s
5546
                on s.id = cs.service_id
5547
        ";
5548
5549
        return Database::select(
5550
            ['cs.service_id as id', 's.name'],
5551
            $couponFrom,
5552
            [
5553
                'where' => [
5554
                    'cs.coupon_id = ? ' => $couponId,
5555
                ],
5556
            ]
5557
        );
5558
    }
5559
5560
    /**
5561
     * Get an array of coupons filtered by their status.
5562
     *
5563
     * @param int $status The coupon activation status
5564
     *
5565
     * @return array Coupons data
5566
     */
5567
    private function getDataCoupons(int $status = null)
5568
    {
5569
        $couponTable = Database::get_main_table(self::TABLE_COUPON);
5570
5571
        if ($status != null) {
5572
            return Database::select(
5573
                ['*'],
5574
                $couponTable,
5575
                [
5576
                    'where' => [
5577
                        ' active = ? ' => (int) $status,
5578
                    ],
5579
                    'order' => 'id DESC',
5580
                ]
5581
            );
5582
        } else {
5583
            return Database::select(
5584
                ['*'],
5585
                $couponTable,
5586
                [
5587
                    'order' => 'id DESC',
5588
                ]
5589
            );
5590
        }
5591
    }
5592
5593
    /**
5594
     * Get data of a coupon for a product (course or service) by the coupon ID.
5595
     *
5596
     * @param int $couponId    The coupon code code
5597
     * @param int $productType The product type
5598
     * @param int $productId   The product ID
5599
     *
5600
     * @return array The coupon data
5601
     */
5602
    private function getDataCoupon(int $couponId, int $productType = null, int $productId = null)
5603
    {
5604
        $couponTable = Database::get_main_table(self::TABLE_COUPON);
5605
5606
        if ($productType == null || $productId == null) {
5607
            return Database::select(
5608
                ['*'],
5609
                $couponTable,
5610
                [
5611
                    'where' => [
5612
                        'id = ? ' => $couponId,
5613
                    ],
5614
                ],
5615
                'first'
5616
            );
5617
        } else {
5618
            $couponItemTable = Database::get_main_table(self::TABLE_COUPON_ITEM);
5619
            $dtmNow = api_get_utc_datetime();
5620
5621
            $couponFrom = "
5622
                $couponTable c
5623
                INNER JOIN $couponItemTable ci
5624
                    on ci.coupon_id = c.id
5625
            ";
5626
5627
            return Database::select(
5628
                ['c.*'],
5629
                $couponFrom,
5630
                [
5631
                    'where' => [
5632
                        'c.id = ? AND ' => $couponId,
5633
                        'c.valid_start <= ? AND ' => $dtmNow,
5634
                        'c.valid_end >= ? AND ' => $dtmNow,
5635
                        'ci.product_type = ? AND ' => $productType,
5636
                        'ci.product_id = ?' => $productId,
5637
                    ],
5638
                ],
5639
                'first'
5640
            );
5641
        }
5642
    }
5643
5644
    /**
5645
     * Get data of a coupon for a product (course or service) by the coupon code.
5646
     *
5647
     * @param string $couponCode  The coupon code code
5648
     * @param int    $productType The product type
5649
     * @param int    $productId   The product ID
5650
     *
5651
     * @return array The coupon data
5652
     */
5653
    private function getDataCouponByCode(string $couponCode, int $productType = null, int $productId = null)
5654
    {
5655
        $couponTable = Database::get_main_table(self::TABLE_COUPON);
5656
        $couponItemTable = Database::get_main_table(self::TABLE_COUPON_ITEM);
5657
        $dtmNow = api_get_utc_datetime();
5658
5659
        if ($productType == null || $productId == null) {
5660
            return Database::select(
5661
                ['*'],
5662
                $couponTable,
5663
                [
5664
                    'where' => [
5665
                        'code = ? ' => $couponCode,
5666
                    ],
5667
                ],
5668
                'first'
5669
            );
5670
        } else {
5671
            $couponFrom = "
5672
                $couponTable c
5673
                INNER JOIN $couponItemTable ci
5674
                    on ci.coupon_id = c.id
5675
            ";
5676
5677
            return Database::select(
5678
                ['c.*'],
5679
                $couponFrom,
5680
                [
5681
                    'where' => [
5682
                        'c.code = ? AND ' => $couponCode,
5683
                        'c.valid_start <= ? AND ' => $dtmNow,
5684
                        'c.valid_end >= ? AND ' => $dtmNow,
5685
                        'ci.product_type = ? AND ' => $productType,
5686
                        'ci.product_id = ?' => $productId,
5687
                    ],
5688
                ],
5689
                'first'
5690
            );
5691
        }
5692
    }
5693
5694
    /**
5695
     * Get data of a coupon for a service by the coupon ID.
5696
     *
5697
     * @param int $couponId  The coupon ID
5698
     * @param int $serviceId The service ID
5699
     *
5700
     * @return array The coupon data
5701
     */
5702
    private function getDataCouponService(int $couponId, int $serviceId)
5703
    {
5704
        $couponTable = Database::get_main_table(self::TABLE_COUPON);
5705
        $couponServiceTable = Database::get_main_table(self::TABLE_COUPON_SERVICE);
5706
        $dtmNow = api_get_utc_datetime();
5707
5708
        $couponFrom = "
5709
            $couponTable c
5710
            INNER JOIN $couponServiceTable cs
5711
                on cs.coupon_id = c.id
5712
        ";
5713
5714
        return Database::select(
5715
            ['c.*'],
5716
            $couponFrom,
5717
            [
5718
                'where' => [
5719
                    'c.id = ? AND ' => $couponId,
5720
                    'c.valid_start <= ? AND ' => $dtmNow,
5721
                    'c.valid_end >= ? AND ' => $dtmNow,
5722
                    'cs.service_id = ?' => $serviceId,
5723
                ],
5724
            ],
5725
            'first'
5726
        );
5727
    }
5728
5729
    /**
5730
     * Get data of coupon for a service by the coupon code.
5731
     *
5732
     * @param string $couponCode The coupon code
5733
     * @param int    $serviceId  The service ID
5734
     *
5735
     * @return array The coupon data
5736
     */
5737
    private function getDataCouponServiceByCode(string $couponCode, int $serviceId)
5738
    {
5739
        $couponTable = Database::get_main_table(self::TABLE_COUPON);
5740
        $couponServiceTable = Database::get_main_table(self::TABLE_COUPON_SERVICE);
5741
        $dtmNow = api_get_utc_datetime();
5742
5743
        $couponFrom = "
5744
            $couponTable c
5745
            INNER JOIN $couponServiceTable cs
5746
                on cs.coupon_id = c.id
5747
        ";
5748
5749
        return Database::select(
5750
            ['c.*'],
5751
            $couponFrom,
5752
            [
5753
                'where' => [
5754
                    'c.code = ? AND ' => $couponCode,
5755
                    'c.valid_start <= ? AND ' => $dtmNow,
5756
                    'c.valid_end >= ? AND ' => $dtmNow,
5757
                    'cs.service_id = ?' => $serviceId,
5758
                ],
5759
            ],
5760
            'first'
5761
        );
5762
    }
5763
5764
    /**
5765
     * Update a coupon.
5766
     *
5767
     * @return int
5768
     */
5769
    private function updateCoupon(array $coupon)
5770
    {
5771
        $couponExist = $this->getCouponByCode($coupon['code']);
5772
        if (!$couponExist) {
5773
            Display::addFlash(
5774
                Display::return_message(
5775
                    $this->get_lang('CouponNoExists'),
5776
                    'error',
5777
                    false
5778
                )
5779
            );
5780
5781
            return false;
5782
        }
5783
5784
        $values = [
5785
            'valid_start' => $coupon['valid_start'],
5786
            'valid_end' => $coupon['valid_end'],
5787
            'active' => $coupon['active'],
5788
        ];
5789
5790
        return Database::update(
5791
            self::TABLE_COUPON,
5792
            $values,
5793
            ['id = ?' => $coupon['id']]
5794
        );
5795
    }
5796
5797
    /**
5798
     * Register a coupon.
5799
     *
5800
     * @return int
5801
     */
5802
    private function registerCoupon(array $coupon)
5803
    {
5804
        $couponExist = $this->getCouponByCode($coupon['code']);
5805
        if ($couponExist) {
5806
            Display::addFlash(
5807
                Display::return_message(
5808
                    $this->get_lang('CouponCodeUsed'),
5809
                    'error',
5810
                    false
5811
                )
5812
            );
5813
5814
            return false;
5815
        }
5816
5817
        $values = [
5818
            'code' => (string) $coupon['code'],
5819
            'discount_type' => (int) $coupon['discount_type'],
5820
            'discount_amount' => $coupon['discount_amount'],
5821
            'valid_start' => $coupon['valid_start'],
5822
            'valid_end' => $coupon['valid_end'],
5823
            'delivered' => 0,
5824
            'active' => $coupon['active'],
5825
        ];
5826
5827
        return Database::insert(self::TABLE_COUPON, $values);
5828
    }
5829
5830
    /**
5831
     * Register a coupon item.
5832
     *
5833
     * @param int $couponId    The coupon ID
5834
     * @param int $productType The product type
5835
     * @param int $productId   The product ID
5836
     *
5837
     * @return int
5838
     */
5839
    private function registerCouponItem(int $couponId, int $productType, int $productId)
5840
    {
5841
        $coupon = $this->getDataCoupon($couponId);
5842
        if (empty($coupon)) {
5843
            Display::addFlash(
5844
                Display::return_message(
5845
                    $this->get_lang('CouponNoExists'),
5846
                    'error',
5847
                    false
5848
                )
5849
            );
5850
5851
            return false;
5852
        }
5853
5854
        $values = [
5855
            'coupon_id' => $couponId,
5856
            'product_type' => $productType,
5857
            'product_id' => $productId,
5858
        ];
5859
5860
        return Database::insert(self::TABLE_COUPON_ITEM, $values);
5861
    }
5862
5863
    /**
5864
     * Remove all coupon items for a product type and coupon ID.
5865
     *
5866
     * @param int $productType The product type
5867
     * @param int $couponId    The coupon ID
5868
     *
5869
     * @return int Rows affected. Otherwise return false
5870
     */
5871
    private function deleteCouponItemsByCoupon(int $productType, int $couponId)
5872
    {
5873
        return Database::delete(
5874
            Database::get_main_table(self::TABLE_COUPON_ITEM),
5875
            [
5876
                'product_type = ? AND ' => $productType,
5877
                'coupon_id = ?' => $couponId,
5878
            ]
5879
        );
5880
    }
5881
5882
    /**
5883
     * Register a coupon service.
5884
     *
5885
     * @param int $couponId  The coupon ID
5886
     * @param int $serviceId The service ID
5887
     *
5888
     * @return int
5889
     */
5890
    private function registerCouponService(int $couponId, int $serviceId)
5891
    {
5892
        $coupon = $this->getDataCoupon($couponId);
5893
        if (empty($coupon)) {
5894
            Display::addFlash(
5895
                Display::return_message(
5896
                    $this->get_lang('CouponNoExists'),
5897
                    'error',
5898
                    false
5899
                )
5900
            );
5901
5902
            return false;
5903
        }
5904
5905
        $values = [
5906
            'coupon_id' => $couponId,
5907
            'service_id' => $serviceId,
5908
        ];
5909
5910
        return Database::insert(self::TABLE_COUPON_SERVICE, $values);
5911
    }
5912
5913
    /**
5914
     * Remove all coupon services for a product type and coupon ID.
5915
     *
5916
     * @return int Rows affected. Otherwise, return false
5917
     */
5918
    private function deleteCouponServicesByCoupon(int $couponId)
5919
    {
5920
        return Database::delete(
5921
            Database::get_main_table(self::TABLE_COUPON_SERVICE),
5922
            [
5923
                'coupon_id = ?' => (int) $couponId,
5924
            ]
5925
        );
5926
    }
5927
5928
    /**
5929
     * Get an array of subscriptions.
5930
     *
5931
     * @return array Subscriptions data
5932
     */
5933
    private function getDataSubscriptions(int $productType, int $productId)
5934
    {
5935
        $subscriptionTable = Database::get_main_table(self::TABLE_SUBSCRIPTION);
5936
5937
        return Database::select(
5938
            ['*'],
5939
            $subscriptionTable,
5940
            [
5941
                'where' => [
5942
                    'product_type = ? AND ' => (int) $productType,
5943
                    'product_id = ?  ' => (int) $productId,
5944
                ],
5945
                'order' => 'duration ASC',
5946
            ]
5947
        );
5948
    }
5949
5950
    /**
5951
     * Get data of a subscription for a product (course or service) by the subscription ID.
5952
     *
5953
     * @param int $productType The product type
5954
     * @param int $productId   The product ID
5955
     * @param int $duration    The duration (in seconds)
5956
     *
5957
     * @return array The subscription data
5958
     */
5959
    private function getDataSubscription(int $productType, int $productId, int $duration)
5960
    {
5961
        $subscriptionTable = Database::get_main_table(self::TABLE_SUBSCRIPTION);
5962
5963
        return Database::select(
5964
            ['*'],
5965
            $subscriptionTable,
5966
            [
5967
                'where' => [
5968
                    'product_type = ? AND ' => $productType,
5969
                    'product_id = ? AND ' => $productId,
5970
                    'duration = ? ' => $duration,
5971
                ],
5972
            ],
5973
            'first'
5974
        );
5975
    }
5976
5977
    /**
5978
     * Update a subscription.
5979
     *
5980
     * @return int
5981
     */
5982
    private function updateSubscription(int $productType, int $productId, int $taxPerc)
5983
    {
5984
        $values = [
5985
            'tax_perc' => $taxPerc,
5986
        ];
5987
5988
        return Database::update(
5989
            self::TABLE_SUBSCRIPTION,
5990
            $values,
5991
            [
5992
                'product_type = ? AND ' => $productType,
5993
                'product_id = ?' => $productId,
5994
            ]
5995
        );
5996
5997
        return true;
0 ignored issues
show
Unused Code introduced by
return true is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
5998
    }
5999
6000
    /**
6001
     * Register a subscription.
6002
     *
6003
     * @return int
6004
     */
6005
    private function registerSubscription(array $subscription, array $frequency)
6006
    {
6007
        $values = [
6008
            'product_type' => (int) $subscription['product_type'],
6009
            'product_id' => (int) $subscription['product_id'],
6010
            'duration' => (int) $frequency['duration'],
6011
            'currency_id' => (int) $subscription['currency_id'],
6012
            'tax_perc' => (int) $subscription['tax_perc'],
6013
            'price' => (float) $frequency['price'],
6014
        ];
6015
6016
        Database::insert(self::TABLE_SUBSCRIPTION, $values);
6017
6018
        return true;
6019
    }
6020
6021
    /**
6022
     * Update the subscription sale status.
6023
     *
6024
     * @param int $saleId    The sale ID
6025
     * @param int $newStatus The new status
6026
     *
6027
     * @return bool
6028
     */
6029
    private function updateSubscriptionSaleStatus(int $saleId, int $newStatus = self::SALE_STATUS_PENDING)
6030
    {
6031
        $saleTable = Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE);
6032
6033
        return Database::update(
6034
            $saleTable,
6035
            ['status' => $newStatus],
6036
            ['id = ?' => $saleId]
6037
        );
6038
    }
6039
6040
    /**
6041
     * Get the user status for the subscription session.
6042
     *
6043
     * @param int     $userId  The user ID
6044
     * @param Session $session The session
6045
     *
6046
     * @return string
6047
     */
6048
    private function getUserStatusForSubscriptionSession(int $userId, Session $session)
6049
    {
6050
        if (empty($userId)) {
6051
            return 'NO';
6052
        }
6053
6054
        $entityManager = Database::getManager();
6055
        $scuRepo = $entityManager->getRepository('ChamiloCoreBundle:SessionRelCourseRelUser');
6056
6057
        $buySaleTable = Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE);
6058
6059
        // Check if user bought the course
6060
        $sale = Database::select(
6061
            'COUNT(1) as qty',
6062
            $buySaleTable,
6063
            [
6064
                'where' => [
6065
                    'user_id = ? AND product_type = ? AND product_id = ? AND status = ? AND (expired is NULL OR expired <> ?)' => [
6066
                        $userId,
6067
                        self::PRODUCT_TYPE_SESSION,
6068
                        $session->getId(),
6069
                        self::SALE_STATUS_PENDING,
6070
                        1,
6071
                    ],
6072
                ],
6073
            ],
6074
            'first'
6075
        );
6076
6077
        if ($sale['qty'] > 0) {
6078
            return 'TMP';
6079
        }
6080
6081
        // Check if user is already subscribe to session
6082
        $userSubscription = $scuRepo->findBy([
6083
            'session' => $session,
6084
            'user' => $userId,
6085
        ]);
6086
6087
        if (!empty($userSubscription)) {
6088
            return 'YES';
6089
        }
6090
6091
        return 'NO';
6092
    }
6093
6094
    /**
6095
     * Get the user status for the subscription course.
6096
     *
6097
     * @param int    $userId The user Id
6098
     * @param Course $course The course
6099
     *
6100
     * @return string
6101
     */
6102
    private function getUserStatusForSubscriptionCourse(int $userId, Course $course)
6103
    {
6104
        if (empty($userId)) {
6105
            return 'NO';
6106
        }
6107
6108
        $entityManager = Database::getManager();
6109
        $cuRepo = $entityManager->getRepository('ChamiloCoreBundle:CourseRelUser');
6110
        $buySaleTable = Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE);
6111
6112
        // Check if user bought the course
6113
        $sale = Database::select(
6114
            'COUNT(1) as qty',
6115
            $buySaleTable,
6116
            [
6117
                'where' => [
6118
                    'user_id = ? AND product_type = ? AND product_id = ? AND status = ? AND (expired is NULL OR expired <> ?)' => [
6119
                        $userId,
6120
                        self::PRODUCT_TYPE_COURSE,
6121
                        $course->getId(),
6122
                        self::SALE_STATUS_PENDING,
6123
                        1,
6124
                    ],
6125
                ],
6126
            ],
6127
            'first'
6128
        );
6129
6130
        if ($sale['qty'] > 0) {
6131
            return 'TMP';
6132
        }
6133
6134
        // Check if user is already subscribe to course
6135
        $userSubscription = $cuRepo->findBy([
6136
            'course' => $course,
6137
            'user' => $userId,
6138
        ]);
6139
6140
        if (!empty($userSubscription)) {
6141
            return 'YES';
6142
        }
6143
6144
        return 'NO';
6145
    }
6146
}
6147