MDL-69166 core_payment: add payment accounts
This commit is contained in:
committed by
Shamim Rezaie
parent
3c87455f4b
commit
6ff3087fe6
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
// This file defines settingpages and externalpages under the "Payment" category
|
||||
|
||||
$ADMIN->add('payment', new admin_externalpage(
|
||||
'paymentaccounts',
|
||||
new lang_string('paymentaccounts', 'payment'),
|
||||
new moodle_url("/payment/accounts.php"),
|
||||
['moodle/payment:manageaccounts', 'moodle/payment:viewpayments']));
|
||||
@@ -39,6 +39,7 @@ $ADMIN->add('root', new admin_category('license', new lang_string('license')));
|
||||
$ADMIN->add('root', new admin_category('location', new lang_string('location','admin')));
|
||||
$ADMIN->add('root', new admin_category('language', new lang_string('language')));
|
||||
$ADMIN->add('root', new admin_category('messaging', new lang_string('messagingcategory', 'admin')));
|
||||
$ADMIN->add('root', new admin_category('payment', new lang_string('payments', 'payment')));
|
||||
$ADMIN->add('root', new admin_category('modules', new lang_string('plugins', 'admin')));
|
||||
$ADMIN->add('root', new admin_category('security', new lang_string('security','admin')));
|
||||
$ADMIN->add('root', new admin_category('appearance', new lang_string('appearance','admin')));
|
||||
|
||||
@@ -37,7 +37,7 @@ class provider implements \core_payment\local\callback\provider {
|
||||
* Callback function that returns the enrolment cost for the course that $instanceid enrolment instance belongs to.
|
||||
*
|
||||
* @param int $instanceid The enrolment instance id
|
||||
* @return array['amount' => float, 'currency' => string]
|
||||
* @return array['amount' => float, 'currency' => string, 'accountid' => int]
|
||||
*/
|
||||
public static function get_cost(int $instanceid): array {
|
||||
global $DB;
|
||||
@@ -47,6 +47,7 @@ class provider implements \core_payment\local\callback\provider {
|
||||
return [
|
||||
'amount' => (float) $instance->cost,
|
||||
'currency' => $instance->currency,
|
||||
'accountid' => $instance->customint1,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -210,6 +210,7 @@ class enrol_fee_plugin extends enrol_plugin {
|
||||
'isguestuser' => isguestuser(),
|
||||
'cost' => $localisedcost,
|
||||
'currency' => $instance->currency,
|
||||
'accountid' => $instance->customint1,
|
||||
'amount' => $cost,
|
||||
'instanceid' => $instance->id,
|
||||
'description' => get_string('purchasedescription', 'enrol_fee',
|
||||
@@ -309,6 +310,10 @@ class enrol_fee_plugin extends enrol_plugin {
|
||||
$mform->addElement('select', 'status', get_string('status', 'enrol_fee'), $options);
|
||||
$mform->setDefault('status', $this->get_config('status'));
|
||||
|
||||
$mform->addElement('select', 'customint1', get_string('paymentaccount', 'payment'),
|
||||
['' => ''] + \core_payment\helper::get_payment_accounts_menu($context));
|
||||
$mform->addRule('customint1', get_string('required'), 'required', null, 'client');
|
||||
|
||||
$mform->addElement('text', 'cost', get_string('cost', 'enrol_fee'), array('size' => 4));
|
||||
$mform->setType('cost', PARAM_RAW);
|
||||
$mform->setDefault('cost', format_float($this->get_config('cost'), 2, true));
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
"cost": "$108.50",
|
||||
"amount": 108.50,
|
||||
"currency": "AUD",
|
||||
"accountid": 1,
|
||||
"instanceid": 11,
|
||||
"description": "Enrolment in course Introduction to algorithms",
|
||||
"isguestuser": false
|
||||
@@ -64,6 +65,7 @@
|
||||
id="gateways-modal-trigger-{{ uniqid }}"
|
||||
data-amount="{{amount}}"
|
||||
data-currency="{{currency}}"
|
||||
data-accountid="{{accountid}}"
|
||||
data-component="enrol_fee"
|
||||
data-componentid="{{instanceid}}"
|
||||
data-description={{# quote }}{{description}}{{/ quote }}
|
||||
|
||||
@@ -22,11 +22,21 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['accountname'] = 'Account name';
|
||||
$string['accountnotavailable'] = 'Not available';
|
||||
$string['callbacknotimplemented'] = 'The callback is not implemented for component {$a}.';
|
||||
$string['createaccount'] = 'Create payment account';
|
||||
$string['feeincludesurcharge'] = '{$a->fee} (includes {$a->surcharge}% surcharge for using this payment type)';
|
||||
$string['gatewaycannotbeenabled'] = 'The payment gateway cannot be enabled because the configuration is incomplete.';
|
||||
$string['gatewaydisabled'] = 'Disabled';
|
||||
$string['gatewayenabled'] = 'Enabled';
|
||||
$string['gatewaynotfound'] = 'Gateway not found';
|
||||
$string['nocurrencysupported'] = 'No payment in any currency is supported. Please make sure that at least one payment gateway is enabled.';
|
||||
$string['nogateway'] = 'There is no payment gateway that can be used.';
|
||||
$string['nogatewayselected'] = 'You first need to select a payment gateway.';
|
||||
$string['payments'] = 'Payments';
|
||||
$string['paymentaccount'] = 'Payment account';
|
||||
$string['paymentaccounts'] = 'Payment accounts';
|
||||
$string['selectpaymenttype'] = 'Select payment type';
|
||||
$string['supportedcurrencies'] = 'Supported currencies';
|
||||
$string['surcharge'] = 'Surcharge (percentage)';
|
||||
|
||||
@@ -166,6 +166,7 @@ $string['type_mnetservice_plural'] = 'MNet services';
|
||||
$string['type_mod'] = 'Activity module';
|
||||
$string['type_mod_plural'] = 'Activity modules';
|
||||
$string['type_pgmanage'] = 'Manage payment gateways';
|
||||
$string['type_pg'] = 'Payment gateway';
|
||||
$string['type_pg_plural'] = 'Payment gateways';
|
||||
$string['type_plagiarism'] = 'Plagiarism plugin';
|
||||
$string['type_plagiarism_plural'] = 'Plagiarism plugins';
|
||||
|
||||
@@ -268,7 +268,7 @@ abstract class persistent extends moodleform {
|
||||
/**
|
||||
* Return the persistent object associated with this form instance.
|
||||
*
|
||||
* @return core\persistent
|
||||
* @return \core\persistent
|
||||
*/
|
||||
final protected function get_persistent() {
|
||||
return $this->persistent;
|
||||
|
||||
@@ -2576,4 +2576,22 @@ $capabilities = array(
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
]
|
||||
],
|
||||
|
||||
// Allow to manage payment accounts.
|
||||
'moodle/payment:manageaccounts' => [
|
||||
'captype' => 'write',
|
||||
'riskbitmask' => RISK_PERSONAL | RISK_CONFIG | RISK_DATALOSS,
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'archetypes' => [
|
||||
]
|
||||
],
|
||||
|
||||
// Allow to view payments.
|
||||
'moodle/payment:viewpayments' => [
|
||||
'captype' => 'read',
|
||||
'riskbitmask' => RISK_PERSONAL,
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'archetypes' => [
|
||||
]
|
||||
],
|
||||
);
|
||||
|
||||
@@ -4288,6 +4288,35 @@
|
||||
<INDEX NAME="instance" UNIQUE="false" FIELDS="contextid, contenttype, instanceid"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
<TABLE NAME="payment_accounts" COMMENT="Payment accounts">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="idnumber" TYPE="char" LENGTH="100" NOTNULL="false" SEQUENCE="false"/>
|
||||
<FIELD NAME="contextid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="enabled" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false"/>
|
||||
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="payment_gateways" COMMENT="Configuration for one gateway for one payment account">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="accountid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="gateway" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="enabled" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
|
||||
<FIELD NAME="config" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
|
||||
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
<KEY NAME="accountid" TYPE="foreign" FIELDS="accountid" REFTABLE="payment_accounts" REFFIELDS="id"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="payments" COMMENT="Stores information about payments">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
@@ -4296,6 +4325,7 @@
|
||||
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="amount" TYPE="char" LENGTH="20" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="currency" TYPE="char" LENGTH="3" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="accountid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="gateway" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
@@ -4303,6 +4333,7 @@
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
<KEY NAME="userid" TYPE="foreign" FIELDS="userid" REFTABLE="user" REFFIELDS="id"/>
|
||||
<KEY NAME="accountid" TYPE="foreign" FIELDS="accountid" REFTABLE="payment_accounts" REFFIELDS="id"/>
|
||||
</KEYS>
|
||||
<INDEXES>
|
||||
<INDEX NAME="component" UNIQUE="false" FIELDS="component"/>
|
||||
|
||||
@@ -2896,5 +2896,68 @@ function xmldb_main_upgrade($oldversion) {
|
||||
upgrade_main_savepoint(true, 2021052500.32);
|
||||
}
|
||||
|
||||
if ($oldversion < 2021052500.33) {
|
||||
|
||||
// Define table payment_accounts to be created.
|
||||
$table = new xmldb_table('payment_accounts');
|
||||
|
||||
// Adding fields to table payment_accounts.
|
||||
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
|
||||
$table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('idnumber', XMLDB_TYPE_CHAR, '100', null, null, null, null);
|
||||
$table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('enabled', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0');
|
||||
$table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
|
||||
$table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
|
||||
|
||||
// Adding keys to table payment_accounts.
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
|
||||
|
||||
// Conditionally launch create table for payment_accounts.
|
||||
if (!$dbman->table_exists($table)) {
|
||||
$dbman->create_table($table);
|
||||
}
|
||||
|
||||
// Define table payment_gateways to be created.
|
||||
$table = new xmldb_table('payment_gateways');
|
||||
|
||||
// Adding fields to table payment_gateways.
|
||||
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
|
||||
$table->add_field('accountid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('gateway', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('enabled', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1');
|
||||
$table->add_field('config', XMLDB_TYPE_TEXT, null, null, null, null, null);
|
||||
$table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
|
||||
|
||||
// Adding keys to table payment_gateways.
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
|
||||
$table->add_key('accountid', XMLDB_KEY_FOREIGN, ['accountid'], 'payment_accounts', ['id']);
|
||||
|
||||
// Conditionally launch create table for payment_gateways.
|
||||
if (!$dbman->table_exists($table)) {
|
||||
$dbman->create_table($table);
|
||||
}
|
||||
|
||||
// Define field accountid to be added to payments.
|
||||
$table = new xmldb_table('payments');
|
||||
$field = new xmldb_field('accountid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'currency');
|
||||
|
||||
// Conditionally launch add field accountid.
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
// Define key accountid (foreign) to be added to payments.
|
||||
$table = new xmldb_table('payments');
|
||||
$key = new xmldb_key('accountid', XMLDB_KEY_FOREIGN, ['accountid'], 'payment_accounts', ['id']);
|
||||
|
||||
// Launch add key accountid.
|
||||
$dbman->add_key($table, $key);
|
||||
|
||||
// Main savepoint reached.
|
||||
upgrade_main_savepoint(true, 2021052500.33);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Management of payment accounts
|
||||
*
|
||||
* @package core_payment
|
||||
* @copyright 2020 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(__DIR__ . '/../config.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
|
||||
admin_externalpage_setup('paymentaccounts');
|
||||
$PAGE->set_heading(get_string('paymentaccounts', 'payment'));
|
||||
|
||||
$enabledplugins = \core\plugininfo\pg::get_enabled_plugins();
|
||||
|
||||
echo $OUTPUT->header();
|
||||
|
||||
$accounts = \core_payment\helper::get_payment_accounts_to_manage(context_system::instance());
|
||||
$table = new html_table();
|
||||
$table->head = [get_string('accountname', 'payment'), get_string('type_pg', 'plugin'), ''];
|
||||
$table->colclasses = ['', '', 'mdl-right'];
|
||||
$table->data = [];
|
||||
foreach ($accounts as $account) {
|
||||
$gateways = [];
|
||||
$canmanage = has_capability('moodle/payment:manageaccounts', $account->get_context());
|
||||
foreach ($account->get_gateways() as $gateway) {
|
||||
$status = $gateway->get('enabled') ? $OUTPUT->pix_icon('i/valid', get_string('gatewayenabled', 'payment')) :
|
||||
$OUTPUT->pix_icon('i/invalid', get_string('gatewaydisabled', 'payment'));
|
||||
$gateways[] = $status .
|
||||
($canmanage ? html_writer::link($gateway->get_edit_url(), $gateway->get_display_name()) : $gateway->get_display_name());
|
||||
}
|
||||
$name = $account->get_formatted_name();
|
||||
if (!$account->is_available()) {
|
||||
$name .= ' ' . html_writer::span(get_string('accountnotavailable', 'payment'), 'badge badge-warning');
|
||||
}
|
||||
|
||||
$menu = new action_menu();
|
||||
$menu->set_alignment(action_menu::TL, action_menu::BL);
|
||||
$menu->set_menu_trigger(get_string('edit'));
|
||||
if ($canmanage) {
|
||||
$menu->add(new action_menu_link_secondary($account->get_edit_url(), null, get_string('edit')));
|
||||
$deleteurl = $account->get_edit_url(['delete' => 1, 'sesskey' => sesskey()]);
|
||||
$deleteaction = new confirm_action(get_string('deleteconfirm', 'tool_recyclebin'));
|
||||
$menu->add(new action_menu_link_secondary($deleteurl, null, get_string('delete')));
|
||||
}
|
||||
|
||||
$table->data[] = [$name, join(', ', $gateways), $OUTPUT->render($menu)];
|
||||
}
|
||||
|
||||
echo html_writer::table($table);
|
||||
|
||||
echo $OUTPUT->single_button(new moodle_url('/payment/manage_account.php'), get_string('createaccount', 'payment'), 'get');
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
define ("core_payment/gateways_modal",["exports","core/modal_factory","core/templates","core/str","./repository","./selectors","core/modal_events","core_payment/events","core/toast","core/notification","./modal_gateways"],function(a,b,c,d,e,f,g,h,i,j,k){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.registerEventListeners=a.registerEventListenersBySelector=void 0;b=l(b);c=l(c);f=l(f);g=l(g);h=l(h);j=l(j);k=l(k);var o="undefined"!=typeof window?window:"undefined"!=typeof self?self:"undefined"!=typeof global?global:{};function l(a){return a&&a.__esModule?a:{default:a}}function m(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function n(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){m(h,d,e,f,g,"next",a)}function g(a){m(h,d,e,f,g,"throw",a)}f(void 0)})}}a.registerEventListenersBySelector=function registerEventListenersBySelector(a){document.querySelectorAll(a).forEach(function(a){p(a)})};var p=function(a){a.addEventListener("click",function(b){b.preventDefault();q(a,{focusOnClose:b.target})})};a.registerEventListeners=p;var q=function(){var a=n(regeneratorRuntime.mark(function a(l){var m,n,o,p,q,u,v,w,x,y,z,A=arguments;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:m=1<A.length&&A[1]!==void 0?A[1]:{},n=m.focusOnClose,o=void 0===n?null:n;a.t0=b.default;a.t1=k.default.TYPE;a.next=5;return(0,d.get_string)("selectpaymenttype","core_payment");case 5:a.t2=a.sent;a.next=8;return c.default.render("core_payment/gateways_modal",{});case 8:a.t3=a.sent;a.t4={type:a.t1,title:a.t2,body:a.t3};a.next=12;return a.t0.create.call(a.t0,a.t4);case 12:p=a.sent;q=p.getRoot()[0];(0,i.addToastRegion)(q);p.show();p.getRoot().on(g.default.hidden,function(){p.destroy();try{o.focus()}catch(a){}});p.getRoot().on(h.default.proceed,function(a){var b=(q.querySelector(f.default.values.gateway)||{value:""}).value;if(b){t(b,{value:parseFloat(l.dataset.amount),currency:l.dataset.currency,surcharge:parseInt((q.querySelector(f.default.values.gateway)||{dataset:{surcharge:0}}).dataset.surcharge)},l.dataset.component,l.dataset.componentid,l.dataset.description,function(a){var b=a.success,c=a.message,d=void 0===c?"":c;p.hide();if(b){j.default.addNotification({message:d,type:"success"});location.reload()}else{j.default.alert("",d)}})}else{(0,d.get_string)("nogatewayselected","core_payment").then(function(a){return(0,i.add)(a)})}a.preventDefault()});q.addEventListener("change",function(a){if(a.target.matches(f.default.elements.gateways)){s(q,parseFloat(l.dataset.amount),l.dataset.currency)}});u=l.dataset.currency;a.next=22;return(0,e.getGatewaysSupportingCurrency)(u);case 22:v=a.sent;w={gateways:v};a.next=26;return c.default.renderForPromise("core_payment/gateways",w);case 26:x=a.sent;y=x.html;z=x.js;c.default.replaceNodeContents(q.querySelector(f.default.regions.gatewaysContainer),y,z);r(q);a.next=33;return s(q,parseFloat(l.dataset.amount),l.dataset.currency);case 33:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}(),r=function(a){var b=a.querySelectorAll(f.default.elements.gateways);if(1==b.length){b[0].checked=!0}},s=function(){var a=n(regeneratorRuntime.mark(function a(b,d,e){var g,h,i,j,k,l;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:a.next=2;return s.locale;case 2:g=a.sent;h=parseInt((b.querySelector(f.default.values.gateway)||{dataset:{surcharge:0}}).dataset.surcharge);d+=d*h/100;i=d.toLocaleString(g,{style:"currency",currency:e});a.next=8;return c.default.renderForPromise("core_payment/fee_breakdown",{fee:i,surcharge:h});case 8:j=a.sent;k=j.html;l=j.js;c.default.replaceNodeContents(b.querySelector(f.default.regions.costContainer),k,l);case 12:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}();s.locale=(0,d.get_string)("localecldr","langconfig");var t=function(){var a=n(regeneratorRuntime.mark(function a(b,c,d,e,f,g){var h,i,j,k,l;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:h=c.value,i=c.currency,j=c.surcharge,k=void 0===j?0:j;a.next=3;return"function"==typeof o.define&&o.define.amd?new Promise(function(a,c){o.require(["pg_".concat(b,"/gateways_modal")],a,c)}):"undefined"!=typeof module&&module.exports&&"undefined"!=typeof require||"undefined"!=typeof module&&module.component&&o.require&&"component"===o.require.loader?Promise.resolve(require(("pg_".concat(b,"/gateways_modal")))):Promise.resolve(o["pg_".concat(b,"/gateways_modal")]);case 3:l=a.sent;h+=h*k/100;l.process(h,i,d,e,f,g);case 6:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}()});
|
||||
define ("core_payment/gateways_modal",["exports","core/modal_factory","core/templates","core/str","./repository","./selectors","core/modal_events","core_payment/events","core/toast","core/notification","./modal_gateways"],function(a,b,c,d,e,f,g,h,i,j,k){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.registerEventListeners=a.registerEventListenersBySelector=void 0;b=l(b);c=l(c);f=l(f);g=l(g);h=l(h);j=l(j);k=l(k);var o="undefined"!=typeof window?window:"undefined"!=typeof self?self:"undefined"!=typeof global?global:{};function l(a){return a&&a.__esModule?a:{default:a}}function m(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function n(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){m(h,d,e,f,g,"next",a)}function g(a){m(h,d,e,f,g,"throw",a)}f(void 0)})}}a.registerEventListenersBySelector=function registerEventListenersBySelector(a){document.querySelectorAll(a).forEach(function(a){p(a)})};var p=function(a){a.addEventListener("click",function(b){b.preventDefault();q(a,{focusOnClose:b.target})})};a.registerEventListeners=p;var q=function(){var a=n(regeneratorRuntime.mark(function a(l){var m,n,o,p,q,u,v,w,x,y,z,A,B=arguments;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:m=1<B.length&&B[1]!==void 0?B[1]:{},n=m.focusOnClose,o=void 0===n?null:n;a.t0=b.default;a.t1=k.default.TYPE;a.next=5;return(0,d.get_string)("selectpaymenttype","core_payment");case 5:a.t2=a.sent;a.next=8;return c.default.render("core_payment/gateways_modal",{});case 8:a.t3=a.sent;a.t4={type:a.t1,title:a.t2,body:a.t3};a.next=12;return a.t0.create.call(a.t0,a.t4);case 12:p=a.sent;q=p.getRoot()[0];(0,i.addToastRegion)(q);p.show();p.getRoot().on(g.default.hidden,function(){p.destroy();try{o.focus()}catch(a){}});p.getRoot().on(h.default.proceed,function(a){var b=(q.querySelector(f.default.values.gateway)||{value:""}).value;if(b){t(b,{value:parseFloat(l.dataset.amount),currency:l.dataset.currency,surcharge:parseInt((q.querySelector(f.default.values.gateway)||{dataset:{surcharge:0}}).dataset.surcharge)},l.dataset.component,l.dataset.componentid,l.dataset.description,function(a){var b=a.success,c=a.message,d=void 0===c?"":c;p.hide();if(b){j.default.addNotification({message:d,type:"success"});location.reload()}else{j.default.alert("",d)}})}else{(0,d.get_string)("nogatewayselected","core_payment").then(function(a){return(0,i.add)(a)})}a.preventDefault()});q.addEventListener("change",function(a){if(a.target.matches(f.default.elements.gateways)){s(q,parseFloat(l.dataset.amount),l.dataset.currency)}});u=l.dataset.currency;v=l.dataset.accountid;a.next=23;return(0,e.getGatewaysSupportingCurrency)(u,v);case 23:w=a.sent;x={gateways:w};a.next=27;return c.default.renderForPromise("core_payment/gateways",x);case 27:y=a.sent;z=y.html;A=y.js;c.default.replaceNodeContents(q.querySelector(f.default.regions.gatewaysContainer),z,A);r(q);a.next=34;return s(q,parseFloat(l.dataset.amount),l.dataset.currency);case 34:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}(),r=function(a){var b=a.querySelectorAll(f.default.elements.gateways);if(1==b.length){b[0].checked=!0}},s=function(){var a=n(regeneratorRuntime.mark(function a(b,d,e){var g,h,i,j,k,l;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:a.next=2;return s.locale;case 2:g=a.sent;h=parseInt((b.querySelector(f.default.values.gateway)||{dataset:{surcharge:0}}).dataset.surcharge);d+=d*h/100;i=d.toLocaleString(g,{style:"currency",currency:e});a.next=8;return c.default.renderForPromise("core_payment/fee_breakdown",{fee:i,surcharge:h});case 8:j=a.sent;k=j.html;l=j.js;c.default.replaceNodeContents(b.querySelector(f.default.regions.costContainer),k,l);case 12:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}();s.locale=(0,d.get_string)("localecldr","langconfig");var t=function(){var a=n(regeneratorRuntime.mark(function a(b,c,d,e,f,g){var h,i,j,k,l;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:h=c.value,i=c.currency,j=c.surcharge,k=void 0===j?0:j;a.next=3;return"function"==typeof o.define&&o.define.amd?new Promise(function(a,c){o.require(["pg_".concat(b,"/gateways_modal")],a,c)}):"undefined"!=typeof module&&module.exports&&"undefined"!=typeof require||"undefined"!=typeof module&&module.component&&o.require&&"component"===o.require.loader?Promise.resolve(require(("pg_".concat(b,"/gateways_modal")))):Promise.resolve(o["pg_".concat(b,"/gateways_modal")]);case 3:l=a.sent;h+=h*k/100;l.process(h,i,d,e,f,g);case 6:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}()});
|
||||
//# sourceMappingURL=gateways_modal.min.js.map
|
||||
|
||||
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -1,2 +1,2 @@
|
||||
define ("core_payment/repository",["exports","core/ajax"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.getGatewaysSupportingCurrency=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);var c=function(a){return b.default.call([{methodname:"core_payment_get_gateways_for_currency",args:{currency:a}}])[0]};a.getGatewaysSupportingCurrency=c});
|
||||
define ("core_payment/repository",["exports","core/ajax"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.getGatewaysSupportingCurrency=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);var c=function(a,c){return b.default.call([{methodname:"core_payment_get_gateways_for_currency",args:{currency:a,accountid:c}}])[0]};a.getGatewaysSupportingCurrency=c});
|
||||
//# sourceMappingURL=repository.min.js.map
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"sources":["../src/repository.js"],"names":["getGatewaysSupportingCurrency","currency","Ajax","call","methodname","args"],"mappings":"6KAwBA,uDAQO,GAAMA,CAAAA,CAA6B,CAAG,SAAAC,CAAQ,CAAI,CAOrD,MAAOC,WAAKC,IAAL,CAAU,CAND,CACZC,UAAU,CAAE,wCADA,CAEZC,IAAI,CAAE,CACFJ,QAAQ,CAARA,CADE,CAFM,CAMC,CAAV,EAAqB,CAArB,CACV,CARM,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Repository for payment subsystem.\n *\n * @module core_payment/repository\n * @package core_payment\n * @copyright 2020 Shamim Rezaie <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\n\n/**\n * Returns the list of gateways that can process payments in the given currency.\n *\n * @param {string} currency The currency in the three-character ISO-4217 format\n * @returns {Promise<{shortname: string, name: string, description: String}[]>}\n */\nexport const getGatewaysSupportingCurrency = currency => {\n const request = {\n methodname: 'core_payment_get_gateways_for_currency',\n args: {\n currency\n }\n };\n return Ajax.call([request])[0];\n};\n"],"file":"repository.min.js"}
|
||||
{"version":3,"sources":["../src/repository.js"],"names":["getGatewaysSupportingCurrency","currency","accountid","Ajax","call","methodname","args"],"mappings":"6KAwBA,uDASO,GAAMA,CAAAA,CAA6B,CAAG,SAACC,CAAD,CAAWC,CAAX,CAAyB,CAQlE,MAAOC,WAAKC,IAAL,CAAU,CAPD,CACZC,UAAU,CAAE,wCADA,CAEZC,IAAI,CAAE,CACFL,QAAQ,CAARA,CADE,CAEFC,SAAS,CAATA,CAFE,CAFM,CAOC,CAAV,EAAqB,CAArB,CACV,CATM,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Repository for payment subsystem.\n *\n * @module core_payment/repository\n * @package core_payment\n * @copyright 2020 Shamim Rezaie <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\n\n/**\n * Returns the list of gateways that can process payments in the given currency.\n *\n * @param {string} currency The currency in the three-character ISO-4217 format\n * @param {int} accountid\n * @returns {Promise<{shortname: string, name: string, description: String}[]>}\n */\nexport const getGatewaysSupportingCurrency = (currency, accountid) => {\n const request = {\n methodname: 'core_payment_get_gateways_for_currency',\n args: {\n currency,\n accountid\n }\n };\n return Ajax.call([request])[0];\n};\n"],"file":"repository.min.js"}
|
||||
@@ -133,7 +133,8 @@ const show = async(rootNode, {
|
||||
});
|
||||
|
||||
const currency = rootNode.dataset.currency;
|
||||
const gateways = await getGatewaysSupportingCurrency(currency);
|
||||
const accountid = rootNode.dataset.accountid;
|
||||
const gateways = await getGatewaysSupportingCurrency(currency, accountid);
|
||||
const context = {
|
||||
gateways
|
||||
};
|
||||
|
||||
@@ -28,13 +28,15 @@ import Ajax from 'core/ajax';
|
||||
* Returns the list of gateways that can process payments in the given currency.
|
||||
*
|
||||
* @param {string} currency The currency in the three-character ISO-4217 format
|
||||
* @param {int} accountid
|
||||
* @returns {Promise<{shortname: string, name: string, description: String}[]>}
|
||||
*/
|
||||
export const getGatewaysSupportingCurrency = currency => {
|
||||
export const getGatewaysSupportingCurrency = (currency, accountid) => {
|
||||
const request = {
|
||||
methodname: 'core_payment_get_gateways_for_currency',
|
||||
args: {
|
||||
currency
|
||||
currency,
|
||||
accountid
|
||||
}
|
||||
};
|
||||
return Ajax.call([request])[0];
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Class account
|
||||
*
|
||||
* @package core_payment
|
||||
* @copyright 2020 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_payment;
|
||||
|
||||
use core\persistent;
|
||||
|
||||
/**
|
||||
* Class account
|
||||
*
|
||||
* @package core_payment
|
||||
* @copyright 2020 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class account extends persistent {
|
||||
/**
|
||||
* Database table.
|
||||
*/
|
||||
const TABLE = 'payment_accounts';
|
||||
|
||||
/** @var array */
|
||||
protected $gateways;
|
||||
|
||||
/**
|
||||
* Return the definition of the properties of this model.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function define_properties() : array {
|
||||
return array(
|
||||
'name' => [
|
||||
'type' => PARAM_TEXT,
|
||||
],
|
||||
'idnumber' => [
|
||||
'type' => PARAM_RAW_TRIMMED,
|
||||
],
|
||||
'contextid' => [
|
||||
'type' => PARAM_INT,
|
||||
'default' => function() {
|
||||
return \context_system::instance()->id;
|
||||
}
|
||||
],
|
||||
'enabled' => [
|
||||
'type' => PARAM_BOOL,
|
||||
'default' => true
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Account context
|
||||
*
|
||||
* @return \context
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function get_context(): \context {
|
||||
return \context::instance_by_id($this->get('contextid'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Account name ready for display
|
||||
*
|
||||
* @return string
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function get_formatted_name(): string {
|
||||
return format_string($this->get('name'), true, ['context' => $this->get_context(), 'escape' => false]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage account url
|
||||
*
|
||||
* @param array $extraparams
|
||||
* @return \moodle_url
|
||||
* @throws \coding_exception
|
||||
* @throws \moodle_exception
|
||||
*/
|
||||
public function get_edit_url(array $extraparams = []): \moodle_url {
|
||||
return new \moodle_url('/payment/manage_account.php',
|
||||
($this->get('id') ? ['id' => $this->get('id')] : []) + $extraparams);
|
||||
}
|
||||
|
||||
/**
|
||||
* List of gateways configured (or possible) for this account
|
||||
*
|
||||
* @param bool $enabledpluginsonly only return payment plugins that are enabled
|
||||
* @return account_gateway[]
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function get_gateways(bool $enabledpluginsonly = true): array {
|
||||
$id = $this->get('id');
|
||||
if (!$id) {
|
||||
return [];
|
||||
}
|
||||
if ($this->gateways === null) {
|
||||
\core_component::get_plugin_list('pg');
|
||||
$this->gateways = [];
|
||||
foreach (\core_component::get_plugin_list('pg') as $gatewayname => $unused) {
|
||||
$gateway = account_gateway::get_record(['accountid' => $id, 'gateway' => $gatewayname]);
|
||||
if (!$gateway) {
|
||||
$gateway = new account_gateway(0, (object)['accountid' => $id, 'gateway' => $gatewayname,
|
||||
'enabled' => false, 'config' => null]);
|
||||
}
|
||||
$this->gateways[$gatewayname] = $gateway;
|
||||
}
|
||||
}
|
||||
if ($enabledpluginsonly) {
|
||||
$enabledplugins = \core\plugininfo\pg::get_enabled_plugins();
|
||||
return array_intersect_key($this->gateways, $enabledplugins);
|
||||
}
|
||||
return $this->gateways;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this account available (used in management interface)
|
||||
*
|
||||
* @return bool
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function is_available(): bool {
|
||||
if (!$this->get('id') || !$this->get('enabled')) {
|
||||
return false;
|
||||
}
|
||||
foreach ($this->get_gateways() as $gateway) {
|
||||
if ($gateway->get('id') && $gateway->get('enabled')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Class account_gateway
|
||||
*
|
||||
* @package core_payment
|
||||
* @copyright 2020 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_payment;
|
||||
|
||||
use core\persistent;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class account_gateway
|
||||
*
|
||||
* @package core_payment
|
||||
* @copyright 2020 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class account_gateway extends persistent {
|
||||
/**
|
||||
* Database table.
|
||||
*/
|
||||
const TABLE = 'payment_gateways';
|
||||
|
||||
/**
|
||||
* Return the definition of the properties of this model.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function define_properties() : array {
|
||||
return array(
|
||||
'accountid' => [
|
||||
'type' => PARAM_INT,
|
||||
],
|
||||
'gateway' => [
|
||||
'type' => PARAM_COMPONENT,
|
||||
// TODO select with options?
|
||||
],
|
||||
'enabled' => [
|
||||
'type' => PARAM_BOOL,
|
||||
'default' => true
|
||||
],
|
||||
'config' => [
|
||||
'type' => PARAM_RAW,
|
||||
'optional' => true,
|
||||
'null' => NULL_ALLOWED,
|
||||
'default' => null
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the gateway name ready for display
|
||||
*
|
||||
* @return string
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function get_display_name(): string {
|
||||
return get_string('pluginname', 'pg_' . $this->get('gateway'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gateway management url
|
||||
*
|
||||
* @return \moodle_url
|
||||
* @throws \coding_exception
|
||||
* @throws \moodle_exception
|
||||
*/
|
||||
public function get_edit_url(): \moodle_url {
|
||||
$params = $this->get('id') ? ['id' => $this->get('id')] :
|
||||
['accountid' => $this->get('accountid'), 'gateway' => $this->get('gateway')];
|
||||
return new \moodle_url('/payment/manage_gateway.php', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get corresponding account
|
||||
*
|
||||
* @return account
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function get_account(): account {
|
||||
return new account($this->get('accountid'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse configuration from the json-encoded stored value
|
||||
*
|
||||
* @return array
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function get_configuration(): array {
|
||||
$config = @json_decode($this->get('config'), true);
|
||||
return ($config && is_array($config)) ? $config : [];
|
||||
}
|
||||
}
|
||||
+6
-3
@@ -43,7 +43,8 @@ class get_gateways_for_currency extends external_api {
|
||||
*/
|
||||
public static function execute_parameters(): external_function_parameters {
|
||||
return new external_function_parameters(
|
||||
['currency' => new external_value(PARAM_ALPHA, 'Currency code')]
|
||||
['currency' => new external_value(PARAM_ALPHA, 'Currency code'),
|
||||
'accountid' => new external_value(PARAM_INT, 'Account id')]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -51,16 +52,18 @@ class get_gateways_for_currency extends external_api {
|
||||
* Returns the list of gateways that can process payments in the given currency.
|
||||
*
|
||||
* @param string $currency The currency in the three-character ISO-4217 format.
|
||||
* @param int $accountid
|
||||
* @return \stdClass[]
|
||||
*/
|
||||
public static function execute(string $currency): array {
|
||||
public static function execute(string $currency, int $accountid): array {
|
||||
|
||||
$params = external_api::validate_parameters(self::execute_parameters(), [
|
||||
'currency' => $currency,
|
||||
'accountid' => $accountid,
|
||||
]);
|
||||
|
||||
$list = [];
|
||||
$gateways = \core_payment\helper::get_gateways_for_currency($params['currency']);
|
||||
$gateways = \core_payment\helper::get_gateways_for_currency($params['currency'], $params['accountid']);
|
||||
|
||||
foreach ($gateways as $gateway) {
|
||||
$list[] = (object)[
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Class account
|
||||
*
|
||||
* @package core_payment
|
||||
* @copyright 2020 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_payment\form;
|
||||
|
||||
use core\form\persistent;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class account
|
||||
*
|
||||
* @package core_payment
|
||||
* @copyright 2020 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class account extends persistent {
|
||||
|
||||
/** @var string The persistent class. */
|
||||
protected static $persistentclass = 'core_payment\account';
|
||||
|
||||
/**
|
||||
* Define the form - called by parent constructor
|
||||
*/
|
||||
public function definition() {
|
||||
$mform = $this->_form;
|
||||
|
||||
$mform->addElement('hidden', 'id');
|
||||
$mform->addElement('hidden', 'contextid');
|
||||
|
||||
$mform->addElement('text', 'name', get_string('accountname', 'payment'), 'maxlength="255"');
|
||||
$mform->setType('name', PARAM_TEXT);
|
||||
$mform->addRule('name', get_string('required'), 'required', null, 'client');
|
||||
$mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'server');
|
||||
|
||||
$mform->addElement('text', 'idnumber', get_string('idnumber'), 'maxlength="100"');
|
||||
$mform->setType('idnumber', PARAM_RAW_TRIMMED);
|
||||
$mform->addRule('idnumber', get_string('maximumchars', '', 100), 'maxlength', 100, 'server');
|
||||
|
||||
$mform->addElement('advcheckbox', 'enabled', get_string('enable'));
|
||||
$this->add_action_buttons();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Class account_gateway
|
||||
*
|
||||
* @package core_payment
|
||||
* @copyright 2020 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_payment\form;
|
||||
|
||||
use core\form\persistent;
|
||||
use core_payment\gateway;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class account_gateway
|
||||
*
|
||||
* @package core_payment
|
||||
* @copyright 2020 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class account_gateway extends persistent {
|
||||
|
||||
/** @var string The persistent class. */
|
||||
protected static $persistentclass = \core_payment\account_gateway::class;
|
||||
|
||||
protected static $fieldstoremove = ['accountname', 'gatewayname', 'submitbutton'];
|
||||
|
||||
/**
|
||||
* Define the form - called by parent constructor
|
||||
*/
|
||||
public function definition() {
|
||||
$mform = $this->_form;
|
||||
|
||||
$mform->addElement('hidden', 'id');
|
||||
$mform->addElement('hidden', 'accountid');
|
||||
$mform->addElement('hidden', 'gateway');
|
||||
|
||||
$mform->addElement('static', 'accountname', get_string('accountname', 'payment'),
|
||||
$this->get_gateway_persistent()->get_account()->get_formatted_name());
|
||||
|
||||
$mform->addElement('static', 'gatewayname', get_string('type_pg', 'plugin'),
|
||||
$this->get_gateway_persistent()->get_display_name());
|
||||
|
||||
$mform->addElement('advcheckbox', 'enabled', get_string('enable'));
|
||||
|
||||
/** @var \core_payment\gateway $classname */
|
||||
$classname = '\pg_' . $this->get_gateway_persistent()->get('gateway') . '\gateway';
|
||||
if (class_exists($classname)) {
|
||||
$classname::add_configuration_to_gateway_form($this);
|
||||
}
|
||||
|
||||
$this->add_action_buttons();
|
||||
}
|
||||
|
||||
/**
|
||||
* Form validation
|
||||
*
|
||||
* @param \stdClass $data
|
||||
* @param array $files
|
||||
* @param array $errors
|
||||
*/
|
||||
protected function extra_validation($data, $files, array &$errors) {
|
||||
/** @var \core_payment\gateway $classname */
|
||||
$classname = '\pg_' . $this->get_gateway_persistent()->get('gateway') . '\gateway';
|
||||
if (class_exists($classname)) {
|
||||
$classname::validate_gateway_form($this, $data, $files, $errors);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exposes the protected attribute to be accessed by the \core_payment\gateway callback
|
||||
*
|
||||
* @return \MoodleQuickForm
|
||||
*/
|
||||
public function get_mform(): \MoodleQuickForm {
|
||||
return $this->_form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exposes the protected attribute to be accessed by the \core_payment\gateway callback
|
||||
*
|
||||
* @return \core_payment\account_gateway
|
||||
*/
|
||||
public function get_gateway_persistent(): \core_payment\account_gateway {
|
||||
return $this->get_persistent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter out the foreign fields of the persistent.
|
||||
*
|
||||
* This can be overridden to filter out more complex fields.
|
||||
*
|
||||
* @param \stdClass $data The data to filter the fields out of.
|
||||
* @return \stdClass.
|
||||
*/
|
||||
protected function filter_data_for_persistent($data) {
|
||||
$data = parent::filter_data_for_persistent($data);
|
||||
return (object) array_intersect_key((array)$data, \core_payment\account_gateway::properties_definition());
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite parent method to json encode config
|
||||
*
|
||||
* @return object|\stdClass|null
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function get_data() {
|
||||
if (!$data = parent::get_data()) {
|
||||
return $data;
|
||||
}
|
||||
// Everything that is not a property of the account_gateway class is a gateway config.
|
||||
$data = (array)$data;
|
||||
$properties = \core_payment\account_gateway::properties_definition() + ['id' => 1];
|
||||
$config = array_diff_key($data, $properties, ['timemodified' => 1, 'timecreated' => 1]);
|
||||
$data = array_intersect_key($data, $properties);
|
||||
$data['config'] = json_encode($config);
|
||||
return (object)$data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite parent method to json decode config
|
||||
*
|
||||
* @param array|\stdClass $values
|
||||
*/
|
||||
public function set_data($values) {
|
||||
if (($config = isset($values->config) ? @json_decode($values->config, true) : null) && is_array($config)) {
|
||||
$values = (object)((array)$values + $config);
|
||||
}
|
||||
unset($values->config);
|
||||
parent::set_data($values);
|
||||
}
|
||||
}
|
||||
@@ -39,4 +39,30 @@ abstract class gateway {
|
||||
* @return string[] An array of the currency codes in the three-character ISO-4217 format
|
||||
*/
|
||||
public abstract static function get_supported_currencies(): array;
|
||||
|
||||
/**
|
||||
* Configuration form for the gateway instance
|
||||
*
|
||||
* Use $form->get_mform() to access the \MoodleQuickForm instance
|
||||
*
|
||||
* @param \core_payment\form\account_gateway $form
|
||||
*/
|
||||
public abstract static function add_configuration_to_gateway_form(\core_payment\form\account_gateway $form): void;
|
||||
|
||||
/**
|
||||
* Validates the gateway configuration form.
|
||||
*
|
||||
* Needs to be overridden to make sure the incomplete configuration can not be enabled.
|
||||
*
|
||||
* @param \core_payment\form\account_gateway $form
|
||||
* @param \stdClass $data
|
||||
* @param array $files
|
||||
* @param array $errors form errors (passed by reference)
|
||||
*/
|
||||
public static function validate_gateway_form(\core_payment\form\account_gateway $form,
|
||||
\stdClass $data, array $files, array &$errors): void {
|
||||
if ($data->enabled) {
|
||||
$errors['enabled'] = get_string('gatewaycannotbeenabled', 'payment');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+116
-5
@@ -44,6 +44,7 @@ class helper {
|
||||
|
||||
$plugins = \core_plugin_manager::instance()->get_enabled_plugins('pg');
|
||||
foreach ($plugins as $plugin) {
|
||||
/** @var \pg_paypal\gateway $classname */
|
||||
$classname = '\pg_' . $plugin . '\gateway';
|
||||
|
||||
$currencies += $classname::get_supported_currencies();
|
||||
@@ -58,13 +59,22 @@ class helper {
|
||||
* Returns the list of gateways that can process payments in the given currency.
|
||||
*
|
||||
* @param string $currency The currency in the three-character ISO-4217 format.
|
||||
* @param int $accountid
|
||||
* @return string[]
|
||||
*/
|
||||
public static function get_gateways_for_currency(string $currency): array {
|
||||
public static function get_gateways_for_currency(string $currency, int $accountid): array {
|
||||
$gateways = [];
|
||||
|
||||
$plugins = \core_plugin_manager::instance()->get_enabled_plugins('pg');
|
||||
foreach ($plugins as $plugin) {
|
||||
$account = new account($accountid);
|
||||
if (!$account->get('id') || !$account->get('enabled')) {
|
||||
return $gateways;
|
||||
}
|
||||
|
||||
foreach ($account->get_gateways() as $plugin => $gateway) {
|
||||
if (!$gateway->get('enabled')) {
|
||||
continue;
|
||||
}
|
||||
/** @var gateway $classname */
|
||||
$classname = '\pg_' . $plugin . '\gateway';
|
||||
|
||||
$currencies = $classname::get_supported_currencies();
|
||||
@@ -114,19 +124,42 @@ class helper {
|
||||
*
|
||||
* @param string $component Name of the component that the componentid belongs to
|
||||
* @param int $componentid An internal identifier that is used by the component
|
||||
* @return array['amount' => float, 'currency' => string]
|
||||
* @return array['amount' => float, 'currency' => string, 'accountid' => int]
|
||||
* @throws \moodle_exception
|
||||
*/
|
||||
public static function get_cost(string $component, int $componentid): array {
|
||||
$cost = component_class_callback("$component\\payment\\provider", 'get_cost', [$componentid]);
|
||||
|
||||
if ($cost === null) {
|
||||
if ($cost === null || !is_array($cost) || !array_key_exists('amount', $cost)
|
||||
|| !array_key_exists('currency', $cost) || !array_key_exists('accountid', $cost) ) {
|
||||
throw new \moodle_exception('callbacknotimplemented', 'core_payment', '', $component);
|
||||
}
|
||||
|
||||
return $cost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the gateway configuration for given component and gateway
|
||||
*
|
||||
* @param string $component
|
||||
* @param int $componentid
|
||||
* @param string $gatewayname
|
||||
* @return array
|
||||
* @throws \moodle_exception
|
||||
*/
|
||||
public static function get_gateway_configuration(string $component, int $componentid, string $gatewayname): array {
|
||||
$x = self::get_cost($component, $componentid);
|
||||
$gateway = null;
|
||||
$account = new account($x['accountid']);
|
||||
if ($account && $account->get('enabled')) {
|
||||
$gateway = $account->get_gateways()[$gatewayname] ?? null;
|
||||
}
|
||||
if (!$gateway) {
|
||||
throw new \moodle_exception('gatewaynotfound', 'payment');
|
||||
}
|
||||
return $gateway->get_configuration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delivers what the user paid for.
|
||||
*
|
||||
@@ -186,4 +219,82 @@ class helper {
|
||||
get_string('surcharge_desc', 'core_payment'), 0, PARAM_INT));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a new or edited payment account (used in management interface)
|
||||
*
|
||||
* @param \stdClass $data
|
||||
*/
|
||||
public static function save_payment_account(\stdClass $data) {
|
||||
|
||||
if (empty($data->id)) {
|
||||
$account = new account(0, $data);
|
||||
} else {
|
||||
$account = new account($data->id);
|
||||
$account->from_record($data);
|
||||
}
|
||||
|
||||
$account->save();
|
||||
// TODO trigger event.
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a payment account (used in management interface)
|
||||
*
|
||||
* @param account $account
|
||||
*/
|
||||
public static function delete_payment_account(account $account) {
|
||||
foreach ($account->get_gateways(false) as $gateway) {
|
||||
if ($gateway->get('id')) {
|
||||
$gateway->delete();
|
||||
}
|
||||
}
|
||||
$account->delete();
|
||||
// TODO trigger event.
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a payment gateway linked to an existing account (used in management interface)
|
||||
*
|
||||
* @param \stdClass $data
|
||||
*/
|
||||
public static function save_payment_gateway(\stdClass $data) {
|
||||
if (empty($data->id)) {
|
||||
$gateway = new account_gateway(0, $data);
|
||||
} else {
|
||||
$gateway = new account_gateway($data->id);
|
||||
unset($data->accountid, $data->gateway, $data->id);
|
||||
$gateway->from_record($data);
|
||||
}
|
||||
|
||||
$gateway->save();
|
||||
// TODO trigger event.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of payment accounts in the given context (used in management interface)
|
||||
*
|
||||
* @param \context $context
|
||||
* @return account[]
|
||||
*/
|
||||
public static function get_payment_accounts_to_manage(\context $context): array {
|
||||
return account::get_records(['contextid' => $context->id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of accounts available in the given context
|
||||
*
|
||||
* @param \context $context
|
||||
* @return array
|
||||
*/
|
||||
public static function get_payment_accounts_menu(\context $context): array {
|
||||
global $DB;
|
||||
[$sql, $params] = $DB->get_in_or_equal($context->get_parent_context_ids(true));
|
||||
$accounts = array_filter(account::get_records_select('contextid '.$sql, $params), function($account) {
|
||||
return $account->is_available();
|
||||
});
|
||||
return array_map(function($account) {
|
||||
return $account->get_formatted_name();
|
||||
}, $accounts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ interface provider {
|
||||
|
||||
/**
|
||||
* @param int $identifier An identifier that is known to the plugin
|
||||
* @return array['amount' => float, 'currency' => string]
|
||||
* @return array['amount' => float, 'currency' => string, 'accountid' => int]
|
||||
*/
|
||||
public static function get_cost(int $identifier): array;
|
||||
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
function _typeof(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){_typeof=function(a){return typeof a}}else{_typeof=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return _typeof(a)}define ("pg_paypal/gateways_modal",["exports","./repository","core/templates","core/truncate","core/ajax","core/modal_factory","core/modal_events","core/str"],function(a,b,c,d,e,f,g,h){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.process=void 0;b=k(b);c=i(c);d=i(d);e=i(e);f=i(f);g=i(g);function i(a){return a&&a.__esModule?a:{default:a}}function j(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;j=function(){return a};return a}function k(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=j();if(b&&b.has(a)){return b.get(a)}var c={},d=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var e in a){if(Object.prototype.hasOwnProperty.call(a,e)){var f=d?Object.getOwnPropertyDescriptor(a,e):null;if(f&&(f.get||f.set)){Object.defineProperty(c,e,f)}else{c[e]=a[e]}}}c.default=a;if(b){b.set(a,c)}return c}function l(a,b){return r(a)||q(a,b)||n(a,b)||m()}function m(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function n(a,b){if(!a)return;if("string"==typeof a)return p(a,b);var c=Object.prototype.toString.call(a).slice(8,-1);if("Object"===c&&a.constructor)c=a.constructor.name;if("Map"===c||"Set"===c)return Array.from(c);if("Arguments"===c||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(c))return p(a,b)}function p(a,b){if(null==b||b>a.length)b=a.length;for(var c=0,d=Array(b);c<b;c++){d[c]=a[c]}return d}function q(a,b){if("undefined"==typeof Symbol||!(Symbol.iterator in Object(a)))return;var c=[],d=!0,e=!1,f=void 0;try{for(var g=a[Symbol.iterator](),h;!(d=(h=g.next()).done);d=!0){c.push(h.value);if(b&&c.length===b)break}}catch(a){e=!0;f=a}finally{try{if(!d&&null!=g["return"])g["return"]()}finally{if(e)throw f}}return c}function r(a){if(Array.isArray(a))return a}function s(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function t(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){s(h,d,e,f,g,"next",a)}function g(a){s(h,d,e,f,g,"throw",a)}f(void 0)})}}var u=function(){var a=t(regeneratorRuntime.mark(function a(){var b;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:a.t0=f.default;a.next=3;return c.default.render("pg_paypal/paypal_button_placeholder",{});case 3:a.t1=a.sent;a.t2={body:a.t1};a.next=7;return a.t0.create.call(a.t0,a.t2);case 7:b=a.sent;b.show();return a.abrupt("return",b);case 10:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}(),v=function(){var a=t(regeneratorRuntime.mark(function a(c,f,i,j,k,m){var n,o,p,q,r;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:a.next=2;return Promise.all([u(),b.getConfigForJs()]);case 2:n=a.sent;o=l(n,2);p=o[0];q=o[1];p.getRoot().on(g.default.hidden,function(){p.destroy()});r="https://www.paypal.com/sdk/js?client-id=".concat(q.clientid,"¤cy=").concat(f);w(r,function(){p.setBody("");paypal.Buttons({createOrder:function createOrder(a,b){return b.order.create({purchase_units:[{amount:{currency_code:f,value:c},description:d.default.truncate(k,{length:127,stripTags:!0})}],application_context:{shipping_preference:"NO_SHIPPING",brand_name:d.default.truncate(q.brandname,{length:127,stripTags:!0})}})},onApprove:function onApprove(a){p.getRoot().on(g.default.outsideClick,function(a){a.preventDefault()});p.setBody((0,h.get_string)("authorising","pg_paypal"));return e.default.call([{methodname:"pg_paypal_create_transaction_complete",args:{component:i,componentid:j,orderid:a.orderID}}])[0].then(function(a){p.hide();return m(a)})}}).render(p.getBody()[0])});case 9:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}();a.process=v;var w=function(a,b){if(w.currentlyloaded==a){b();return}if(w.currentlyloaded){var d=document.querySelector("script[src=\"".concat(w.currentlyloaded,"\"]"));if(d){d.parentNode.removeChild(d)}}var c=document.createElement("script");if(c.readyState){c.onreadystatechange=function(){if("complete"==this.readyState||"loaded"==this.readyState){this.onreadystatechange=null;b()}}}else{c.onload=function(){b()}}c.setAttribute("src",a);document.head.appendChild(c);w.currentlyloaded=a};w.currentlyloaded=""});
|
||||
function _typeof(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){_typeof=function(a){return typeof a}}else{_typeof=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return _typeof(a)}define ("pg_paypal/gateways_modal",["exports","./repository","core/templates","core/truncate","core/ajax","core/modal_factory","core/modal_events","core/str"],function(a,b,c,d,e,f,g,h){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.process=void 0;b=k(b);c=i(c);d=i(d);e=i(e);f=i(f);g=i(g);function i(a){return a&&a.__esModule?a:{default:a}}function j(){if("function"!=typeof WeakMap)return null;var a=new WeakMap;j=function(){return a};return a}function k(a){if(a&&a.__esModule){return a}if(null===a||"object"!==_typeof(a)&&"function"!=typeof a){return{default:a}}var b=j();if(b&&b.has(a)){return b.get(a)}var c={},d=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var e in a){if(Object.prototype.hasOwnProperty.call(a,e)){var f=d?Object.getOwnPropertyDescriptor(a,e):null;if(f&&(f.get||f.set)){Object.defineProperty(c,e,f)}else{c[e]=a[e]}}}c.default=a;if(b){b.set(a,c)}return c}function l(a,b){return r(a)||q(a,b)||n(a,b)||m()}function m(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function n(a,b){if(!a)return;if("string"==typeof a)return p(a,b);var c=Object.prototype.toString.call(a).slice(8,-1);if("Object"===c&&a.constructor)c=a.constructor.name;if("Map"===c||"Set"===c)return Array.from(c);if("Arguments"===c||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(c))return p(a,b)}function p(a,b){if(null==b||b>a.length)b=a.length;for(var c=0,d=Array(b);c<b;c++){d[c]=a[c]}return d}function q(a,b){if("undefined"==typeof Symbol||!(Symbol.iterator in Object(a)))return;var c=[],d=!0,e=!1,f=void 0;try{for(var g=a[Symbol.iterator](),h;!(d=(h=g.next()).done);d=!0){c.push(h.value);if(b&&c.length===b)break}}catch(a){e=!0;f=a}finally{try{if(!d&&null!=g["return"])g["return"]()}finally{if(e)throw f}}return c}function r(a){if(Array.isArray(a))return a}function s(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function t(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){s(h,d,e,f,g,"next",a)}function g(a){s(h,d,e,f,g,"throw",a)}f(void 0)})}}var u=function(){var a=t(regeneratorRuntime.mark(function a(){var b;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:a.t0=f.default;a.next=3;return c.default.render("pg_paypal/paypal_button_placeholder",{});case 3:a.t1=a.sent;a.t2={body:a.t1};a.next=7;return a.t0.create.call(a.t0,a.t2);case 7:b=a.sent;b.show();return a.abrupt("return",b);case 10:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}(),v=function(){var a=t(regeneratorRuntime.mark(function a(c,f,i,j,k,m){var n,o,p,q,r;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:a.next=2;return Promise.all([u(),b.getConfigForJs(i,j)]);case 2:n=a.sent;o=l(n,2);p=o[0];q=o[1];p.getRoot().on(g.default.hidden,function(){p.destroy()});r="https://www.paypal.com/sdk/js?client-id=".concat(q.clientid,"¤cy=").concat(f);w(r,function(){p.setBody("");paypal.Buttons({createOrder:function createOrder(a,b){return b.order.create({purchase_units:[{amount:{currency_code:f,value:c},description:d.default.truncate(k,{length:127,stripTags:!0})}],application_context:{shipping_preference:"NO_SHIPPING",brand_name:d.default.truncate(q.brandname,{length:127,stripTags:!0})}})},onApprove:function onApprove(a){p.getRoot().on(g.default.outsideClick,function(a){a.preventDefault()});p.setBody((0,h.get_string)("authorising","pg_paypal"));return e.default.call([{methodname:"pg_paypal_create_transaction_complete",args:{component:i,componentid:j,orderid:a.orderID}}])[0].then(function(a){p.hide();return m(a)})}}).render(p.getBody()[0])});case 9:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}();a.process=v;var w=function(a,b){if(w.currentlyloaded==a){b();return}if(w.currentlyloaded){var d=document.querySelector("script[src=\"".concat(w.currentlyloaded,"\"]"));if(d){d.parentNode.removeChild(d)}}var c=document.createElement("script");if(c.readyState){c.onreadystatechange=function(){if("complete"==this.readyState||"loaded"==this.readyState){this.onreadystatechange=null;b()}}}else{c.onload=function(){b()}}c.setAttribute("src",a);document.head.appendChild(c);w.currentlyloaded=a};w.currentlyloaded=""});
|
||||
//# sourceMappingURL=gateways_modal.min.js.map
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
-1
@@ -1,2 +1,2 @@
|
||||
define ("pg_paypal/repository",["exports","core/ajax"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.getConfigForJs=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);var c=function(){return b.default.call([{methodname:"pg_paypal_get_config_for_js",args:{}}])[0]};a.getConfigForJs=c});
|
||||
define ("pg_paypal/repository",["exports","core/ajax"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.getConfigForJs=void 0;b=function(a){return a&&a.__esModule?a:{default:a}}(b);var c=function(a,c){return b.default.call([{methodname:"pg_paypal_get_config_for_js",args:{component:a,componentid:c}}])[0]};a.getConfigForJs=c});
|
||||
//# sourceMappingURL=repository.min.js.map
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"sources":["../src/repository.js"],"names":["getConfigForJs","Ajax","call","methodname","args"],"mappings":"2JAwBA,uDAOO,GAAMA,CAAAA,CAAc,CAAG,UAAM,CAMhC,MAAOC,WAAKC,IAAL,CAAU,CALD,CACZC,UAAU,CAAE,6BADA,CAEZC,IAAI,CAAE,EAFM,CAKC,CAAV,EAAqB,CAArB,CACV,CAPM,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * PayPal repository module to encapsulate all of the AJAX requests that can be sent for PayPal.\n *\n * @module pg_paypal/repository\n * @package pg_paypal\n * @copyright 2020 Shamim Rezaie <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\n\n/**\n * Return the PayPal JavaScript SDK URL.\n *\n * @returns {Promise<{clientid: String, brandname: String}>}\n */\nexport const getConfigForJs = () => {\n const request = {\n methodname: 'pg_paypal_get_config_for_js',\n args: {},\n };\n\n return Ajax.call([request])[0];\n};\n"],"file":"repository.min.js"}
|
||||
{"version":3,"sources":["../src/repository.js"],"names":["getConfigForJs","component","componentid","Ajax","call","methodname","args"],"mappings":"2JAwBA,uDAOO,GAAMA,CAAAA,CAAc,CAAG,SAACC,CAAD,CAAYC,CAAZ,CAA4B,CAMtD,MAAOC,WAAKC,IAAL,CAAU,CALD,CACZC,UAAU,CAAE,6BADA,CAEZC,IAAI,CAAE,CAACL,SAAS,CAATA,CAAD,CAAYC,WAAW,CAAXA,CAAZ,CAFM,CAKC,CAAV,EAAqB,CAArB,CACV,CAPM,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * PayPal repository module to encapsulate all of the AJAX requests that can be sent for PayPal.\n *\n * @module pg_paypal/repository\n * @package pg_paypal\n * @copyright 2020 Shamim Rezaie <[email protected]>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\n\n/**\n * Return the PayPal JavaScript SDK URL.\n *\n * @returns {Promise<{clientid: String, brandname: String}>}\n */\nexport const getConfigForJs = (component, componentid) => {\n const request = {\n methodname: 'pg_paypal_get_config_for_js',\n args: {component, componentid},\n };\n\n return Ajax.call([request])[0];\n};\n"],"file":"repository.min.js"}
|
||||
@@ -60,7 +60,7 @@ export const process = async(amount, currency, component, componentid, descripti
|
||||
paypalConfig,
|
||||
] = await Promise.all([
|
||||
showModalWithPlaceholder(),
|
||||
Repository.getConfigForJs(),
|
||||
Repository.getConfigForJs(component, componentid),
|
||||
]);
|
||||
|
||||
modal.getRoot().on(ModalEvents.hidden, () => {
|
||||
|
||||
@@ -29,10 +29,10 @@ import Ajax from 'core/ajax';
|
||||
*
|
||||
* @returns {Promise<{clientid: String, brandname: String}>}
|
||||
*/
|
||||
export const getConfigForJs = () => {
|
||||
export const getConfigForJs = (component, componentid) => {
|
||||
const request = {
|
||||
methodname: 'pg_paypal_get_config_for_js',
|
||||
args: {},
|
||||
args: {component, componentid},
|
||||
};
|
||||
|
||||
return Ajax.call([request])[0];
|
||||
|
||||
@@ -26,6 +26,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pg_paypal\external;
|
||||
|
||||
use core_payment\helper;
|
||||
use external_api;
|
||||
use external_function_parameters;
|
||||
use external_value;
|
||||
@@ -43,7 +44,10 @@ class get_config_for_js extends external_api {
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function execute_parameters(): external_function_parameters {
|
||||
return new external_function_parameters([]);
|
||||
return new external_function_parameters([
|
||||
'component' => new external_value(PARAM_COMPONENT, ''),
|
||||
'componentid' => new external_value(PARAM_INT, ''),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,12 +55,17 @@ class get_config_for_js extends external_api {
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function execute(): array {
|
||||
$config = get_config('pg_paypal');
|
||||
public static function execute($component, $componentid): array {
|
||||
self::validate_parameters(self::execute_parameters(), [
|
||||
'component' => $component,
|
||||
'componentid' => $componentid,
|
||||
]);
|
||||
|
||||
$config = helper::get_gateway_configuration($component, $componentid, 'paypal');
|
||||
|
||||
return [
|
||||
'clientid' => $config->clientid,
|
||||
'brandname' => $config->brandname,
|
||||
'clientid' => $config['clientid'],
|
||||
'brandname' => $config['brandname'],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pg_paypal\external;
|
||||
|
||||
use core_payment\helper;
|
||||
use external_api;
|
||||
use external_function_parameters;
|
||||
use external_value;
|
||||
@@ -69,12 +70,13 @@ class transaction_complete extends external_api {
|
||||
'orderid' => $orderid,
|
||||
]);
|
||||
|
||||
$config = get_config('pg_paypal');
|
||||
$config = (object)helper::get_gateway_configuration($component, $componentid, 'paypal');
|
||||
$sandbox = $config->environment == 'sandbox';
|
||||
|
||||
[
|
||||
'amount' => $amount,
|
||||
'currency' => $currency
|
||||
'currency' => $currency,
|
||||
'accountid' => $accountid,
|
||||
] = payment_helper::get_cost($component, $componentid);
|
||||
|
||||
// Add surcharge if there is any.
|
||||
|
||||
@@ -41,4 +41,51 @@ class gateway extends \core_payment\gateway {
|
||||
'MXN', 'MYR', 'NOK', 'NZD', 'PHP', 'PLN', 'RUB', 'SEK', 'SGD', 'THB', 'TRY', 'TWD', 'USD'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration form for the gateway instance
|
||||
*
|
||||
* Use $form->get_mform() to access the \MoodleQuickForm instance
|
||||
*
|
||||
* @param \core_payment\form\account_gateway $form
|
||||
*/
|
||||
public static function add_configuration_to_gateway_form(\core_payment\form\account_gateway $form): void {
|
||||
$mform = $form->get_mform();
|
||||
|
||||
$mform->addElement('text', 'brandname', get_string('brandname', 'pg_paypal'));
|
||||
$mform->setType('brandname', PARAM_TEXT);
|
||||
$mform->addHelpButton('brandname', 'brandname', 'pg_paypal');
|
||||
|
||||
$mform->addElement('text', 'clientid', get_string('clientid', 'pg_paypal'));
|
||||
$mform->setType('clientid', PARAM_TEXT);
|
||||
$mform->addHelpButton('clientid', 'clientid', 'pg_paypal');
|
||||
|
||||
$mform->addElement('text', 'secret', get_string('secret', 'pg_paypal'));
|
||||
$mform->setType('secret', PARAM_TEXT);
|
||||
$mform->addHelpButton('secret', 'secret', 'pg_paypal');
|
||||
|
||||
$options = [
|
||||
'live' => get_string('live', 'pg_paypal'),
|
||||
'sandbox' => get_string('sandbox', 'pg_paypal'),
|
||||
];
|
||||
|
||||
$mform->addElement('select', 'environment', get_string('environment', 'pg_paypal'), $options);
|
||||
$mform->addHelpButton('environment', 'environment', 'pg_paypal');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the gateway configuration form.
|
||||
*
|
||||
* @param \core_payment\form\account_gateway $form
|
||||
* @param \stdClass $data
|
||||
* @param array $files
|
||||
* @param array $errors form errors (passed by reference)
|
||||
*/
|
||||
public static function validate_gateway_form(\core_payment\form\account_gateway $form,
|
||||
\stdClass $data, array $files, array &$errors): void {
|
||||
if ($data->enabled &&
|
||||
(empty($data->brandname) || empty($data->clientid) || empty($data->secret))) {
|
||||
$errors['enabled'] = get_string('gatewaycannotbeenabled', 'payment');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,14 +33,6 @@ $functions = [
|
||||
'type' => 'read',
|
||||
'ajax' => true,
|
||||
],
|
||||
'pg_paypal_get_sdk_url' => [
|
||||
'classname' => 'pg_paypal\external\get_sdk_url',
|
||||
'methodname' => 'execute',
|
||||
'classpath' => '',
|
||||
'description' => 'Generates and returns the URL of the PayPal JavaScript SDK',
|
||||
'type' => 'read',
|
||||
'ajax' => true,
|
||||
],
|
||||
'pg_paypal_create_transaction_complete' => [
|
||||
'classname' => 'pg_paypal\external\transaction_complete',
|
||||
'methodname' => 'execute',
|
||||
|
||||
@@ -25,12 +25,12 @@
|
||||
$string['amountmismatch'] = 'The amount you attempted to pay does not match the required fee. Your account has not been debited.';
|
||||
$string['authorising'] = 'Authorising the payment. Please wait...';
|
||||
$string['brandname'] = 'Brand name';
|
||||
$string['brandname_desc'] = 'The optional label that overrides the business name in the PayPal account on the PayPal site.';
|
||||
$string['brandname_help'] = 'An optional label that overrides the business name for the PayPal account on the PayPal site.';
|
||||
$string['cannotfetchorderdatails'] = 'Could not fetch payment details from PayPal. Your account has not been debited.';
|
||||
$string['clientid'] = 'Client ID';
|
||||
$string['clientid_desc'] = 'The client ID that PayPal generated for your application.';
|
||||
$string['clientid_help'] = 'The client ID that PayPal generated for your application.';
|
||||
$string['environment'] = 'Environment';
|
||||
$string['environment_desc'] = 'You can set this to Sandbox if you are using sandbox accounts (for testing purpose only).';
|
||||
$string['environment_help'] = 'You can set this to Sandbox if you are using sandbox accounts (for testing purpose only).';
|
||||
$string['gatewaydescription'] = 'PayPal is an authorised payment gateway provider for processing credit card transactions.';
|
||||
$string['gatewayname'] = 'PayPal';
|
||||
$string['internalerror'] = 'An internal error has occurred. Please contact us.';
|
||||
@@ -41,4 +41,4 @@ $string['pluginname_desc'] = 'The PayPal plugin allows you to receive payments v
|
||||
$string['repeatedorder'] = 'This order has already been processed earlier.';
|
||||
$string['sandbox'] = 'Sandbox';
|
||||
$string['secret'] = 'Secret';
|
||||
$string['secret_desc'] = 'The secret thatPayPal generated for your application.';
|
||||
$string['secret_help'] = 'The secret thatPayPal generated for your application.';
|
||||
|
||||
@@ -28,19 +28,5 @@ if ($ADMIN->fulltree) {
|
||||
|
||||
$settings->add(new admin_setting_heading('pg_paypal_settings', '', get_string('pluginname_desc', 'pg_paypal')));
|
||||
|
||||
$settings->add(new admin_setting_configtext('pg_paypal/brandname', get_string('brandname', 'pg_paypal'),
|
||||
get_string('brandname', 'pg_paypal'), '', PARAM_TEXT));
|
||||
$settings->add(new admin_setting_configtext('pg_paypal/clientid', get_string('clientid', 'pg_paypal'),
|
||||
get_string('clientid_desc', 'pg_paypal'), '', PARAM_TEXT));
|
||||
$settings->add(new admin_setting_configtext('pg_paypal/secret', get_string('secret', 'pg_paypal'),
|
||||
get_string('secret_desc', 'pg_paypal'), '', PARAM_TEXT));
|
||||
|
||||
$options = [
|
||||
'live' => get_string('live', 'pg_paypal'),
|
||||
'sandbox' => get_string('sandbox', 'pg_paypal'),
|
||||
];
|
||||
$settings->add(new admin_setting_configselect('pg_paypal/environment', get_string('environment', 'pg_paypal'),
|
||||
get_string('environment_desc', 'pg_paypal'), 'live', $options));
|
||||
|
||||
\core_payment\helper::add_common_gateway_settings($settings, 'pg_paypal');
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Manage one payment accounts
|
||||
*
|
||||
* @package core_payment
|
||||
* @copyright 2020 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(__DIR__ . '/../config.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
|
||||
$id = optional_param('id', 0, PARAM_INT);
|
||||
$delete = optional_param('delete', false, PARAM_BOOL);
|
||||
|
||||
$pageurl = new moodle_url('/payment/manage_account.php');
|
||||
admin_externalpage_setup('paymentaccounts', '', [], $pageurl);
|
||||
|
||||
$enabledplugins = \core\plugininfo\pg::get_enabled_plugins();
|
||||
|
||||
$account = new \core_payment\account($id);
|
||||
require_capability('moodle/payment:manageaccounts', $account->get_context());
|
||||
|
||||
if ($delete && confirm_sesskey()) {
|
||||
\core_payment\helper::delete_payment_account($account);
|
||||
redirect(new moodle_url('/payment/accounts.php'));
|
||||
}
|
||||
|
||||
$PAGE->set_heading($id ? format_string($account->get('name')) : get_string('createaccount', 'payment'));
|
||||
|
||||
$form = new \core_payment\form\account($pageurl->out(false), ['persistent' => $account]);
|
||||
|
||||
if ($form->is_cancelled()) {
|
||||
redirect(new moodle_url('/payment/accounts.php'));
|
||||
} else if ($data = $form->get_data()) {
|
||||
\core_payment\helper::save_payment_account($data);
|
||||
redirect(new moodle_url('/payment/accounts.php'));
|
||||
}
|
||||
|
||||
echo $OUTPUT->header();
|
||||
$form->display();
|
||||
echo $OUTPUT->footer();
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Manage one payment gateway
|
||||
*
|
||||
* @package core_payment
|
||||
* @copyright 2020 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(__DIR__ . '/../config.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
|
||||
$id = optional_param('id', 0, PARAM_INT);
|
||||
$accountid = optional_param('accountid', 0, PARAM_INT);
|
||||
$gatewayname = optional_param('gateway', null, PARAM_COMPONENT);
|
||||
|
||||
$pageurl = new moodle_url('/payment/manage_gateway.php');
|
||||
admin_externalpage_setup('paymentaccounts', '', [], $pageurl);
|
||||
|
||||
$enabledplugins = \core\plugininfo\pg::get_enabled_plugins();
|
||||
|
||||
if ($id) {
|
||||
$gateway = new \core_payment\account_gateway($id);
|
||||
$account = new \core_payment\account($gateway->get('accountid'));
|
||||
} else if ($accountid) {
|
||||
$account = new \core_payment\account($accountid);
|
||||
$gateway = $account->get_gateways()[$gatewayname] ?? null;
|
||||
}
|
||||
|
||||
if (empty($account) || empty($gateway)) {
|
||||
throw new moodle_exception('gatewaynotfound', 'payment');
|
||||
}
|
||||
require_capability('moodle/payment:manageaccounts', $account->get_context());
|
||||
|
||||
$PAGE->set_heading($id ? format_string($account->get('name')) : get_string('createaccount', 'payment'));
|
||||
|
||||
$form = new \core_payment\form\account_gateway($pageurl->out(false), ['persistent' => $gateway]);
|
||||
|
||||
if ($form->is_cancelled()) {
|
||||
redirect(new moodle_url('/payment/accounts.php'));
|
||||
} else if ($data = $form->get_data()) {
|
||||
\core_payment\helper::save_payment_gateway($data);
|
||||
redirect(new moodle_url('/payment/accounts.php'));
|
||||
}
|
||||
|
||||
echo $OUTPUT->header();
|
||||
$form->display();
|
||||
echo $OUTPUT->footer();
|
||||
Reference in New Issue
Block a user