Chamilo is a learning management system focused on ease of use and accessibility
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
chamilo-lms/plugin/buycourses/src/buy_course_plugin.class.php

1664 lines
51 KiB

<?php
/* For license terms, see /license.txt */
use Chamilo\CoreBundle\Entity\Session;
use Chamilo\CoreBundle\Entity\Course;
/**
* Plugin class for the BuyCourses plugin
* @package chamilo.plugin.buycourses
* @author Jose Angel Ruiz <jaruiz@nosolored.com>
* @author Imanol Losada <imanol.losada@beeznest.com>
* @author Alex Aragón <alex.aragon@beeznest.com>
* @author Angel Fernando Quiroz Campos <angel.quiroz@beeznest.com>
* @author José Loguercio Silva <jose.loguercio@beeznest.com>
*/
class BuyCoursesPlugin extends Plugin
{
const TABLE_PAYPAL = 'plugin_buycourses_paypal_account';
const TABLE_CURRENCY = 'plugin_buycourses_currency';
const TABLE_ITEM = 'plugin_buycourses_item';
const TABLE_ITEM_BENEFICIARY = 'plugin_buycourses_item_rel_beneficiary';
const TABLE_SALE = 'plugin_buycourses_sale';
const TABLE_TRANSFER = 'plugin_buycourses_transfer';
const TABLE_COMMISSION = 'plugin_buycourses_commission';
const TABLE_PAYPAL_PAYOUTS = 'plugin_buycourses_paypal_payouts';
const PRODUCT_TYPE_COURSE = 1;
const PRODUCT_TYPE_SESSION = 2;
const PAYMENT_TYPE_PAYPAL = 1;
const PAYMENT_TYPE_TRANSFER = 2;
const PAYOUT_STATUS_CANCELED = 2;
const PAYOUT_STATUS_PENDING = 0;
const PAYOUT_STATUS_COMPLETED = 1;
const SALE_STATUS_CANCELED = -1;
const SALE_STATUS_PENDING = 0;
const SALE_STATUS_COMPLETED = 1;
/**
*
* @return StaticPlugin
*/
static function create()
{
static $result = null;
return $result ? $result : $result = new self();
}
protected function __construct()
{
parent::__construct(
'1.0',
"
Jose Angel Ruiz - NoSoloRed (original author) <br/>
Francis Gonzales and Yannick Warnier - BeezNest (integration) <br/>
Alex Aragón - BeezNest (Design icons and css styles) <br/>
Imanol Losada - BeezNest (introduction of sessions purchase) <br/>
Angel Fernando Quiroz Campos - BeezNest (cleanup and new reports) <br/>
José Loguercio Silva - BeezNest (pay teachers and commissions)
",
array(
'show_main_menu_tab' => 'boolean',
'include_sessions' => 'boolean',
'paypal_enable' => 'boolean',
'transfer_enable' => 'boolean',
'commissions_enable' => 'boolean',
'unregistered_users_enable' => 'boolean'
)
);
}
/**
* This method creates the tables required to this plugin
*/
function install()
{
$tablesToBeCompared = array(
self::TABLE_PAYPAL,
self::TABLE_TRANSFER,
self::TABLE_ITEM_BENEFICIARY,
self::TABLE_ITEM,
self::TABLE_SALE,
self::TABLE_CURRENCY,
self::TABLE_COMMISSION,
self::TABLE_PAYPAL_PAYOUTS
);
$em = Database::getManager();
$cn = $em->getConnection();
$sm = $cn->getSchemaManager();
$tables = $sm->tablesExist($tablesToBeCompared);
if ($tables) {
return false;
}
require_once api_get_path(SYS_PLUGIN_PATH) . 'buycourses/database.php';
}
/**
* This method drops the plugin tables
*/
function uninstall()
{
$tablesToBeDeleted = array(
self::TABLE_PAYPAL,
self::TABLE_TRANSFER,
self::TABLE_ITEM_BENEFICIARY,
self::TABLE_ITEM,
self::TABLE_SALE,
self::TABLE_CURRENCY,
self::TABLE_COMMISSION,
self::TABLE_PAYPAL_PAYOUTS
);
foreach ($tablesToBeDeleted as $tableToBeDeleted) {
$table = Database::get_main_table($tableToBeDeleted);
$sql = "DROP TABLE IF EXISTS $table";
Database::query($sql);
}
$this->manageTab(false);
}
/**
* This function verify if the plugin is enable and return the price info for a course in the new grid catalog
* for 1.11.x , the main purpose is to show if a course is in sale it shows in the main platform course catalog
* so the old buycourses plugin catalog can be deprecated.
* @param Array $course course info
* @return mixed bool|string html
*/
public function buyCoursesForGridCatalogVerificator($course) {
$return = [];
$paypal = $this->get('paypal_enable') === 'true';
$transfer = $this->get('transfer_enable') === 'true';
if ($paypal || $transfer) {
$item = $this->getItemByProduct(intval($course['real_id']), self::PRODUCT_TYPE_COURSE);
$return['html'] = '<div class="buycourses-price">';
if ($item) {
$return['html'] .= '<span class="label label-primary"><b>'. $item['iso_code'] .' ' . $item['price'] . '</b></span>';
$return['verificator'] = true;
} else {
$return['html'] .= '<span class="label label-primary"><b>'. $this->get_lang('Free'). '</b></span>';
$return['verificator'] = false;
}
$return['html'] .= '</div>';
} else {
return false;
}
return $return;
}
/**
* Return the buyCourses plugin button to buy the course
* @param array $course course info
* @return string $html
*/
public function returnBuyCourseButton($course) {
$url = api_get_path(WEB_PLUGIN_PATH) .
'buycourses/src/process.php?i=' .
intval($course['real_id']) .
'&t=' .
self::PRODUCT_TYPE_COURSE
;
$html = ' <a class="btn btn-success btn-sm" title="' . $this->get_lang('Buy') . '" href="' . $url . '">' .
Display::returnFontAwesomeIcon('fa fa-shopping-cart') . '</a>';
return $html;
}
/**
* Get the currency for sales
* @return array The selected currency. Otherwise return false
*/
public function getSelectedCurrency()
{
return Database::select(
'*',
Database::get_main_table(BuyCoursesPlugin::TABLE_CURRENCY),
[
'where' => ['status = ?' => true]
],
'first'
);
}
/**
* Get a list of currencies
* @return array The currencies. Otherwise return false
*/
public function getCurrencies()
{
return Database::select(
'*',
Database::get_main_table(BuyCoursesPlugin::TABLE_CURRENCY)
);
}
/**
* Save the selected currency
* @param int $selectedId The currency Id
*/
public function selectCurrency($selectedId)
{
$currencyTable = Database::get_main_table(
BuyCoursesPlugin::TABLE_CURRENCY
);
Database::update(
$currencyTable,
['status' => 0]
);
Database::update(
$currencyTable,
['status' => 1],
['id = ?' => intval($selectedId)]
);
}
/**
* Save the PayPal configuration params
* @param array $params
* @return int Rows affected. Otherwise return false
*/
public function savePaypalParams($params)
{
return Database::update(
Database::get_main_table(BuyCoursesPlugin::TABLE_PAYPAL),
[
'username' => $params['username'],
'password' => $params['password'],
'signature' => $params['signature'],
'sandbox' => isset($params['sandbox'])
],
['id = ?' => 1]
);
}
/**
* Gets the stored PayPal params
* @return array
*/
public function getPaypalParams()
{
return Database::select(
'*',
Database::get_main_table(BuyCoursesPlugin::TABLE_PAYPAL),
['id = ?' => 1],
'first'
);
}
/**
* Save a transfer account information
* @param array $params The transfer account
* @return int Rows affected. Otherwise return false
*/
public function saveTransferAccount($params)
{
return Database::insert(
Database::get_main_table(self::TABLE_TRANSFER),
[
'name' => $params['tname'],
'account' => $params['taccount'],
'swift' => $params['tswift']
]
);
}
/**
* Get a list of transfer accounts
* @return array
*/
public function getTransferAccounts()
{
return Database::select(
'*',
Database::get_main_table(self::TABLE_TRANSFER)
);
}
/**
* Remove a transfer account
* @param int $id The transfer account ID
* @return int Rows affected. Otherwise return false
*/
public function deleteTransferAccount($id)
{
return Database::delete(
Database::get_main_table(self::TABLE_TRANSFER),
['id = ?' => intval($id)]
);
}
/**
* Filter the registered courses for show in plugin catalog
* @return array
*/
private function getCourses()
{
$entityManager = Database::getManager();
$query = $entityManager->createQueryBuilder();
$courses = $query
->select('c')
->from('ChamiloCoreBundle:Course', 'c')
->leftJoin(
'ChamiloCoreBundle:SessionRelCourse',
'sc',
\Doctrine\ORM\Query\Expr\Join::WITH,
'c = sc.course'
)
->where(
$query->expr()->isNull('sc.course')
)
->getQuery()
->getResult();
return $courses;
}
/**
* Get the item data
* @param int $productId The item ID
* @param int $itemType The item type
* @return array
*/
public function getItemByProduct($productId, $itemType)
{
$buyItemTable = Database::get_main_table(BuyCoursesPlugin::TABLE_ITEM);
$buyCurrencyTable = Database::get_main_table(BuyCoursesPlugin::TABLE_CURRENCY);
$fakeItemFrom = "
$buyItemTable i
INNER JOIN $buyCurrencyTable c
ON i.currency_id = c.id
";
return Database::select(
['i.*', 'c.iso_code'],
$fakeItemFrom,
[
'where' => [
'i.product_id = ? AND i.product_type = ?' => [
intval($productId),
intval($itemType)
]
]
],
'first'
);
}
/**
* List courses details from the configuration page
* @return array
*/
public function getCoursesForConfiguration()
{
$courses = $this->getCourses();
if (empty($courses)) {
return[];
}
$configurationCourses = [];
$currency = $this->getSelectedCurrency();
foreach ($courses as $course) {
$configurationCourses[] = $this->getCourseForConfiguration($course, $currency);
}
return $configurationCourses;
}
/**
* List sessions details from the buy-session table and the session table
* @return array The sessions. Otherwise return false
*/
public function getSessionsForConfiguration()
{
$auth = new Auth();
$sessions = $auth->browseSessions();
$currency = $this->getSelectedCurrency();
$items = [];
foreach ($sessions as $session) {
$items[] = $this->getSessionForConfiguration($session, $currency);
}
return $items;
}
/**
* Get the user status for the session
* @param int $userId The user ID
* @param Session $session The session
* @return string
*/
private function getUserStatusForSession($userId, Session $session)
{
if (empty($userId)) {
return 'NO';
}
$entityManager = Database::getManager();
$scuRepo = $entityManager->getRepository('ChamiloCoreBundle:SessionRelCourseRelUser');
$buySaleTable = Database::get_main_table(self::TABLE_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 = ?' => [
$userId,
self::PRODUCT_TYPE_SESSION,
$session->getId(),
self::SALE_STATUS_PENDING
]
]
],
'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';
}
/**
* Lists current user session details, including each session course details
* @param string $name Optional. The name filter
* @param int $min Optional. The minimum price filter
* @param int $max Optional. The maximum price filter
* @return array
*/
public function getCatalogSessionList($name = null, $min = 0, $max = 0)
{
$sessions = $this->filterSessionList($name, $min, $max);
$sessionCatalog = array();
// loop through all sessions
foreach ($sessions as $session) {
$sessionCourses = $session->getCourses();
if (empty($sessionCourses)) {
continue;
}
$item = $this->getItemByProduct($session->getId(), self::PRODUCT_TYPE_SESSION);
if (empty($item)) {
continue;
}
$sessionData = $this->getSessionInfo($session->getId());
$sessionData['coach'] = $session->getGeneralCoach()->getCompleteName();
$sessionData['enrolled'] = $this->getUserStatusForSession(api_get_user_id(), $session);
$sessionData['courses'] = array();
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;
}
/**
* Get the user status for the course
* @param int $userId The user Id
* @param Course $course The course
*
* @return string
*/
private function getUserStatusForCourse($userId, Course $course)
{
if (empty($userId)) {
return 'NO';
}
$entityManager = Database::getManager();
$cuRepo = $entityManager->getRepository('ChamiloCoreBundle:CourseRelUser');
$buySaleTable = Database::get_main_table(self::TABLE_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 = ?' => [
$userId,
self::PRODUCT_TYPE_COURSE,
$course->getId(),
self::SALE_STATUS_PENDING
]
]
],
'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';
}
/**
* Lists current user course details
* @param string $name Optional. The name filter
* @param int $min Optional. The minimum price filter
* @param int $max Optional. The maximum price filter
* @return array
*/
public function getCatalogCourseList($name = null, $min = 0, $max = 0)
{
$courses = $this->filterCourseList($name, $min, $max);
if (empty($courses)) {
return [];
}
$courseCatalog = [];
foreach ($courses as $course) {
$item = $this->getItemByProduct($course->getId(), self::PRODUCT_TYPE_COURSE);
if (empty($item)) {
continue;
}
$courseItem = [
'id' => $course->getId(),
'title' => $course->getTitle(),
'code' => $course->getCode(),
'course_img' => null,
'price' => $item['price'],
'currency' => $item['iso_code'],
'teachers' => [],
'enrolled' => $this->getUserStatusForCourse(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;
}
/**
* Get course info
* @param int $courseId The course ID
* @return array
*/
public function getCourseInfo($courseId)
{
$entityManager = Database::getManager();
$course = $entityManager->find('ChamiloCoreBundle:Course', $courseId);
if (empty($course)) {
return [];
}
$item = $this->getItemByProduct($course->getId(), self::PRODUCT_TYPE_COURSE);
if (empty($item)) {
return [];
}
$courseInfo = [
'id' => $course->getId(),
'title' => $course->getTitle(),
'code' => $course->getCode(),
'visual_code' => $course->getVisualCode(),
'teachers' => [],
'price' => $item['price'],
'currency' => $item['iso_code'],
'course_img' => null
];
$courseTeachers = $course->getTeachers();
foreach ($courseTeachers as $teacher) {
$courseInfo['teachers'][] = $teacher->getUser()->getCompleteName();
}
$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 getSessionInfo($sessionId)
{
$entityManager = Database::getManager();
$session = $entityManager->find('ChamiloCoreBundle:Session', $sessionId);
if (empty($session)) {
return [];
}
$item = $this->getItemByProduct($session->getId(), self::PRODUCT_TYPE_SESSION);
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()
]);
$sessionInfo = [
'id' => $session->getId(),
'name' => $session->getName(),
'dates' => $sessionDates,
'courses' => [],
'price' => $item['price'],
'currency' => $item['iso_code'],
'image' => null
];
$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();
$sessionCourseData['coaches'][] = $user->getCompleteName();
}
$sessionInfo['courses'][] = $sessionCourseData;
}
return $sessionInfo;
}
/**
* Get registered item data
* @param int $itemId The item ID
* @return array
*/
public function getItem($itemId)
{
return Database::select(
'*',
Database::get_main_table(self::TABLE_ITEM),
[
'where' => ['id = ?' => intval($itemId)]
],
'first'
);
}
/**
* Register a sale
* @param int $itemId The product ID
* @param int $paymentType The payment type
* @return boolean
*/
public function registerSale($itemId, $paymentType)
{
if (!in_array($paymentType, [self::PAYMENT_TYPE_PAYPAL, self::PAYMENT_TYPE_TRANSFER])) {
return false;
}
$entityManager = Database::getManager();
$item = $this->getItem($itemId);
if (empty($item)) {
return false;
}
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();
}
$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' => $item['price'],
'status' => self::SALE_STATUS_PENDING,
'payment_type' => intval($paymentType)
];
return Database::insert(self::TABLE_SALE, $values);
}
/**
* Get sale data by ID
* @param int $saleId The sale ID
* @return array
*/
public function getSale($saleId)
{
return Database::select(
'*',
Database::get_main_table(self::TABLE_SALE),
[
'where' => ['id = ?' => intval($saleId)]
],
'first'
);
}
/**
* Get a list of sales by the payment type
* @param int $paymentType The payment type to filter (default : Paypal)
* @return array The sale list. Otherwise return false
*/
public function getSaleListByPaymentType($paymentType = self::PAYMENT_TYPE_PAYPAL)
{
$saleTable = Database::get_main_table(BuyCoursesPlugin::TABLE_SALE);
$currencyTable = Database::get_main_table(BuyCoursesPlugin::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' => ['s.payment_type = ? AND s.status = ?' => [intval($paymentType), self::SALE_STATUS_COMPLETED]],
'order' => 'id DESC'
]
);
}
/**
* Get currency data by ID
* @param int $currencyId The currency ID
* @return array
*/
public function getCurrency($currencyId)
{
return Database::select(
'*',
Database::get_main_table(BuyCoursesPlugin::TABLE_CURRENCY),
[
'where' => ['id = ?' => intval($currencyId)]
],
'first'
);
}
/**
* Update the sale status
* @param int $saleId The sale ID
* @param int $newStatus The new status
* @return boolean
*/
private function updateSaleStatus($saleId, $newStatus = self::SALE_STATUS_PENDING)
{
$saleTable = Database::get_main_table(self::TABLE_SALE);
return Database::update(
$saleTable,
['status' => intval($newStatus)],
['id = ?' => intval($saleId)]
);
}
/**
* Complete sale process. Update sale status to completed
* @param int $saleId The sale ID
* @return boolean
*/
public function completeSale($saleId)
{
$sale = $this->getSale($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::subscribe_user($sale['user_id'], $course['code']);
break;
case self::PRODUCT_TYPE_SESSION:
SessionManager::suscribe_users_to_session(
$sale['product_id'],
[$sale['user_id']],
api_get_session_visibility($sale['product_id']),
false
);
$saleIsCompleted = true;
break;
}
if ($saleIsCompleted) {
$this->updateSaleStatus($sale['id'], self::SALE_STATUS_COMPLETED);
}
return $saleIsCompleted;
}
/**
* Update sale status to canceled
* @param int $saleId The sale ID
*/
public function cancelSale($saleId)
{
$this->updateSaleStatus($saleId, self::SALE_STATUS_CANCELED);
}
/**
* Get payment types
* @return array
*/
public function getPaymentTypes()
{
return [
self::PAYMENT_TYPE_PAYPAL => 'PayPal',
self::PAYMENT_TYPE_TRANSFER => $this->get_lang('BankTransfer')
];
}
/**
* Get a list of sales by the status
* @param int $status The status to filter
* @return array The sale list. Otherwise return false
*/
public function getSaleListByStatus($status = self::SALE_STATUS_PENDING)
{
$saleTable = Database::get_main_table(BuyCoursesPlugin::TABLE_SALE);
$currencyTable = Database::get_main_table(BuyCoursesPlugin::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' => ['s.status = ?' => intval($status)],
'order' => 'id DESC'
]
);
}
/**
* Get the statuses for sales
* @return array
*/
public function getSaleStatuses()
{
return [
self::SALE_STATUS_CANCELED => $this->get_lang('SaleStatusCanceled'),
self::SALE_STATUS_PENDING => $this->get_lang('SaleStatusPending'),
self::SALE_STATUS_COMPLETED => $this->get_lang('SaleStatusCompleted')
];
}
/**
* Get the statuses for Payouts
* @return array
*/
public function getPayoutStatuses()
{
return [
self::PAYOUT_STATUS_CANCELED => $this->get_lang('PayoutStatusCanceled'),
self::PAYOUT_STATUS_PENDING => $this->get_lang('PayoutStatusPending'),
self::PAYOUT_STATUS_COMPLETED => $this->get_lang('PayoutStatusCompleted')
];
}
/**
* Get the list of product types
* @return array
*/
public function getProductTypes()
{
return [
self::PRODUCT_TYPE_COURSE => get_lang('Course'),
self::PRODUCT_TYPE_SESSION => get_lang('Session')
];
}
/**
* Search filtered sessions 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 filterSessionList($name = null, $min = 0, $max = 0)
{
if (empty($name) && empty($min) && empty($max)) {
$auth = new Auth();
return $auth->browseSessions();
}
$itemTable = Database::get_main_table(self::TABLE_ITEM);
$sessionTable = Database::get_main_table(TABLE_MAIN_SESSION);
$min = floatval($min);
$max = floatval($max);
$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;
}
$sessionIds = Database::select(
's.id',
"$sessionTable s INNER JOIN $innerJoin",
['where' => $whereConditions]
);
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($name = null, $min = 0, $max = 0)
{
if (empty($name) && empty($min) && empty($max)) {
return $this->getCourses();
}
$itemTable = Database::get_main_table(self::TABLE_ITEM);
$courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
$min = floatval($min);
$max = floatval($max);
$innerJoin = "$itemTable i ON c.id = i.product_id";
$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;
}
$courseIds = Database::select(
'c.id',
"$courseTable c INNER JOIN $innerJoin",
['where' => $whereConditions]
);
if (!$courseIds) {
return [];
}
$courses = [];
foreach ($courseIds as $courseId) {
$courses[] = Database::getManager()->find('ChamiloCoreBundle:Course', $courseId);
}
return $courses;
}
/**
* Generates a random text (used for order references)
* @param int $length Optional. Length of characters
* @param boolean $lowercase Optional. Include lowercase characters
* @param boolean $uppercase Optional. Include uppercase characters
* @param boolean $numbers Optional. Include numbers
* @return string
*/
public static function randomText(
$length = 6,
$lowercase = true,
$uppercase = true,
$numbers = true
)
{
$salt = $lowercase ? 'abchefghknpqrstuvwxyz' : '';
$salt .= $uppercase ? 'ACDEFHKNPRSTUVWXYZ' : '';
$salt .= $numbers ? (strlen($salt) ? '2345679' : '0123456789') : '';
if (strlen($salt) == 0) {
return '';
}
$str = '';
srand((double)microtime() * 1000000);
for ($i = 0; $i < $length; $i++) {
$numbers = rand(0, strlen($salt) - 1);
$str .= substr($salt, $numbers, 1);
}
return $str;
}
/**
* Generates an order reference
* @param int $userId The user ID
* @param int $productType The course/session type
* @param int $productId The course/session ID
* @return string
*/
public function generateReference($userId, $productType, $productId)
{
return vsprintf(
"%d-%d-%d-%s",
[$userId, $productType, $productId, self::randomText()]
);
}
/**
* Get a list of sales by the user
* @param string $term The search term
* @return array The sale list. Otherwise return false
*/
public function getSaleListByUser($term)
{
$term = trim($term);
if (empty($term)) {
return [];
}
$saleTable = Database::get_main_table(BuyCoursesPlugin::TABLE_SALE);
$currencyTable = Database::get_main_table(BuyCoursesPlugin::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.username LIKE %?% OR ' => $term,
'u.lastname LIKE %?% OR ' => $term,
'u.firstname LIKE %?%' => $term
],
'order' => 'id DESC'
]
);
}
/**
* Get a list of sales by the user id
* @param int $id The user id
* @return array The sale list. Otherwise return false
*/
public function getSaleListByUserId($id)
{
if (empty($id)) {
return [];
}
$saleTable = Database::get_main_table(BuyCoursesPlugin::TABLE_SALE);
$currencyTable = Database::get_main_table(BuyCoursesPlugin::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 = ?' => [intval($id), BuyCoursesPlugin::SALE_STATUS_COMPLETED]
],
'order' => 'id DESC'
]
);
}
/**
* Convert the course info to array with necessary course data for save item
* @param Course $course
* @param array $defaultCurrency Optional. Currency data
* @return array
*/
public function getCourseForConfiguration(Course $course, $defaultCurrency = null)
{
$courseItem = [
'item_id' => null,
'course_id' => $course->getId(),
'course_visual_code' => $course->getVisualCode(),
'course_code' => $course->getCode(),
'course_title' => $course->getTitle(),
'course_visibility' => $course->getVisibility(),
'visible' => false,
'currency' => empty($defaultCurrency) ? null : $defaultCurrency['iso_code'],
'price' => 0.00
];
$item = $this->getItemByProduct($course->getId(), self::PRODUCT_TYPE_COURSE);
if ($item !== false) {
$courseItem['item_id'] = $item['id'];
$courseItem['visible'] = true;
$courseItem['currency'] = $item['iso_code'];
$courseItem['price'] = $item['price'];
}
return $courseItem;
}
/**
* Convert the session info to array with necessary session data for save item
* @param Session $session The session data
* @param array $defaultCurrency Optional. Currency data
* @return array
*/
public function getSessionForConfiguration(Session $session, $defaultCurrency = null)
{
$buyItemTable = Database::get_main_table(BuyCoursesPlugin::TABLE_ITEM);
$buyCurrencyTable = Database::get_main_table(BuyCoursesPlugin::TABLE_CURRENCY);
$fakeItemFrom = "
$buyItemTable i
INNER JOIN $buyCurrencyTable c ON i.currency_id = c.id
";
$sessionItem = [
'item_id' => null,
'session_id' => $session->getId(),
'session_name' => $session->getName(),
'session_visibility' => $session->getVisibility(),
'session_display_start_date' => null,
'session_display_end_date' => null,
'visible' => false,
'currency' => empty($defaultCurrency) ? null : $defaultCurrency['iso_code'],
'price' => 0.00
];
$displayStartDate = $session->getDisplayStartDate();
if (!empty($displayStartDate)) {
$sessionItem['session_display_start_date'] = api_format_date(
$session->getDisplayStartDate()->format('Y-m-d h:i:s')
);
}
$displayEndDate = $session->getDisplayEndDate();
if (!empty($displayEndDate)) {
$sessionItem['session_display_end_date'] = api_format_date(
$session->getDisplayEndDate()->format('Y-m-d h:i:s'),
DATE_TIME_FORMAT_LONG_24H
);
}
$item = Database::select(
['i.*', 'c.iso_code'],
$fakeItemFrom,
[
'where' => [
'i.product_id = ? AND ' => $session->getId(),
'i.product_type = ?' => self::PRODUCT_TYPE_SESSION
]
],
'first'
);
if ($item !== false) {
$sessionItem['item_id'] = $item['id'];
$sessionItem['visible'] = true;
$sessionItem['currency'] = $item['iso_code'];
$sessionItem['price'] = $item['price'];
}
return $sessionItem;
}
/**
* Get all beneficiaries for a item
* @param int $itemId The item ID
* @return array The beneficiries. Otherwise return false
*/
public function getItemBeneficiaries($itemId)
{
$beneficiaryTable = Database::get_main_table(self::TABLE_ITEM_BENEFICIARY);
return Database::select(
'*',
$beneficiaryTable,
['where' => [
'item_id = ?' => intval($itemId)
]]
);
}
/**
* Delete a item with its beneficiaries
* @param int $itemId The item ID
* @return int The number of affected rows. Otherwise return false
*/
public function deleteItem($itemId)
{
$itemTable = Database::get_main_table(BuyCoursesPlugin::TABLE_ITEM);
$affectedRows = Database::delete(
$itemTable,
['id = ?' => intval($itemId)]
);
if (!$affectedRows) {
return false;
}
return $this->deleteItemBeneficiaries($itemId);
}
/**
* Register a item
* @param array $itemData The item data
* @return int The item ID. Otherwise return false
*/
public function registerItem(array $itemData)
{
$itemTable = Database::get_main_table(BuyCoursesPlugin::TABLE_ITEM);
return Database::insert($itemTable, $itemData);
}
/**
* Update the item data by product
* @param array $itemData The item data to be updated
* @param int $productId The product ID
* @param int $productType The type of product
* @return int The number of affected rows. Otherwise return false
*/
public function updateItem(array $itemData, $productId, $productType)
{
$itemTable = Database::get_main_table(BuyCoursesPlugin::TABLE_ITEM);
return Database::update(
$itemTable,
$itemData,
[
'product_id = ? AND ' => intval($productId),
'product_type' => $productType
]
);
}
/**
* Remove all beneficiaries for a item
* @param int $itemId The user ID
* @return int The number of affected rows. Otherwise return false
*/
public function deleteItemBeneficiaries($itemId)
{
$beneficiaryTable = Database::get_main_table(BuyCoursesPlugin::TABLE_ITEM_BENEFICIARY);
return Database::delete(
$beneficiaryTable,
['item_id = ?' => intval($itemId)]
);
}
/**
* Register the beneficiaries users with the sale of item
* @param int $itemId The item ID
* @param array $userIds The beneficiary user ID and Teachers commissions if enabled
*/
public function registerItemBeneficiaries($itemId, array $userIds)
{
$beneficiaryTable = Database::get_main_table(BuyCoursesPlugin::TABLE_ITEM_BENEFICIARY);
$this->deleteItemBeneficiaries($itemId);
foreach ($userIds as $userId => $commissions) {
Database::insert(
$beneficiaryTable,
[
'item_id' => intval($itemId),
'user_id' => intval($userId),
'commissions' => intval($commissions)
]
);
}
}
/**
* Check if a course is valid for sale
* @param Course $course The course
* @return boolean
*/
public function isValidCourse(Course $course)
{
$courses = $this->getCourses();
foreach ($courses as $_c) {
if ($_c->getCode() === $course->getCode()) {
return true;
}
}
return false;
}
/**
* Gets the beneficiaries with commissions and current paypal accounts by sale
* @param int $saleId The sale ID
* @return array
*/
public function getBeneficiariesBySale($saleId)
{
$userTable = Database::get_main_table(TABLE_MAIN_USER);
$beneficiaries = [];
$sale = $this->getSale($saleId);
$item = $this->getItemByProduct($sale['product_id'], $sale['product_type']);
$itemBeneficiaries = $this->getItemBeneficiaries($item['id']);
return $itemBeneficiaries;
}
/**
* gets all payouts
* @param int $status - default 0 - pending
* @param int $payoutId - for get an individual payout if want all then false
* @return array
*/
public function getPayouts($status = self::PAYOUT_STATUS_PENDING, $payoutId = false, $userId = false)
{
$condition = ($payoutId) ? 'AND p.id = '. intval($payoutId) : '';
$condition2 = ($userId) ? ' AND p.user_id = ' . intval($userId) : '';
$typeResult = ($condition) ? 'first' : 'all';
$payoutsTable = Database::get_main_table(BuyCoursesPlugin::TABLE_PAYPAL_PAYOUTS);
$saleTable = Database::get_main_table(BuyCoursesPlugin::TABLE_SALE);
$currencyTable = Database::get_main_table(BuyCoursesPlugin::TABLE_CURRENCY);
$userTable = Database::get_main_table(TABLE_MAIN_USER);
$extraFieldTable = Database::get_main_table(TABLE_EXTRA_FIELD);
$extraFieldValues = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
$paypalExtraField = Database::select(
"*",
$extraFieldTable,
[
'where' => ['variable = ?' => 'paypal']
],
'first'
);
if (!$paypalExtraField) {
return false;
}
$innerJoins = "
INNER JOIN $userTable u ON p.user_id = u.id
INNER JOIN $saleTable s ON s.id = p.sale_id
INNER JOIN $currencyTable c ON s.currency_id = c.id
LEFT JOIN $extraFieldValues efv ON p.user_id = efv.item_id
AND field_id = " . intval($paypalExtraField['id']) . "
";
$payouts = Database::select(
"p.* , u.firstname, u.lastname, efv.value as paypal_account, s.reference as sale_reference, s.price as item_price, c.iso_code",
"$payoutsTable p $innerJoins",
[
'where' => ['p.status = ? '.$condition . ' ' .$condition2 => $status]
],
$typeResult
);
return $payouts;
}
/**
* Verify if the beneficiary have a paypal account
* @param int $userId
* @return true if the user have a paypal account, false if not
*/
public function verifyPaypalAccountByBeneficiary($userId)
{
$extraFieldTable = Database::get_main_table(TABLE_EXTRA_FIELD);
$extraFieldValues = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
$paypalExtraField = Database::select(
"*",
$extraFieldTable,
[
'where' => ['variable = ?' => 'paypal']
],
'first'
);
if (!$paypalExtraField) {
return false;
}
$paypalFieldId = $paypalExtraField['id'];
$paypalAccount = Database::select(
"value",
$extraFieldValues,
[
'where' => ['field_id = ? AND item_id = ?' => [intval($paypalFieldId), intval($userId)]]
],
'first'
);
if (!$paypalAccount) {
return false;
}
if ($paypalAccount['value'] === '') {
return false;
}
return true;
}
/**
* Register the users payouts
* @param int $saleId The sale ID
* @return array
*/
public function storePayouts($saleId)
{
$payoutsTable = Database::get_main_table(BuyCoursesPlugin::TABLE_PAYPAL_PAYOUTS);
$platformCommission = $this->getPlatformCommission();
$sale = $this->getSale($saleId);
$teachersCommission = number_format((floatval($sale['price']) * intval($platformCommission['commission']))/100, 2);
$beneficiaries = $this->getBeneficiariesBySale($saleId);
foreach ($beneficiaries as $beneficiary) {
Database::insert(
$payoutsTable,
[
'date' => $sale['date'],
'payout_date' => getdate(),
'sale_id' => intval($saleId),
'user_id' => $beneficiary['user_id'],
'commission' => number_format((floatval($teachersCommission) * intval($beneficiary['commissions']))/100, 2),
'status' => self::PAYOUT_STATUS_PENDING
]
);
}
}
/**
* Register the users payouts
* @param int $payoutId The payout ID
* @param int $status The status to set (-1 to cancel, 0 to pending, 1 to completed)
* @return array
*/
public function setStatusPayouts($payoutId, $status)
{
$payoutsTable = Database::get_main_table(BuyCoursesPlugin::TABLE_PAYPAL_PAYOUTS);
Database::update(
$payoutsTable,
['status' => intval($status)],
['id = ?' => intval($payoutId)]
);
}
/**
* Gets the stored platform commission params
* @return array
*/
public function getPlatformCommission()
{
return Database::select(
'*',
Database::get_main_table(BuyCoursesPlugin::TABLE_COMMISSION),
['id = ?' => 1],
'first'
);
}
/**
* Update the platform commission
* @param int $params platform commission
* @return int The number of affected rows. Otherwise return false
*/
public function updateCommission($params)
{
$commissionTable = Database::get_main_table(BuyCoursesPlugin::TABLE_COMMISSION);
return Database::update(
$commissionTable,
['commission' => intval($params['commission'])]
);
}
}