diff --git a/main/inc/lib/CoursesAndSessionsCatalog.class.php b/main/inc/lib/CoursesAndSessionsCatalog.class.php index c548a61757..b9c489b42a 100644 --- a/main/inc/lib/CoursesAndSessionsCatalog.class.php +++ b/main/inc/lib/CoursesAndSessionsCatalog.class.php @@ -477,7 +477,7 @@ class CoursesAndSessionsCatalog { $em = Database::getManager(); $urlId = api_get_current_access_url_id(); - $date = Database::escape_string($date); + $sql = "SELECT s.id FROM session s "; $sql .= " INNER JOIN access_url_rel_session ars @@ -490,6 +490,7 @@ class CoursesAndSessionsCatalog "; if (!is_null($date)) { + $date = Database::escape_string($date); $sql .= " AND ( ('$date' BETWEEN DATE(s.access_start_date) AND DATE(s.access_end_date)) diff --git a/plugin/buycourses/CHANGELOG.md b/plugin/buycourses/CHANGELOG.md index 865d81d154..ab30cadbc4 100644 --- a/plugin/buycourses/CHANGELOG.md +++ b/plugin/buycourses/CHANGELOG.md @@ -1,3 +1,13 @@ +v5.0 - 2019-02-06 +==== + +This version includes two additional modules (taxes and invoices), +which can be enabled from the configuration. + +The file update.php must be executed to update the structure of the tables + in the database. + + v4.0 - 2017-04-25 ==== diff --git a/plugin/buycourses/database.php b/plugin/buycourses/database.php index fa270bda1b..7e8442101b 100644 --- a/plugin/buycourses/database.php +++ b/plugin/buycourses/database.php @@ -90,6 +90,11 @@ $itemTable->addColumn( \Doctrine\DBAL\Types\Type::INTEGER, ['unsigned' => true] ); +$itemTable->addColumn( + 'tax_perc', + \Doctrine\DBAL\Types\Type::INTEGER, + ['unsigned' => true, 'notnull' => false] +); $itemTable->setPrimaryKey(['id']); $itemTable->addForeignKeyConstraint( $currencyTable, @@ -195,6 +200,21 @@ $saleTable->addColumn( \Doctrine\DBAL\Types\Type::DECIMAL, ['scale' => 2] ); +$saleTable->addColumn( + 'price_without_tax', + \Doctrine\DBAL\Types\Type::DECIMAL, + ['scale' => 2, 'notnull' => false] +); +$saleTable->addColumn( + 'tax_perc', + \Doctrine\DBAL\Types\Type::INTEGER, + ['unsigned' => true, 'notnull' => false] +); +$saleTable->addColumn( + 'tax_amount', + \Doctrine\DBAL\Types\Type::DECIMAL, + ['scale' => 2, 'notnull' => false] +); $saleTable->addColumn( 'currency_id', \Doctrine\DBAL\Types\Type::INTEGER, @@ -202,6 +222,7 @@ $saleTable->addColumn( ); $saleTable->addColumn('status', \Doctrine\DBAL\Types\Type::INTEGER); $saleTable->addColumn('payment_type', \Doctrine\DBAL\Types\Type::INTEGER); +$saleTable->addColumn('invoice', \Doctrine\DBAL\Types\Type::INTEGER); $saleTable->setPrimaryKey(['id']); $saleTable->addForeignKeyConstraint( $currencyTable, @@ -250,6 +271,21 @@ $servicesNodeTable->addColumn( \Doctrine\DBAL\Types\Type::DECIMAL, ['scale' => 2] ); +$servicesNodeTable->addColumn( + 'price_without_tax', + \Doctrine\DBAL\Types\Type::DECIMAL, + ['scale' => 2, 'notnull' => false] +); +$servicesNodeTable->addColumn( + 'tax_perc', + \Doctrine\DBAL\Types\Type::INTEGER, + ['unsigned' => true, 'notnull' => false] +); +$servicesNodeTable->addColumn( + 'tax_amount', + \Doctrine\DBAL\Types\Type::DECIMAL, + ['scale' => 2, 'notnull' => false] +); $servicesNodeTable->addColumn('node_type', \Doctrine\DBAL\Types\Type::INTEGER); $servicesNodeTable->addColumn('node_id', \Doctrine\DBAL\Types\Type::INTEGER); $servicesNodeTable->addColumn('buyer_id', \Doctrine\DBAL\Types\Type::INTEGER); @@ -265,6 +301,7 @@ $servicesNodeTable->addColumn( ); $servicesNodeTable->addColumn('status', \Doctrine\DBAL\Types\Type::INTEGER); $servicesNodeTable->addColumn('payment_type', \Doctrine\DBAL\Types\Type::INTEGER); +$servicesNodeTable->addColumn('invoice', \Doctrine\DBAL\Types\Type::INTEGER); $servicesNodeTable->setPrimaryKey(['id']); $servicesNodeTable->addForeignKeyConstraint( $servicesTable, @@ -291,8 +328,39 @@ $globalTable->addColumn( ['autoincrement' => true, 'unsigned' => true] ); $globalTable->addColumn('terms_and_conditions', \Doctrine\DBAL\Types\Type::TEXT); +$globalTable->addColumn('global_tax_perc', \Doctrine\DBAL\Types\Type::INTEGER); +$globalTable->addColumn('tax_applies_to', \Doctrine\DBAL\Types\Type::INTEGER); +$globalTable->addColumn('tax_name', \Doctrine\DBAL\Types\Type::STRING); +$globalTable->addColumn('seller_name', \Doctrine\DBAL\Types\Type::STRING); +$globalTable->addColumn('seller_id', \Doctrine\DBAL\Types\Type::STRING); +$globalTable->addColumn('seller_address', \Doctrine\DBAL\Types\Type::STRING); +$globalTable->addColumn('seller_email', \Doctrine\DBAL\Types\Type::STRING); +$globalTable->addColumn('next_number_invoice', \Doctrine\DBAL\Types\Type::INTEGER); +$globalTable->addColumn('invoice_series', \Doctrine\DBAL\Types\Type::STRING); $globalTable->setPrimaryKey(['id']); +$invoiceTable = $pluginSchema->createTable(BuyCoursesPlugin::TABLE_INVOICE); +$invoiceTable->addColumn( + 'id', + \Doctrine\DBAL\Types\Type::INTEGER, + ['autoincrement' => true, 'unsigned' => true] +); +$invoiceTable->addColumn('sale_id', \Doctrine\DBAL\Types\Type::INTEGER); +$invoiceTable->addColumn('is_service', \Doctrine\DBAL\Types\Type::INTEGER); +$invoiceTable->addColumn( + 'num_invoice', + \Doctrine\DBAL\Types\Type::INTEGER, + ['unsigned' => true, 'notnull' => false] +); +$invoiceTable->addColumn( + 'year', + \Doctrine\DBAL\Types\Type::INTEGER, + ['unsigned' => true, 'notnull' => false] +); +$invoiceTable->addColumn('serie', \Doctrine\DBAL\Types\Type::STRING); +$invoiceTable->addColumn('date_invoice', \Doctrine\DBAL\Types\Type::DATETIME); +$invoiceTable->setPrimaryKey(['id']); + $queries = $pluginSchema->toSql($platform); foreach ($queries as $query) { @@ -631,3 +699,21 @@ foreach ($currencies as $currency) { ] ); } + +$fieldlabel = 'buycourses_company'; +$fieldtype = '1'; +$fieldtitle = BuyCoursesPlugin::get_lang('Company'); +$fielddefault = ''; +$field_id = UserManager::create_extra_field($fieldlabel, $fieldtype, $fieldtitle, $fielddefault); + +$fieldlabel = 'buycourses_vat'; +$fieldtype = '1'; +$fieldtitle = BuyCoursesPlugin::get_lang('VAT'); +$fielddefault = ''; +$field_id = UserManager::create_extra_field($fieldlabel, $fieldtype, $fieldtitle, $fielddefault); + +$fieldlabel = 'buycourses_address'; +$fieldtype = '1'; +$fieldtitle = BuyCoursesPlugin::get_lang('Address'); +$fielddefault = ''; +$field_id = UserManager::create_extra_field($fieldlabel, $fieldtype, $fieldtitle, $fielddefault); diff --git a/plugin/buycourses/lang/english.php b/plugin/buycourses/lang/english.php index 1a5ca76432..eca6ea392c 100644 --- a/plugin/buycourses/lang/english.php +++ b/plugin/buycourses/lang/english.php @@ -9,6 +9,8 @@ $strings['paypal_enable'] = "Enable PayPal"; $strings['commissions_enable'] = "Enable Commissions"; $strings['transfer_enable'] = "Enable bank transfer"; $strings['unregistered_users_enable'] = "Allow anonymous users"; +$strings['invoicing_enable'] = "Enable Invoicing"; +$strings['tax_enable'] = "Enable Taxation"; $strings['Free'] = "FREE"; $strings['PaypalPayoutCommissions'] = "Paypal Payout Commissions"; $strings['MyPayouts'] = "My payments"; @@ -160,3 +162,24 @@ $strings['BoughtBy'] = "BoughtBy"; $strings['PurchaserUser'] = "Purchaser user"; $strings['Pending'] = "Pending"; $strings['Names'] = "Names"; +$strings['SellerName'] = "Seller name"; +$strings['SellerId'] = "Seller id"; +$strings['SellerAddress'] = "Seller address"; +$strings['SellerEmail'] = "Seller e-mail"; +$strings['NextNumberInvoice'] = "Next invoice number"; +$strings['NextNumberInvoiceDescription'] = "Number of the following invoice"; +$strings['InvoiceSeries'] = "Invoice series"; +$strings['InvoiceSeriesDescription'] = "Optional parameter: Example invoice Id <series><year>/<number>"; +$strings['InvoiceView'] = "View invoice"; +$strings['NoInvoiceEnable'] = "No invoicing block enable"; +$strings['Company'] = "Company"; +$strings['VAT'] = "VAT"; +$strings['Address'] = "Address"; +$strings['InvoiceNumber'] = "Invoice number"; +$strings['InvoiceDate'] = "Invoice date"; +$strings['Invoice'] = "Invoice"; +$strings['SaleEmail'] = "Sales e-mail"; +$strings['PurchaseDetailsIntro'] = "Purchase details"; +$strings['PurchaseDetailsEnd'] = "Regards"; +$strings['ProductName'] = "Product name"; +$strings['BankAccountIntro'] = "Bank Account Info"; diff --git a/plugin/buycourses/lang/spanish.php b/plugin/buycourses/lang/spanish.php index 35b11882ce..50dcd64890 100644 --- a/plugin/buycourses/lang/spanish.php +++ b/plugin/buycourses/lang/spanish.php @@ -9,8 +9,9 @@ $strings['paypal_enable'] = "Habilitar PayPal"; $strings['commissions_enable'] = "Habilitar Comisiones"; $strings['transfer_enable'] = "Habilitar transferencia"; $strings['unregistered_users_enable'] = "Permitir usuarios sin registro en la plataforma"; +$strings['invoicing_enable'] = "Habilitar Facturación"; +$strings['tax_enable'] = "Habilitar Impuestos"; $strings['Free'] = "GRATIS"; - $strings['PaypalPayoutCommissions'] = "Pagar comisiones por Paypal"; $strings['MyPayouts'] = "Mis Pagos"; $strings['Commission'] = "Comisión"; @@ -40,7 +41,7 @@ $strings['Buyer'] = "Comprador"; $strings['BankTransfer'] = "Transferencia Bancaria"; $strings['SaleInfo'] = "Información de la venta"; $strings['SaleStatusPending'] = "Venta pendiente"; -$strings['SaleStatusCancelled'] = "Venta cancelada"; +$strings['SaleStatusCanceled'] = "Venta cancelada"; $strings['SaleStatusCompleted'] = "Venta completada"; $strings['PayoutStatusPending'] = "Pago pendiente"; $strings['PayoutStatusCanceled'] = "Pago cancelado"; @@ -173,3 +174,37 @@ $strings['DeleteThisService'] = 'Eliminar este servicio'; $strings['YourCoursesNeedAtLeastOneLearningPath'] = 'Los cursos en los que estás registrado necesitan tener al menos una lección que contenga un item de cerficado final'; $strings['NoPaymentOptionAvailable'] = 'No existen opciones de pago. Por favor reporte este problema al administrador.'; $strings['XIsOnlyPaymentMethodAvailable'] = '%s es el único método de pago disponible para esta compra.'; +$strings['GlobalTaxPerc'] = "Porcentaje del impuesto global"; +$strings['GlobalTaxPercDescription'] = "Porcentaje por defecto que se usará, excepto si existe un impuesto específico en el curso, sesión o servicio."; +$strings['TaxPerc'] = "Porcentaje del impuesto"; +$strings['TaxPercDescription'] = "Si se deja vacío se usará valor global por defecto."; +$strings['ByDefault'] = "por defecto (valor global)"; +$strings['OnlyCourses'] = "Solo Cursos"; +$strings['OnlySessions'] = "Solo Sesiones"; +$strings['OnlyServices'] = "Solo Servicios"; +$strings['TaxAppliesTo'] = "Impuestos aplicados a"; +$strings['AllCoursesSessionsAndServices'] = "Todos (Cursos, sesiones y servicios)"; +$strings['TaxNameCustom'] = "Nombre del impuesto"; +$strings['TaxNameExamples'] = "VAT, IVA, IGV, TVA, IV ..."; +$strings['ErrorUpdateFieldDB'] = "Error al actualizar los campos de la base de datos"; +$strings['SellerName'] = "Nombre vendedor"; +$strings['SellerId'] = "Identificador vendedor"; +$strings['SellerAddress'] = "Dirección vendedor"; +$strings['SellerEmail'] = "E-mail vendedor"; +$strings['NextNumberInvoice'] = "Número siguiente factura"; +$strings['NextNumberInvoiceDescription'] = "Número de la siguiente factura asignado de forma manual"; +$strings['InvoiceSeries'] = "Serie factura"; +$strings['InvoiceSeriesDescription'] = "Parámetro opcional: Ejemplo de numeración factura <serie><año>/<número>"; +$strings['InvoiceView'] = "Ver factura"; +$strings['NoInvoiceEnable'] = "No está habilitado el bloque de facturación"; +$strings['Company'] = "Empresa"; +$strings['VAT'] = "CIF"; +$strings['Address'] = "Dirección"; +$strings['InvoiceNumber'] = "Num. factura"; +$strings['InvoiceDate'] = "Fecha de emisión"; +$strings['Invoice'] = "Factura"; +$strings['SaleEmail'] = "E-mail de ventas"; +$strings['PurchaseDetailsIntro'] = "Detalles de la comprar"; +$strings['PurchaseDetailsEnd'] = "Atentamente"; +$strings['ProductName'] = "Nombre producto"; +$strings['BankAccountIntro'] = "Información cuentas bancarias"; diff --git a/plugin/buycourses/resources/css/style.css b/plugin/buycourses/resources/css/style.css index ff9e395394..11317a086c 100644 --- a/plugin/buycourses/resources/css/style.css +++ b/plugin/buycourses/resources/css/style.css @@ -41,6 +41,15 @@ letter-spacing: -0.020em; } +.buy-info .price-details-tax, .service-buy .price-details-tax { + font-size: 18px; + line-height: 24px; + font-weight: bold; + padding-bottom: 0px; + padding-top: 10px; + letter-spacing: -0.020em; +} + .buy-info .buy-item .title { margin-top: 5px; font-weight: bold; diff --git a/plugin/buycourses/src/buy_course_plugin.class.php b/plugin/buycourses/src/buy_course_plugin.class.php index 5497ca4d7b..c2197eaf8d 100644 --- a/plugin/buycourses/src/buy_course_plugin.class.php +++ b/plugin/buycourses/src/buy_course_plugin.class.php @@ -31,6 +31,7 @@ class BuyCoursesPlugin extends Plugin const TABLE_SERVICES_SALE = 'plugin_buycourses_service_sale'; const TABLE_CULQI = 'plugin_buycourses_culqi'; const TABLE_GLOBAL_CONFIG = 'plugin_buycourses_global_config'; + const TABLE_INVOICE = 'plugin_buycourses_invoices'; const PRODUCT_TYPE_COURSE = 1; const PRODUCT_TYPE_SESSION = 2; const PAYMENT_TYPE_PAYPAL = 1; @@ -51,6 +52,10 @@ class BuyCoursesPlugin extends Plugin const SERVICE_TYPE_LP_FINAL_ITEM = 4; const CULQI_INTEGRATION_TYPE = 'INTEG'; const CULQI_PRODUCTION_TYPE = 'PRODUC'; + const TAX_APPLIES_TO_ALL = 1; + const TAX_APPLIES_TO_ONLY_COURSE = 2; + const TAX_APPLIES_TO_ONLY_SESSION = 3; + const TAX_APPLIES_TO_ONLY_SERVICES = 4; public $isAdminPlugin = true; @@ -60,7 +65,7 @@ class BuyCoursesPlugin extends Plugin public function __construct() { parent::__construct( - '1.0', + '5.0', " Jose Angel Ruiz - NoSoloRed (original author)
Francis Gonzales and Yannick Warnier - BeezNest (integration)
@@ -81,6 +86,8 @@ class BuyCoursesPlugin extends Plugin 'commissions_enable' => 'boolean', 'unregistered_users_enable' => 'boolean', 'hide_free_text' => 'boolean', + 'invoicing_enable' => 'boolean', + 'tax_enable' => 'boolean', ] ); } @@ -164,6 +171,131 @@ class BuyCoursesPlugin extends Plugin $this->manageTab(false); } + public function update() + { + $table = self::TABLE_GLOBAL_CONFIG; + $sql = "SHOW COLUMNS FROM $table WHERE Field = 'global_tax_perc'"; + $res = Database::query($sql); + + if (Database::num_rows($res) === 0) { + $sql = "ALTER TABLE $table ADD ( + sale_email varchar(255) NOT NULL, + global_tax_perc int unsigned NOT NULL, + tax_applies_to int unsigned NOT NULL, + tax_name varchar(255) NOT NULL, + seller_name varchar(255) NOT NULL, + seller_id varchar(255) NOT NULL, + seller_address varchar(255) NOT NULL, + seller_email varchar(255) NOT NULL, + next_number_invoice int unsigned NOT NULL, + invoice_series varchar(255) NOT NULL + )"; + $res = Database::query($sql); + if (!$res) { + echo Display::return_message($this->get_lang('ErrorUpdateFieldDB'), 'warning'); + } + } + + $table = self::TABLE_ITEM; + $sql = "SHOW COLUMNS FROM $table WHERE Field = 'tax_perc'"; + $res = Database::query($sql); + + if (Database::num_rows($res) === 0) { + $sql = "ALTER TABLE $table ADD tax_perc int unsigned NULL"; + $res = Database::query($sql); + if (!$res) { + echo Display::return_message($this->get_lang('ErrorUpdateFieldDB'), 'warning'); + } + } + + $table = self::TABLE_SERVICES; + $sql = "SHOW COLUMNS FROM $table WHERE Field = 'tax_perc'"; + $res = Database::query($sql); + + if (Database::num_rows($res) === 0) { + $sql = "ALTER TABLE $table ADD tax_perc int unsigned NULL"; + $res = Database::query($sql); + if (!$res) { + echo Display::return_message($this->get_lang('ErrorUpdateFieldDB'), 'warning'); + } + } + + $table = self::TABLE_SALE; + $sql = "SHOW COLUMNS FROM $table WHERE Field = 'tax_perc'"; + $res = Database::query($sql); + + if (Database::num_rows($res) === 0) { + $sql = "ALTER TABLE $table ADD ( + price_without_tax decimal(10,2) NULL, + tax_perc int unsigned NULL, + tax_amount decimal(10,2) NULL, + invoice int unsigned NULL + )"; + $res = Database::query($sql); + if (!$res) { + echo Display::return_message($this->get_lang('ErrorUpdateFieldDB'), 'warning'); + } + } + + $table = self::TABLE_SERVICES_SALE; + $sql = "SHOW COLUMNS FROM $table WHERE Field = 'tax_perc'"; + $res = Database::query($sql); + + if (Database::num_rows($res) === 0) { + $sql = "ALTER TABLE $table ADD ( + price_without_tax decimal(10,2) NULL, + tax_perc int unsigned NULL, + tax_amount decimal(10,2) NULL, + invoice int unsigned NULL + )"; + $res = Database::query($sql); + if (!$res) { + echo Display::return_message($this->get_lang('ErrorUpdateFieldDB'), 'warning'); + } + } + + $table = self::TABLE_INVOICE; + $sql = "CREATE TABLE IF NOT EXISTS $table ( + id int unsigned NOT NULL AUTO_INCREMENT, + sale_id int unsigned NOT NULL, + is_service int unsigned NOT NULL, + num_invoice int unsigned NOT NULL, + year int(4) unsigned NOT NULL, + serie varchar(255) NOT NULL, + date_invoice datetime NOT NULL, + PRIMARY KEY (id) + )"; + $res = Database::query($sql); + + Display::addFlash( + Display::return_message( + $this->get_lang('Updated'), + 'info', + false + ) + ); + + $fieldlabel = 'buycourses_company'; + $fieldtype = '1'; + $fieldtitle = $this->get_lang('Company'); + $fielddefault = ''; + $field_id = UserManager::create_extra_field($fieldlabel, $fieldtype, $fieldtitle, $fielddefault); + + $fieldlabel = 'buycourses_vat'; + $fieldtype = '1'; + $fieldtitle = $this->get_lang('VAT'); + $fielddefault = ''; + $field_id = UserManager::create_extra_field($fieldlabel, $fieldtype, $fieldtitle, $fielddefault); + + $fieldlabel = 'buycourses_address'; + $fieldtype = '1'; + $fieldtitle = $this->get_lang('Address'); + $fielddefault = ''; + $field_id = UserManager::create_extra_field($fieldlabel, $fieldtype, $fieldtitle, $fielddefault); + + header('Location: '.api_get_path(WEB_PLUGIN_PATH).'buycourses'); + } + /** * This function verify if the plugin is enable and return the price info for a course or session in the new grid * 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 @@ -212,7 +344,8 @@ class BuyCoursesPlugin extends Plugin */ public function returnBuyCourseButton($productId, $productType) { - $url = api_get_path(WEB_PLUGIN_PATH).'buycourses/src/process.php?i='.intval($productId).'&t='.$productType; + $productId = (int) $productId; + $url = api_get_path(WEB_PLUGIN_PATH).'buycourses/src/process.php?i='.$productId.'&t='.Security::remove_XSS($productType); $html = ''. Display::returnFontAwesomeIcon('shopping-cart').''; @@ -267,7 +400,7 @@ class BuyCoursesPlugin extends Plugin Database::update( $currencyTable, ['status' => 1], - ['id = ?' => intval($selectedId)] + ['id = ?' => (int) $selectedId] ); } @@ -350,7 +483,7 @@ class BuyCoursesPlugin extends Plugin { return Database::delete( Database::get_main_table(self::TABLE_TRANSFER), - ['id = ?' => intval($id)] + ['id = ?' => (int) $id] ); } @@ -379,8 +512,8 @@ class BuyCoursesPlugin extends Plugin [ 'where' => [ 'i.product_id = ? AND i.product_type = ?' => [ - intval($productId), - intval($itemType), + (int) $productId, + (int) $itemType, ], ], ], @@ -525,12 +658,29 @@ class BuyCoursesPlugin extends Plugin continue; } + $price = $item['price']; + $taxPerc = null; + $priceWithoutTax = $item['price']; + + $taxEnable = $this->get('tax_enable') === 'true'; + $globalParameters = $this->getGlobalParameters(); + $taxAppliesTo = $globalParameters['tax_applies_to']; + if ($taxEnable && + ($taxAppliesTo == self::TAX_APPLIES_TO_ALL || $taxAppliesTo == self::TAX_APPLIES_TO_ONLY_COURSE) + ) { + $globalTaxPerc = $globalParameters['global_tax_perc']; + $precision = 2; + $taxPerc = is_null($item['tax_perc']) ? $globalTaxPerc : $item['tax_perc']; + $taxAmount = round($priceWithoutTax * $taxPerc / 100, $precision); + $price = $priceWithoutTax + $taxAmount; + } + $courseItem = [ 'id' => $course->getId(), 'title' => $course->getTitle(), 'code' => $course->getCode(), 'course_img' => null, - 'price' => $item['price'], + 'price' => $price, 'currency' => $item['iso_code'], 'teachers' => [], 'enrolled' => $this->getUserStatusForCourse(api_get_user_id(), $course), @@ -592,6 +742,24 @@ class BuyCoursesPlugin extends Plugin ] ); + $price = $item['price']; + $taxPerc = null; + $priceWithoutTax = $item['price']; + $precision = 2; + + $taxEnable = $this->get('tax_enable') === 'true'; + $globalParameters = $this->getGlobalParameters(); + $taxAppliesTo = $globalParameters['tax_applies_to']; + if ($taxEnable && + ($taxAppliesTo == self::TAX_APPLIES_TO_ALL || $taxAppliesTo == self::TAX_APPLIES_TO_ONLY_COURSE) + ) { + $globalTaxPerc = $globalParameters['global_tax_perc']; + $precision = 2; + $taxPerc = is_null($item['tax_perc']) ? $globalTaxPerc : $item['tax_perc']; + $taxAmount = round($priceWithoutTax * $taxPerc / 100, $precision); + $price = $priceWithoutTax + $taxAmount; + } + $courseInfo = [ 'id' => $course->getId(), 'title' => $course->getTitle(), @@ -599,7 +767,13 @@ class BuyCoursesPlugin extends Plugin 'code' => $course->getCode(), 'visual_code' => $course->getVisualCode(), 'teachers' => [], - 'price' => $item['price'], + 'price' => number_format($price, $precision), + 'price_without_tax' => number_format($priceWithoutTax, $precision), + 'tax_amount' => number_format($taxAmount, $precision), + 'tax_perc' => $taxPerc, + 'tax_name' => $globalParameters['tax_name'], + 'tax_enable' => $taxEnable && + ($taxAppliesTo == self::TAX_APPLIES_TO_ALL || $taxAppliesTo == self::TAX_APPLIES_TO_ONLY_COURSE), 'currency' => $item['iso_code'], 'course_img' => null, ]; @@ -658,13 +832,36 @@ class BuyCoursesPlugin extends Plugin 'coach_access_end_date' => $session->getCoachAccessEndDate(), ]); + $price = $item['price']; + $taxPerc = null; + $priceWithoutTax = $item['price']; + $precision = 2; + + $taxEnable = $this->get('tax_enable') === 'true'; + $globalParameters = $this->getGlobalParameters(); + $taxAppliesTo = $globalParameters['tax_applies_to']; + if ($taxEnable && + ($taxAppliesTo == self::TAX_APPLIES_TO_ALL || $taxAppliesTo == self::TAX_APPLIES_TO_ONLY_SESSION) + ) { + $globalTaxPerc = $globalParameters['global_tax_perc']; + $taxPerc = is_null($item['tax_perc']) ? $globalTaxPerc : $item['tax_perc']; + $taxAmount = round($priceWithoutTax * $taxPerc / 100, $precision); + $price = $priceWithoutTax + $taxAmount; + } + $sessionInfo = [ 'id' => $session->getId(), 'name' => $session->getName(), 'description' => $session->getDescription(), 'dates' => $sessionDates, 'courses' => [], - 'price' => $item['price'], + 'price' => number_format($price, $precision), + 'price_without_tax' => number_format($priceWithoutTax, $precision), + 'tax_amount' => number_format($taxAmount, $precision), + 'tax_perc' => $taxPerc, + 'tax_name' => $globalParameters['tax_name'], + 'tax_enable' => $taxEnable && + ($taxAppliesTo == self::TAX_APPLIES_TO_ALL || $taxAppliesTo == self::TAX_APPLIES_TO_ONLY_SESSION), 'currency' => $item['iso_code'], 'image' => null, 'nbrCourses' => $session->getNbrCourses(), @@ -722,7 +919,7 @@ class BuyCoursesPlugin extends Plugin '*', Database::get_main_table(self::TABLE_ITEM), [ - 'where' => ['id = ?' => intval($itemId)], + 'where' => ['id = ?' => (int) $itemId], ], 'first' ); @@ -771,6 +968,26 @@ class BuyCoursesPlugin extends Plugin $productName = $session->getName(); } + $price = $item['price']; + $priceWithoutTax = null; + $taxPerc = null; + + $taxEnable = $this->get('tax_enable') === 'true'; + $globalParameters = $this->getGlobalParameters(); + $taxAppliesTo = $globalParameters['tax_applies_to']; + if ($taxEnable && + ($taxAppliesTo == self::TAX_APPLIES_TO_ALL || + ($taxAppliesTo == TAX_APPLIES_TO_ONLY_COURSE && $item['product_type'] == self::PRODUCT_TYPE_COURSE) || + ($taxAppliesTo == TAX_APPLIES_TO_ONLY_SESSION && $item['product_type'] == self::PRODUCT_TYPE_SESSION)) + ) { + $priceWithoutTax = $item['price']; + $globalTaxPerc = $globalParameters['global_tax_perc']; + $precision = 2; + $taxPerc = is_null($item['tax_perc']) ? $globalTaxPerc : $item['tax_perc']; + $taxAmount = round($priceWithoutTax * $taxPerc / 100, $precision); + $price = $priceWithoutTax + $taxAmount; + } + $values = [ 'reference' => $this->generateReference( api_get_user_id(), @@ -783,9 +1000,12 @@ class BuyCoursesPlugin extends Plugin 'product_type' => $item['product_type'], 'product_name' => $productName, 'product_id' => $item['product_id'], - 'price' => $item['price'], + 'price' => $price, + 'price_without_tax' => $priceWithoutTax, + 'tax_perc' => $taxPerc, + 'tax_amount' => $taxAmount, 'status' => self::SALE_STATUS_PENDING, - 'payment_type' => intval($paymentType), + 'payment_type' => (int) $paymentType, ]; return Database::insert(self::TABLE_SALE, $values); @@ -804,7 +1024,7 @@ class BuyCoursesPlugin extends Plugin '*', Database::get_main_table(self::TABLE_SALE), [ - 'where' => ['id = ?' => intval($saleId)], + 'where' => ['id = ?' => (int) $saleId], ], 'first' ); @@ -834,7 +1054,7 @@ class BuyCoursesPlugin extends Plugin [ 'where' => [ 's.payment_type = ? AND s.status = ?' => [ - intval($paymentType), + (int) $paymentType, self::SALE_STATUS_COMPLETED, ], ], @@ -843,6 +1063,87 @@ class BuyCoursesPlugin extends Plugin ); } + /** + * Get data of sales. + * + * @param int $saleId The sale id + * @param int $isService Check if a service + * + * @return array The sale data + */ + public function getDataSaleInvoice($saleId, $isService) + { + $data = []; + if ($isService) { + $sale = $this->getServiceSale($saleId); + $data['reference'] = $sale['reference']; + $data['product_name'] = $sale['service']['name']; + $data['payment_type'] = $sale['payment_type']; + $data['user_id'] = $sale['buyer']['id']; + $data['price'] = $sale['price']; + $data['price_without_tax'] = $sale['price_without_tax']; + $data['tax_perc'] = $sale['tax_perc']; + $data['tax_amount'] = $sale['tax_amount']; + $data['currency_id'] = $sale['currency_id']; + $data['date'] = $sale['buy_date']; + } else { + $sale = $this->getSale($saleId); + $data['reference'] = $sale['reference']; + $data['product_name'] = $sale['product_name']; + $data['payment_type'] = $sale['payment_type']; + $data['user_id'] = $sale['user_id']; + $data['price'] = $sale['price']; + $data['price_without_tax'] = $sale['price_without_tax']; + $data['tax_perc'] = $sale['tax_perc']; + $data['tax_amount'] = $sale['tax_amount']; + $data['currency_id'] = $sale['currency_id']; + $data['date'] = $sale['date']; + } + + return $data; + } + + /** + * Get data of invoice. + * + * @param int $saleId The sale id + * @param int $isService Check if a service + * + * @return array The invoice data + */ + public function getDataInvoice($saleId, $isService) + { + return Database::select( + '*', + Database::get_main_table(self::TABLE_INVOICE), + [ + 'where' => [ + 'sale_id = ? AND ' => (int) $saleId, + 'is_service = ?' => (int) $isService, + ], + ], + 'first' + ); + } + + /** + * Get invoice numbering + * + * @param int $saleId The sale id + * @param int $isService Check if a service + * + * @return array The invoice numbers + */ + public function getNumInvoice($saleId, $isService) + { + $dataInvoice = $this->getDataInvoice($saleId, $isService); + if (empty($dataInvoice)) { + return '-'; + } + + return $dataInvoice['serie'].$dataInvoice['year'].'/'.$dataInvoice['num_invoice']; + } + /** * Get currency data by ID. * @@ -856,7 +1157,7 @@ class BuyCoursesPlugin extends Plugin '*', Database::get_main_table(self::TABLE_CURRENCY), [ - 'where' => ['id = ?' => intval($currencyId)], + 'where' => ['id = ?' => (int) $currencyId], ], 'first' ); @@ -897,6 +1198,9 @@ class BuyCoursesPlugin extends Plugin if ($saleIsCompleted) { $this->updateSaleStatus($sale['id'], self::SALE_STATUS_COMPLETED); + if ($this->get('invoicing_enable') === 'true') { + $this->setInvoice($sale['id']); + } } return $saleIsCompleted; @@ -926,6 +1230,82 @@ class BuyCoursesPlugin extends Plugin ]; } + /** + * Register a invoice. + * + * @param int $saleId The sale ID + * @param int $isService The service type to filter (default : 0) + */ + public function setInvoice($saleId, $isService = 0) + { + $invoiceTable = Database::get_main_table(self::TABLE_INVOICE); + $year = date('Y'); + + $globalParameters = $this->getGlobalParameters(); + $numInvoice = $globalParameters['next_number_invoice']; + $serie = $globalParameters['invoice_series']; + + if (empty($numInvoice)) { + $item = Database::select( + ['MAX(num_invoice) AS num_invoice'], + $invoiceTable, + [ + 'where' => ['year = ?' => $year], + ], + 'first' + ); + + $numInvoice = 1; + if ($item !== false) { + $numInvoice = (int) ($item['num_invoice'] + 1); + } + } else { + Database::update( + Database::get_main_table(self::TABLE_GLOBAL_CONFIG), + ['next_number_invoice' => 0], + ['id = ?' => 1] + ); + } + + Database::insert( + $invoiceTable, + [ + 'sale_id' => $saleId, + 'is_service' => $isService, + 'num_invoice' => $numInvoice, + 'year' => $year, + 'serie' => $serie, + 'date_invoice' => api_get_utc_datetime(), + ] + ); + + // Record invoice in the sales table + $table = Database::get_main_table(self::TABLE_SALE); + if (empty($isService)) { + $table = Database::get_main_table(self::TABLE_SERVICES_SALE); + } + Database::update( + $table, + ['invoice' => 1], + ['id = ?' => $saleId] + ); + } + + /** + * Get Tax's types. + * + * @return array + */ + public function getTaxAppliesTo() + { + return [ + self::TAX_APPLIES_TO_ALL => $this->get_lang('AllCoursesSessionsAndServices'), + self::TAX_APPLIES_TO_ONLY_COURSE => $this->get_lang('OnlyCourses'), + self::TAX_APPLIES_TO_ONLY_SESSION => $this->get_lang('OnlySessions'), + self::TAX_APPLIES_TO_ONLY_SERVICES => $this->get_lang('OnlyServices'), + ]; + } + /** * Get a list of sales by the status. * @@ -948,7 +1328,7 @@ class BuyCoursesPlugin extends Plugin ['c.iso_code', 'u.firstname', 'u.lastname', 's.*'], "$saleTable s $innerJoins", [ - 'where' => ['s.status = ?' => intval($status)], + 'where' => ['s.status = ?' => (int) $status], 'order' => 'id DESC', ] ); @@ -1127,7 +1507,7 @@ class BuyCoursesPlugin extends Plugin "$saleTable s $innerJoins", [ 'where' => [ - 'u.id = ? AND s.status = ?' => [intval($id), self::SALE_STATUS_COMPLETED], + 'u.id = ? AND s.status = ?' => [(int) $id, self::SALE_STATUS_COMPLETED], ], 'order' => 'id DESC', ] @@ -1155,6 +1535,7 @@ class BuyCoursesPlugin extends Plugin 'visible' => false, 'currency' => empty($defaultCurrency) ? null : $defaultCurrency['iso_code'], 'price' => 0.00, + 'tax_perc' => null, ]; $item = $this->getItemByProduct($course->getId(), self::PRODUCT_TYPE_COURSE); @@ -1164,6 +1545,7 @@ class BuyCoursesPlugin extends Plugin $courseItem['visible'] = true; $courseItem['currency'] = $item['iso_code']; $courseItem['price'] = $item['price']; + $courseItem['tax_perc'] = $item['tax_perc']; } return $courseItem; @@ -1197,6 +1579,7 @@ class BuyCoursesPlugin extends Plugin 'visible' => false, 'currency' => empty($defaultCurrency) ? null : $defaultCurrency['iso_code'], 'price' => 0.00, + 'tax_perc' => null, ]; $displayStartDate = $session->getDisplayStartDate(); @@ -1233,6 +1616,7 @@ class BuyCoursesPlugin extends Plugin $sessionItem['visible'] = true; $sessionItem['currency'] = $item['iso_code']; $sessionItem['price'] = $item['price']; + $sessionItem['tax_perc'] = $item['tax_perc']; } return $sessionItem; @@ -1254,7 +1638,7 @@ class BuyCoursesPlugin extends Plugin $beneficiaryTable, [ 'where' => [ - 'item_id = ?' => intval($itemId), + 'item_id = ?' => (int) $itemId, ], ] ); @@ -1272,7 +1656,7 @@ class BuyCoursesPlugin extends Plugin $itemTable = Database::get_main_table(self::TABLE_ITEM); $affectedRows = Database::delete( $itemTable, - ['id = ?' => intval($itemId)] + ['id = ?' => (int) $itemId] ); if (!$affectedRows) { @@ -1313,7 +1697,7 @@ class BuyCoursesPlugin extends Plugin $itemTable, $itemData, [ - 'product_id = ? AND ' => intval($productId), + 'product_id = ? AND ' => (int) $productId, 'product_type' => $productType, ] ); @@ -1332,7 +1716,7 @@ class BuyCoursesPlugin extends Plugin return Database::delete( $beneficiaryTable, - ['item_id = ?' => intval($itemId)] + ['item_id = ?' => (int) $itemId] ); } @@ -1352,9 +1736,9 @@ class BuyCoursesPlugin extends Plugin Database::insert( $beneficiaryTable, [ - 'item_id' => intval($itemId), - 'user_id' => intval($userId), - 'commissions' => intval($commissions), + 'item_id' => (int) $itemId, + 'user_id' => (int) $userId, + 'commissions' => (int) $commissions, ] ); } @@ -1410,8 +1794,8 @@ class BuyCoursesPlugin extends Plugin $payoutId = false, $userId = false ) { - $condition = ($payoutId) ? 'AND p.id = '.intval($payoutId) : ''; - $condition2 = ($userId) ? ' AND p.user_id = '.intval($userId) : ''; + $condition = ($payoutId) ? 'AND p.id = '.((int) $payoutId) : ''; + $condition2 = ($userId) ? ' AND p.user_id = '.((int) $userId) : ''; $typeResult = ($condition) ? 'first' : 'all'; $payoutsTable = Database::get_main_table(self::TABLE_PAYPAL_PAYOUTS); $saleTable = Database::get_main_table(self::TABLE_SALE); @@ -1438,7 +1822,7 @@ class BuyCoursesPlugin extends Plugin INNER JOIN $saleTable s ON s.id = p.sale_id INNER JOIN $currencyTable c ON s.currency_id = c.id LEFT JOIN $extraFieldValues efv ON p.user_id = efv.item_id - AND field_id = ".intval($paypalExtraField['id'])." + AND field_id = ".((int) $paypalExtraField['id'])." "; $payouts = Database::select( @@ -1483,7 +1867,7 @@ class BuyCoursesPlugin extends Plugin "value", $extraFieldValues, [ - 'where' => ['field_id = ? AND item_id = ?' => [intval($paypalFieldId), intval($userId)]], + 'where' => ['field_id = ? AND item_id = ?' => [(int) $paypalFieldId, (int) $userId]], ], 'first' ); @@ -1512,22 +1896,24 @@ class BuyCoursesPlugin extends Plugin $platformCommission = $this->getPlatformCommission(); $sale = $this->getSale($saleId); + $commission = (int) $platformCommission['commission']; $teachersCommission = number_format( - (floatval($sale['price']) * intval($platformCommission['commission'])) / 100, + (floatval($sale['price']) * $commission) / 100, 2 ); $beneficiaries = $this->getBeneficiariesBySale($saleId); foreach ($beneficiaries as $beneficiary) { + $beneficiaryCommission = (int) $beneficiary['commissions']; Database::insert( $payoutsTable, [ 'date' => $sale['date'], 'payout_date' => getdate(), - 'sale_id' => intval($saleId), + 'sale_id' => (int) $saleId, 'user_id' => $beneficiary['user_id'], 'commission' => number_format( - (floatval($teachersCommission) * intval($beneficiary['commissions'])) / 100, + (floatval($teachersCommission) * $beneficiaryCommission) / 100, 2 ), 'status' => self::PAYOUT_STATUS_PENDING, @@ -1550,8 +1936,8 @@ class BuyCoursesPlugin extends Plugin Database::update( $payoutsTable, - ['status' => intval($status)], - ['id = ?' => intval($payoutId)] + ['status' => (int) $status], + ['id = ?' => (int) $payoutId] ); } @@ -1583,7 +1969,7 @@ class BuyCoursesPlugin extends Plugin return Database::update( $commissionTable, - ['commission' => intval($params['commission'])] + ['commission' => (int) $params['commission']] ); } @@ -1604,10 +1990,11 @@ class BuyCoursesPlugin extends Plugin 'name' => Security::remove_XSS($service['name']), 'description' => Security::remove_XSS($service['description']), 'price' => $service['price'], - 'duration_days' => intval($service['duration_days']), - 'applies_to' => intval($service['applies_to']), - 'owner_id' => intval($service['owner_id']), - 'visibility' => intval($service['visibility']), + 'tax_perc' => $service['tax_perc'] != '' ? (int) $service['tax_perc'] : null, + 'duration_days' => (int) $service['duration_days'], + 'applies_to' => (int) $service['applies_to'], + 'owner_id' => (int) $service['owner_id'], + 'visibility' => (int) $service['visibility'], 'image' => '', 'video_url' => $service['video_url'], 'service_information' => $service['service_information'], @@ -1626,7 +2013,7 @@ class BuyCoursesPlugin extends Plugin Database::update( $servicesTable, ['image' => 'simg-'.$return.'.png'], - ['id = ?' => intval($return)] + ['id = ?' => (int) $return] ); } @@ -1658,15 +2045,16 @@ class BuyCoursesPlugin extends Plugin 'name' => Security::remove_XSS($service['name']), 'description' => Security::remove_XSS($service['description']), 'price' => $service['price'], - 'duration_days' => intval($service['duration_days']), - 'applies_to' => intval($service['applies_to']), - 'owner_id' => intval($service['owner_id']), - 'visibility' => intval($service['visibility']), + 'tax_perc' => $service['tax_perc'] != '' ? (int) $service['tax_perc'] : null, + 'duration_days' => (int) $service['duration_days'], + 'applies_to' => (int) $service['applies_to'], + 'owner_id' => (int) $service['owner_id'], + 'visibility' => (int) $service['visibility'], 'image' => 'simg-'.$id.'.png', 'video_url' => $service['video_url'], 'service_information' => $service['service_information'], ], - ['id = ?' => intval($id)] + ['id = ?' => (int) $id] ); } @@ -1681,12 +2069,12 @@ class BuyCoursesPlugin extends Plugin { Database::delete( Database::get_main_table(self::TABLE_SERVICES_SALE), - ['service_id = ?' => intval($id)] + ['service_id = ?' => (int) $id] ); return Database::delete( Database::get_main_table(self::TABLE_SERVICES), - ['id = ?' => intval($id)] + ['id = ?' => (int) $id] ); } @@ -1723,10 +2111,36 @@ class BuyCoursesPlugin extends Plugin $services = []; if ($id) { + $price = $return['price']; + $taxPerc = null; + $priceWithoutTax = $priceWithTax = $return['price']; + $precision = 2; + + $taxEnable = $this->get('tax_enable') === 'true'; + $globalParameters = $this->getGlobalParameters(); + $taxAppliesTo = $globalParameters['tax_applies_to']; + if ($taxEnable && + ($taxAppliesTo == self::TAX_APPLIES_TO_ALL || $taxAppliesTo == self::TAX_APPLIES_TO_ONLY_SERVICES) + ) { + $globalTaxPerc = $globalParameters['global_tax_perc']; + $precision = 2; + $taxPerc = is_null($return['tax_perc']) ? $globalTaxPerc : $return['tax_perc']; + $taxAmount = round($priceWithoutTax * $taxPerc / 100, $precision); + $priceWithTax = $priceWithoutTax + $taxAmount; + } + $services['id'] = $return['id']; $services['name'] = $return['name']; $services['description'] = $return['description']; - $services['price'] = $return['price']; + $services['price'] = $price; + $services['tax_perc'] = $return['tax_perc']; + $services['price_with_tax'] = number_format($priceWithTax, $precision); + $services['price_without_tax'] = number_format($priceWithoutTax, $precision); + $services['tax_amount'] = number_format($taxAmount, $precision); + $services['tax_perc_show'] = $taxPerc; + $services['tax_name'] = $globalParameters['tax_name']; + $services['tax_enable'] = $taxEnable && + ($taxAppliesTo == self::TAX_APPLIES_TO_ALL || $taxAppliesTo == self::TAX_APPLIES_TO_ONLY_SERVICES); $services['currency'] = $return['currency']; $services['duration_days'] = $return['duration_days']; $services['applies_to'] = $return['applies_to']; @@ -1747,6 +2161,7 @@ class BuyCoursesPlugin extends Plugin $services[$index]['name'] = $service['name']; $services[$index]['description'] = $service['description']; $services[$index]['price'] = $service['price']; + $services[$index]['tax_perc'] = $service['tax_perc']; $services[$index]['currency'] = $service['currency']; $services[$index]['duration_days'] = $service['duration_days']; $services[$index]['applies_to'] = $service['applies_to']; @@ -1818,7 +2233,7 @@ class BuyCoursesPlugin extends Plugin $conditions = ['WHERE' => ['ss.buyer_id = ?' => $buyerId], 'ORDER' => 'id ASC']; } - if (is_numeric($status)) { + if (is_numeric($status) && empty($id)) { $conditions = ['WHERE' => ['ss.status = ?' => $status], 'ORDER' => 'id ASC']; } @@ -1862,7 +2277,6 @@ class BuyCoursesPlugin extends Plugin $conditions, $showData ); - $servicesSale = []; if ($id) { @@ -1885,6 +2299,9 @@ class BuyCoursesPlugin extends Plugin $servicesSale['currency_id'] = $return['currency_id']; $servicesSale['currency'] = $return['currency']; $servicesSale['price'] = $return['price']; + $servicesSale['price_without_tax'] = $return['price_without_tax']; + $servicesSale['tax_perc'] = $return['tax_perc']; + $servicesSale['tax_amount'] = $return['tax_amount']; $servicesSale['node_type'] = $return['node_type']; $servicesSale['node_id'] = $return['node_id']; $servicesSale['buyer']['id'] = $buyer['user_id']; @@ -1895,6 +2312,7 @@ class BuyCoursesPlugin extends Plugin $servicesSale['date_end'] = $return['date_end']; $servicesSale['status'] = $return['status']; $servicesSale['payment_type'] = $return['payment_type']; + $servicesSale['invoice'] = $return['invoice']; return $servicesSale; } @@ -1931,6 +2349,7 @@ class BuyCoursesPlugin extends Plugin $servicesSale[$index]['date_end'] = $service['date_end']; $servicesSale[$index]['status'] = $service['status']; $servicesSale[$index]['payment_type'] = $service['payment_type']; + $servicesSale[$index]['invoice'] = $service['invoice']; } return $servicesSale; @@ -1972,6 +2391,10 @@ class BuyCoursesPlugin extends Plugin self::SERVICE_STATUS_COMPLETED ); + if ($this->get('invoicing_enable') === 'true') { + $this->setInvoice($serviceSaleId, 1); + } + return true; } @@ -2022,10 +2445,27 @@ class BuyCoursesPlugin extends Plugin $services = []; foreach ($return as $index => $service) { + $price = $service['price']; + $taxPerc = null; + $priceWithoutTax = $service['price']; + + $taxEnable = $this->get('tax_enable') === 'true'; + $globalParameters = $this->getGlobalParameters(); + $taxAppliesTo = $globalParameters['tax_applies_to']; + if ($taxEnable && + ($taxAppliesTo == self::TAX_APPLIES_TO_ALL || $taxAppliesTo == self::TAX_APPLIES_TO_ONLY_SERVICES) + ) { + $globalTaxPerc = $globalParameters['global_tax_perc']; + $precision = 2; + $taxPerc = is_null($service['tax_perc']) ? $globalTaxPerc : $service['tax_perc']; + $taxAmount = round($priceWithoutTax * $taxPerc / 100, $precision); + $price = $priceWithoutTax + $taxAmount; + } + $services[$index]['id'] = $service['id']; $services[$index]['name'] = $service['name']; $services[$index]['description'] = $service['description']; - $services[$index]['price'] = $service['price']; + $services[$index]['price'] = number_format($price, $precision); $services[$index]['currency'] = $service['currency']; $services[$index]['duration_days'] = $service['duration_days']; $services[$index]['applies_to'] = $service['applies_to']; @@ -2070,6 +2510,23 @@ class BuyCoursesPlugin extends Plugin } $currency = $this->getSelectedCurrency(); + $price = $service['price']; + $priceWithoutTax = null; + $taxPerc = null; + + $taxEnable = $this->get('tax_enable') === 'true'; + $globalParameters = $this->getGlobalParameters(); + $taxAppliesTo = $globalParameters['tax_applies_to']; + if ($taxEnable && + ($taxAppliesTo == self::TAX_APPLIES_TO_ALL || $taxAppliesTo == TAX_APPLIES_TO_ONLY_SERVICES) + ) { + $priceWithoutTax = $service['price']; + $globalTaxPerc = $globalParameters['global_tax_perc']; + $precision = 2; + $taxPerc = is_null($service['tax_perc']) ? $globalTaxPerc : $service['tax_perc']; + $taxAmount = round($priceWithoutTax * $taxPerc / 100, $precision); + $price = $priceWithoutTax + $taxAmount; + } $values = [ 'service_id' => $serviceId, @@ -2079,9 +2536,12 @@ class BuyCoursesPlugin extends Plugin $infoSelect ), 'currency_id' => $currency['id'], - 'price' => $service['price'], + 'price' => $price, + 'price_without_tax' => $priceWithoutTax, + 'tax_perc' => $taxPerc, + 'tax_amount' => $taxAmount, 'node_type' => $service['applies_to'], - 'node_id' => intval($infoSelect), + 'node_id' => (int) $infoSelect, 'buyer_id' => $userId, 'buy_date' => api_get_utc_datetime(), 'date_start' => api_get_utc_datetime(), @@ -2093,7 +2553,7 @@ class BuyCoursesPlugin extends Plugin 'Y-m-d H:i:s' ), 'status' => self::SERVICE_STATUS_PENDING, - 'payment_type' => intval($paymentType), + 'payment_type' => (int) $paymentType, ]; $returnedServiceSaleId = Database::insert(self::TABLE_SERVICES_SALE, $values); @@ -2145,11 +2605,29 @@ class BuyCoursesPlugin extends Plugin */ public function saveGlobalParameters($params) { + $sqlParams = [ + 'terms_and_conditions' => $params['terms_and_conditions'], + 'sale_email' => $params['sale_email'], + ]; + + if ($this->get('tax_enable') === 'true') { + $sqlParams['global_tax_perc'] = $params['global_tax_perc']; + $sqlParams['tax_applies_to'] = $params['tax_applies_to']; + $sqlParams['tax_name'] = $params['tax_name']; + } + + if ($this->get('invoicing_enable') === 'true') { + $sqlParams['seller_name'] = $params['seller_name']; + $sqlParams['seller_id'] = $params['seller_id']; + $sqlParams['seller_address'] = $params['seller_address']; + $sqlParams['seller_email'] = $params['seller_email']; + $sqlParams['next_number_invoice'] = $params['next_number_invoice']; + $sqlParams['invoice_series'] = $params['invoice_series']; + } + return Database::update( Database::get_main_table(self::TABLE_GLOBAL_CONFIG), - [ - 'terms_and_conditions' => $params['terms_and_conditions'], - ], + $sqlParams, ['id = ?' => 1] ); } @@ -2422,8 +2900,8 @@ class BuyCoursesPlugin extends Plugin return Database::update( $saleTable, - ['status' => intval($newStatus)], - ['id = ?' => intval($saleId)] + ['status' => (int) $newStatus], + ['id = ?' => (int) $saleId] ); } diff --git a/plugin/buycourses/src/buycourses.ajax.php b/plugin/buycourses/src/buycourses.ajax.php index 02529ecc97..4efc20bcee 100644 --- a/plugin/buycourses/src/buycourses.ajax.php +++ b/plugin/buycourses/src/buycourses.ajax.php @@ -235,6 +235,9 @@ switch ($action) { $payout['id'], BuyCoursesPlugin::PAYOUT_STATUS_COMPLETED ); + if ($plugin->get('invoicing_enable') === 'true') { + $plugin->setInvoice($payout['id']); + } } echo Display::return_message( diff --git a/plugin/buycourses/src/configuration.php b/plugin/buycourses/src/configuration.php index 317b2ed964..65882893eb 100644 --- a/plugin/buycourses/src/configuration.php +++ b/plugin/buycourses/src/configuration.php @@ -12,6 +12,7 @@ require_once __DIR__.'/../../../main/inc/global.inc.php'; $plugin = BuyCoursesPlugin::create(); $includeSession = $plugin->get('include_sessions') === 'true'; $includeServices = $plugin->get('include_services') === 'true'; +$taxEnable = $plugin->get('tax_enable') === 'true'; api_protect_admin_script(true); @@ -39,6 +40,7 @@ $tpl->assign('product_type_session', BuyCoursesPlugin::PRODUCT_TYPE_SESSION); $tpl->assign('courses', $courses); $tpl->assign('sessions_are_included', $includeSession); $tpl->assign('services_are_included', $includeServices); +$tpl->assign('tax_enable', $taxEnable); if ($includeSession) { $sessions = $plugin->getSessionsForConfiguration(); @@ -50,6 +52,13 @@ if ($includeServices) { $tpl->assign('services', $services); } +if ($taxEnable) { + $globalParameters = $plugin->getGlobalParameters(); + $tpl->assign('global_tax_perc', $globalParameters['global_tax_perc']); + $tpl->assign('tax_applies_to', $globalParameters['tax_applies_to']); + $tpl->assign('tax_name', $globalParameters['tax_name']); +} + $content = $tpl->fetch('buycourses/view/configuration.tpl'); $tpl->assign('header', $templateName); diff --git a/plugin/buycourses/src/configure_course.php b/plugin/buycourses/src/configure_course.php index e9157ecfdb..1c5885b5ac 100644 --- a/plugin/buycourses/src/configure_course.php +++ b/plugin/buycourses/src/configure_course.php @@ -88,6 +88,7 @@ if ($editingCourse) { 'name' => $courseItem['course_title'], 'visible' => $courseItem['visible'], 'price' => $courseItem['price'], + 'tax_perc' => $courseItem['tax_perc'], 'beneficiaries' => $defaultBeneficiaries, ($commissionsEnable == "true") ? 'commissions' : '' => ($commissionsEnable == "true") ? $commissions : '', ]; @@ -154,6 +155,7 @@ if ($editingCourse) { 'name' => $sessionItem['session_name'], 'visible' => $sessionItem['visible'], 'price' => $sessionItem['price'], + 'tax_perc' => $sessionItem['tax_perc'], 'beneficiaries' => $defaultBeneficiaries, ($commissionsEnable == "true") ? 'commissions' : '' => ($commissionsEnable == "true") ? $commissions : '', ]; @@ -190,6 +192,8 @@ if ($commissionsEnable === 'true') { "; } +$globalSettingsParams = $plugin->getGlobalParameters(); + $form = new FormValidator('beneficiaries'); $form->addText('product_type', $plugin->get_lang('ProductType'), false); $form->addText('name', get_lang('Name'), false); @@ -204,6 +208,12 @@ $form->addElement( [$plugin->get_lang('Price'), null, $currencyIso], ['step' => 0.01] ); +$form->addElement( + 'number', + 'tax_perc', + [$plugin->get_lang('TaxPerc'), $plugin->get_lang('TaxPercDescription'), '%'], + ['step' => 1, 'placeholder' => $globalSettingsParams['global_tax_perc'].'% '.$plugin->get_lang('ByDefault')] +); $beneficiariesSelect = $form->addSelect( 'beneficiaries', $plugin->get_lang('Beneficiaries'), @@ -252,9 +262,13 @@ if ($form->validate()) { $productItem = $plugin->getItemByProduct($formValues['i'], $formValues['t']); if (isset($formValues['visible'])) { + $taxPerc = $formValues['tax_perc'] != '' ? (int) $formValues['tax_perc'] : null; if (!empty($productItem)) { $plugin->updateItem( - ['price' => floatval($formValues['price'])], + [ + 'price' => floatval($formValues['price']), + 'tax_perc' => $taxPerc, + ], $formValues['i'], $formValues['t'] ); @@ -264,6 +278,7 @@ if ($form->validate()) { 'product_type' => $formValues['t'], 'product_id' => intval($formValues['i']), 'price' => floatval($_POST['price']), + 'tax_perc' => $taxPerc, ]); $productItem['id'] = $itemId; } diff --git a/plugin/buycourses/src/invoice.php b/plugin/buycourses/src/invoice.php new file mode 100644 index 0000000000..de004e521a --- /dev/null +++ b/plugin/buycourses/src/invoice.php @@ -0,0 +1,122 @@ +get('invoicing_enable') === 'true'; +if (!$invoicingEnable) { + api_not_allowed(true, $plugin->get_lang('NoInvoiceEnable')); +} + +$saleId = isset($_GET['invoice']) ? (int) $_GET['invoice'] : 0; +$isService = isset($_GET['is_service']) ? (int) $_GET['is_service'] : 0; + +$globalParameters = $plugin->getGlobalParameters(); +$infoSale = $plugin->getDataSaleInvoice($saleId, $isService); +$buyer = api_get_user_info($infoSale['user_id']); +$extraUserInfoData = UserManager::get_extra_user_data($infoSale['user_id']); +$infoInvoice = $plugin->getDataInvoice($saleId, $isService); + +$htmlText = ''; +$htmlText .= ''; +$htmlText .= ''; +$htmlText .= ''; + +$organization = ChamiloApi::getPlatformLogo('', [], true); +// Use custom logo image. +$pdfLogo = api_get_setting('pdf_logo_header'); +if ($pdfLogo === 'true') { + $visualTheme = api_get_visual_theme(); + $img = api_get_path(SYS_CSS_PATH).'themes/'.$visualTheme.'/images/pdf_logo_header.png'; + if (file_exists($img)) { + $organization = ""; + } +} +$htmlText .= $organization; + +// Seller and customer info +$htmlText .= ''; +$htmlText .= ''; +$htmlText .= ''; +$htmlText .= ''; +$htmlText .= ''; +$htmlText .= '
'; +$htmlText .= ''.$globalParameters['seller_name'].'
'; +$htmlText .= $globalParameters['seller_id'].'
'; +$htmlText .= $globalParameters['seller_address'].'
'; +$htmlText .= $globalParameters['seller_email'].'
'; +$htmlText .= '
'; +$htmlText .= ''.$buyer['complete_name'].'
'; +$htmlText .= ($extraUserInfoData['buycourses_company'] ? $extraUserInfoData['buycourses_company'].'
' : ''); +$htmlText .= ($extraUserInfoData['buycourses_vat'] ? $extraUserInfoData['buycourses_vat'].'
' : ''); +$htmlText .= ($extraUserInfoData['buycourses_address'] ? $extraUserInfoData['buycourses_address'].'
' : ''); +$htmlText .= ($buyer['phone'] ? $buyer['phone'].'
' : ''); +$htmlText .= ($buyer['email'] ? $buyer['email'].'
' : ''); +$htmlText .= '
'; + +$htmlText .= '

'; +$htmlText .= '

'; +$htmlText .= $plugin->get_lang('InvoiceDate').': '.api_format_date($infoInvoice['date_invoice'], DATE_TIME_FORMAT_LONG_24H).'
'; +$htmlText .= $plugin->get_lang('InvoiceNumber').': '.$infoInvoice['serie'].$infoInvoice['year'].'/'.$infoInvoice['num_invoice'].'
'; +$htmlText .= '



'; + +$header = [ + $plugin->get_lang('OrderReference'), + $plugin->get_lang('ProductType'), + $plugin->get_lang('Price'), + $globalParameters['tax_name'], + $plugin->get_lang('TotalPayout'), +]; + +$data = []; +$row = [ + $infoSale['reference'], + $infoSale['product_name'], + $plugin->getCurrency($infoSale['currency_id'])['iso_code']. + ' '.$infoSale['price_without_tax'], + $plugin->getCurrency($infoSale['currency_id'])['iso_code']. + ' '.$infoSale['tax_amount']. + ' ('.(int) $infoSale['tax_perc'].'%)', + $plugin->getCurrency($infoSale['currency_id'])['iso_code']. + ' '.$infoSale['price'], +]; +$data[] = $row; + +$row = [ + '', + '', + '', + $plugin->get_lang('TotalPayout'), + $plugin->getCurrency($infoSale['currency_id'])['iso_code'].' '.$infoSale['price'], +]; +$data[] = $row; +$attr = []; +$attr['class'] = "table data_table"; +$attr['width'] = "100%"; +$htmlText .= Display::table($header, $data, $attr); +$htmlText .= ''; + +$fileName = $infoInvoice['serie'].$infoInvoice['year'].'-'.$infoInvoice['num_invoice']; +$fileName = api_replace_dangerous_char($fileName); +$params = [ + 'filename' => $fileName, + 'pdf_title' => $plugin->get_lang('Invoice'), + 'pdf_description' => '', + 'format' => 'A4', + 'orientation' => 'P', +]; +$pdf = new PDF($params['format'], $params['orientation'], $params); +$pdf->content_to_pdf($htmlText, '', $fileName, null, 'D', false, null, false, false, false); +exit; diff --git a/plugin/buycourses/src/paymentsetup.php b/plugin/buycourses/src/paymentsetup.php index 2b0477c27c..e584d342c7 100644 --- a/plugin/buycourses/src/paymentsetup.php +++ b/plugin/buycourses/src/paymentsetup.php @@ -32,14 +32,14 @@ if (isset($_GET['action'], $_GET['id'])) { } } -$currencyForm = new FormValidator('currency'); +$globalSettingForm = new FormValidator('currency'); -if ($currencyForm->validate()) { - $currencyFormValues = $currencyForm->getSubmitValues(); +if ($globalSettingForm->validate()) { + $globalSettingFormValues = $globalSettingForm->getSubmitValues(); - $plugin->selectCurrency($currencyFormValues['currency']); - unset($currencyFormValues['currency']); - $plugin->saveGlobalParameters($currencyFormValues); + $plugin->selectCurrency($globalSettingFormValues['currency']); + unset($globalSettingFormValues['currency']); + $plugin->saveGlobalParameters($globalSettingFormValues); Display::addFlash( Display::return_message(get_lang('Saved'), 'success') @@ -51,7 +51,7 @@ if ($currencyForm->validate()) { $currencies = $plugin->getCurrencies(); -$currencySelect = $currencyForm->addSelect( +$currencySelect = $globalSettingForm->addSelect( 'currency', [ $plugin->get_lang('CurrencyType'), @@ -77,14 +77,98 @@ foreach ($currencies as $currency) { } } -$currencyForm->addTextarea( +$globalSettingForm->addTextarea( 'terms_and_conditions', [get_lang('TermsAndConditions'), - $plugin->get_lang('WriteHereTheTermsAndConditionsOfYourECommerce'), ], + $plugin->get_lang('WriteHereTheTermsAndConditionsOfYourECommerce'), ], [] ); -$currencyForm->addButtonSave(get_lang('Save')); -$currencyForm->setDefaults($plugin->getGlobalParameters()); + +$globalSettingForm->addElement( + 'text', + 'sale_email', + $plugin->get_lang('SaleEmail') +); + +$taxEnable = $plugin->get('tax_enable') === 'true'; +$invoicingEnable = $plugin->get('invoicing_enable') === 'true'; + +if ($taxEnable) { + $globalSettingForm->addHtml('
'); + + $globalSettingForm->addElement( + 'number', + 'global_tax_perc', + [$plugin->get_lang('GlobalTaxPerc'), $plugin->get_lang('GlobalTaxPercDescription'), '%'], + ['step' => 1] + ); + + $taxAppliesTo = $plugin->getTaxAppliesTo(); + + $taxTypeSelect = $globalSettingForm->addSelect( + 'tax_applies_to', + $plugin->get_lang('TaxAppliesTo'), + [get_lang('Select')] + ); + + foreach ($taxAppliesTo as $key => $value) { + $optionText = $value; + $optionyValue = $key; + + $taxTypeSelect->addOption($optionText, $optionyValue); + } + + $globalSettingForm->addElement( + 'text', + 'tax_name', + $plugin->get_lang('TaxNameCustom'), + ['placeholder' => $plugin->get_lang('TaxNameExamples')] + ); +} + +if ($invoicingEnable) { + $globalSettingForm->addHtml('
'); + + $globalSettingForm->addElement( + 'text', + 'seller_name', + $plugin->get_lang('SellerName') + ); + + $globalSettingForm->addElement( + 'text', + 'seller_id', + $plugin->get_lang('SellerId') + ); + + $globalSettingForm->addElement( + 'text', + 'seller_address', + $plugin->get_lang('SellerAddress') + ); + + $globalSettingForm->addElement( + 'text', + 'seller_email', + $plugin->get_lang('SellerEmail') + ); + + $globalSettingForm->addElement( + 'number', + 'next_number_invoice', + [$plugin->get_lang('NextNumberInvoice'), $plugin->get_lang('NextNumberInvoiceDescription')], + ['step' => 1] + ); + + $globalSettingForm->addElement( + 'text', + 'invoice_series', + [$plugin->get_lang('InvoiceSeries'), $plugin->get_lang('InvoiceSeriesDescription')] + ); +} + +$globalSettingForm->addButtonSave(get_lang('Save')); +$globalSettingForm->setDefaults($plugin->getGlobalParameters()); $termsAndConditionsForm = new FormValidator('termsconditions'); @@ -231,7 +315,7 @@ $interbreadcrumb[] = [ $templateName = $plugin->get_lang('PaymentsConfiguration'); $tpl = new Template($templateName); $tpl->assign('header', $templateName); -$tpl->assign('global_config_form', $currencyForm->returnForm()); +$tpl->assign('global_config_form', $globalSettingForm->returnForm()); $tpl->assign('paypal_form', $paypalForm->returnForm()); $tpl->assign('commission_form', $commissionForm->returnForm()); $tpl->assign('transfer_form', $transferForm->returnForm()); diff --git a/plugin/buycourses/src/process_confirm.php b/plugin/buycourses/src/process_confirm.php index b59b38771d..3ef17f5636 100644 --- a/plugin/buycourses/src/process_confirm.php +++ b/plugin/buycourses/src/process_confirm.php @@ -25,7 +25,7 @@ if (empty($sale)) { } $currency = $plugin->getCurrency($sale['currency_id']); -$terms = $plugin->getGlobalParameters(); +$globalParameters = $plugin->getGlobalParameters(); switch ($sale['payment_type']) { case BuyCoursesPlugin::PAYMENT_TYPE_PAYPAL: @@ -64,6 +64,28 @@ switch ($sale['payment_type']) { exit; } + if (!empty($globalParameters['sale_email'])) { + $messageConfirmTemplate = new Template(); + $messageConfirmTemplate->assign('user', $userInfo); + $messageConfirmTemplate->assign( + 'sale', + [ + 'date' => $sale['date'], + 'product' => $sale['product_name'], + 'currency' => $currency['iso_code'], + 'price' => $sale['price'], + 'reference' => $sale['reference'], + ] + ); + + api_mail_html( + '', + $globalParameters['sale_email'], + $plugin->get_lang('bc_subject'), + $messageConfirmTemplate->fetch('buycourses/view/message_confirm.tpl') + ); + } + RedirectToPayPal($expressCheckout["TOKEN"]); break; case BuyCoursesPlugin::PAYMENT_TYPE_TRANSFER: @@ -109,7 +131,7 @@ switch ($sale['payment_type']) { $messageTemplate->assign( 'sale', [ - 'date' => api_format_date($sale['date'], DATE_FORMAT_LONG_NO_DAY), + 'date' => $sale['date'], 'product' => $sale['product_name'], 'currency' => $currency['iso_code'], 'price' => $sale['price'], @@ -125,6 +147,28 @@ switch ($sale['payment_type']) { $messageTemplate->fetch('buycourses/view/message_transfer.tpl') ); + if (!empty($globalParameters['sale_email'])) { + $messageConfirmTemplate = new Template(); + $messageConfirmTemplate->assign('user', $userInfo); + $messageConfirmTemplate->assign( + 'sale', + [ + 'date' => $sale['date'], + 'product' => $sale['product_name'], + 'currency' => $currency['iso_code'], + 'price' => $sale['price'], + 'reference' => $sale['reference'], + ] + ); + + api_mail_html( + '', + $globalParameters['sale_email'], + $plugin->get_lang('bc_subject'), + $messageConfirmTemplate->fetch('buycourses/view/message_confirm.tpl') + ); + } + Display::addFlash( Display::return_message( sprintf( @@ -162,7 +206,7 @@ switch ($sale['payment_type']) { $template->assign('buying_course', $buyingCourse); $template->assign('buying_session', $buyingSession); - $template->assign('terms', $terms['terms_and_conditions']); + $template->assign('terms', $globalParameters['terms_and_conditions']); $template->assign('title', $sale['product_name']); $template->assign('price', $sale['price']); $template->assign('currency', $sale['currency_id']); @@ -253,7 +297,7 @@ switch ($sale['payment_type']) { $template->assign('buying_course', $buyingCourse); $template->assign('buying_session', $buyingSession); - $template->assign('terms', $terms['terms_and_conditions']); + $template->assign('terms', $globalParameters['terms_and_conditions']); $template->assign('title', $sale['product_name']); $template->assign('price', floatval($sale['price'])); $template->assign('currency', $plugin->getSelectedCurrency()); diff --git a/plugin/buycourses/src/sales_report.php b/plugin/buycourses/src/sales_report.php index 1184497620..4935a57479 100644 --- a/plugin/buycourses/src/sales_report.php +++ b/plugin/buycourses/src/sales_report.php @@ -18,6 +18,7 @@ $plugin = BuyCoursesPlugin::create(); $paypalEnable = $plugin->get('paypal_enable'); $commissionsEnable = $plugin->get('commissions_enable'); $includeServices = $plugin->get('include_services'); +$invoicingEnable = $plugin->get('invoicing_enable') === 'true'; if (isset($_GET['order'])) { $sale = $plugin->getSale($_GET['order']); @@ -127,6 +128,8 @@ foreach ($sales as $sale) { 'product_type' => $productTypes[$sale['product_type']], 'complete_user_name' => api_get_person_name($sale['firstname'], $sale['lastname']), 'payment_type' => $paymentTypes[$sale['payment_type']], + 'invoice' => $sale['invoice'], + 'num_invoice' => $plugin->getNumInvoice($sale['id'], 0), ]; } @@ -176,6 +179,7 @@ $template->assign('sale_list', $saleList); $template->assign('sale_status_canceled', BuyCoursesPlugin::SALE_STATUS_CANCELED); $template->assign('sale_status_pending', BuyCoursesPlugin::SALE_STATUS_PENDING); $template->assign('sale_status_completed', BuyCoursesPlugin::SALE_STATUS_COMPLETED); +$template->assign('invoicing_enable', $invoicingEnable); $content = $template->fetch('buycourses/view/sales_report.tpl'); diff --git a/plugin/buycourses/src/service_process_confirm.php b/plugin/buycourses/src/service_process_confirm.php index 73da970f29..d91e08580d 100644 --- a/plugin/buycourses/src/service_process_confirm.php +++ b/plugin/buycourses/src/service_process_confirm.php @@ -25,7 +25,7 @@ if (empty($serviceSale)) { } $currency = $plugin->getCurrency($serviceSale['currency_id']); -$terms = $plugin->getGlobalParameters(); +$globalParameters = $plugin->getGlobalParameters(); switch ($serviceSale['payment_type']) { case BuyCoursesPlugin::PAYMENT_TYPE_PAYPAL: @@ -78,6 +78,28 @@ switch ($serviceSale['payment_type']) { exit; } + if (!empty($globalParameters['sale_email'])) { + $messageConfirmTemplate = new Template(); + $messageConfirmTemplate->assign('user', $userInfo); + $messageConfirmTemplate->assign( + 'sale', + [ + 'date' => $serviceSale['buy_date'], + 'product' => $serviceSale['service']['name'], + 'currency' => $currency['iso_code'], + 'price' => $serviceSale['price'], + 'reference' => $serviceSale['reference'], + ] + ); + + api_mail_html( + '', + $globalParameters['sale_email'], + $plugin->get_lang('bc_subject'), + $messageConfirmTemplate->fetch('buycourses/view/message_confirm.tpl') + ); + } + RedirectToPayPal($expressCheckout['TOKEN']); break; case BuyCoursesPlugin::PAYMENT_TYPE_TRANSFER: @@ -112,10 +134,10 @@ switch ($serviceSale['payment_type']) { [ 'name' => $serviceSale['service']['name'], 'buyer' => $serviceSale['buyer']['name'], - 'buy_date' => api_format_date($serviceSale['buy_date'], DATE_TIME_FORMAT_LONG_24H), - 'start_date' => api_format_date($serviceSale['start_date'], DATE_TIME_FORMAT_LONG_24H), - 'end_date' => api_format_date($serviceSale['end_date'], DATE_TIME_FORMAT_LONG_24H), - 'currency' => $currency['currency'], + 'buy_date' => $serviceSale['buy_date'], + 'start_date' => $serviceSale['start_date'], + 'end_date' => $serviceSale['end_date'], + 'currency' => $currency['iso_code'], 'price' => $serviceSale['price'], 'reference' => $serviceSale['reference'], ] @@ -126,9 +148,31 @@ switch ($serviceSale['payment_type']) { $buyer['complete_name'], $buyer['email'], $plugin->get_lang('bc_subject'), - $messageTemplate->fetch('buycourses/view/message_transfer.tpl') + $messageTemplate->fetch('buycourses/view/service_message_transfer.tpl') ); + if (!empty($globalParameters['sale_email'])) { + $messageConfirmTemplate = new Template(); + $messageConfirmTemplate->assign('user', $userInfo); + $messageConfirmTemplate->assign( + 'sale', + [ + 'date' => $serviceSale['buy_date'], + 'product' => $serviceSale['service']['name'], + 'currency' => $currency['iso_code'], + 'price' => $serviceSale['price'], + 'reference' => $serviceSale['reference'], + ] + ); + + api_mail_html( + '', + $globalParameters['sale_email'], + $plugin->get_lang('bc_subject'), + $messageConfirmTemplate->fetch('buycourses/view/message_confirm.tpl') + ); + } + Display::addFlash( Display::return_message( sprintf( @@ -166,7 +210,7 @@ switch ($serviceSale['payment_type']) { $template = new Template(); - $template->assign('terms', $terms['terms_and_conditions']); + $template->assign('terms', $globalParameters['terms_and_conditions']); $template->assign('title', $serviceSale['service']['name']); $template->assign('price', $serviceSale['price']); $template->assign('currency', $serviceSale['currency_id']); @@ -235,7 +279,7 @@ switch ($serviceSale['payment_type']) { ); $template = new Template(); - $template->assign('terms', $terms['terms_and_conditions']); + $template->assign('terms', $globalParameters['terms_and_conditions']); $template->assign('title', $serviceSale['service']['name']); $template->assign('price', floatval($serviceSale['price'])); $template->assign('currency', $plugin->getSelectedCurrency()); diff --git a/plugin/buycourses/src/service_sales_report.php b/plugin/buycourses/src/service_sales_report.php index b1eb36423f..065dd06448 100644 --- a/plugin/buycourses/src/service_sales_report.php +++ b/plugin/buycourses/src/service_sales_report.php @@ -17,17 +17,30 @@ $plugin = BuyCoursesPlugin::create(); $paypalEnable = $plugin->get('paypal_enable'); $commissionsEnable = $plugin->get('commissions_enable'); $includeServices = $plugin->get('include_services'); +$invoicingEnable = $plugin->get('invoicing_enable') === 'true'; $saleStatuses = $plugin->getServiceSaleStatuses(); $paymentTypes = $plugin->getPaymentTypes(); +$selectedStatus = isset($_GET['status']) ? $_GET['status'] : BuyCoursesPlugin::SALE_STATUS_PENDING; +$searchTerm = ''; + $form = new FormValidator('search', 'get'); +if ($form->validate()) { + $selectedStatus = $form->getSubmitValue('status'); + $searchTerm = $form->getSubmitValue('user'); + + if ($selectedStatus === false) { + $selectedStatus = BuyCoursesPlugin::SALE_STATUS_PENDING; + } +} + $form->addSelect('status', $plugin->get_lang('OrderStatus'), $saleStatuses, ['cols-size' => [0, 0, 0]]); $form->addText('user', get_lang('User'), false, ['cols-size' => [0, 0, 0]]); $form->addButtonSearch(get_lang('Search'), 'search'); -$servicesSales = $plugin->getServiceSale(); +$servicesSales = $plugin->getServiceSale(null, null, $selectedStatus); $serviceSaleList = []; foreach ($servicesSales as $sale) { @@ -41,6 +54,8 @@ foreach ($servicesSales as $sale) { 'service_type' => $sale['service']['applies_to'], 'service_name' => $sale['service']['name'], 'complete_user_name' => $sale['buyer']['name'], + 'invoice' => $sale['invoice'], + 'num_invoice' => $plugin->getNumInvoice($sale['id'], 1), ]; } @@ -87,6 +102,7 @@ $template->assign('sale_list', $serviceSaleList); $template->assign('sale_status_cancelled', BuyCoursesPlugin::SERVICE_STATUS_CANCELLED); $template->assign('sale_status_pending', BuyCoursesPlugin::SERVICE_STATUS_PENDING); $template->assign('sale_status_completed', BuyCoursesPlugin::SERVICE_STATUS_COMPLETED); +$template->assign('invoicing_enable', $invoicingEnable); $content = $template->fetch('buycourses/view/service_sales_report.tpl'); $template->assign('content', $content); $template->display_one_col_template(); diff --git a/plugin/buycourses/src/services_add.php b/plugin/buycourses/src/services_add.php index 7baa13465e..5c45d740b2 100644 --- a/plugin/buycourses/src/services_add.php +++ b/plugin/buycourses/src/services_add.php @@ -32,8 +32,11 @@ $interbreadcrumb[] = [ 'name' => $plugin->get_lang('Configuration'), ]; +$globalSettingsParams = $plugin->getGlobalParameters(); + $formDefaultValues = [ 'price' => 0, + 'tax_perc' => $globalSettingsParams['global_tax_perc'], 'duration_days' => 0, 'applies_to' => 0, 'visibility' => true, @@ -48,6 +51,12 @@ $form->addElement( [$plugin->get_lang('Price'), null, $currency['iso_code']], ['step' => 0.01] ); +$form->addElement( + 'number', + 'tax_perc', + [$plugin->get_lang('TaxPerc'), $plugin->get_lang('TaxPercDescription'), '%'], + ['step' => 1, 'placeholder' => $globalSettingsParams['global_tax_perc'].'% '.$plugin->get_lang('ByDefault')] +); $form->addElement( 'number', 'duration_days', diff --git a/plugin/buycourses/src/services_edit.php b/plugin/buycourses/src/services_edit.php index 00b08884fa..f955918a88 100644 --- a/plugin/buycourses/src/services_edit.php +++ b/plugin/buycourses/src/services_edit.php @@ -37,12 +37,14 @@ $interbreadcrumb[] = [ 'name' => $plugin->get_lang('Configuration'), ]; +$globalSettingsParams = $plugin->getGlobalParameters(); $service = $plugin->getServices($serviceId); $formDefaultValues = [ 'name' => $service['name'], 'description' => $service['description'], 'price' => $service['price'], + 'tax_perc' => $service['tax_perc'], 'duration_days' => $service['duration_days'], 'owner_id' => intval($service['owner_id']), 'applies_to' => intval($service['applies_to']), @@ -63,6 +65,12 @@ $form->addElement( [$plugin->get_lang('Price'), null, $currency['iso_code']], ['step' => 0.01] ); +$form->addElement( + 'number', + 'tax_perc', + [$plugin->get_lang('TaxPerc'), $plugin->get_lang('TaxPercDescription'), '%'], + ['step' => 1, 'placeholder' => $globalSettingsParams['global_tax_perc'].'% '.$plugin->get_lang('ByDefault')] +); $form->addElement( 'number', 'duration_days', diff --git a/plugin/buycourses/update.php b/plugin/buycourses/update.php new file mode 100644 index 0000000000..8023695e14 --- /dev/null +++ b/plugin/buycourses/update.php @@ -0,0 +1,14 @@ +update(); diff --git a/plugin/buycourses/view/configuration.tpl b/plugin/buycourses/view/configuration.tpl index 0b4ba3ad70..3f4828ffcd 100644 --- a/plugin/buycourses/view/configuration.tpl +++ b/plugin/buycourses/view/configuration.tpl @@ -1,13 +1,15 @@ -{% if sessions_are_included %} +{% if sessions_are_included or services_are_included %}