Added new feature to payouts and comissions to the buy course plugin - Refs #10563

1.10.x
José Loguercio 11 years ago
parent 9e2909595b
commit 7ca48ec35d
  1. 252
      plugin/buycourses/src/buy_course_plugin.class.php
  2. 97
      plugin/buycourses/src/configure_course.php
  3. 31
      plugin/buycourses/src/paymentsetup.php
  4. 28
      plugin/buycourses/src/paypalfunctions.php
  5. 11
      plugin/buycourses/src/process.php
  6. 35
      plugin/buycourses/src/sales_report.php
  7. 2
      plugin/buycourses/src/success.php
  8. 18
      plugin/buycourses/view/paymentsetup.tpl

@ -7,6 +7,7 @@
* @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
{
@ -16,10 +17,15 @@ class BuyCoursesPlugin extends Plugin
const TABLE_ITEM_BENEFICIARY = 'plugin_buycourses_item_rel_beneficiary';
const TABLE_SALE = 'plugin_buycourses_sale';
const TABLE_TRANSFER = 'plugin_buycourses_transfer';
const TABLE_COMISSION = 'plugin_buycourses_comission';
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;
@ -39,17 +45,19 @@ class BuyCoursesPlugin extends Plugin
parent::__construct(
'1.0',
"
Jose Angel Ruiz - NoSoloRed (original author),
Francis Gonzales and Yannick Warnier - BeezNest (integration),
Alex Aragón - BeezNest (Design icons and css styles),
Imanol Losada - BeezNest (introduction of sessions purchase),
Angel Fernando Quiroz Campos - BeezNest (cleanup and new reports)
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 comissions)
",
array(
'show_main_menu_tab' => 'boolean',
'include_sessions' => 'boolean',
'paypal_enable' => 'boolean',
'transfer_enable' => 'boolean',
'comissions_enable' => 'boolean',
'unregistered_users_enable' => 'boolean'
)
);
@ -66,7 +74,9 @@ class BuyCoursesPlugin extends Plugin
self::TABLE_ITEM_BENEFICIARY,
self::TABLE_ITEM,
self::TABLE_SALE,
self::TABLE_CURRENCY
self::TABLE_CURRENCY,
self::TABLE_COMISSION,
self::TABLE_PAYPAL_PAYOUTS
);
$em = Database::getManager();
$cn = $em->getConnection();
@ -91,7 +101,9 @@ class BuyCoursesPlugin extends Plugin
self::TABLE_ITEM_BENEFICIARY,
self::TABLE_ITEM,
self::TABLE_SALE,
self::TABLE_CURRENCY
self::TABLE_CURRENCY,
self::TABLE_COMISSION,
self::TABLE_PAYPAL_PAYOUTS
);
foreach ($tablesToBeDeleted as $tableToBeDeleted) {
@ -760,6 +772,32 @@ class BuyCoursesPlugin extends Plugin
'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
@ -894,6 +932,19 @@ class BuyCoursesPlugin extends Plugin
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
@ -1293,7 +1344,7 @@ class BuyCoursesPlugin extends Plugin
/**
* Register the beneficiaries users with the sale of item
* @param int $itemId The item ID
* @param array $userIds The beneficiary user ID
* @param array $userIds The beneficiary user ID and Teachers comissions if enabled
*/
public function registerItemBeneficiaries($itemId, array $userIds)
{
@ -1301,12 +1352,13 @@ class BuyCoursesPlugin extends Plugin
$this->deleteItemBeneficiaries($itemId);
foreach ($userIds as $userId) {
foreach ($userIds as $userId => $comissions) {
Database::insert(
$beneficiaryTable,
[
'item_id' => intval($itemId),
'user_id' => intval($userId)
'user_id' => intval($userId),
'comissions' => intval($comissions)
]
);
}
@ -1329,5 +1381,185 @@ class BuyCoursesPlugin extends Plugin
return false;
}
/**
* Gets the beneficiaries with comissions 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);
$extraFieldTable = Database::get_main_table(TABLE_EXTRA_FIELD);
$extraFieldValues = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
$itemTable = Database::get_main_table(self::TABLE_ITEM);
$itemBeneficiariesTable = Database::get_main_table(self::TABLE_ITEM_BENEFICIARY);
$paypalExtraField = Database::select(
"*",
$extraFieldTable,
[
'where' => ['variable = ?' => 'paypal']
],
'first'
);
if (!$paypalExtraField) {
return false;
}
$beneficiaries = [];
$sale = $this->getSale($saleId);
$item = $this->getItemByProduct($sale['product_id'], $sale['product_type']);
$itemBeneficiaries = $this->getItemBeneficiaries($item['id']);
$innerJoins = "
INNER JOIN $userTable u ON e.item_id = u.id
INNER JOIN $itemBeneficiariesTable ib ON e.item_id = ib.user_id
INNER JOIN $itemTable i ON ib.item_id = " . $item['id'] . "
";
foreach($itemBeneficiaries as $itemBeneficiarie) {
$beneficiaries[] = Database::select(
"ib.item_id, e.item_id as user_id, u.firstname, u.lastname, e.value as paypal_account, ib.comissions as comission",
"$extraFieldValues e $innerJoins",
[
'where' => ['e.field_id = ? AND e.item_id = ? AND ib.item_id = ?' => [intval($paypalExtraField['id']), $itemBeneficiarie['user_id'], intval($item['id'])]]
],
'first'
);
}
return $beneficiaries;
}
/**
* 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)
{
$condition = ($payoutId) ? 'AND p.id = '. intval($payoutId) : '';
$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 => $status]
],
$typeResult
);
return $payouts;
}
/**
* 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);
$platformComission = $this->getPlatformComission();
$sale = $this->getSale($saleId);
$teachersComission = number_format((floatval($sale['price']) * intval($platformComission['comission']))/100, 2);
$beneficiaries = $this->getBeneficiariesBySale($saleId);
foreach ($beneficiaries as $beneficiarie) {
Database::insert(
$payoutsTable,
[
'date' => $sale['date'],
'payout_date' => getdate(),
'sale_id' => intval($saleId),
'user_id' => $beneficiarie['user_id'],
'comission' => number_format((floatval($teachersComission) * intval($beneficiarie['comission']))/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' => $status],
['id = ?' => intval($payoutId)]
);
}
/**
* Gets the stored platform comission params
* @return array
*/
public function getPlatformComission()
{
return Database::select(
'*',
Database::get_main_table(BuyCoursesPlugin::TABLE_COMISSION),
['id = ?' => 1],
'first'
);
}
/**
* Update the platform comission
* @param int $params platform comission
* @return int The number of affected rows. Otherwise return false
*/
public function updateComission($params)
{
$comissionTable = Database::get_main_table(BuyCoursesPlugin::TABLE_COMISSION);
return Database::update(
$comissionTable,
['comission' => intval($params['comission'])]
);
}
}

@ -19,6 +19,15 @@ if (!isset($_REQUEST['t'], $_REQUEST['i'])) {
$plugin = BuyCoursesPlugin::create();
$comissionsEnable = $plugin->get('comissions_enable');
if ($comissionsEnable == "true") {
$htmlHeadXtra[] = '<script type="text/javascript" src="' . api_get_path(WEB_PLUGIN_PATH) . 'buycourses/resources/js/comissions.js"></script>';
$defaultComissions = [];
$comissions = "";
}
$includeSession = $plugin->get('include_sessions') === 'true';
@ -62,6 +71,16 @@ if ($editingCourse) {
if (!empty($currentBeneficiaries)) {
$defaultBeneficiaries = array_column($currentBeneficiaries, 'user_id');
if ($comissionsEnable == "true") {
$defaultComissions = array_column($currentBeneficiaries, 'comissions');
foreach ($defaultComissions as $defaultComission) {
$comissions .= $defaultComission.',';
}
$comissions = substr($comissions, 0, -1);
}
}
$currencyIso = $courseItem['currency'];
@ -72,7 +91,8 @@ if ($editingCourse) {
'name' => $courseItem['course_title'],
'visible' => $courseItem['visible'],
'price' => $courseItem['price'],
'beneficiaries' => $defaultBeneficiaries
'beneficiaries' => $defaultBeneficiaries,
($comissionsEnable == "true") ? 'comissions' : '' => ($comissionsEnable == "true") ? $comissions : ''
];
} elseif ($editingSession) {
if (!$includeSession) {
@ -117,6 +137,16 @@ if ($editingCourse) {
if (!empty($currentBeneficiaries)) {
$defaultBeneficiaries = array_column($currentBeneficiaries, 'user_id');
if ($comissionsEnable == "true") {
$defaultComissions = array_column($currentBeneficiaries, 'comissions');
foreach ($defaultComissions as $defaultComission) {
$comissions .= $defaultComission.',';
}
$comissions = substr($comissions, 0, -1);
}
}
$currencyIso = $sessionItem['currency'];
@ -127,12 +157,41 @@ if ($editingCourse) {
'name' => $sessionItem['session_name'],
'visible' => $sessionItem['visible'],
'price' => $sessionItem['price'],
'beneficiaries' => $defaultBeneficiaries
'beneficiaries' => $defaultBeneficiaries,
($comissionsEnable == "true") ? 'comissions' : '' => ($comissionsEnable == "true") ? $comissions : ''
];
} else {
api_not_allowed(true);
}
if ($comissionsEnable == "true") {
$htmlHeadXtra[] = ''
. '<script>'
. '$(function(){'
. 'if ($("[name=\'comissions\']").val() === "") {'
. '$("#panelSliders").html("<button id=\"setComissionsButton\" class=\"btn btn-warning\">' . get_plugin_lang("SetComissions", "BuyCoursesPlugin") . '</button>");'
. '} else {'
. 'showSliders(100, "default", "' . $comissions . '");'
. '}'
. '});'
. '$(document).ready(function() {'
. 'var maxPercentage = 100;'
. '$("#selectBox").on("change", function() {'
. ' $("#panelSliders").html("");'
. 'showSliders(maxPercentage, "renew");'
. '});'
. '$("#setComissionsButton").on("click", function() {'
. ' $("#panelSliders").html("");'
. 'showSliders(maxPercentage, "renew");'
. '});'
. '});'
. '</script>';
}
$form = new FormValidator('beneficiaries');
$form->addText('product_type', $plugin->get_lang('ProductType'), false);
$form->addText('name', get_lang('Name'), false);
@ -151,16 +210,35 @@ $beneficiariesSelect = $form->addSelect(
'beneficiaries',
$plugin->get_lang('Beneficiaries'),
null,
['multiple' => 'multiple']
['multiple' => 'multiple', 'id' => 'selectBox']
);
if ($editingCourse) {
$teachersOptions = api_unique_multidim_array($teachersOptions, 'value');
$beneficiariesSelect->addOptGroup($teachersOptions, get_lang('Teachers'));
} elseif ($editingSession) {
$courseCoachesOptions = api_unique_multidim_array($courseCoachesOptions, 'value');
$beneficiariesSelect->addOptGroup([$generalCoachOption], get_lang('SessionGeneralCoach'));
$beneficiariesSelect->addOptGroup($courseCoachesOptions, get_lang('SessionCourseCoach'));
}
if ($comissionsEnable == "true") {
$form->addHtml( ''
. '<div class="form-group">'
. '<label for="sliders" class="col-sm-2 control-label">'
. get_plugin_lang('Comissions', 'BuyCoursesPlugin')
. '</label>'
. '<div class="col-sm-8">'
. '<div class="" id="panelSliders"></div>'
. '</div>'
. '</div>'
);
$form->addHidden('comissions', '');
}
$form->addHidden('t', null);
$form->addHidden('i', null);
$form->addButtonSave(get_lang('Save'));
@ -190,7 +268,18 @@ if ($form->validate()) {
$plugin->deleteItemBeneficiaries($productItem['id']);
if (isset($formValues['beneficiaries'])) {
$plugin->registerItemBeneficiaries($productItem['id'], $formValues['beneficiaries']);
if ($comissionsEnable == "true") {
$usersId = $formValues['beneficiaries'];
$comissions = explode(",", $formValues['comissions']);
$comissions = (count($usersId) != count($comissions)) ? array_fill(0, count($usersId), 0) : $comissions;
$beneficiaries = array_combine($usersId, $comissions);
} else {
$usersId = $formValues['beneficiaries'];
$comissions = array_fill(0, count($usersId), 0);
$beneficiaries = array_combine($usersId, $comissions);
}
$plugin->registerItemBeneficiaries($productItem['id'], $beneficiaries);
}
} else {
$plugin->deleteItem($productItem['id']);

@ -17,6 +17,7 @@ $plugin = BuyCoursesPlugin::create();
$paypalEnable = $plugin->get('paypal_enable');
$transferEnable = $plugin->get('transfer_enable');
$comissionsEnable = $plugin->get('comissions_enable');
if (isset($_GET['action'], $_GET['id'])) {
if ($_GET['action'] == 'delete_taccount') {
@ -113,6 +114,34 @@ $paypalForm->addCheckBox('sandbox', null, $plugin->get_lang('Sandbox'));
$paypalForm->addButtonSave(get_lang('Save'));
$paypalForm->setDefaults($plugin->getPaypalParams());
// Platform Comissions
$comissionForm = new FormValidator('comissions');
if ($comissionForm->validate()) {
$comissionFormValues = $comissionForm->getSubmitValues();
$plugin->updateComission($comissionFormValues);
Display::addFlash(
Display::return_message(get_lang('Saved'), 'success')
);
header('Location:' . api_get_self());
exit;
}
$comissionForm->addElement(
'number',
'comission',
[$plugin->get_lang('Comission'), null, '%'],
['step' => 1, 'cols-size' => [3, 7, 1], 'min' => 0, 'max' => 100]
);
$comissionForm->addButtonSave(get_lang('Save'));
$comissionForm->setDefaults($plugin->getPlatformComission());
$transferForm = new FormValidator('transfer_account');
if ($transferForm->validate()) {
@ -165,9 +194,11 @@ $tpl = new Template($templateName);
$tpl->assign('header', $templateName);
$tpl->assign('curency_form', $currencyForm->returnForm());
$tpl->assign('paypal_form', $paypalForm->returnForm());
$tpl->assign('comission_form', $comissionForm->returnForm());
$tpl->assign('transfer_form', $transferForm->returnForm());
$tpl->assign('transfer_accounts', $transferAccounts);
$tpl->assign('paypal_enable', $paypalEnable);
$tpl->assign('comissions_enable', $comissionsEnable);
$tpl->assign('transfer_enable', $transferEnable);
$content = $tpl->fetch('buycourses/view/paymentsetup.tpl');

@ -290,6 +290,34 @@ function DirectPayment($paymentType, $paymentAmount, $creditCardType, $creditCar
}
/**
* Purpose: This function makes a MassPay API call
* Inputs:
* Beneficiarie: Array that contains the Beneficiearie paypal account and the payout amount
* Currency Code: The currency Iso code
* Returns:
* The NVP Collection object of the MassPay Call Response.
*/
function MassPayment(array $beneficiaries, $currencyCode) {
$nvpstr = "&RECEIVERTYPE=EmailAddress";
$nvpstr .= "&CURRENCYCODE=".$currencyCode;
$index = 0;
foreach($beneficiaries as $beneficiarie) {
$nvpstr .= "&L_EMAIL".$index."=".$beneficiarie['paypal_account'];
$nvpstr .= "&L_AMT".$index."=".$beneficiarie['comission'];
$nvpstr .= "&L_NOTE".$index."= Thanks baby";
$index++;
}
$resArray = hash_call("MassPay", $nvpstr);
return $resArray;
}
/**
*
* hash_call: Function to perform the API call to PayPal using API signature

@ -27,6 +27,7 @@ if (!isset($_REQUEST['t'], $_REQUEST['i'])) {
$buyingCourse = intval($_REQUEST['t']) === BuyCoursesPlugin::PRODUCT_TYPE_COURSE;
$buyingSession = intval($_REQUEST['t']) === BuyCoursesPlugin::PRODUCT_TYPE_SESSION;
$queryString = 'i=' . intval($_REQUEST['i']) . '&t=' . intval($_REQUEST['t']);
if ($buyingCourse) {
$courseInfo = $plugin->getCourseInfo($_REQUEST['i']);
@ -42,7 +43,15 @@ $form = new FormValidator('confirm_sale');
if ($form->validate()) {
$formValues = $form->getSubmitValues();
if (!$formValues['payment_type']) {
Display::addFlash(
Display::return_message($plugin->get_lang('NeedToSelectPaymentType'), 'error', false)
);
header('Location:' . api_get_self() . '?' . $queryString);
exit;
}
$saleId = $plugin->registerSale($item['id'], $formValues['payment_type']);
if ($saleId !== false) {

@ -14,6 +14,9 @@ api_protect_admin_script();
$plugin = BuyCoursesPlugin::create();
$paypalEnable = $plugin->get('paypal_enable');
$comissionsEnable = $plugin->get('comissions_enable');
if (isset($_GET['order'])) {
$sale = $plugin->getSale($_GET['order']);
@ -26,7 +29,7 @@ if (isset($_GET['order'])) {
switch ($_GET['action']) {
case 'confirm':
$plugin->completeSale($sale['id']);
$plugin->storePayouts($sale['id']);
Display::addFlash(
Display::return_message(
sprintf($plugin->get_lang('SubscriptionToCourseXSuccessful'), $sale['product_name']),
@ -134,6 +137,36 @@ $interbreadcrumb[] = ['url' => '../index.php', 'name' => $plugin->get_lang('plug
$templateName = $plugin->get_lang('SalesReport');
$template = new Template($templateName);
$toolbar = '';
if ($paypalEnable == "true" && $comissionsEnable == "true") {
$toolbar .= Display::toolbarButton(
$plugin->get_lang('PaypalPayoutComissions'),
api_get_path(WEB_PLUGIN_PATH) . 'buycourses/src/paypal_payout.php',
'paypal',
'primary',
['title' => $plugin->get_lang('PaypalPayoutComissions')]
);
$template->assign('actions', $toolbar);
}
if ($comissionsEnable == "true") {
$toolbar .= Display::toolbarButton(
$plugin->get_lang('PayoutReport'),
api_get_path(WEB_PLUGIN_PATH) . 'buycourses/src/payout_report.php',
'money',
'info',
['title' => $plugin->get_lang('PayoutReport')]
);
$template->assign('actions', $toolbar);
}
$template->assign('form', $form->returnForm());
$template->assign('selected_sale', $selectedSale);
$template->assign('selected_status', $selectedStatus);

@ -89,6 +89,7 @@ if ($form->validate()) {
'success'
)
);
$plugin->storePayouts($sale['id']);
break;
}
@ -99,6 +100,7 @@ if ($form->validate()) {
'success'
)
);
$plugin->storePayouts($sale['id']);
break;
}

@ -32,6 +32,24 @@
</div>
{% endif %}
{% if comissions_enable == "true" %}
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{{ 'ComissionsConfig'|get_plugin_lang('BuyCoursesPlugin') }}</h3>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-5">
<p>{{ 'InfoComissions'|get_plugin_lang('BuyCoursesPlugin') }}</p>
</div>
<div class="col-md-7">
{{ comission_form }}
</div>
</div>
</div>
</div>
{% endif %}
{% if transfer_enable == "true" %}
<div class="panel panel-default">
<div class="panel-heading">

Loading…
Cancel
Save