diff --git a/plugin/buycourses/database.php b/plugin/buycourses/database.php index a4b47203af..819f95bf9f 100644 --- a/plugin/buycourses/database.php +++ b/plugin/buycourses/database.php @@ -477,6 +477,68 @@ if (false === $sm->tablesExist(BuyCoursesPlugin::TABLE_COUPON_SERVICE)) { $couponService->setPrimaryKey(['id']); } +if (false === $sm->tablesExist(BuyCoursesPlugin::TABLE_SUBSCRIPTION)) { + $subscriptionTable = $pluginSchema->createTable(BuyCoursesPlugin::TABLE_SUBSCRIPTION); + $subscriptionTable->addColumn( + 'product_type', + Types::INTEGER, + ['unsigned' => true] + ); + $subscriptionTable->addColumn( + 'product_id', + Types::INTEGER, + ['unsigned' => true] + ); + $subscriptionTable->addColumn( + 'duration', + Types::INTEGER, + ['unsigned' => true] + ); + $subscriptionTable->addColumn('currency_id', Types::INTEGER); + $subscriptionTable->addColumn('price', Types::DECIMAL); + $subscriptionTable->addColumn('tax_perc', Types::INTEGER); + $subscriptionTable->setPrimaryKey(['product_type', 'product_id', 'duration']); +} + +if (false === $sm->tablesExist(BuyCoursesPlugin::TABLE_SUBSCRIPTION_SALE)) { + $subscriptionSaleTable = $pluginSchema->createTable(BuyCoursesPlugin::TABLE_SUBSCRIPTION_SALE); + $subscriptionSaleTable->addColumn( + 'id', + Types::INTEGER, + ['autoincrement' => true, 'unsigned' => true] + ); + $subscriptionSaleTable->addColumn('currency_id', Types::INTEGER); + $subscriptionSaleTable->addColumn('reference', Types::STRING); + $subscriptionSaleTable->addColumn('date', Types::DATETIME_MUTABLE); + $subscriptionSaleTable->addColumn('user_id', Types::INTEGER); + $subscriptionSaleTable->addColumn('product_type', Types::INTEGER); + $subscriptionSaleTable->addColumn('product_name', Types::STRING); + $subscriptionSaleTable->addColumn('product_id', Types::INTEGER); + $subscriptionSaleTable->addColumn('price', Types::DECIMAL); + $subscriptionSaleTable->addColumn('price_without_tax', Types::DECIMAL, ['notnull' => false]); + $subscriptionSaleTable->addColumn('tax_perc', Types::INTEGER, ['notnull' => false]); + $subscriptionSaleTable->addColumn('tax_amount', Types::DECIMAL, ['notnull' => false]); + $subscriptionSaleTable->addColumn('status', Types::INTEGER); + $subscriptionSaleTable->addColumn('payment_type', Types::INTEGER); + $subscriptionSaleTable->addColumn('invoice', Types::INTEGER); + $subscriptionSaleTable->addColumn('price_without_discount', Types::DECIMAL); + $subscriptionSaleTable->addColumn('discount_amount', Types::DECIMAL); + $subscriptionSaleTable->addColumn('subscription_end', Types::DATETIME_MUTABLE); + $subscriptionSaleTable->addColumn('expired', Types::BOOLEAN); + $subscriptionSaleTable->setPrimaryKey(['id']); +} + +if (false === $sm->tablesExist(BuyCoursesPlugin::TABLE_SUBSCRIPTION_PERIOD)) { + $subscriptionPeriodTable = $pluginSchema->createTable(BuyCoursesPlugin::TABLE_SUBSCRIPTION_PERIOD); + $subscriptionPeriodTable->addColumn( + 'duration', + Types::INTEGER, + ['unsigned' => true] + ); + $subscriptionPeriodTable->addColumn('name', Types::STRING); + $subscriptionPeriodTable->setPrimaryKey(['duration']); +} + if (false === $sm->tablesExist(BuyCoursesPlugin::TABLE_COUPON_SALE)) { $couponSaleTable = $pluginSchema->createTable(BuyCoursesPlugin::TABLE_COUPON_SALE); $couponSaleTable->addColumn( @@ -532,6 +594,18 @@ if (false === $sm->tablesExist(BuyCoursesPlugin::TABLE_TPV_CECABANK)) { $tpvCecabankTable->setPrimaryKey(['id']); } +if (false === $sm->tablesExist(BuyCoursesPlugin::TABLE_COUPON_SUBSCRIPTION_SALE)) { + $couponSubscriptionSaleTable = $pluginSchema->createTable(BuyCoursesPlugin::TABLE_COUPON_SUBSCRIPTION_SALE); + $couponSubscriptionSaleTable->addColumn( + 'id', + Types::INTEGER, + ['autoincrement' => true, 'unsigned' => true] + ); + $couponSubscriptionSaleTable->addColumn('coupon_id', Types::INTEGER); + $couponSubscriptionSaleTable->addColumn('sale_id', Types::INTEGER); + $couponSubscriptionSaleTable->setPrimaryKey(['id']); +} + $queries = $pluginSchema->toSql($platform); foreach ($queries as $query) { diff --git a/plugin/buycourses/lang/english.php b/plugin/buycourses/lang/english.php index 6328856dfb..91e586c8a6 100644 --- a/plugin/buycourses/lang/english.php +++ b/plugin/buycourses/lang/english.php @@ -285,3 +285,27 @@ $strings['CecaCurrency'] = "Moneda"; $strings['CecaExponent'] = "Exponent"; $strings['CecaSupportedPayment'] = "Pago soportado"; $strings['CecabankConfig'] = "Cecabank configuration"; +$strings['Duration'] = "Duration"; +$strings['SubscriptionAdd'] = "Add subscription"; +$strings['SubscriptionList'] = "Subscription list"; +$strings['SubscriptionListOnSale'] = "Subscriptions on sale"; +$strings['SelectSubscription'] = "Select duration"; +$strings['SubscriptionNotValid'] = "Subscription not valid"; +$strings['SubscriptionSalesReport'] = "Sales report"; +$strings['BuySubscriptions'] = "Buy subscriptions"; +$strings['ConfigurationOfSubscriptionsAndPrices'] = "Subscriptions and prices configuration"; +$strings['FrequencyConfig'] = "Frequency config"; +$strings['Subscriptions'] = "Subscriptions"; +$strings['HasSubscriptions'] = "Has subscriptions"; +$strings['FrequencyRemoved'] = "Frequency removed"; +$strings['SubscriptionPeriodOnUse'] = "Subscription period in use"; +$strings['FrequencyNotExits'] = "Frequency not exists"; +$strings['SubscriptionFrequencyValueDays'] = "Value on days"; +$strings['FrequencyNotUpdated'] = "Frequency not updated"; +$strings['FrequencyNotSaved'] = "Frequency not saved"; +$strings['NeedToAddDuration'] = "Need to add duration"; +$strings['SubscriptionNotValid'] = "Subscription not valid"; +$strings['SelecSubscription'] = "Select a subscription"; +$strings['ConfigureSubscriptionsFrequencies'] = "Configure subscriptions periods"; +$strings['FrequencyAdd'] = "Add Frequency"; +$strings['SubscriptionAlreadyExists'] = "Subscription already exists"; \ No newline at end of file diff --git a/plugin/buycourses/lang/spanish.php b/plugin/buycourses/lang/spanish.php index ffe44db199..ef644371c7 100644 --- a/plugin/buycourses/lang/spanish.php +++ b/plugin/buycourses/lang/spanish.php @@ -285,3 +285,32 @@ $strings['CecaCurrency'] = "Moneda"; $strings['CecaExponent'] = "Exponent"; $strings['CecaSupportedPayment'] = "Pago soportado"; $strings['CecabankConfig'] = "Configuración Cecabank"; +$strings['Country'] = "País"; +$strings['PaymentType'] = "Tipo de pago"; +$strings['CountryRelPaymentConfig'] = "Configuración del tipo de pago por país"; +$strings['CountryRelPaymentMessage'] = "Para realizar un pedido es necesario definir el tipo de pago por país, en caso contrario no se permite la realización del pedido"; +$strings['CountryEmpty'] = "Para realizar un pedido es necesario definir en el perfil del usuario el campo país"; +$strings['Duration'] = "Duración"; +$strings['SubscriptionAdd'] = "Añadir suscripción"; +$strings['SubscriptionList'] = "Lista de suscripciones"; +$strings['SubscriptionListOnSale'] = "Lista de suscripciones a la venta"; +$strings['SelectSubscription'] = "Seleciona duración"; +$strings['SubscriptionNotValid'] = "Suscripción no valida"; +$strings['SubscriptionSalesReport'] = "Reporte de ventas"; +$strings['BuySubscriptions'] = "Compra suscripciones"; +$strings['ConfigurationOfSubscriptionsAndPrices'] = "Configuración de suscripciones y precios"; +$strings['FrequencyConfig'] = "Configuración frecuencia"; +$strings['Subscriptions'] = "Suscripciones"; +$strings['HasSubscriptions'] = "Tiene suscripciones"; +$strings['FrequencyRemoved'] = "Frecuencia eliminada"; +$strings['SubscriptionPeriodOnUse'] = "Período de suscription en uso"; +$strings['FrequencyNotExits'] = "La frecuencia no existe"; +$strings['SubscriptionFrequencyValueDays'] = "Valor de la suscripción en días"; +$strings['FrequencyNotUpdated'] = "Frecuencia no actualizada"; +$strings['FrequencyNotSaved'] = "Frequencia no guardada"; +$strings['NeedToAddDuration'] = "Hay que especificar una duración"; +$strings['SubscriptionNotValid'] = "Suscripción no valida"; +$strings['SelecSubscription'] = "Seleccione una suscripción"; +$strings['ConfigureSubscriptionsFrequencies'] = "Configurar los períodos de suscripciones"; +$strings['FrequencyAdd'] = "Agregar período"; +$strings['SubscriptionAlreadyExists'] = "La suscripción ya existe"; \ No newline at end of file diff --git a/plugin/buycourses/resources/img/128/buysubscriptions.png b/plugin/buycourses/resources/img/128/buysubscriptions.png new file mode 100644 index 0000000000..97a4eed529 Binary files /dev/null and b/plugin/buycourses/resources/img/128/buysubscriptions.png differ diff --git a/plugin/buycourses/resources/img/128/subscriptionssettings.png b/plugin/buycourses/resources/img/128/subscriptionssettings.png new file mode 100644 index 0000000000..9c50507130 Binary files /dev/null and b/plugin/buycourses/resources/img/128/subscriptionssettings.png differ diff --git a/plugin/buycourses/resources/img/32/buysubscription.png b/plugin/buycourses/resources/img/32/buysubscription.png new file mode 100644 index 0000000000..359169ef61 Binary files /dev/null and b/plugin/buycourses/resources/img/32/buysubscription.png differ diff --git a/plugin/buycourses/resources/img/32/buysubscriptions.png b/plugin/buycourses/resources/img/32/buysubscriptions.png new file mode 100644 index 0000000000..359169ef61 Binary files /dev/null and b/plugin/buycourses/resources/img/32/buysubscriptions.png differ diff --git a/plugin/buycourses/resources/img/32/subscriptionsettings.png b/plugin/buycourses/resources/img/32/subscriptionsettings.png new file mode 100644 index 0000000000..21f37ff019 Binary files /dev/null and b/plugin/buycourses/resources/img/32/subscriptionsettings.png differ diff --git a/plugin/buycourses/resources/img/32/subscriptionssettings.png b/plugin/buycourses/resources/img/32/subscriptionssettings.png new file mode 100644 index 0000000000..21f37ff019 Binary files /dev/null and b/plugin/buycourses/resources/img/32/subscriptionssettings.png differ diff --git a/plugin/buycourses/resources/img/42/buysubscriptions.png b/plugin/buycourses/resources/img/42/buysubscriptions.png new file mode 100644 index 0000000000..359169ef61 Binary files /dev/null and b/plugin/buycourses/resources/img/42/buysubscriptions.png differ diff --git a/plugin/buycourses/resources/img/42/subscriptionssettings.png b/plugin/buycourses/resources/img/42/subscriptionssettings.png new file mode 100644 index 0000000000..21f37ff019 Binary files /dev/null and b/plugin/buycourses/resources/img/42/subscriptionssettings.png differ diff --git a/plugin/buycourses/resources/img/64/buysubscriptions.png b/plugin/buycourses/resources/img/64/buysubscriptions.png new file mode 100644 index 0000000000..be1bed82d1 Binary files /dev/null and b/plugin/buycourses/resources/img/64/buysubscriptions.png differ diff --git a/plugin/buycourses/resources/img/64/subscriptionssettings.png b/plugin/buycourses/resources/img/64/subscriptionssettings.png new file mode 100644 index 0000000000..2e2d327e75 Binary files /dev/null and b/plugin/buycourses/resources/img/64/subscriptionssettings.png differ diff --git a/plugin/buycourses/src/buy_course_plugin.class.php b/plugin/buycourses/src/buy_course_plugin.class.php index 117be52cdb..e5faff8e91 100644 --- a/plugin/buycourses/src/buy_course_plugin.class.php +++ b/plugin/buycourses/src/buy_course_plugin.class.php @@ -41,6 +41,11 @@ class BuyCoursesPlugin extends Plugin const TABLE_COUPON_SERVICE_SALE = 'plugin_buycourses_coupon_rel_service_sale'; const TABLE_STRIPE = 'plugin_buycourses_stripe_account'; const TABLE_TPV_CECABANK = 'plugin_buycourses_cecabank_account'; + const COUPON_SUBSCRIPTION_WEEKLY = 7; + const COUPON_SUBSCRIPTION_MONTHLY = 30; + const COUPON_SUBSCRIPTION_QUARTERLY = 60; + const COUPON_SUBSCRIPTION_BIANNUAL = 180; + const COUPON_SUBSCRIPTION_ANNUAL = 360; const PRODUCT_TYPE_COURSE = 1; const PRODUCT_TYPE_SESSION = 2; const PRODUCT_TYPE_SERVICE = 3; @@ -159,8 +164,12 @@ class BuyCoursesPlugin extends Plugin self::TABLE_COUPON, self::TABLE_COUPON_ITEM, self::TABLE_COUPON_SERVICE, + self::TABLE_SUBSCRIPTION, + self::TABLE_SUBSCRIPTION_SALE, + self::TABLE_SUBSCRIPTION_PERIOD, self::TABLE_COUPON_SALE, self::TABLE_COUPON_SERVICE_SALE, + self::TABLE_COUPON_SUBSCRIPTION_SALE, self::TABLE_STRIPE, self::TABLE_TPV_CECABANK, ]; @@ -199,8 +208,12 @@ class BuyCoursesPlugin extends Plugin self::TABLE_COUPON, self::TABLE_COUPON_ITEM, self::TABLE_COUPON_SERVICE, + self::TABLE_SUBSCRIPTION, + self::TABLE_SUBSCRIPTION_SALE, + self::TABLE_SUBSCRIPTION_PERIOD, self::TABLE_COUPON_SALE, self::TABLE_COUPON_SERVICE_SALE, + self::TABLE_COUPON_SUBSCRIPTION_SALE, self::TABLE_STRIPE, ]; @@ -403,6 +416,51 @@ class BuyCoursesPlugin extends Plugin )"; Database::query($sql); + $table = self::TABLE_SUBSCRIPTION; + $sql = "CREATE TABLE IF NOT EXISTS $table ( + product_type int unsigned NOT NULL, + product_id int unsigned NOT NULL, + duration int unsigned NOT NULL, + currency_id int unsigned NOT NULL, + price decimal(10, 2) NOT NULL, + tax_perc int unsigned, + PRIMARY KEY (product_type, product_id, duration) + )"; + Database::query($sql); + + $table = self::TABLE_SUBSCRIPTION_SALE; + $sql = "CREATE TABLE IF NOT EXISTS $table ( + id int unsigned NOT NULL AUTO_INCREMENT, + currency_id int unsigned NOT NULL, + reference varchar(255) NOT NULL, + date datetime NOT NULL, + user_id int unsigned NOT NULL, + product_type int NOT NULL, + product_name varchar(255) NOT NULL, + product_id int unsigned NOT NULL, + price decimal(10,2) NOT NULL, + price_without_tax decimal(10,2) NULL, + tax_perc int unsigned NULL, + tax_amount decimal(10,2) NULL, + status int NOT NULL, + payment_type int NOT NULL, + invoice int NOT NULL, + price_without_discount decimal(10,2), + discount_amount decimal(10,2), + subscription_end datetime NOT NULL, + expired tinyint NULL, + PRIMARY KEY (id) + )"; + Database::query($sql); + + $table = self::TABLE_SUBSCRIPTION_PERIOD; + $sql = "CREATE TABLE IF NOT EXISTS $table ( + duration int unsigned NOT NULL, + name varchar(50) NOT NULL, + PRIMARY KEY (duration) + )"; + Database::query($sql); + $table = self::TABLE_COUPON_SALE; $sql = "CREATE TABLE IF NOT EXISTS $table ( id int unsigned NOT NULL AUTO_INCREMENT, @@ -421,6 +479,15 @@ class BuyCoursesPlugin extends Plugin )"; Database::query($sql); + $table = self::TABLE_COUPON_SUBSCRIPTION_SALE; + $sql = "CREATE TABLE IF NOT EXISTS $table ( + id int unsigned NOT NULL AUTO_INCREMENT, + coupon_id int unsigned NOT NULL, + sale_id int unsigned NOT NULL, + PRIMARY KEY (id) + )"; + Database::query($sql); + $table = self::TABLE_STRIPE; $sql = "CREATE TABLE IF NOT EXISTS $table ( id int unsigned NOT NULL AUTO_INCREMENT, @@ -849,6 +916,133 @@ class BuyCoursesPlugin extends Plugin return $product; } + /** + * Get registered item data. + * + * @param int $itemId The product ID + * @param int $productType The product type + * + * @return array + */ + public function getSubscriptionItem($itemId, $productType) + { + return Database::select( + '*', + Database::get_main_table(self::TABLE_SUBSCRIPTION), + [ + 'where' => ['product_id = ? AND product_type = ?' => [ + (int) $itemId], + (int) $productType, + ], + ], + 'first' + ); + } + + /** + * Get the item data. + * + * @param int $productId The item ID + * @param int $itemType The item type + * + * @return array + */ + public function getSubscriptionItemByProduct($productId, $itemType, $coupon =null) + { + $buySubscriptionItemTable = Database::get_main_table(self::TABLE_SUBSCRIPTION); + $buyCurrencyTable = Database::get_main_table(self::TABLE_CURRENCY); + + $fakeItemFrom = " + $buySubscriptionItemTable s + INNER JOIN $buyCurrencyTable c + ON s.currency_id = c.id + "; + + $item = Database::select( + ['s.*', 'c.iso_code'], + $fakeItemFrom, + [ + 'where' => [ + 's.product_id = ? AND s.product_type = ?' => [ + (int) $productId, + (int) $itemType, + ], + ], + ], + 'first' + ); + + if (empty($item)) { + return false; + } + + $this->setPriceSettings($item, self::TAX_APPLIES_TO_ONLY_COURSE, $coupon); + + return $item; + } + /** + * Get the item data. + * + * @param int $productId The item ID + * @param int $itemType The item type + * + * @return array + */ + public function getSubscriptionsItemsByProduct($productId, $itemType) + { + $buySubscriptionItemTable = Database::get_main_table(self::TABLE_SUBSCRIPTION); + $buyCurrencyTable = Database::get_main_table(self::TABLE_CURRENCY); + + $fakeItemFrom = " + $buySubscriptionItemTable s + INNER JOIN $buyCurrencyTable c + ON s.currency_id = c.id + "; + + $items = Database::select( + ['s.*', 'c.iso_code'], + $fakeItemFrom, + [ + 'where' => [ + 's.product_id = ? AND s.product_type = ?' => [ + (int) $productId, + (int) $itemType, + ], + ], + ] + ); + + for ($i = 0; $i < count($items); $i++) { + $this->setPriceSettings($items[$i], self::TAX_APPLIES_TO_ONLY_COURSE); + } + + if (empty($items)) { + return false; + } + + return $items; + } + + /** + * Get registered item data.by duration + * + * @param int $duration The subscription duration + * + * @return array + */ + public function getSubscriptiosnItemsByDuration($duration) + { + return Database::select( + '*', + Database::get_main_table(self::TABLE_SUBSCRIPTION), + [ + 'where' => ['duration = ?' => [ + (int) $duration], + ], + ] + ); + } + /** * List courses details from the configuration page. * @@ -994,6 +1188,140 @@ class BuyCoursesPlugin extends Plugin return $courseCatalog; } + /** + * Lists current user subscription session details, including each session course details. + * + * It can return the number of rows when $typeResult is 'count'. + * + * @param int $start + * @param int $end + * @param string $name Optional. The name filter. + * @param string $typeResult Optional. 'all', 'first' or 'count'. + * + * @return array|int + */ + public function getCatalogSubscriptionSessionList($start, $end, $name = null, $typeResult = 'all', $sessionCategory = 0) + { + $sessions = $this->filterSubscriptionSessionList($start, $end, $name, $typeResult, $sessionCategory); + + if ($typeResult === 'count') { + return $sessions; + } + + $sessionCatalog = []; + // loop through all sessions + foreach ($sessions as $session) { + $sessionCourses = $session->getCourses(); + + if (empty($sessionCourses)) { + continue; + } + + $item = $this->getSubscriptionItemByProduct( + $session->getId(), + self::PRODUCT_TYPE_SESSION + ); + + if (empty($item)) { + continue; + } + + $sessionData = $this->getSubscriptionSessionInfo($session->getId()); + $sessionData['coach'] = $session->getGeneralCoach()->getCompleteName(); + $sessionData['enrolled'] = $this->getUserStatusForSubscriptionSession( + api_get_user_id(), + $session + ); + $sessionData['courses'] = []; + + foreach ($sessionCourses as $sessionCourse) { + $course = $sessionCourse->getCourse(); + + $sessionCourseData = [ + 'title' => $course->getTitle(), + 'coaches' => [], + ]; + + $userCourseSubscriptions = $session->getUserCourseSubscriptionsByStatus( + $course, + Chamilo\CoreBundle\Entity\Session::COACH + ); + + foreach ($userCourseSubscriptions as $userCourseSubscription) { + $user = $userCourseSubscription->getUser(); + $sessionCourseData['coaches'][] = $user->getCompleteName(); + } + $sessionData['courses'][] = $sessionCourseData; + } + + $sessionCatalog[] = $sessionData; + } + + return $sessionCatalog; + } + + /** + * Lists current user subscription course details. + * + * @param int $start + * @param int $end + * @param string $name Optional. The name filter. + * @param string $typeResult Optional. 'all', 'first' or 'count'. + * + * @return array|int + */ + public function getCatalogSubscriptionCourseList($first, $pageSize, $name = null, $typeResult = 'all') + { + $courses = $this->filterSubscriptionCourseList($first, $pageSize, $name, $typeResult); + + if ($typeResult === 'count') { + return $courses; + } + + if (empty($courses)) { + return []; + } + + $courseCatalog = []; + foreach ($courses as $course) { + $item = $this->getSubscriptionItemByProduct( + $course->getId(), + self::PRODUCT_TYPE_COURSE + ); + + if (empty($item)) { + continue; + } + + $courseItem = [ + 'id' => $course->getId(), + 'title' => $course->getTitle(), + 'code' => $course->getCode(), + 'course_img' => null, + 'item' => $item, + 'teachers' => [], + 'enrolled' => $this->getUserStatusForSubscriptionCourse(api_get_user_id(), $course), + ]; + + foreach ($course->getTeachers() as $courseUser) { + $teacher = $courseUser->getUser(); + $courseItem['teachers'][] = $teacher->getCompleteName(); + } + + // Check images + $possiblePath = api_get_path(SYS_COURSE_PATH); + $possiblePath .= $course->getDirectory(); + $possiblePath .= '/course-pic.png'; + + if (file_exists($possiblePath)) { + $courseItem['course_img'] = api_get_path(WEB_COURSE_PATH).$course->getDirectory().'/course-pic.png'; + } + $courseCatalog[] = $courseItem; + } + + return $courseCatalog; + } + /** * @param $price * @param $isoCode @@ -1178,19 +1506,179 @@ class BuyCoursesPlugin extends Plugin } /** - * Register a sale. + * Get course info. * - * @param int $itemId The product ID - * @param int $paymentType The payment type - * @param string $couponId The coupon ID + * @param int $courseId The course ID * - * @return bool + * @return array */ - public function registerSale($itemId, $paymentType, $couponId = null) + public function getSubscriptionCourseInfo($courseId, $coupon = null) { - if (!in_array( - $paymentType, - [ + $entityManager = Database::getManager(); + $course = $entityManager->find('ChamiloCoreBundle:Course', $courseId); + + if (empty($course)) { + return []; + } + + $item = $this->getSubscriptionItemByProduct( + $course->getId(), + self::PRODUCT_TYPE_COURSE, + $coupon + ); + + if (empty($item)) { + return []; + } + + $courseDescription = $entityManager->getRepository('ChamiloCourseBundle:CCourseDescription') + ->findOneBy( + [ + 'cId' => $course->getId(), + 'sessionId' => 0, + ], + [ + 'descriptionType' => 'ASC', + ] + ); + + $globalParameters = $this->getGlobalParameters(); + $courseInfo = [ + 'id' => $course->getId(), + 'title' => $course->getTitle(), + 'description' => $courseDescription ? $courseDescription->getContent() : null, + 'code' => $course->getCode(), + 'visual_code' => $course->getVisualCode(), + 'teachers' => [], + 'item' => $item, + 'tax_name' => $globalParameters['tax_name'], + 'tax_enable' => $this->checkTaxEnabledInProduct(self::TAX_APPLIES_TO_ONLY_COURSE), + 'course_img' => null, + ]; + + $courseTeachers = $course->getTeachers(); + + foreach ($courseTeachers as $teachers) { + $user = $teachers->getUser(); + $teacher['id'] = $user->getId(); + $teacher['name'] = $user->getCompleteName(); + $courseInfo['teachers'][] = $teacher; + } + + $possiblePath = api_get_path(SYS_COURSE_PATH); + $possiblePath .= $course->getDirectory(); + $possiblePath .= '/course-pic.png'; + + if (file_exists($possiblePath)) { + $courseInfo['course_img'] = api_get_path(WEB_COURSE_PATH).$course->getDirectory().'/course-pic.png'; + } + + return $courseInfo; + } + + /** + * Get session info. + * + * @param array $sessionId The session ID + * + * @return array + */ + public function getSubscriptionSessionInfo($sessionId, $coupon = null) + { + $entityManager = Database::getManager(); + $session = $entityManager->find('ChamiloCoreBundle:Session', $sessionId); + + if (empty($session)) { + return []; + } + + $item = $this->getSubscriptionItemByProduct( + $session->getId(), + self::PRODUCT_TYPE_SESSION, + $coupon + ); + + if (empty($item)) { + return []; + } + + $sessionDates = SessionManager::parseSessionDates( + [ + 'display_start_date' => $session->getDisplayStartDate(), + 'display_end_date' => $session->getDisplayEndDate(), + 'access_start_date' => $session->getAccessStartDate(), + 'access_end_date' => $session->getAccessEndDate(), + 'coach_access_start_date' => $session->getCoachAccessStartDate(), + 'coach_access_end_date' => $session->getCoachAccessEndDate(), + ] + ); + + $globalParameters = $this->getGlobalParameters(); + $sessionInfo = [ + 'id' => $session->getId(), + 'name' => $session->getName(), + 'description' => $session->getDescription(), + 'dates' => $sessionDates, + 'courses' => [], + 'tax_name' => $globalParameters['tax_name'], + 'tax_enable' => $this->checkTaxEnabledInProduct(self::TAX_APPLIES_TO_ONLY_SESSION), + 'image' => null, + 'nbrCourses' => $session->getNbrCourses(), + 'nbrUsers' => $session->getNbrUsers(), + 'item' => $item, + 'duration' => $session->getDuration(), + ]; + + $fieldValue = new ExtraFieldValue('session'); + $sessionImage = $fieldValue->get_values_by_handler_and_field_variable( + $session->getId(), + 'image' + ); + + if (!empty($sessionImage)) { + $sessionInfo['image'] = api_get_path(WEB_UPLOAD_PATH).$sessionImage['value']; + } + + $sessionCourses = $session->getCourses(); + foreach ($sessionCourses as $sessionCourse) { + $course = $sessionCourse->getCourse(); + $sessionCourseData = [ + 'title' => $course->getTitle(), + 'coaches' => [], + ]; + + $userCourseSubscriptions = $session->getUserCourseSubscriptionsByStatus( + $course, + Chamilo\CoreBundle\Entity\Session::COACH + ); + + foreach ($userCourseSubscriptions as $userCourseSubscription) { + $user = $userCourseSubscription->getUser(); + $coaches['id'] = $user->getUserId(); + $coaches['name'] = $user->getCompleteName(); + $sessionCourseData['coaches'][] = $coaches; + } + + $sessionInfo['courses'][] = $sessionCourseData; + } + + return $sessionInfo; + } + + /** + * Register a sale. + * + * @param int $itemId The product ID + * @param int $paymentType The payment type + * @param string $couponId The coupon ID + * + * @return bool + */ + public function registerSale($itemId, $paymentType, $couponId = null) + { + if (!in_array( + $paymentType, + [ self::PAYMENT_TYPE_PAYPAL, self::PAYMENT_TYPE_TRANSFER, self::PAYMENT_TYPE_CULQI, @@ -2452,6 +2940,45 @@ class BuyCoursesPlugin extends Plugin } } + /** + * Register the users payouts. + * + * @param int $saleId The subscription sale ID + * + * @return array + */ + public function storeSubscriptionPayouts($saleId) + { + $payoutsTable = Database::get_main_table(self::TABLE_PAYPAL_PAYOUTS); + $platformCommission = $this->getPlatformCommission(); + + $sale = $this->getSubscriptionSale($saleId); + $commission = (int) $platformCommission['commission']; + $teachersCommission = number_format( + (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' => api_get_utc_datetime(), + 'sale_id' => (int) $saleId, + 'user_id' => $beneficiary['user_id'], + 'commission' => number_format( + (floatval($teachersCommission) * $beneficiaryCommission) / 100, + 2 + ), + 'status' => self::PAYOUT_STATUS_PENDING, + ] + ); + } + } + /** * Register the users payouts. * @@ -3369,6 +3896,30 @@ class BuyCoursesPlugin extends Plugin return Database::insert(self::TABLE_COUPON_SERVICE_SALE, $values); } + /** + * Register a coupon sale. + * + * @param int $saleId The sale ID + * @param int $couponId The coupon ID + * + * @return int + */ + public function registerCouponSubscriptionSale($saleId, $couponId) + { + $sale = $this->getSubscriptionSale($saleId); + + if (empty($sale)) { + return false; + } + + $values = [ + 'coupon_id' => (int) $couponId, + 'sale_id' => (int) $saleId, + ]; + + return Database::insert(self::TABLE_COUPON_SUBSCRIPTION_SALE, $values); + } + /** * Add a new coupon. * @@ -3657,33 +4208,792 @@ class BuyCoursesPlugin extends Plugin } /** - * @return string + * Register a subscription sale. + * + * @param int $productId The product ID + * @param int $productType The product type + * @param int $paymentType The payment type + * @param int $duration The subscription duration + * @param string $couponId The coupon ID + * + * @return int */ - public function getSubscriptionSuccessMessage(array $saleInfo) + public function registerSubscriptionSale($productId, $productType, $paymentType, $duration, $couponId = null) { - switch ($saleInfo['product_type']) { - case self::PRODUCT_TYPE_COURSE: - $courseInfo = api_get_course_info_by_id($saleInfo['product_id']); - $url = api_get_course_url($courseInfo['code']); - break; - case self::PRODUCT_TYPE_SESSION: - $sessionId = (int) $saleInfo['product_id']; - $url = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$sessionId; - break; - default: - $url = '#'; + if (!in_array( + $paymentType, + [ + self::PAYMENT_TYPE_PAYPAL, + self::PAYMENT_TYPE_TRANSFER, + self::PAYMENT_TYPE_CULQI, + self::PAYMENT_TYPE_TPV_REDSYS, + ] + ) + ) { + return false; } - return Display::return_message( - sprintf( - $this->get_lang('SubscriptionToCourseXSuccessful'), - $url, - $saleInfo['product_name'] - ), - 'success', - false - ); - } + $entityManager = Database::getManager(); + $item = $this->getSubscriptionItem($productId, $productType); + + if (empty($item)) { + return false; + } + + $productName = ''; + if ($item['product_type'] == self::PRODUCT_TYPE_COURSE) { + $course = $entityManager->find('ChamiloCoreBundle:Course', $item['product_id']); + + if (empty($course)) { + return false; + } + + $productName = $course->getTitle(); + } elseif ($item['product_type'] == self::PRODUCT_TYPE_SESSION) { + $session = $entityManager->find('ChamiloCoreBundle:Session', $item['product_id']); + + if (empty($session)) { + return false; + } + + $productName = $session->getName(); + } + + if ($couponId != null) { + $coupon = $this->getCoupon($couponId, $item['product_type'], $item['product_id']); + } + + $couponDiscount = 0; + $priceWithoutDiscount = 0; + if ($coupon != null) { + if ($coupon['discount_type'] == self::COUPON_DISCOUNT_TYPE_AMOUNT) { + $couponDiscount = $coupon['discount_amount']; + } elseif ($coupon['discount_type'] == self::COUPON_DISCOUNT_TYPE_PERCENTAGE) { + $couponDiscount = ($item['price'] * $coupon['discount_amount']) / 100; + } + $priceWithoutDiscount = $item['price']; + } + $item['price'] = $item['price'] - $couponDiscount; + $price = $item['price']; + $priceWithoutTax = null; + $taxPerc = null; + $taxAmount = 0; + $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 && $item['product_type'] == self::PRODUCT_TYPE_COURSE) || + ($taxAppliesTo == self::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; + } + + $subscriptionEnd = Date('y:m:d', strtotime('+'. $duration .' days')); + + $values = [ + 'reference' => $this->generateReference( + api_get_user_id(), + $item['product_type'], + $item['product_id'] + ), + 'currency_id' => $item['currency_id'], + 'date' => api_get_utc_datetime(), + 'user_id' => api_get_user_id(), + 'product_type' => $item['product_type'], + 'product_name' => $productName, + 'product_id' => $item['product_id'], + 'price' => $price, + 'price_without_tax' => $priceWithoutTax, + 'tax_perc' => $taxPerc, + 'tax_amount' => $taxAmount, + 'status' => self::SALE_STATUS_PENDING, + 'payment_type' => (int) $paymentType, + 'price_without_discount' => $priceWithoutDiscount, + 'discount_amount' => $couponDiscount, + 'subscription_end' => $subscriptionEnd, + ]; + + return Database::insert(self::TABLE_SUBSCRIPTION_SALE, $values); + } + + /** + * Add a new subscription. + * + * @param array $subscription + * + * @return bool + */ + public function addNewSubscription($subscription) + { + $result = false; + + if(isset($subscription['frequencies'])) { + foreach ($subscription['frequencies'] as $frequency) { + $subscriptionDb = $this->getSubscription($subscription['product_type'], $subscription['product_id'], $frequency['duration']); + + if (!isset($subscriptionDb) || empty($subscription)) { + Display::addFlash( + Display::return_message( + $this->get_lang('SubscriptionAlreadyExists').' ('.$frequency['duration'].')', + 'error', + false + ) + ); + + return false; + } else { + $subscriptionId = $this->registerSubscription($subscription, $frequency); + if ($subscriptionId) { + $result = true; + } else { + Display::addFlash( + Display::return_message( + $this->get_lang('SubscriptionErrorInsert'), + 'error', + false + ) + ); + + return false; + } + } + } + } else { + Display::addFlash( + Display::return_message( + $this->get_lang('FrequenciesNotSetError'), + 'error', + false + ) + ); + + return false ; + } + + return $result ; + } + + /** + * Add a new subscription. + * + * @param array $subscription + * + * @return bool + */ + public function updateSubscriptions($productType, $productId, $taxPerc) + { + $this->updateSubscription($productType, $productId, $taxPerc); + } + + /** + * Delete a subscription. + * + * @param int $productType + * @param int $productId + * @param int $duration + * + * @return int + */ + public function deleteSubscription($productType, $productId, $duration) + { + return Database::delete( + Database::get_main_table(self::TABLE_SUBSCRIPTION), + [ + 'product_type = ? AND ' => (int) $productType, + 'product_id = ? AND ' => (int) $productId, + 'duration = ? ' => (int) $duration, + ] + ); + } + + /** + * Get a list of subscriptions by product ID and type. + * + * @param string $productId The product ID + * @param int $productType The product type + * + * @return array Subscriptions data + */ + public function getSubscriptions($productType, $productId) + { + $subscriptions = $this->getDataSubscriptions($productType, $productId); + + return $subscriptions; + } + + /** + * Get data of the subscription. + * + * @param string $productId The product ID + * @param int $productType The product type + * @param int $duration The duration + * + * @return array The subscription data + */ + public function getSubscription($productType, $productId, $duration, $coupon = null) + { + $subscription = $this->getDataSubscription($productType, $productId, $duration); + + $currency = $this->getSelectedCurrency(); + $isoCode = $currency['iso_code']; + + $subscription['iso_code'] = $isoCode; + + $this->setPriceSettings($subscription, self::TAX_APPLIES_TO_ONLY_COURSE, $coupon); + + return $subscription; + } + + /** + * Get subscription sale data by ID. + * + * @param int $saleId The sale ID + * + * @return array + */ + public function getSubscriptionSale($saleId) + { + return Database::select( + '*', + Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE), + [ + 'where' => ['id = ?' => (int) $saleId], + ], + 'first' + ); + } + + /** + * Complete subscription sale process. Update sale status to completed. + * + * @param int $saleId The subscription sale ID + * + * @return bool + */ + public function completeSubscriptionSale($saleId) + { + $sale = $this->getSubscriptionSale($saleId); + + if ($sale['status'] == self::SALE_STATUS_COMPLETED) { + return true; + } + + $saleIsCompleted = false; + switch ($sale['product_type']) { + case self::PRODUCT_TYPE_COURSE: + $course = api_get_course_info_by_id($sale['product_id']); + $saleIsCompleted = CourseManager::subscribeUser($sale['user_id'], $course['code']); + break; + case self::PRODUCT_TYPE_SESSION: + SessionManager::subscribeUsersToSession( + $sale['product_id'], + [$sale['user_id']], + api_get_session_visibility($sale['product_id']), + false + ); + + $saleIsCompleted = true; + break; + } + + if ($saleIsCompleted) { + $this->updateSubscriptionSaleStatus($sale['id'], self::SALE_STATUS_COMPLETED); + if ($this->get('invoicing_enable') === 'true') { + $this->setInvoice($sale['id']); + } + } + + return $saleIsCompleted; + } + + /** + * Update subscription sale status to canceled. + * + * @param int $saleId The subscription sale ID + */ + public function cancelSubscriptionSale($saleId) + { + $this->updateSubscriptionSaleStatus($saleId, self::SALE_STATUS_CANCELED); + } + + /** + * Get a list of subscription sales by the status. + * + * @param int $status The status to filter + * + * @return array The sale list. Otherwise return false + */ + public function getSubscriptionSaleListByStatus($status = self::SALE_STATUS_PENDING) + { + $saleTable = Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE); + $currencyTable = Database::get_main_table(self::TABLE_CURRENCY); + $userTable = Database::get_main_table(TABLE_MAIN_USER); + + $innerJoins = " + INNER JOIN $currencyTable c ON s.currency_id = c.id + INNER JOIN $userTable u ON s.user_id = u.id + "; + + return Database::select( + ['c.iso_code', 'u.firstname', 'u.lastname', 'u.email', 's.*'], + "$saleTable s $innerJoins", + [ + 'where' => ['s.status = ?' => (int) $status], + 'order' => 'id DESC', + ] + ); + } + + /** + * Get the list statuses for subscriptions sales. + * + * @param string $dateStart + * @param string $dateEnd + * + * @throws Exception + * + * @return array + */ + public function getSubscriptionSaleListReport($dateStart = null, $dateEnd = null) + { + $saleTable = Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE); + $currencyTable = Database::get_main_table(self::TABLE_CURRENCY); + $userTable = Database::get_main_table(TABLE_MAIN_USER); + $innerJoins = " + INNER JOIN $currencyTable c ON s.currency_id = c.id + INNER JOIN $userTable u ON s.user_id = u.id + "; + $list = Database::select( + ['c.iso_code', 'u.firstname', 'u.lastname', 'u.email', 's.*'], + "$saleTable s $innerJoins", + [ + 'order' => 'id DESC', + ] + ); + $listExportTemp = []; + $listExport = []; + $textStatus = null; + $paymentTypes = $this->getPaymentTypes(); + $productTypes = $this->getProductTypes(); + foreach ($list as $item) { + $statusSaleOrder = $item['status']; + switch ($statusSaleOrder) { + case 0: + $textStatus = $this->get_lang('SaleStatusPending'); + break; + case 1: + $textStatus = $this->get_lang('SaleStatusCompleted'); + break; + case -1: + $textStatus = $this->get_lang('SaleStatusCanceled'); + break; + } + $dateFilter = new DateTime($item['date']); + $listExportTemp[] = [ + 'id' => $item['id'], + 'reference' => $item['reference'], + 'status' => $textStatus, + 'status_filter' => $item['status'], + 'date' => $dateFilter->format('Y-m-d'), + 'order_time' => $dateFilter->format('H:i:s'), + 'price' => $item['iso_code'].' '.$item['price'], + 'product_type' => $productTypes[$item['product_type']], + 'product_name' => $item['product_name'], + 'payment_type' => $paymentTypes[$item['payment_type']], + 'complete_user_name' => api_get_person_name($item['firstname'], $item['lastname']), + 'email' => $item['email'], + ]; + } + $listExport[] = [ + get_lang('Number'), + $this->get_lang('OrderStatus'), + $this->get_lang('OrderDate'), + $this->get_lang('OrderTime'), + $this->get_lang('PaymentMethod'), + $this->get_lang('SalePrice'), + $this->get_lang('ProductType'), + $this->get_lang('ProductName'), + $this->get_lang('UserName'), + get_lang('Email'), + ]; + //Validation Export + $dateStart = strtotime($dateStart); + $dateEnd = strtotime($dateEnd); + foreach ($listExportTemp as $item) { + $dateFilter = strtotime($item['date']); + if (($dateFilter >= $dateStart) && ($dateFilter <= $dateEnd)) { + $listExport[] = [ + 'id' => $item['id'], + 'status' => $item['status'], + 'date' => $item['date'], + 'order_time' => $item['order_time'], + 'payment_type' => $item['payment_type'], + 'price' => $item['price'], + 'product_type' => $item['product_type'], + 'product_name' => $item['product_name'], + 'complete_user_name' => $item['complete_user_name'], + 'email' => $item['email'], + ]; + } + } + + return $listExport; + } + + /** + * Get a list of subscription sales by the user. + * + * @param string $term The search term + * + * @return array The sale list. Otherwise return false + */ + public function getSubscriptionSaleListByUser($term) + { + $term = trim($term); + + if (empty($term)) { + return []; + } + + $saleTable = Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE); + $currencyTable = Database::get_main_table(self::TABLE_CURRENCY); + $userTable = Database::get_main_table(TABLE_MAIN_USER); + $innerJoins = " + INNER JOIN $currencyTable c ON s.currency_id = c.id + INNER JOIN $userTable u ON s.user_id = u.id + "; + + return Database::select( + ['c.iso_code', 'u.firstname', 'u.lastname', 'u.email', 's.*'], + "$saleTable s $innerJoins", + [ + 'where' => [ + 'u.username LIKE %?% OR ' => $term, + 'u.lastname LIKE %?% OR ' => $term, + 'u.firstname LIKE %?%' => $term, + ], + 'order' => 'id DESC', + ] + ); + } + + /** + * Get a list of subscription sales by the user id. + * + * @param int $id The user id + * + * @return array The sale list. Otherwise return false + */ + public function getSubscriptionSaleListByUserId($id) + { + if (empty($id)) { + return []; + } + + $saleTable = Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE); + $currencyTable = Database::get_main_table(self::TABLE_CURRENCY); + $userTable = Database::get_main_table(TABLE_MAIN_USER); + + $innerJoins = " + INNER JOIN $currencyTable c ON s.currency_id = c.id + INNER JOIN $userTable u ON s.user_id = u.id + "; + + return Database::select( + ['c.iso_code', 'u.firstname', 'u.lastname', 's.*'], + "$saleTable s $innerJoins", + [ + 'where' => [ + 'u.id = ? AND s.status = ?' => [(int) $id, self::SALE_STATUS_COMPLETED], + ], + 'order' => 'id DESC', + ] + ); + } + + /** + * Get a list of subscription sales by date range. + * + * @param string $dateStart + * @param string $dateEnd + * + * @return array The sale list. Otherwise return false + */ + public function getSubscriptionSaleListByDate($dateStart, $dateEnd) + { + $dateStart = trim($dateStart); + $dateEnd = trim($dateEnd); + if (empty($dateStart)) { + return []; + } + if (empty($dateEnd)) { + return []; + } + $saleTable = Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE); + $currencyTable = Database::get_main_table(self::TABLE_CURRENCY); + $userTable = Database::get_main_table(TABLE_MAIN_USER); + $innerJoins = " + INNER JOIN $currencyTable c ON s.currency_id = c.id + INNER JOIN $userTable u ON s.user_id = u.id + "; + + return Database::select( + ['c.iso_code', 'u.firstname', 'u.lastname', 'u.email', 's.*'], + "$saleTable s $innerJoins", + [ + 'where' => [ + 's.date BETWEEN ? AND ' => $dateStart, + ' ? ' => $dateEnd, + ], + 'order' => 'id DESC', + ] + ); + } + + /** + * Get a list of subscription sales by the user Email. + * + * @param string $term The search term + * + * @return array The sale list. Otherwise return false + */ + public function getSubscriptionSaleListByEmail($term) + { + $term = trim($term); + if (empty($term)) { + return []; + } + $saleTable = Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE); + $currencyTable = Database::get_main_table(self::TABLE_CURRENCY); + $userTable = Database::get_main_table(TABLE_MAIN_USER); + $innerJoins = " + INNER JOIN $currencyTable c ON s.currency_id = c.id + INNER JOIN $userTable u ON s.user_id = u.id + "; + + return Database::select( + ['c.iso_code', 'u.firstname', 'u.lastname', 'u.email', 's.*'], + "$saleTable s $innerJoins", + [ + 'where' => [ + 'u.email LIKE %?% ' => $term, + ], + 'order' => 'id DESC', + ] + ); + } + + /** + * Get subscription sale data by ID. + * + * @param date $date The date + * + * @return array + */ + public function getSubscriptionsDue($date) + { + return Database::select( + 'id, user_id, product_id, product_type', + Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE), + [ + 'where' => ['subscription_end < ? AND status <> ? AND (expired is NULL OR expired <> ?)' => [ + $date, + self::SALE_STATUS_COMPLETED, + 1, + ] + ], + ], + 'first' + ); + } + + /** + * Get subscription sale data by ID. + * + * @param int $userId The user ID + * @param int $productId The product ID + * @param int $productType The product type + * + * @return array + */ + public function checkItemSubscriptionActive($userId, $productId, $productType) + { + return Database::select( + '*', + Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE), + [ + 'where' => ['subscription_end >= ? AND userId = ? AND productId = ? AND productType = ? AND status <> ?' => [ + api_get_utc_datetime(), + $userId, + $productId, + $productType, + self::SALE_STATUS_COMPLETED, + ] + ], + ], + 'first' + ); + } + + /** + * Get subscription sale data by ID. + * + * @param int $date The date + * + * @return array + */ + public function updateSubscriptionSaleExpirationStatus($id) + { + $saleTable = Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE); + + return Database::update( + $saleTable, + ['expired' => 1], + ['id = ?' => (int) $id] + ); + } + + /** + * Get the list of frequencies discount types. + * + * @return array + */ + public function getFrequencies() + { + $data = Database::select( + '*', + Database::get_main_table(self::TABLE_SUBSCRIPTION_PERIOD), + [] + ); + + $frequenciesList = $this->getFrequenciesList(); + $frequencies = array(); + + foreach($data as $key => $items) { + $frequencies[$items['duration']] = $items['name']; + } + + return $frequencies; + } + + /** + * Get the list of frequencies discount types. + * + * @return array + */ + public function getFrequenciesList() + { + return Database::select( + '*', + Database::get_main_table(self::TABLE_SUBSCRIPTION_PERIOD), + [] + ); + } + + /** + * Get the a frequency + * + * @return array + */ + public function selectFrequency($duration) + { + return Database::select( + '*', + Database::get_main_table(self::TABLE_SUBSCRIPTION_PERIOD), + [ + 'where' => [ + 'duration = ?' => [ + (int) $duration, + ], + ], + ], + 'first' + ); + } + + /** + * Add a new subscription frequency. + * + * @return array + */ + public function addFrequency($duration, $name) + { + $values = [ + 'duration' => (int) $duration, + 'name' => (string) $name, + ]; + + return Database::insert(self::TABLE_SUBSCRIPTION_PERIOD, $values); + } + + /** + * Update a subscription frequency. + * + * @return array + */ + public function updateFrequency($duration, $name) + { + $periodTable = Database::get_main_table(self::TABLE_SUBSCRIPTION_PERIOD); + + return Database::update( + $periodTable, + ['name' => (string) $name], + ['duration = ?' => (int) $duration] + ); + } + + /** + * Delete a subscription frequency. + * + * @return array + */ + public function deleteFrequency($duration) + { + return Database::delete( + Database::get_main_table(self::TABLE_SUBSCRIPTION_PERIOD), + [ + 'duration = ?' => (int) $duration, + ] + ); + } + + /** + * @return string + */ + public function getSubscriptionSuccessMessage(array $saleInfo) + { + switch ($saleInfo['product_type']) { + case self::PRODUCT_TYPE_COURSE: + $courseInfo = api_get_course_info_by_id($saleInfo['product_id']); + $url = api_get_course_url($courseInfo['code']); + break; + case self::PRODUCT_TYPE_SESSION: + $sessionId = (int) $saleInfo['product_id']; + $url = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$sessionId; + break; + default: + $url = '#'; + } + + return Display::return_message( + sprintf( + $this->get_lang('SubscriptionToCourseXSuccessful'), + $url, + $saleInfo['product_name'] + ), + 'success', + false + ); + } /** * @param string $baseUrl @@ -3968,30 +5278,174 @@ class BuyCoursesPlugin extends Plugin 'user' => $userId, ]); - if (!empty($userSubscription)) { - return 'YES'; + if (!empty($userSubscription)) { + return 'YES'; + } + + return 'NO'; + } + + /** + * Update the sale status. + * + * @param int $saleId The sale ID + * @param int $newStatus The new status + * + * @return bool + */ + private function updateSaleStatus($saleId, $newStatus = self::SALE_STATUS_PENDING) + { + $saleTable = Database::get_main_table(self::TABLE_SALE); + + return Database::update( + $saleTable, + ['status' => (int) $newStatus], + ['id = ?' => (int) $saleId] + ); + } + + /** + * Search filtered sessions by name, and range of price. + * + * @param int $start + * @param int $end + * @param string $name Optional. The name filter + * @param int $min Optional. The minimun price filter + * @param int $max Optional. The maximum price filter + * @param string $max Optional. all and count + * @param int $sessionCategory Optional. Session category id + * + * @return array + */ + private function filterSessionList($start, $end, $name = null, $min = 0, $max = 0, $typeResult = 'all', $sessionCategory = 0) + { + $itemTable = Database::get_main_table(self::TABLE_ITEM); + $sessionTable = Database::get_main_table(TABLE_MAIN_SESSION); + + $min = floatval($min); + $max = floatval($max); + $sessionCategory = (int) $sessionCategory; + + $innerJoin = "$itemTable i ON s.id = i.product_id"; + $whereConditions = [ + 'i.product_type = ? ' => self::PRODUCT_TYPE_SESSION, + ]; + + if (!empty($name)) { + $whereConditions['AND s.name LIKE %?%'] = $name; + } + + if (!empty($min)) { + $whereConditions['AND i.price >= ?'] = $min; + } + + if (!empty($max)) { + $whereConditions['AND i.price <= ?'] = $max; + } + + $start = (int) $start; + $end = (int) $end; + + if ($sessionCategory != 0) { + $whereConditions['AND s.session_category_id = ?'] = $sessionCategory; + } + + $sessionIds = Database::select( + 's.id', + "$sessionTable s INNER JOIN $innerJoin", + ['where' => $whereConditions, 'limit' => "$start, $end"], + $typeResult + ); + + if ($typeResult === 'count') { + return $sessionIds; + } + + if (!$sessionIds) { + return []; + } + + $sessions = []; + + foreach ($sessionIds as $sessionId) { + $sessions[] = Database::getManager()->find( + 'ChamiloCoreBundle:Session', + $sessionId + ); + } + + return $sessions; + } + + /** + * Search filtered courses by name, and range of price. + * + * @param string $name Optional. The name filter + * @param int $min Optional. The minimun price filter + * @param int $max Optional. The maximum price filter + * + * @return array + */ + private function filterCourseList($start, $end, $name = '', $min = 0, $max = 0, $typeResult = 'all') + { + $itemTable = Database::get_main_table(self::TABLE_ITEM); + $courseTable = Database::get_main_table(TABLE_MAIN_COURSE); + $urlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE); + + $urlId = api_get_current_access_url_id(); + + $min = floatval($min); + $max = floatval($max); + + $whereConditions = [ + 'i.product_type = ? ' => self::PRODUCT_TYPE_COURSE, + ]; + + if (!empty($name)) { + $whereConditions['AND c.title LIKE %?%'] = $name; + } + + if (!empty($min)) { + $whereConditions['AND i.price >= ?'] = $min; + } + + if (!empty($max)) { + $whereConditions['AND i.price <= ?'] = $max; + } + + $whereConditions['AND url.access_url_id = ?'] = $urlId; + $start = (int) $start; + $end = (int) $end; + + $courseIds = Database::select( + 'c.id', + "$courseTable c + INNER JOIN $itemTable i + ON c.id = i.product_id + INNER JOIN $urlTable url + ON c.id = url.c_id + ", + ['where' => $whereConditions, 'limit' => "$start, $end"], + $typeResult + ); + + if ($typeResult === 'count') { + return $courseIds; } - return 'NO'; - } + if (!$courseIds) { + return []; + } - /** - * Update the sale status. - * - * @param int $saleId The sale ID - * @param int $newStatus The new status - * - * @return bool - */ - private function updateSaleStatus($saleId, $newStatus = self::SALE_STATUS_PENDING) - { - $saleTable = Database::get_main_table(self::TABLE_SALE); + $courses = []; + foreach ($courseIds as $courseId) { + $courses[] = Database::getManager()->find( + 'ChamiloCoreBundle:Course', + $courseId + ); + } - return Database::update( - $saleTable, - ['status' => (int) $newStatus], - ['id = ?' => (int) $saleId] - ); + return $courses; } /** @@ -4000,39 +5454,27 @@ class BuyCoursesPlugin extends Plugin * @param int $start * @param int $end * @param string $name Optional. The name filter - * @param int $min Optional. The minimun price filter - * @param int $max Optional. The maximum price filter * @param string $max Optional. all and count * @param int $sessionCategory Optional. Session category id * * @return array */ - private function filterSessionList($start, $end, $name = null, $min = 0, $max = 0, $typeResult = 'all', $sessionCategory = 0) + private function filterSubscriptionSessionList($start, $end, $name = null, $typeResult = 'all', $sessionCategory = 0) { - $itemTable = Database::get_main_table(self::TABLE_ITEM); + $subscriptionTable = Database::get_main_table(self::TABLE_SUBSCRIPTION); $sessionTable = Database::get_main_table(TABLE_MAIN_SESSION); - $min = floatval($min); - $max = floatval($max); $sessionCategory = (int) $sessionCategory; - $innerJoin = "$itemTable i ON s.id = i.product_id"; + $innerJoin = "$subscriptionTable st ON s.id = st.product_id"; $whereConditions = [ - 'i.product_type = ? ' => self::PRODUCT_TYPE_SESSION, + 'st.product_type = ? ' => self::PRODUCT_TYPE_SESSION, ]; if (!empty($name)) { $whereConditions['AND s.name LIKE %?%'] = $name; } - if (!empty($min)) { - $whereConditions['AND i.price >= ?'] = $min; - } - - if (!empty($max)) { - $whereConditions['AND i.price <= ?'] = $max; - } - $start = (int) $start; $end = (int) $end; @@ -4041,7 +5483,7 @@ class BuyCoursesPlugin extends Plugin } $sessionIds = Database::select( - 's.id', + 'DISTINCT s.id', "$sessionTable s INNER JOIN $innerJoin", ['where' => $whereConditions, 'limit' => "$start, $end"], $typeResult @@ -4068,50 +5510,41 @@ class BuyCoursesPlugin extends Plugin } /** - * Search filtered courses by name, and range of price. + * Search filtered subscriptions courses by name, and range of price. * - * @param string $name Optional. The name filter - * @param int $min Optional. The minimun price filter - * @param int $max Optional. The maximum price filter + * @param int $start + * @param int $end + * @param string $name Optional. The name filter + * @param string $max Optional. all and count + * @param int $sessionCategory Optional. Session category id * * @return array */ - private function filterCourseList($start, $end, $name = '', $min = 0, $max = 0, $typeResult = 'all') + private function filterSubscriptionCourseList($start, $end, $name = '', $typeResult = 'all') { - $itemTable = Database::get_main_table(self::TABLE_ITEM); + $subscriptionTable = Database::get_main_table(self::TABLE_SUBSCRIPTION); $courseTable = Database::get_main_table(TABLE_MAIN_COURSE); $urlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE); $urlId = api_get_current_access_url_id(); - $min = floatval($min); - $max = floatval($max); - $whereConditions = [ - 'i.product_type = ? ' => self::PRODUCT_TYPE_COURSE, + 'st.product_type = ? ' => self::PRODUCT_TYPE_COURSE, ]; if (!empty($name)) { $whereConditions['AND c.title LIKE %?%'] = $name; } - if (!empty($min)) { - $whereConditions['AND i.price >= ?'] = $min; - } - - if (!empty($max)) { - $whereConditions['AND i.price <= ?'] = $max; - } - $whereConditions['AND url.access_url_id = ?'] = $urlId; $start = (int) $start; $end = (int) $end; $courseIds = Database::select( - 'c.id', + 'DISTINCT c.id', "$courseTable c - INNER JOIN $itemTable i - ON c.id = i.product_id + INNER JOIN $subscriptionTable st + ON c.id = st.product_id INNER JOIN $urlTable url ON c.id = url.c_id ", @@ -4601,4 +6034,230 @@ class BuyCoursesPlugin extends Plugin ] ); } + + /** + * Get an array of subscriptions. + * + * @param int $productType The product type + * @param int $productId The product ID + * + * @return array Subscriptions data + */ + private function getDataSubscriptions($productType, $productId) + { + $subscriptionTable = Database::get_main_table(self::TABLE_SUBSCRIPTION); + + return Database::select( + ['*'], + $subscriptionTable, + [ + 'where' => [ + 'product_type = ? AND ' => (int) $productType, + 'product_id = ? ' => (int) $productId, + ], + 'order' => 'duration ASC', + ] + ); + } + + /** + * Get data of a subscription for a product (course or service) by the subscription ID. + * + * @param int $productType The product type + * @param int $productId The product ID + * @param int $duration The duration + * + * @return array The subscription data + */ + private function getDataSubscription($productType, $productId, $duration) + { + $subscriptionTable = Database::get_main_table(self::TABLE_SUBSCRIPTION); + + return Database::select( + ['*'], + $subscriptionTable, + [ + 'where' => [ + 'product_type = ? AND ' => (int) $productType, + 'product_id = ? AND ' => (int) $productId, + 'duration = ? ' => (int) $duration, + ], + ], + 'first' + ); + } + + /** + * Update a subscription. + * + * @param array $subscription + * + * @return int + */ + private function updateSubscription($productType, $productId, $taxPerc) + { + $values = [ + 'tax_perc' => (int) $taxPerc, + ]; + + return Database::update( + self::TABLE_SUBSCRIPTION, + $values, + [ + 'product_type = ? AND ' => $productType, + 'product_id = ?' => $productId + ] + ); + + return true; + } + + /** + * Register a subscription. + * + * @param array $subscription + * + * @return int + */ + private function registerSubscription($subscription, $frequency) + { + $values = [ + 'product_type' => (int) $subscription['product_type'], + 'product_id' => (int) $subscription['product_id'], + 'duration' => (int) $frequency['duration'], + 'currency_id' => (int) $subscription['currency_id'], + 'tax_perc' => (int) $subscription['tax_perc'], + 'price' => (float) $frequency['price'], + ]; + + Database::insert(self::TABLE_SUBSCRIPTION, $values); + + return true; + } + + /** + * Update the subscription sale status. + * + * @param int $saleId The sale ID + * @param int $newStatus The new status + * + * @return bool + */ + private function updateSubscriptionSaleStatus($saleId, $newStatus = self::SALE_STATUS_PENDING) + { + $saleTable = Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE); + + return Database::update( + $saleTable, + ['status' => (int) $newStatus], + ['id = ?' => (int) $saleId] + ); + } + + /** + * Get the user status for the subscription session. + * + * @param int $userId The user ID + * @param Session $session The session + * + * @return string + */ + private function getUserStatusForSubscriptionSession($userId, Session $session) + { + if (empty($userId)) { + return 'NO'; + } + + $entityManager = Database::getManager(); + $scuRepo = $entityManager->getRepository('ChamiloCoreBundle:SessionRelCourseRelUser'); + + $buySaleTable = Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE); + + // Check if user bought the course + $sale = Database::select( + 'COUNT(1) as qty', + $buySaleTable, + [ + 'where' => [ + 'user_id = ? AND product_type = ? AND product_id = ? AND status = ? AND (expired is NULL OR expired <> ?)' => [ + $userId, + self::PRODUCT_TYPE_SESSION, + $session->getId(), + self::SALE_STATUS_PENDING, + 1, + ], + ], + ], + 'first' + ); + + if ($sale['qty'] > 0) { + return 'TMP'; + } + + // Check if user is already subscribe to session + $userSubscription = $scuRepo->findBy([ + 'session' => $session, + 'user' => $userId, + ]); + + if (!empty($userSubscription)) { + return 'YES'; + } + + return 'NO'; + } + + /** + * Get the user status for the subscription course. + * + * @param int $userId The user Id + * @param Course $course The course + * + * @return string + */ + private function getUserStatusForSubscriptionCourse($userId, Course $course) + { + if (empty($userId)) { + return 'NO'; + } + + $entityManager = Database::getManager(); + $cuRepo = $entityManager->getRepository('ChamiloCoreBundle:CourseRelUser'); + $buySaleTable = Database::get_main_table(self::TABLE_SUBSCRIPTION_SALE); + + // Check if user bought the course + $sale = Database::select( + 'COUNT(1) as qty', + $buySaleTable, + [ + 'where' => [ + 'user_id = ? AND product_type = ? AND product_id = ? AND status = ? AND (expired is NULL OR expired <> ?)' => [ + $userId, + self::PRODUCT_TYPE_COURSE, + $course->getId(), + self::SALE_STATUS_PENDING, + 1, + ], + ], + ], + 'first' + ); + + if ($sale['qty'] > 0) { + return 'TMP'; + } + + // Check if user is already subscribe to course + $userSubscription = $cuRepo->findBy([ + 'course' => $course, + 'user' => $userId, + ]); + + if (!empty($userSubscription)) { + return 'YES'; + } + + return 'NO'; + } } diff --git a/plugin/buycourses/src/configure_frequency.php b/plugin/buycourses/src/configure_frequency.php new file mode 100644 index 0000000000..0647adff4c --- /dev/null +++ b/plugin/buycourses/src/configure_frequency.php @@ -0,0 +1,115 @@ +selectFrequency($_GET['d']); + + if (!empty($frequency)) { + $subscriptionsItems = $plugin->getSubscriptiosnItemsByDuration($_GET['d']); + + if (empty($subscriptionsItems)) { + $plugin->deleteFrequency($_GET['d']); + + Display::addFlash( + Display::return_message($plugin->get_lang('FrequencyRemoved'), 'success') + ); + } else { + Display::addFlash( + Display::return_message($plugin->get_lang('SubscriptionPeriodOnUse'), 'error') + ); + } + } + else{ + Display::addFlash( + Display::return_message($plugin->get_lang('FrequencyNotExits'), 'error') + ); + } + + header('Location: '.api_get_self()); + exit; + } +} + +$frequencies = $plugin->getFrequenciesList(); + +$globalSettingsParams = $plugin->getGlobalParameters(); + +$form = new FormValidator('add_frequency'); + +$form->addText('name', get_lang('Name'), false); + +$form->addElement( + 'number', + 'duration', + [$plugin->get_lang('Duration'), $plugin->get_lang('Days')], + ['step' => 1, 'placeholder' => $plugin->get_lang('SubscriptionFrequencyValueDays')] +); + +$button = $form->addButtonSave(get_lang('Save')); + +if ($form->validate()) { + $formValues = $form->getSubmitValues(); + $duration = $formValues['duration']; + $name = $formValues['name']; + + $frequency = $plugin->selectFrequency($duration); + + if (!empty($frequency)) { + $result = $plugin->updateFrequency($duration, $name); + + if (!isset($result)) { + Display::addFlash( + Display::return_message($plugin->get_lang('FrequencyNotUpdated'), 'error') + ); + } + } else { + $result = $plugin->addFrequency($duration, $name); + + if (!isset($result)) { + Display::addFlash( + Display::return_message($plugin->get_lang('FrequencyNotSaved'), 'error') + ); + } + } + + header('Location: '.api_get_path(WEB_PLUGIN_PATH).'buycourses/src/configure_frequency.php'); + + exit; +} + +$form->setDefaults($formDefaults); + +$templateName = $plugin->get_lang('FrequencyAdd'); +$interbreadcrumb[] = [ + 'url' => 'subscriptions_courses.php', + 'name' => get_lang('Configuration'), +]; +$interbreadcrumb[] = [ + 'url' => 'subscriptions_courses.php', + 'name' => $plugin->get_lang('SubscriptionList'), +]; + +$template = new Template($templateName); +$template->assign('header', $templateName); +$template->assign('items_form', $form->returnForm()); +$template->assign('frequencies_list', $frequencies); + +$content = $template->fetch('buycourses/view/configure_frequency.tpl'); +$template->assign('content', $content); + +$template->display_one_col_template(); diff --git a/plugin/buycourses/src/configure_subscription.php b/plugin/buycourses/src/configure_subscription.php new file mode 100644 index 0000000000..fdb1e873a5 --- /dev/null +++ b/plugin/buycourses/src/configure_subscription.php @@ -0,0 +1,246 @@ +get('include_sessions') === 'true'; + +if (isset($_GET['action'], $_GET['d'])) { + if ($_GET['action'] == 'delete_frequency') { + $plugin->deleteSubscription($type, $id, $_GET['d']); + + Display::addFlash( + Display::return_message(get_lang('ItemRemoved'), 'success') + ); + + header('Location: '.api_get_self().'?'.$queryString); + exit; + } +} + +$entityManager = Database::getManager(); +$userRepo = UserManager::getRepository(); +$currency = $plugin->getSelectedCurrency(); + +if (empty($currency)) { + Display::addFlash( + Display::return_message($plugin->get_lang('CurrencyIsNotConfigured'), 'error') + ); +} + +$subscriptions = $plugin->getSubscriptions($type, $id ); + +$taxtPerc = 0; + +if (isset($subscriptions) && !empty($subscriptions )) { + $taxtPerc = $subscriptions[0]['tax_perc']; +} + +$currencyIso = null; + +if ($editingCourse) { + $course = $entityManager->find('ChamiloCoreBundle:Course', $id); + if (!$course) { + api_not_allowed(true); + } + + $courseItem = $plugin->getCourseForConfiguration($course, $currency); + + $currencyIso = $courseItem['currency']; + $formDefaults = [ + 'product_type' => get_lang('Course'), + 'id' => $courseItem['course_id'], + 'type' => BuyCoursesPlugin::PRODUCT_TYPE_COURSE, + 'name' => $courseItem['course_title'], + 'visible' => $courseItem['visible'], + 'tax_perc' => $taxtPerc, + ]; +} else if ($editingSession) { + if (!$includeSession) { + api_not_allowed(true); + } + + $session = $entityManager->find('ChamiloCoreBundle:Session', $id); + if (!$session) { + api_not_allowed(true); + } + + $sessionItem = $plugin->getSessionForConfiguration($session, $currency); + + $currencyIso = $sessionItem['currency']; + $formDefaults = [ + 'product_type' => get_lang('Session'), + 'id' => $session->getId(), + 'type' => BuyCoursesPlugin::PRODUCT_TYPE_SESSION, + 'name' => $sessionItem['session_name'], + 'visible' => $sessionItem['visible'], + 'tax_perc' => $taxtPerc, + ]; +} else { + api_not_allowed(true); +} + +$globalSettingsParams = $plugin->getGlobalParameters(); + +$form = new FormValidator('add_subscription'); + +$form->addText('product_type', $plugin->get_lang('ProductType'), false); +$form->addText('name', get_lang('Name'), false); + +$form->freeze(['product_type', 'name']); + +$form->addElement( + 'number', + 'tax_perc', + [$plugin->get_lang('TaxPerc'), $plugin->get_lang('TaxPercDescription'), '%'], + ['step' => 1, 'placeholder' => $globalSettingsParams['global_tax_perc'].'% '.$plugin->get_lang('ByDefault')] +); + +$frequenciesOptions = $plugin->getFrequencies(); + +$frequencyForm = new FormValidator('frequency_config', 'post', api_get_self().'?'.$queryString); + +$frequencyFormDefaults = [ + 'id' => $id, + 'type' => $type, + 'tax_perc' => $taxtPerc, + 'currency_id' => $currency['id'], +]; + +$frequencyForm->setDefaults($frequencyFormDefaults); + +if ($frequencyForm->validate()) { + $frequencyFormValues = $frequencyForm->getSubmitValues(); + + $subscription['product_id'] = $frequencyFormValues['id']; + $subscription['product_type'] = $frequencyFormValues['type']; + $subscription['tax_perc'] = $frequencyFormValues['tax_perc'] != '' ? (int) $frequencyFormValues['tax_perc'] : null; + $subscription['currency_id'] = $currency['id']; + $duration = $frequencyFormValues['duration']; + $price = $frequencyFormValues['price']; + + for ($i = 0; $i <= count($subscriptions); $i++) { + if ($subscriptions[$i]['duration'] == $duration) { + Display::addFlash( + Display::return_message($plugin->get_lang('SubscriptionAlreadyExists'), 'error') + ); + + header('Location:'.api_get_self().'?'.$queryString); + exit; + } + } + + $subscription['frequencies'] = [['duration' => $duration, 'price' => $price]]; + + $result = $plugin->addNewSubscription($subscription); + + Display::addFlash( + Display::return_message(get_lang('Saved'), 'success') + ); + + header('Location:'.api_get_self().'?'.$queryString); + exit; +} + +$frequencyForm->addElement( + 'select', + 'duration', + $plugin->get_lang('Duration'), + $frequenciesOptions, + ['cols-size' => [2, 8, 2]] +); + +$frequencyForm->addElement( + 'number', + 'price', + [$plugin->get_lang('Price'), null, $currencyIso], + false, + [ + 'step' => 1, + 'cols-size' => [3, 8, 1] + ] +); + +$frequencyForm->addHidden('type', $type); +$frequencyForm->addHidden('id', $id); +$frequencyForm->addHidden('tax_perc', $taxtPerc); +$frequencyForm->addHidden('currency_id', $currency['id']); +$frequencyForm->addButtonCreate('Add'); + +for ($i = 0; $i <= count($subscriptions); $i++) { + if ($subscriptions[$i]['duration'] > 0) { + $subscriptions[$i]['durationName'] = $frequenciesOptions[$subscriptions[$i]['duration']]; + } +} + +$form->addHidden('type', $type); +$form->addHidden('id', $id); +$button = $form->addButtonSave(get_lang('Save')); + +if (empty($currency)) { + $button->setAttribute('disabled'); +} + +if ($form->validate()) { + $formValues = $form->getSubmitValues(); + $id = $formValues['id']; + $type = $formValues['type']; + $taxPerc = $formValues['tax_perc'] != '' ? (int) $formValues['tax_perc'] : null; + + $result = $plugin->updateSubscriptions($type, $id, $taxPerc); + + if ($result) { + header('Location: '.api_get_path(WEB_PLUGIN_PATH).'buycourses/src/subscriptions_courses.php'); + } else { + header('Location:'.api_get_self().'?'.$queryString); + } + + exit; +} + +$form->setDefaults($formDefaults); + +$templateName = $plugin->get_lang('SubscriptionAdd'); +$interbreadcrumb[] = [ + 'url' => 'subscriptions_courses.php', + 'name' => get_lang('Configuration'), +]; +$interbreadcrumb[] = [ + 'url' => 'subscriptions_courses.php', + 'name' => $plugin->get_lang('SubscriptionList'), +]; + +$template = new Template($templateName); +$template->assign('header', $templateName); +$template->assign('items_form', $form->returnForm()); +$template->assign('frequency_form', $frequencyForm->returnForm()); +$template->assign('subscriptions', $subscriptions); +$template->assign('currencyIso', $currencyIso); + +$content = $template->fetch('buycourses/view/configure_subscription.tpl'); +$template->assign('content', $content); + +$template->display_one_col_template(); diff --git a/plugin/buycourses/src/export_subscription_report.php b/plugin/buycourses/src/export_subscription_report.php new file mode 100644 index 0000000000..ba81299e86 --- /dev/null +++ b/plugin/buycourses/src/export_subscription_report.php @@ -0,0 +1,63 @@ +addDatePicker('date_start', get_lang('DateStart'), false); +$form->addDatePicker('date_end', get_lang('DateEnd'), false); +$form->addButton('export_sales', get_lang('ExportExcel'), 'check', 'primary'); +$salesStatus = []; + +if ($form->validate()) { + $reportValues = $form->getSubmitValues(); + + $dateStart = $reportValues['date_start']; + $dateEnd = $reportValues['date_end']; + + if ($dateStart == null || $dateEnd == null) { + Display::addFlash( + Display::return_message($plugin->get_lang('SelectDateRange'), 'error', false) + ); + } elseif ($dateStart > $dateEnd) { + Display::addFlash( + Display::return_message(get_lang('EndDateCannotBeBeforeTheStartDate'), 'error', false) + ); + } else { + $salesStatus = $plugin->getSubscriptionSaleListReport($dateStart, $dateEnd); + } +} + +if (!empty($salesStatus)) { + $archiveFile = 'export_report_sales_'.api_get_local_time(); + Export::arrayToXls($salesStatus, $archiveFile); +} +$interbreadcrumb[] = [ + 'url' => '../index.php', 'name' => $plugin->get_lang('plugin_title'), +]; +$interbreadcrumb[] = [ + 'url' => api_get_path(WEB_PLUGIN_PATH).'buycourses/src/subscription_sales_report.php', + 'name' => $plugin->get_lang('SubscriptionSalesReport'), +]; + +$templateName = $plugin->get_lang('ExportReport'); +$toolbar = Display::url( + Display::return_icon('back.png', get_lang('GoBack'), [], ICON_SIZE_MEDIUM), + api_get_path(WEB_PLUGIN_PATH).'buycourses/src/subscription_sales_report.php' +); +$template = new Template($templateName); +$template->assign( + 'actions', + Display::toolbarAction('toolbar', [$toolbar]) +); +$template->assign('form', $form->returnForm()); +$content = $template->fetch('buycourses/view/export_report.tpl'); +$template->assign('header', $templateName); +$template->assign('content', $content); +$template->display_one_col_template(); diff --git a/plugin/buycourses/src/process_subscription_confirm.php b/plugin/buycourses/src/process_subscription_confirm.php new file mode 100644 index 0000000000..2c334b8f88 --- /dev/null +++ b/plugin/buycourses/src/process_subscription_confirm.php @@ -0,0 +1,375 @@ +getSubscriptionSale($saleId); + +if (!empty($couponId)) { + $coupon = $plugin->getCoupon($couponId, $sale['product_type'], $sale['product_id']); +} + +$userInfo = api_get_user_info($sale['user_id']); + +if (empty($sale)) { + api_not_allowed(true); +} + +$currency = $plugin->getCurrency($sale['currency_id']); +$globalParameters = $plugin->getGlobalParameters(); + +switch ($sale['payment_type']) { + case BuyCoursesPlugin::PAYMENT_TYPE_PAYPAL: + $paypalParams = $plugin->getPaypalParams(); + + $pruebas = $paypalParams['sandbox'] == 1; + $paypalUsername = $paypalParams['username']; + $paypalPassword = $paypalParams['password']; + $paypalSignature = $paypalParams['signature']; + + require_once "paypalfunctions.php"; + + $i = 0; + $extra = "&L_PAYMENTREQUEST_0_NAME0={$sale['product_name']}"; + $extra .= "&L_PAYMENTREQUEST_0_AMT0={$sale['price']}"; + $extra .= "&L_PAYMENTREQUEST_0_QTY0=1"; + + $expressCheckout = CallShortcutExpressCheckout( + $sale['price'], + $currency['iso_code'], + 'paypal', + api_get_path(WEB_PLUGIN_PATH).'buycourses/src/success.php', + api_get_path(WEB_PLUGIN_PATH).'buycourses/src/error.php', + $extra + ); + + if ($expressCheckout["ACK"] !== 'Success') { + $erroMessage = vsprintf( + $plugin->get_lang('ErrorOccurred'), + [$expressCheckout['L_ERRORCODE0'], $expressCheckout['L_LONGMESSAGE0']] + ); + Display::addFlash( + Display::return_message($erroMessage, 'error', false) + ); + header('Location: ../index.php'); + 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: + $buyingCourse = false; + $buyingSession = false; + + switch ($sale['product_type']) { + case BuyCoursesPlugin::PRODUCT_TYPE_COURSE: + $buyingCourse = true; + $course = $plugin->getSubscriptionCourseInfo($sale['product_id'], $coupon); + break; + case BuyCoursesPlugin::PRODUCT_TYPE_SESSION: + $buyingSession = true; + $session = $plugin->getSubscriptionSessionInfo($sale['product_id'], $coupon); + break; + } + + $transferAccounts = $plugin->getTransferAccounts(); + $infoEmailExtra = $plugin->getTransferInfoExtra()['tinfo_email_extra']; + + $form = new FormValidator( + 'success', + 'POST', + api_get_self(), + null, + null, + FormValidator::LAYOUT_INLINE + ); + + if ($form->validate()) { + $formValues = $form->getSubmitValues(); + + if (isset($formValues['cancel'])) { + $plugin->cancelSubscriptionSale($sale['id']); + + unset($_SESSION['bc_sale_id']); + unset($_SESSION['bc_coupon_id']); + + header('Location: '.api_get_path(WEB_PLUGIN_PATH).'buycourses/index.php'); + exit; + } + + $messageTemplate = new Template(); + $messageTemplate->assign('user', $userInfo); + $messageTemplate->assign( + 'sale', + [ + 'date' => $sale['date'], + 'product' => $sale['product_name'], + 'currency' => $currency['iso_code'], + 'price' => $sale['price'], + 'reference' => $sale['reference'], + ] + ); + $messageTemplate->assign('transfer_accounts', $transferAccounts); + $messageTemplate->assign('info_email_extra', $infoEmailExtra); + + MessageManager::send_message_simple( + $userInfo['user_id'], + $plugin->get_lang('bc_subject'), + $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( + $plugin->get_lang('PurchaseStatusX'), + $plugin->get_lang('PendingReasonByTransfer') + ), + 'success', + false + ) + ); + + unset($_SESSION['bc_sale_id']); + unset($_SESSION['bc_coupon_id']); + header('Location: '.api_get_path(WEB_PLUGIN_PATH).'buycourses/src/course_catalog.php'); + exit; + } + + $form->addButton( + 'confirm', + $plugin->get_lang('ConfirmOrder'), + 'check', + 'success', + 'default', + null, + ['id' => 'confirm'] + ); + $form->addButtonCancel($plugin->get_lang('CancelOrder'), 'cancel'); + + $template = new Template(); + + if ($buyingCourse) { + $template->assign('course', $course); + } elseif ($buyingSession) { + $template->assign('session', $session); + } + + $template->assign('buying_course', $buyingCourse); + $template->assign('buying_session', $buyingSession); + $template->assign('terms', $globalParameters['terms_and_conditions']); + $template->assign('title', $sale['product_name']); + $template->assign('price', $sale['price']); + $template->assign('currency', $sale['currency_id']); + $template->assign('user', $userInfo); + $template->assign('transfer_accounts', $transferAccounts); + $template->assign('form', $form->returnForm()); + $template->assign('is_bank_transfer', true); + + $content = $template->fetch('buycourses/view/subscription_process_confirm.tpl'); + + $template->assign('content', $content); + $template->display_one_col_template(); + break; + case BuyCoursesPlugin::PAYMENT_TYPE_CULQI: + // We need to include the main online script, acording to the Culqi documentation the JS needs to be loeaded + // directly from the main url "https://integ-pago.culqi.com" because a local copy of this JS is not supported + $htmlHeadXtra[] = ''; + + $buyingCourse = false; + $buyingSession = false; + + switch ($sale['product_type']) { + case BuyCoursesPlugin::PRODUCT_TYPE_COURSE: + $buyingCourse = true; + $course = $plugin->getSubscriptionCourseInfo($sale['product_id'], $coupon); + break; + case BuyCoursesPlugin::PRODUCT_TYPE_SESSION: + $buyingSession = true; + $session = $plugin->getSubscriptionSessionInfo($sale['product_id'], $coupon); + break; + } + + $form = new FormValidator( + 'success', + 'POST', + api_get_self(), + null, + null, + FormValidator::LAYOUT_INLINE + ); + + if ($form->validate()) { + $formValues = $form->getSubmitValues(); + + if (isset($formValues['cancel'])) { + $plugin->cancelSubscriptionSale($sale['id']); + + unset($_SESSION['bc_sale_id']); + unset($_SESSION['bc_coupon_id']); + + Display::addFlash( + Display::return_message( + $plugin->get_lang('OrderCanceled'), + 'warning', + false + ) + ); + + header('Location: '.api_get_path(WEB_PLUGIN_PATH).'buycourses/index.php'); + exit; + } + } + $form->addButton( + 'confirm', + $plugin->get_lang('ConfirmOrder'), + 'check', + 'success', + 'default', + null, + ['id' => 'confirm'] + ); + $form->addButton( + 'cancel', + $plugin->get_lang('CancelOrder'), + 'times', + 'danger', + 'default', + null, + ['id' => 'cancel'] + ); + + $template = new Template(); + + if ($buyingCourse) { + $template->assign('course', $course); + } elseif ($buyingSession) { + $template->assign('session', $session); + } + + $template->assign('buying_course', $buyingCourse); + $template->assign('buying_session', $buyingSession); + $template->assign('terms', $globalParameters['terms_and_conditions']); + $template->assign('title', $sale['product_name']); + $template->assign('price', floatval($sale['price'])); + $template->assign('currency', $plugin->getSelectedCurrency()); + $template->assign('user', $userInfo); + $template->assign('sale', $sale); + $template->assign('form', $form->returnForm()); + $template->assign('is_culqi_payment', true); + $template->assign('culqi_params', $culqiParams = $plugin->getCulqiParams()); + + $content = $template->fetch('buycourses/view/subscription_process_confirm.tpl'); + + $template->assign('content', $content); + $template->display_one_col_template(); + + break; + case BuyCoursesPlugin::PAYMENT_TYPE_TPV_REDSYS: + $tpvRedsysParams = $plugin->getTpvRedsysParams(); + + require_once '../resources/apiRedsys.php'; + $tpv = new RedsysAPI(); + + $merchantcode = $tpvRedsysParams['merchantcode']; + $terminal = $tpvRedsysParams['terminal']; + $currency = $tpvRedsysParams['currency']; + $transactionType = "0"; + $urlMerchant = api_get_path(WEB_PLUGIN_PATH).'buycourses/src/tpv_response.php'; + $urlSuccess = api_get_path(WEB_PLUGIN_PATH).'buycourses/src/tpv_success.php'; + $urlFailed = api_get_path(WEB_PLUGIN_PATH).'buycourses/src/tpv_error.php'; + $order = str_pad(strval($saleId), 4, "0", STR_PAD_LEFT); + $amount = $sale['price'] * 100; + $description = $plugin->get_lang('OrderReference').": ".$sale['reference']; + $tpv->setParameter("DS_MERCHANT_AMOUNT", $amount); + $tpv->setParameter("DS_MERCHANT_ORDER", $order); + $tpv->setParameter("DS_MERCHANT_MERCHANTCODE", $merchantcode); + $tpv->setParameter("DS_MERCHANT_CURRENCY", $currency); + $tpv->setParameter("DS_MERCHANT_TRANSACTIONTYPE", $transactionType); + $tpv->setParameter("DS_MERCHANT_TERMINAL", $terminal); + $tpv->setParameter("DS_MERCHANT_MERCHANTURL", $urlMerchant); + $tpv->setParameter("DS_MERCHANT_URLOK", $urlSuccess); + $tpv->setParameter("DS_MERCHANT_URLKO", $urlFailed); + $tpv->setParameter("DS_MERCHANT_PRODUCTDESCRIPTION", $description); + + $version = "HMAC_SHA256_V1"; + $kc = $tpvRedsysParams['kc']; + + $urlTpv = $tpvRedsysParams['url_redsys']; + $sandboxFlag = $tpvRedsysParams['sandbox'] == 1; + if ($sandboxFlag === true) { + $urlTpv = $tpvRedsysParams['url_redsys_sandbox']; + } + + $params = $tpv->createMerchantParameters(); + $signature = $tpv->createMerchantSignature($kc); + + echo '
'; + echo ''; + echo ''; + echo ''; + echo '
'; + + echo ''; + + break; +} diff --git a/plugin/buycourses/view/configure_frequency.tpl b/plugin/buycourses/view/configure_frequency.tpl new file mode 100644 index 0000000000..7abce503f2 --- /dev/null +++ b/plugin/buycourses/view/configure_frequency.tpl @@ -0,0 +1,32 @@ +
+
+ {{ items_form }} +
+
+
+ + + + + + + + + + {% for frequency in frequencies_list %} + + + + + + {% endfor %} + +
{{ 'Name'|get_lang }}{{ 'SubscriptionPeriodDuration'|get_plugin_lang('BuyCoursesPlugin') }}{{ 'Options'|get_lang }}
{{ frequency.name }}{{ frequency.duration }} +
+ + + +
+
+
\ No newline at end of file diff --git a/plugin/buycourses/view/configure_subscription.tpl b/plugin/buycourses/view/configure_subscription.tpl new file mode 100644 index 0000000000..556f63e3d3 --- /dev/null +++ b/plugin/buycourses/view/configure_subscription.tpl @@ -0,0 +1,45 @@ +
+
+ {{ items_form }} +
+
+
+
+

{{ 'FrequencyConfig'|get_plugin_lang('BuyCoursesPlugin') }}

+
+
+
+
+ {{ frequency_form }} +
+
+
+ + + + + + + + + + {% for subscription in subscriptions %} + + + + + + {% endfor %} + +
{{ 'Duration'|get_plugin_lang('BuyCoursesPlugin') }}{{ 'Price'|get_plugin_lang('BuyCoursesPlugin') }}{{ 'Actions'|get_lang }}
{{ subscription.durationName }}{{ subscription.price }} {{ currencyIso }} + + + +
+
+
+
+
+
+ diff --git a/plugin/buycourses/view/index.tpl b/plugin/buycourses/view/index.tpl index 1764a56479..a619ac4d5e 100644 --- a/plugin/buycourses/view/index.tpl +++ b/plugin/buycourses/view/index.tpl @@ -35,9 +35,22 @@ +
+
+ + + + +
+
{% if _u.is_admin %} -
+
-
+
+ +
+
-
+
-
+
-
-
{% endif %} diff --git a/plugin/buycourses/view/list_subscription.tpl b/plugin/buycourses/view/list_subscription.tpl new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugin/buycourses/view/service_sales_report.tpl b/plugin/buycourses/view/service_sales_report.tpl index 13672a461e..39ae19e594 100644 --- a/plugin/buycourses/view/service_sales_report.tpl +++ b/plugin/buycourses/view/service_sales_report.tpl @@ -7,6 +7,10 @@
{{ 'Services'|get_plugin_lang('BuyCoursesPlugin') }} +

diff --git a/plugin/buycourses/view/subscription_add.tpl b/plugin/buycourses/view/subscription_add.tpl new file mode 100644 index 0000000000..ce8a838a95 --- /dev/null +++ b/plugin/buycourses/view/subscription_add.tpl @@ -0,0 +1,37 @@ +
+
+ {{ items_form }} +
+
+ + diff --git a/plugin/buycourses/view/subscription_catalog.tpl b/plugin/buycourses/view/subscription_catalog.tpl new file mode 100644 index 0000000000..7edbc2ccde --- /dev/null +++ b/plugin/buycourses/view/subscription_catalog.tpl @@ -0,0 +1,122 @@ +
+ {% if sessions_are_included %} + + {% endif %} + +
+
+
+
+ {{ search_filter_form }} +
+
+
+ {% if showing_courses %} + {% for course in courses %} +
+
+
+
+ {{ course.title }} +
+
+
+ {% set course_description_url = _p.web_ajax ~ 'course_home.ajax.php?' ~ {'code': course.code, 'a': 'show_course_information'}|url_encode() %} +

+ {{ course.title }} +

+
    + {% for teacher in course.teachers %} +
  • {{ teacher }}
  • + {% endfor %} +
+ {% if course.enrolled == "YES" %} +
+ {{ 'TheUserIsAlreadyRegisteredInTheCourse'|get_plugin_lang('BuyCoursesPlugin') }} +
+ {% elseif course.enrolled == "NO" %} + + {% elseif course.enrolled == "TMP" %} +
{{ 'WaitingToReceiveThePayment'|get_plugin_lang('BuyCoursesPlugin') }}
+ {% endif %} +
+
+
+ {% endfor %} + {% endif %} + + {% if showing_sessions %} + {% for session in sessions %} +
+
+
+
+ {{ session.name }} +
+
+
+

+ {{ session.name }} +

+ {% if 'show_session_coach'|api_get_setting == 'true' %} +

{{ session.coach }}

+ {% endif %} +

+ + {% if session.duration %} + {{ 'SessionDurationXDaysTotal'|get_lang|format(session.duration) }} + {% else %} + {{ session.dates.display }} + {% endif %} +

+ {% if session.enrolled == "YES" %} +
+ {{ 'TheUserIsAlreadyRegisteredInTheSession'|get_plugin_lang('BuyCoursesPlugin') }} +
+ {% elseif session.enrolled == "NO" %} + + {% elseif session.enrolled == "TMP" %} +
{{ 'WaitingToReceiveThePayment'|get_plugin_lang('BuyCoursesPlugin') }}
+ {% endif %} +
+
+
+ {% endfor %} + {% endif %} +
+ {{ pagination }} +
+
+
+
+
diff --git a/plugin/buycourses/view/subscription_process.tpl b/plugin/buycourses/view/subscription_process.tpl new file mode 100644 index 0000000000..5df69fdd94 --- /dev/null +++ b/plugin/buycourses/view/subscription_process.tpl @@ -0,0 +1,187 @@ +
+ {% if item_type == 1 %} + {% set back_url = _p.web_plugin ~ 'buycourses/src/subscription_course_catalog.php' %} + {% elseif item_type == 2 %} + {% set back_url = _p.web_plugin ~ 'buycourses/src/subscription_session_catalog.php' %} + {% endif %} + + + {{ + +
+ +
+
+
+
+
+ {% if buying_course %} +
+
+ + {{ course.title }} + + {% if course.tax_enable %} +
+ {{ 'Price'|get_plugin_lang('BuyCoursesPlugin') }} : + {{ subscription.price_formatted }} +
+ {{ course.tax_name }} ({{ subscription.item.tax_perc_show }}%): + {{ subscription.tax_amount_formatted }} +
+ {% endif %} +
+ {{ 'Total'|get_plugin_lang('BuyCoursesPlugin') }} : + {{ subscription.total_price_formatted }} +
+ {% if course.has_coupon %} +
+ {{ 'DiscountAmount'|get_plugin_lang('BuyCoursesPlugin') }}: + {{ course.discount_amount_formatted }} +
+ {% endif %} +
+ {{ 'SelecSubscription'|get_plugin_lang('BuyCoursesPlugin') }} +
+
+ {{ form_subscription }} +
+
+ {{ 'DoYouHaveACoupon'|get_plugin_lang('BuyCoursesPlugin') }} +
+
+ {{ form_coupon }} +
+
+
+
+

+ + {{ course.title }} + +

+ {% if course.description %} +
+ {{ course.description }} +
+ {% endif %} + + {% if course.teachers %} +
+

+ {{ 'Teachers'|get_plugin_lang('BuyCoursesPlugin') }} : + {% for teacher in course.teachers %} + + {{ teacher.name }}, + {% endfor %} +

+
+ {% endif %} +
+
+
+ {% elseif buying_session %} +
+
+ {{ session.name }} + {% if session.tax_enable %} +
+ {{ 'Price'|get_plugin_lang('BuyCoursesPlugin') }} : + {{ subscription.price_formatted }} +
+ {{ session.tax_name }} ({{ subscription.item.tax_perc_show }}%): + {{ subscription.tax_amount_formatted }} +
+ {% endif %} +
+ {{ 'Total'|get_plugin_lang('BuyCoursesPlugin') }} : + {{ subscription.total_price_formatted }} +
+ {% if session.has_coupon %} +
+ {{ 'DiscountAmount'|get_plugin_lang('BuyCoursesPlugin') }}: + {{ session.discount_amount_formatted }} +
+ {% endif %} +
+ {{ 'SelecSubscription'|get_plugin_lang('BuyCoursesPlugin') }} +
+
+ {{ form_subscription }} +
+
+ {{ 'DoYouHaveACoupon'|get_plugin_lang('BuyCoursesPlugin') }} +
+
+ {{ form_coupon }} +
+
+
+
+

{{ session.name }}

+ {% if session.description %} +
+ {{ session.description }} +
+ {% endif %} +
+ {{ session.dates.display }} +
+
+
+ {% for course in session.courses %} +

+ {{ course.title }} +

+ {% if course.coaches|length %} +

+ {{ 'Teachers'|get_plugin_lang('BuyCoursesPlugin') }} : + + {% for coach in course.coaches %} + + {{ coach.name }}, + {% endfor %} +

+ {% endif %} + {% endfor %} +
+
+
+
+ {% endif %} +
+
+

{{ 'PaymentMethods'|get_plugin_lang('BuyCoursesPlugin') }}

+ {% if message_payment %} + {{ message_payment }} + {% else %} + {{ form }} + {% endif %} +
+
+
+
+
+ diff --git a/plugin/buycourses/view/subscription_process_confirm.tpl b/plugin/buycourses/view/subscription_process_confirm.tpl new file mode 100644 index 0000000000..daaad88084 --- /dev/null +++ b/plugin/buycourses/view/subscription_process_confirm.tpl @@ -0,0 +1,283 @@ +
+
+
+
+
+

{{ 'PurchaseData'|get_plugin_lang('BuyCoursesPlugin') }}

+
+
+ {% if buying_course %} +
+
+ + {{ course.title }} + +
+
+

+ {{ course.title }} +

+
    + {% for teacher in course.teachers %} +
  • {{ teacher.name }}
  • + {% endfor %} +
+

+ + {{ course.item.total_price_formatted }} + +

+

+
+
+ {% elseif buying_session %} +
+
+

+ {{ session.name }} +

+
+
+

{{ session.name }}

+

{{ session.dates.display }}

+
    + {% for course in session.courses %} +
  • + {{ course.title }} + {% if course.coaches|length %} +
      + {% for coach in course.coaches %} +
    • {{ coach }}
    • + {% endfor %} +
    + {% endif %} +
  • + {% endfor %} +
+

+ + {{ session.item.total_price_formatted }} + +

+

+
+
+ {% elseif buying_service %} +
+
+ + {{ service.name }} + +
+
+
+
+

+ {{ service.name }} +

+
    + {% if service.applies_to == 0 %} +
  • + {{ 'AppliesTo'|get_plugin_lang('BuyCoursesPlugin') }} {{ 'None'|get_lang }} +
  • + {% elseif service.applies_to == 1 %} +
  • + {{ 'AppliesTo'|get_plugin_lang('BuyCoursesPlugin') }} {{ 'User'|get_lang }} +
  • + {% elseif service.applies_to == 2 %} +
  • + {{ 'AppliesTo'|get_plugin_lang('BuyCoursesPlugin') }} {{ 'Course'|get_lang }} +
  • + {% elseif service.applies_to == 3 %} +
  • + {{ 'AppliesTo'|get_plugin_lang('BuyCoursesPlugin') }} {{ 'Session'|get_lang }} +
  • + {% elseif service.applies_to == 4 %} +
  • + {{ 'AppliesTo'|get_plugin_lang('BuyCoursesPlugin') }} {{ 'TemplateTitleCertificate'|get_lang }} +
  • + {% endif %} +
  • + + {{ 'Price'|get_plugin_lang('BuyCoursesPlugin') }} + : {{ service_item.total_price_formatted }} + / {{ service.duration_days == 0 ? 'NoLimit'|get_lang : service.duration_days ~ ' ' ~ 'Days'|get_lang }} +
  • +
  • {{ service.owner.name }}
  • + {% if service.description %} +
  • {{ service.description }}
  • + {% endif %} +
+

+ + {{ service_item.total_price_formatted }} + +

+

+
+
+ {% endif %} +
+
+
+ {% if terms %} +
+
+
+

{{ 'TermsAndConditions'|get_plugin_lang('BuyCoursesPlugin') }}

+
+
+
+
+ +
+
+ +
+
+
+
+
+ {% endif %} +
+ +{% if is_bank_transfer %} +
+
+ +
+ + + + + + + + + + {% for account in transfer_accounts %} + + + + + + {% endfor %} + +
{{ 'Name'|get_lang }}{{ 'BankAccount'|get_plugin_lang('BuyCoursesPlugin') }}{{ 'SWIFT'|get_plugin_lang('BuyCoursesPlugin') }}
{{ account.name }}{{ account.account }}{{ account.swift }}
+
+

{{ 'OnceItIsConfirmedYouWillReceiveAnEmailWithTheBankInformationAndAnOrderReference'|get_plugin_lang('BuyCoursesPlugin') }}

+
+
+{% endif %} + +
+
+ {{ form }} +
+
+ diff --git a/plugin/buycourses/view/subscription_sales_report.tpl b/plugin/buycourses/view/subscription_sales_report.tpl new file mode 100644 index 0000000000..c882072242 --- /dev/null +++ b/plugin/buycourses/view/subscription_sales_report.tpl @@ -0,0 +1,122 @@ + +
+
+{{ form }} + +
+ + + + + + + + + + + + + + + {% if invoicing_enable %} + + {% endif %} + + + + + {% for sale in sale_list %} + + + + + + + + + + + + + {% if invoicing_enable %} + + {% endif %} + + + {% endfor %} + +
{{ 'OrderReference'|get_plugin_lang('BuyCoursesPlugin') }}{{ 'OrderStatus'|get_plugin_lang('BuyCoursesPlugin') }}{{ 'OrderDate'|get_plugin_lang('BuyCoursesPlugin') }}{{ 'PaymentMethod'|get_plugin_lang('BuyCoursesPlugin') }}{{ 'Price'|get_plugin_lang('BuyCoursesPlugin') }}{{ 'CouponDiscount'|get_plugin_lang('BuyCoursesPlugin') }}{{ 'Coupon'|get_plugin_lang('BuyCoursesPlugin') }}{{ 'ProductType'|get_plugin_lang('BuyCoursesPlugin') }}{{ 'Name'|get_lang }}{{ 'UserName'|get_lang }}{{ 'Email'|get_lang }}{{ 'Invoice'|get_plugin_lang('BuyCoursesPlugin') }}{{ 'Options'|get_lang }}
{{ sale.reference }} + {% if sale.status == sale_status_canceled %} + {{ 'SaleStatusCanceled'|get_plugin_lang('BuyCoursesPlugin') }} + {% elseif sale.status == sale_status_pending %} + {{ 'SaleStatusPending'|get_plugin_lang('BuyCoursesPlugin') }} + {% elseif sale.status == sale_status_completed %} + {{ 'SaleStatusCompleted'|get_plugin_lang('BuyCoursesPlugin') }} + {% endif %} + {{ sale.date | api_get_local_time }}{{ sale.payment_type }}{{ sale.total_price }}{{ sale.total_discount }}{{ sale.coupon_code }}{{ sale.product_type }}{{ sale.product_name }}{{ sale.complete_user_name }}{{ sale.email }} + {% if sale.invoice == 1 %} + + {{ 'InvoiceView'|get_plugin_lang('BuyCoursesPlugin') }} +
{{ sale.num_invoice }} +
+ {% endif %} +
+ {% if sale.status == sale_status_pending %} + + {% endif %} +
+
+ + diff --git a/plugin/buycourses/view/subscriptions.tpl b/plugin/buycourses/view/subscriptions.tpl new file mode 100644 index 0000000000..883ba0f2a1 --- /dev/null +++ b/plugin/buycourses/view/subscriptions.tpl @@ -0,0 +1,152 @@ +{% if sessions_are_included %} + +{% endif %} + +
+
+
+ + + + + + + {% if tax_enable and (tax_applies_to == 1 or tax_applies_to == 2) %} + + {% endif %} + + + + + {% for item in courses %} + + + + + {% if tax_enable and (tax_applies_to == 1 or tax_applies_to == 2) %} + + {% endif %} + + + {% endfor %} + +
{{ 'Title'|get_lang }}{{ 'OfficialCode'|get_lang }}{{ 'HasSubscriptions'|get_plugin_lang('BuyCoursesPlugin') }}{{ tax_name }}{{ 'Options'|get_lang }}
+ {% if item.visibility == 0 %} + {{ 'CourseVisibilityClosed'|get_lang }} + {% elseif item.visibility == 1 %} + {{ 'Private'|get_lang }} + {% elseif item.visibility == 2 %} + {{ 'OpenToThePlatform'|get_lang }} + {% elseif item.visibility == 3 %} + {{ 'OpenToTheWorld'|get_lang }} + {% elseif item.visibility == 4 %} + {{ 'CourseVisibilityHidden'|get_lang }} + {% endif %} + + {{ item.title }} + + {{ item.code }} + + {{ item.code }} + + {% if item.buyCourseData %} + + {% else %} + + {% endif %} + + {{ item.buyCourseData.tax_perc_show }} % + + {% if item.buyCourseData %} + + {{ 'Configure'|get_lang }} + + {% else %} + + {{ 'Configure'|get_lang }} + + {% endif %} +
+
+ {{ course_pagination }} +
+ + {% if sessions_are_included %} +
+
+ + + + + + + + {% if tax_enable and (tax_applies_to == 1 or tax_applies_to == 3) %} + + {% endif %} + + + + + {% for item in sessions %} + + + + + + {% if tax_enable and (tax_applies_to == 1 or tax_applies_to == 3) %} + + {% endif %} + + + {% endfor %} + +
{{ 'Title'|get_lang }}{{ 'StartDate'|get_lang }}{{ 'EndDate'|get_lang }}{{ 'HasSubscriptions'|get_plugin_lang('BuyCoursesPlugin') }}{{ tax_name }}{{ 'Options'|get_lang }}
+ {{ item.name }} + + {{ item.displayStartDate | api_convert_and_format_date(6)}} + + {{ item.displayEndDate |api_convert_and_format_date(6)}} + + {% if item.buyCourseData %} + + {% else %} + + {% endif %} + + {{ item.buyCourseData.tax_perc_show }} % + + {% if item.buyCourseData %} + + {{ 'Configure'|get_lang }} + + {% else %} + + {{ 'Configure'|get_lang }} + + {% endif %} +
+ {{ session_pagination }} +
+
+ {% endif %} +