���ѧۧݧ�ӧ�� �ާ֧ߧ֧էا֧� - ���֧էѧܧ�ڧ��ӧѧ�� - /home3/cpr76684/public_html/payment.tar
���ѧ٧ѧ�
amd/build/repository.min.js.map 0000644 00000004013 15151162547 0012524 0 ustar 00 {"version":3,"file":"repository.min.js","sources":["../src/repository.js"],"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 * @copyright 2020 Shamim Rezaie <shamim@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\n\n/**\n * @typedef {Object} PaymentGateway A Payment Gateway\n * @property {string} shortname\n * @property {string} name\n * @property {string} description\n */\n\n/**\n * Returns the list of gateways that can process payments in the given currency.\n *\n * @method getAvailableGateways\n * @param {string} component\n * @param {string} paymentArea\n * @param {number} itemId\n * @returns {Promise<PaymentGateway[]>}\n */\nexport const getAvailableGateways = (component, paymentArea, itemId) => {\n const request = {\n methodname: 'core_payment_get_available_gateways',\n args: {\n component,\n paymentarea: paymentArea,\n itemid: itemId,\n }\n };\n return Ajax.call([request])[0];\n};\n"],"names":["component","paymentArea","itemId","request","methodname","args","paymentarea","itemid","Ajax","call"],"mappings":";;;;;;;oLAyCoC,CAACA,UAAWC,YAAaC,gBACnDC,QAAU,CACZC,WAAY,sCACZC,KAAM,CACFL,UAAAA,UACAM,YAAaL,YACbM,OAAQL,gBAGTM,cAAKC,KAAK,CAACN,UAAU"} amd/build/selectors.min.js.map 0000644 00000003165 15151162547 0012317 0 ustar 00 {"version":3,"file":"selectors.min.js","sources":["../src/selectors.js"],"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 * Define all of the selectors we will be using on the payment interface.\n *\n * @module core_payment/selectors\n * @copyright 2019 Shamim Rezaie <shamim@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport default {\n elements: {\n gateways: '[data-region=\"gateways-container\"] input[type=\"radio\"]',\n },\n regions: {\n gatewaysContainer: '[data-region=\"gateways-container\"]',\n costContainer: '[data-region=\"fee-breakdown-container\"]',\n },\n values: {\n gateway: '[data-region=\"gateways-container\"] input[type=\"radio\"]:checked',\n },\n};\n"],"names":["elements","gateways","regions","gatewaysContainer","costContainer","values","gateway"],"mappings":"wKAuBe,CACXA,SAAU,CACNC,SAAU,0DAEdC,QAAS,CACLC,kBAAmB,qCACnBC,cAAe,2CAEnBC,OAAQ,CACJC,QAAS"} amd/build/modal_gateways.min.js.map 0000644 00000007600 15151162547 0013312 0 ustar 00 {"version":3,"file":"modal_gateways.min.js","sources":["../src/modal_gateways.js"],"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 * Contain the logic for the gateways modal: A modal with proceed and cancel buttons.\n *\n * @module core_payment/modal_gateways\n * @copyright 2020 Shamim Rezaie <shamim@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from 'jquery';\nimport CustomEvents from 'core/custom_interaction_events';\nimport Modal from 'core/modal';\nimport ModalEvents from 'core/modal_events';\nimport PaymentEvents from 'core_payment/events';\nimport ModalRegistry from 'core/modal_registry';\n\nlet registered = false;\nconst SELECTORS = {\n PROCEED_BUTTON: '[data-action=\"proceed\"]',\n CANCEL_BUTTON: '[data-action=\"cancel\"]',\n};\n\nexport default class ModalGateways extends Modal {\n\n /**\n * Constructor for the Modal.\n *\n * @param {object} root The root jQuery element for the modal\n */\n constructor(root) {\n super(root);\n }\n\n /**\n * Set up all of the event handling for the modal.\n *\n * @method registerEventListeners\n */\n registerEventListeners() {\n // Apply parent event listeners.\n super.registerEventListeners();\n\n this.getModal().on(CustomEvents.events.activate, SELECTORS.PROCEED_BUTTON, (e, data) => {\n var proceedEvent = $.Event(PaymentEvents.proceed);\n this.getRoot().trigger(proceedEvent, this);\n\n if (!proceedEvent.isDefaultPrevented()) {\n this.hide();\n data.originalEvent.preventDefault();\n }\n });\n\n this.getModal().on(CustomEvents.events.activate, SELECTORS.CANCEL_BUTTON, (e, data) => {\n var cancelEvent = $.Event(ModalEvents.cancel);\n this.getRoot().trigger(cancelEvent, this);\n\n if (!cancelEvent.isDefaultPrevented()) {\n this.hide();\n data.originalEvent.preventDefault();\n }\n });\n }\n}\n\nModalGateways.TYPE = 'core_payment-modal_gateways';\n\n// Automatically register with the modal registry the first time this module is imported so that you can create modals\n// of this type using the modal factory.\nif (!registered) {\n ModalRegistry.register(ModalGateways.TYPE, ModalGateways, 'core_payment/modal_gateways');\n registered = true;\n}\n"],"names":["registered","SELECTORS","ModalGateways","Modal","constructor","root","registerEventListeners","getModal","on","CustomEvents","events","activate","e","data","proceedEvent","$","Event","PaymentEvents","proceed","getRoot","trigger","this","isDefaultPrevented","hide","originalEvent","preventDefault","cancelEvent","ModalEvents","cancel","TYPE","register"],"mappings":";;;;;;;yYA8BIA,YAAa,QACXC,yBACc,0BADdA,wBAEa,+BAGEC,sBAAsBC,eAOvCC,YAAYC,YACFA,MAQVC,+BAEUA,8BAEDC,WAAWC,GAAGC,mCAAaC,OAAOC,SAAUV,0BAA0B,CAACW,EAAGC,YACvEC,aAAeC,gBAAEC,MAAMC,gBAAcC,cACpCC,UAAUC,QAAQN,aAAcO,MAEhCP,aAAaQ,4BACTC,OACLV,KAAKW,cAAcC,0BAItBlB,WAAWC,GAAGC,mCAAaC,OAAOC,SAAUV,yBAAyB,CAACW,EAAGC,YACtEa,YAAcX,gBAAEC,MAAMW,sBAAYC,aACjCT,UAAUC,QAAQM,YAAaL,MAE/BK,YAAYJ,4BACRC,OACLV,KAAKW,cAAcC,4DAMnCvB,cAAc2B,KAAO,8BAIhB7B,qCACa8B,SAAS5B,cAAc2B,KAAM3B,cAAe,+BAC1DF,YAAa"} amd/build/repository.min.js 0000644 00000001346 15151162547 0011756 0 ustar 00 define("core_payment/repository",["exports","core/ajax"],(function(_exports,_ajax){var obj; /** * Repository for payment subsystem. * * @module core_payment/repository * @copyright 2020 Shamim Rezaie <shamim@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.getAvailableGateways=void 0,_ajax=(obj=_ajax)&&obj.__esModule?obj:{default:obj};_exports.getAvailableGateways=(component,paymentArea,itemId)=>{const request={methodname:"core_payment_get_available_gateways",args:{component:component,paymentarea:paymentArea,itemid:itemId}};return _ajax.default.call([request])[0]}})); //# sourceMappingURL=repository.min.js.map amd/build/gateways_modal.min.js.map 0000644 00000023256 15151162547 0013317 0 ustar 00 {"version":3,"file":"gateways_modal.min.js","sources":["../src/gateways_modal.js"],"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 * Contain the logic for the gateways modal.\n *\n * @module core_payment/gateways_modal\n * @copyright 2019 Shamim Rezaie <shamim@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport ModalFactory from 'core/modal_factory';\nimport Templates from 'core/templates';\nimport {get_string as getString} from 'core/str';\nimport {getAvailableGateways} from './repository';\nimport Selectors from './selectors';\nimport ModalEvents from 'core/modal_events';\nimport PaymentEvents from 'core_payment/events';\nimport {add as addToast, addToastRegion} from 'core/toast';\nimport Notification from 'core/notification';\nimport ModalGateways from './modal_gateways';\n\n/**\n * Register event listeners for the module.\n */\nconst registerEventListeners = () => {\n document.addEventListener('click', e => {\n const gatewayTrigger = e.target.closest('[data-action=\"core_payment/triggerPayment\"]');\n if (gatewayTrigger) {\n e.preventDefault();\n\n show(gatewayTrigger, {focusOnClose: e.target});\n }\n });\n};\n\n/**\n * Shows the gateway selector modal.\n *\n * @param {HTMLElement} rootNode\n * @param {Object} options - Additional options\n * @param {HTMLElement} options.focusOnClose The element to focus on when the modal is closed.\n */\nconst show = async(rootNode, {\n focusOnClose = null,\n} = {}) => {\n const modal = await ModalFactory.create({\n type: ModalGateways.TYPE,\n title: await getString('selectpaymenttype', 'core_payment'),\n body: await Templates.render('core_payment/gateways_modal', {}),\n });\n\n const rootElement = modal.getRoot()[0];\n addToastRegion(rootElement);\n\n modal.show();\n\n modal.getRoot().on(ModalEvents.hidden, () => {\n // Destroy when hidden.\n modal.destroy();\n try {\n focusOnClose.focus();\n } catch (e) {\n // eslint-disable-line\n }\n });\n\n modal.getRoot().on(PaymentEvents.proceed, (e) => {\n const gateway = (rootElement.querySelector(Selectors.values.gateway) || {value: ''}).value;\n\n if (gateway) {\n processPayment(\n gateway,\n rootNode.dataset.component,\n rootNode.dataset.paymentarea,\n rootNode.dataset.itemid,\n rootNode.dataset.description\n )\n .then(message => {\n modal.hide();\n Notification.addNotification({\n message: message,\n type: 'success',\n });\n location.href = rootNode.dataset.successurl;\n\n // The following return statement is never reached. It is put here just to make eslint happy.\n return message;\n })\n .catch(message => Notification.alert('', message));\n } else {\n // We cannot use await in the following line.\n // The reason is that we are preventing the default action of the save event being triggered,\n // therefore we cannot define the event handler function asynchronous.\n getString('nogatewayselected', 'core_payment').then(message => addToast(message, {type: 'warning'})).catch();\n }\n\n e.preventDefault();\n });\n\n // Re-calculate the cost when gateway is changed.\n rootElement.addEventListener('change', e => {\n if (e.target.matches(Selectors.elements.gateways)) {\n updateCostRegion(rootElement, rootNode.dataset.cost);\n }\n });\n\n const gateways = await getAvailableGateways(rootNode.dataset.component, rootNode.dataset.paymentarea, rootNode.dataset.itemid);\n const context = {\n gateways\n };\n\n const {html, js} = await Templates.renderForPromise('core_payment/gateways', context);\n Templates.replaceNodeContents(rootElement.querySelector(Selectors.regions.gatewaysContainer), html, js);\n selectSingleGateway(rootElement);\n await updateCostRegion(rootElement, rootNode.dataset.cost);\n};\n\n/**\n * Auto-select the gateway if there is only one gateway.\n *\n * @param {HTMLElement} root An HTMLElement that contains the cost region\n */\nconst selectSingleGateway = root => {\n const gateways = root.querySelectorAll(Selectors.elements.gateways);\n\n if (gateways.length == 1) {\n gateways[0].checked = true;\n }\n};\n\n/**\n * Shows the cost of the item the user is purchasing in the cost region.\n *\n * @param {HTMLElement} root An HTMLElement that contains the cost region\n * @param {string} defaultCost The default cost that is going to be displayed if no gateway is selected\n * @returns {Promise<void>}\n */\nconst updateCostRegion = async(root, defaultCost = '') => {\n const gatewayElement = root.querySelector(Selectors.values.gateway);\n const surcharge = parseInt((gatewayElement || {dataset: {surcharge: 0}}).dataset.surcharge);\n const cost = (gatewayElement || {dataset: {cost: defaultCost}}).dataset.cost;\n\n const {html, js} = await Templates.renderForPromise('core_payment/fee_breakdown', {fee: cost, surcharge});\n Templates.replaceNodeContents(root.querySelector(Selectors.regions.costContainer), html, js);\n};\n\n/**\n * Process payment using the selected gateway.\n *\n * @param {string} gateway The gateway to be used for payment\n * @param {string} component Name of the component that the itemId belongs to\n * @param {string} paymentArea Name of the area in the component that the itemId belongs to\n * @param {number} itemId An internal identifier that is used by the component\n * @param {string} description Description of the payment\n * @returns {Promise<string>}\n */\nconst processPayment = async(gateway, component, paymentArea, itemId, description) => {\n const paymentMethod = await import(`paygw_${gateway}/gateways_modal`);\n return paymentMethod.process(component, paymentArea, itemId, description);\n};\n\n/**\n * Set up the payment actions.\n */\nexport const init = () => {\n if (!init.initialised) {\n // Event listeners should only be registered once.\n init.initialised = true;\n registerEventListeners();\n }\n};\n\n/**\n * Whether the init function was called before.\n *\n * @static\n * @type {boolean}\n */\ninit.initialised = false;\n"],"names":["show","async","rootNode","focusOnClose","modal","ModalFactory","create","type","ModalGateways","TYPE","title","body","Templates","render","rootElement","getRoot","on","ModalEvents","hidden","destroy","focus","e","PaymentEvents","proceed","gateway","querySelector","Selectors","values","value","processPayment","dataset","component","paymentarea","itemid","description","then","message","hide","addNotification","location","href","successurl","catch","Notification","alert","preventDefault","addEventListener","target","matches","elements","gateways","updateCostRegion","cost","context","html","js","renderForPromise","replaceNodeContents","regions","gatewaysContainer","selectSingleGateway","root","querySelectorAll","length","checked","defaultCost","gatewayElement","surcharge","parseInt","fee","costContainer","paymentArea","itemId","process","init","initialised","document","gatewayTrigger","closest"],"mappings":"m/BAuDMA,KAAOC,eAAMC,cAAUC,aACzBA,aAAe,6DACf,SACMC,YAAcC,uBAAaC,OAAO,CACpCC,KAAMC,wBAAcC,KACpBC,YAAa,mBAAU,oBAAqB,gBAC5CC,WAAYC,mBAAUC,OAAO,8BAA+B,MAG1DC,YAAcV,MAAMW,UAAU,6BACrBD,aAEfV,MAAMJ,OAENI,MAAMW,UAAUC,GAAGC,sBAAYC,QAAQ,KAEnCd,MAAMe,cAEFhB,aAAaiB,QACf,MAAOC,QAKbjB,MAAMW,UAAUC,GAAGM,gBAAcC,SAAUF,UACjCG,SAAWV,YAAYW,cAAcC,mBAAUC,OAAOH,UAAY,CAACI,MAAO,KAAKA,MAEjFJ,QACAK,eACIL,QACAtB,SAAS4B,QAAQC,UACjB7B,SAAS4B,QAAQE,YACjB9B,SAAS4B,QAAQG,OACjB/B,SAAS4B,QAAQI,aAEpBC,MAAKC,UACFhC,MAAMiC,6BACOC,gBAAgB,CACzBF,QAASA,QACT7B,KAAM,YAEVgC,SAASC,KAAOtC,SAAS4B,QAAQW,WAG1BL,WAEVM,OAAMN,SAAWO,sBAAaC,MAAM,GAAIR,+BAK/B,oBAAqB,gBAAgBD,MAAKC,UAAW,cAASA,QAAS,CAAC7B,KAAM,cAAamC,QAGzGrB,EAAEwB,oBAIN/B,YAAYgC,iBAAiB,UAAUzB,IAC/BA,EAAE0B,OAAOC,QAAQtB,mBAAUuB,SAASC,WACpCC,iBAAiBrC,YAAaZ,SAAS4B,QAAQsB,eAIjDF,eAAiB,oCAAqBhD,SAAS4B,QAAQC,UAAW7B,SAAS4B,QAAQE,YAAa9B,SAAS4B,QAAQG,QACjHoB,QAAU,CACZH,SAAAA,WAGEI,KAACA,KAADC,GAAOA,UAAY3C,mBAAU4C,iBAAiB,wBAAyBH,4BACnEI,oBAAoB3C,YAAYW,cAAcC,mBAAUgC,QAAQC,mBAAoBL,KAAMC,IACpGK,oBAAoB9C,mBACdqC,iBAAiBrC,YAAaZ,SAAS4B,QAAQsB,OAQnDQ,oBAAsBC,aAClBX,SAAWW,KAAKC,iBAAiBpC,mBAAUuB,SAASC,UAEnC,GAAnBA,SAASa,SACTb,SAAS,GAAGc,SAAU,IAWxBb,iBAAmBlD,eAAM4D,UAAMI,mEAAc,SACzCC,eAAiBL,KAAKpC,cAAcC,mBAAUC,OAAOH,SACrD2C,UAAYC,UAAUF,gBAAkB,CAACpC,QAAS,CAACqC,UAAW,KAAKrC,QAAQqC,WAC3Ef,MAAQc,gBAAkB,CAACpC,QAAS,CAACsB,KAAMa,eAAenC,QAAQsB,MAElEE,KAACA,KAADC,GAAOA,UAAY3C,mBAAU4C,iBAAiB,6BAA8B,CAACa,IAAKjB,KAAMe,UAAAA,+BACpFV,oBAAoBI,KAAKpC,cAAcC,mBAAUgC,QAAQY,eAAgBhB,KAAMC,KAavF1B,eAAiB5B,MAAMuB,QAASO,UAAWwC,YAAaC,OAAQtC,qPACtBV,sUAAAA,sGAAAA,+BACvBiD,QAAQ1C,UAAWwC,YAAaC,OAAQtC,aAMpDwC,KAAO,KACXA,KAAKC,cAEND,KAAKC,aAAc,EA9IvBC,SAAS9B,iBAAiB,SAASzB,UACzBwD,eAAiBxD,EAAE0B,OAAO+B,QAAQ,+CACpCD,iBACAxD,EAAEwB,iBAEF7C,KAAK6E,eAAgB,CAAC1E,aAAckB,EAAE0B,kCAoJlD2B,KAAKC,aAAc"} amd/build/selectors.min.js 0000644 00000001001 15151162547 0011526 0 ustar 00 define("core_payment/selectors",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;return _exports.default={elements:{gateways:'[data-region="gateways-container"] input[type="radio"]'},regions:{gatewaysContainer:'[data-region="gateways-container"]',costContainer:'[data-region="fee-breakdown-container"]'},values:{gateway:'[data-region="gateways-container"] input[type="radio"]:checked'}},_exports.default})); //# sourceMappingURL=selectors.min.js.map amd/build/events.min.js 0000644 00000000421 15151162547 0011034 0 ustar 00 define("core_payment/events",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;return _exports.default={proceed:"core_payment-modal_gateways:proceed"},_exports.default})); //# sourceMappingURL=events.min.js.map amd/build/events.min.js.map 0000644 00000002171 15151162547 0011614 0 ustar 00 {"version":3,"file":"events.min.js","sources":["../src/events.js"],"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 * Contain the events the payment modal can fire.\n *\n * @module core_payment/events\n * @copyright 2020 Shamim Rezaie <shamim@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport default {\n proceed: 'core_payment-modal_gateways:proceed',\n};\n"],"names":["proceed"],"mappings":"qKAuBe,CACXA,QAAS"} amd/build/modal_gateways.min.js 0000644 00000004145 15151162547 0012537 0 ustar 00 define("core_payment/modal_gateways",["exports","jquery","core/custom_interaction_events","core/modal","core/modal_events","core_payment/events","core/modal_registry"],(function(_exports,_jquery,_custom_interaction_events,_modal,_modal_events,_events,_modal_registry){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} /** * Contain the logic for the gateways modal: A modal with proceed and cancel buttons. * * @module core_payment/modal_gateways * @copyright 2020 Shamim Rezaie <shamim@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_jquery=_interopRequireDefault(_jquery),_custom_interaction_events=_interopRequireDefault(_custom_interaction_events),_modal=_interopRequireDefault(_modal),_modal_events=_interopRequireDefault(_modal_events),_events=_interopRequireDefault(_events),_modal_registry=_interopRequireDefault(_modal_registry);let registered=!1;const SELECTORS_PROCEED_BUTTON='[data-action="proceed"]',SELECTORS_CANCEL_BUTTON='[data-action="cancel"]';class ModalGateways extends _modal.default{constructor(root){super(root)}registerEventListeners(){super.registerEventListeners(),this.getModal().on(_custom_interaction_events.default.events.activate,SELECTORS_PROCEED_BUTTON,((e,data)=>{var proceedEvent=_jquery.default.Event(_events.default.proceed);this.getRoot().trigger(proceedEvent,this),proceedEvent.isDefaultPrevented()||(this.hide(),data.originalEvent.preventDefault())})),this.getModal().on(_custom_interaction_events.default.events.activate,SELECTORS_CANCEL_BUTTON,((e,data)=>{var cancelEvent=_jquery.default.Event(_modal_events.default.cancel);this.getRoot().trigger(cancelEvent,this),cancelEvent.isDefaultPrevented()||(this.hide(),data.originalEvent.preventDefault())}))}}return _exports.default=ModalGateways,ModalGateways.TYPE="core_payment-modal_gateways",registered||(_modal_registry.default.register(ModalGateways.TYPE,ModalGateways,"core_payment/modal_gateways"),registered=!0),_exports.default})); //# sourceMappingURL=modal_gateways.min.js.map amd/build/gateways_modal.min.js 0000644 00000011120 15151162547 0012526 0 ustar 00 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(_exports,_modal_factory,_templates,_str,_repository,_selectors,_modal_events,_events,_toast,_notification,_modal_gateways){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_modal_factory=_interopRequireDefault(_modal_factory),_templates=_interopRequireDefault(_templates),_selectors=_interopRequireDefault(_selectors),_modal_events=_interopRequireDefault(_modal_events),_events=_interopRequireDefault(_events),_notification=_interopRequireDefault(_notification),_modal_gateways=_interopRequireDefault(_modal_gateways);var _systemImportTransformerGlobalIdentifier="undefined"!=typeof window?window:"undefined"!=typeof self?self:"undefined"!=typeof global?global:{};function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}const show=async function(rootNode){let{focusOnClose:focusOnClose=null}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const modal=await _modal_factory.default.create({type:_modal_gateways.default.TYPE,title:await(0,_str.get_string)("selectpaymenttype","core_payment"),body:await _templates.default.render("core_payment/gateways_modal",{})}),rootElement=modal.getRoot()[0];(0,_toast.addToastRegion)(rootElement),modal.show(),modal.getRoot().on(_modal_events.default.hidden,(()=>{modal.destroy();try{focusOnClose.focus()}catch(e){}})),modal.getRoot().on(_events.default.proceed,(e=>{const gateway=(rootElement.querySelector(_selectors.default.values.gateway)||{value:""}).value;gateway?processPayment(gateway,rootNode.dataset.component,rootNode.dataset.paymentarea,rootNode.dataset.itemid,rootNode.dataset.description).then((message=>(modal.hide(),_notification.default.addNotification({message:message,type:"success"}),location.href=rootNode.dataset.successurl,message))).catch((message=>_notification.default.alert("",message))):(0,_str.get_string)("nogatewayselected","core_payment").then((message=>(0,_toast.add)(message,{type:"warning"}))).catch(),e.preventDefault()})),rootElement.addEventListener("change",(e=>{e.target.matches(_selectors.default.elements.gateways)&&updateCostRegion(rootElement,rootNode.dataset.cost)}));const gateways=await(0,_repository.getAvailableGateways)(rootNode.dataset.component,rootNode.dataset.paymentarea,rootNode.dataset.itemid),context={gateways:gateways},{html:html,js:js}=await _templates.default.renderForPromise("core_payment/gateways",context);_templates.default.replaceNodeContents(rootElement.querySelector(_selectors.default.regions.gatewaysContainer),html,js),selectSingleGateway(rootElement),await updateCostRegion(rootElement,rootNode.dataset.cost)},selectSingleGateway=root=>{const gateways=root.querySelectorAll(_selectors.default.elements.gateways);1==gateways.length&&(gateways[0].checked=!0)},updateCostRegion=async function(root){let defaultCost=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";const gatewayElement=root.querySelector(_selectors.default.values.gateway),surcharge=parseInt((gatewayElement||{dataset:{surcharge:0}}).dataset.surcharge),cost=(gatewayElement||{dataset:{cost:defaultCost}}).dataset.cost,{html:html,js:js}=await _templates.default.renderForPromise("core_payment/fee_breakdown",{fee:cost,surcharge:surcharge});_templates.default.replaceNodeContents(root.querySelector(_selectors.default.regions.costContainer),html,js)},processPayment=async(gateway,component,paymentArea,itemId,description)=>(await("function"==typeof _systemImportTransformerGlobalIdentifier.define&&_systemImportTransformerGlobalIdentifier.define.amd?new Promise((function(resolve,reject){_systemImportTransformerGlobalIdentifier.require(["paygw_".concat(gateway,"/gateways_modal")],resolve,reject)})):"undefined"!=typeof module&&module.exports&&"undefined"!=typeof require||"undefined"!=typeof module&&module.component&&_systemImportTransformerGlobalIdentifier.require&&"component"===_systemImportTransformerGlobalIdentifier.require.loader?Promise.resolve(require("paygw_".concat(gateway,"/gateways_modal"))):Promise.resolve(_systemImportTransformerGlobalIdentifier["paygw_".concat(gateway,"/gateways_modal")]))).process(component,paymentArea,itemId,description),init=()=>{init.initialised||(init.initialised=!0,document.addEventListener("click",(e=>{const gatewayTrigger=e.target.closest('[data-action="core_payment/triggerPayment"]');gatewayTrigger&&(e.preventDefault(),show(gatewayTrigger,{focusOnClose:e.target}))})))};_exports.init=init,init.initialised=!1})); //# sourceMappingURL=gateways_modal.min.js.map amd/src/selectors.js 0000644 00000002436 15151162547 0010451 0 ustar 00 // 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/>. /** * Define all of the selectors we will be using on the payment interface. * * @module core_payment/selectors * @copyright 2019 Shamim Rezaie <shamim@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ export default { elements: { gateways: '[data-region="gateways-container"] input[type="radio"]', }, regions: { gatewaysContainer: '[data-region="gateways-container"]', costContainer: '[data-region="fee-breakdown-container"]', }, values: { gateway: '[data-region="gateways-container"] input[type="radio"]:checked', }, }; amd/src/modal_gateways.js 0000644 00000005550 15151162547 0011446 0 ustar 00 // 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/>. /** * Contain the logic for the gateways modal: A modal with proceed and cancel buttons. * * @module core_payment/modal_gateways * @copyright 2020 Shamim Rezaie <shamim@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ import $ from 'jquery'; import CustomEvents from 'core/custom_interaction_events'; import Modal from 'core/modal'; import ModalEvents from 'core/modal_events'; import PaymentEvents from 'core_payment/events'; import ModalRegistry from 'core/modal_registry'; let registered = false; const SELECTORS = { PROCEED_BUTTON: '[data-action="proceed"]', CANCEL_BUTTON: '[data-action="cancel"]', }; export default class ModalGateways extends Modal { /** * Constructor for the Modal. * * @param {object} root The root jQuery element for the modal */ constructor(root) { super(root); } /** * Set up all of the event handling for the modal. * * @method registerEventListeners */ registerEventListeners() { // Apply parent event listeners. super.registerEventListeners(); this.getModal().on(CustomEvents.events.activate, SELECTORS.PROCEED_BUTTON, (e, data) => { var proceedEvent = $.Event(PaymentEvents.proceed); this.getRoot().trigger(proceedEvent, this); if (!proceedEvent.isDefaultPrevented()) { this.hide(); data.originalEvent.preventDefault(); } }); this.getModal().on(CustomEvents.events.activate, SELECTORS.CANCEL_BUTTON, (e, data) => { var cancelEvent = $.Event(ModalEvents.cancel); this.getRoot().trigger(cancelEvent, this); if (!cancelEvent.isDefaultPrevented()) { this.hide(); data.originalEvent.preventDefault(); } }); } } ModalGateways.TYPE = 'core_payment-modal_gateways'; // Automatically register with the modal registry the first time this module is imported so that you can create modals // of this type using the modal factory. if (!registered) { ModalRegistry.register(ModalGateways.TYPE, ModalGateways, 'core_payment/modal_gateways'); registered = true; } amd/src/repository.js 0000644 00000003163 15151162547 0010663 0 ustar 00 // 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/>. /** * Repository for payment subsystem. * * @module core_payment/repository * @copyright 2020 Shamim Rezaie <shamim@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ import Ajax from 'core/ajax'; /** * @typedef {Object} PaymentGateway A Payment Gateway * @property {string} shortname * @property {string} name * @property {string} description */ /** * Returns the list of gateways that can process payments in the given currency. * * @method getAvailableGateways * @param {string} component * @param {string} paymentArea * @param {number} itemId * @returns {Promise<PaymentGateway[]>} */ export const getAvailableGateways = (component, paymentArea, itemId) => { const request = { methodname: 'core_payment_get_available_gateways', args: { component, paymentarea: paymentArea, itemid: itemId, } }; return Ajax.call([request])[0]; }; amd/src/gateways_modal.js 0000644 00000015350 15151162547 0011445 0 ustar 00 // 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/>. /** * Contain the logic for the gateways modal. * * @module core_payment/gateways_modal * @copyright 2019 Shamim Rezaie <shamim@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ import ModalFactory from 'core/modal_factory'; import Templates from 'core/templates'; import {get_string as getString} from 'core/str'; import {getAvailableGateways} from './repository'; import Selectors from './selectors'; import ModalEvents from 'core/modal_events'; import PaymentEvents from 'core_payment/events'; import {add as addToast, addToastRegion} from 'core/toast'; import Notification from 'core/notification'; import ModalGateways from './modal_gateways'; /** * Register event listeners for the module. */ const registerEventListeners = () => { document.addEventListener('click', e => { const gatewayTrigger = e.target.closest('[data-action="core_payment/triggerPayment"]'); if (gatewayTrigger) { e.preventDefault(); show(gatewayTrigger, {focusOnClose: e.target}); } }); }; /** * Shows the gateway selector modal. * * @param {HTMLElement} rootNode * @param {Object} options - Additional options * @param {HTMLElement} options.focusOnClose The element to focus on when the modal is closed. */ const show = async(rootNode, { focusOnClose = null, } = {}) => { const modal = await ModalFactory.create({ type: ModalGateways.TYPE, title: await getString('selectpaymenttype', 'core_payment'), body: await Templates.render('core_payment/gateways_modal', {}), }); const rootElement = modal.getRoot()[0]; addToastRegion(rootElement); modal.show(); modal.getRoot().on(ModalEvents.hidden, () => { // Destroy when hidden. modal.destroy(); try { focusOnClose.focus(); } catch (e) { // eslint-disable-line } }); modal.getRoot().on(PaymentEvents.proceed, (e) => { const gateway = (rootElement.querySelector(Selectors.values.gateway) || {value: ''}).value; if (gateway) { processPayment( gateway, rootNode.dataset.component, rootNode.dataset.paymentarea, rootNode.dataset.itemid, rootNode.dataset.description ) .then(message => { modal.hide(); Notification.addNotification({ message: message, type: 'success', }); location.href = rootNode.dataset.successurl; // The following return statement is never reached. It is put here just to make eslint happy. return message; }) .catch(message => Notification.alert('', message)); } else { // We cannot use await in the following line. // The reason is that we are preventing the default action of the save event being triggered, // therefore we cannot define the event handler function asynchronous. getString('nogatewayselected', 'core_payment').then(message => addToast(message, {type: 'warning'})).catch(); } e.preventDefault(); }); // Re-calculate the cost when gateway is changed. rootElement.addEventListener('change', e => { if (e.target.matches(Selectors.elements.gateways)) { updateCostRegion(rootElement, rootNode.dataset.cost); } }); const gateways = await getAvailableGateways(rootNode.dataset.component, rootNode.dataset.paymentarea, rootNode.dataset.itemid); const context = { gateways }; const {html, js} = await Templates.renderForPromise('core_payment/gateways', context); Templates.replaceNodeContents(rootElement.querySelector(Selectors.regions.gatewaysContainer), html, js); selectSingleGateway(rootElement); await updateCostRegion(rootElement, rootNode.dataset.cost); }; /** * Auto-select the gateway if there is only one gateway. * * @param {HTMLElement} root An HTMLElement that contains the cost region */ const selectSingleGateway = root => { const gateways = root.querySelectorAll(Selectors.elements.gateways); if (gateways.length == 1) { gateways[0].checked = true; } }; /** * Shows the cost of the item the user is purchasing in the cost region. * * @param {HTMLElement} root An HTMLElement that contains the cost region * @param {string} defaultCost The default cost that is going to be displayed if no gateway is selected * @returns {Promise<void>} */ const updateCostRegion = async(root, defaultCost = '') => { const gatewayElement = root.querySelector(Selectors.values.gateway); const surcharge = parseInt((gatewayElement || {dataset: {surcharge: 0}}).dataset.surcharge); const cost = (gatewayElement || {dataset: {cost: defaultCost}}).dataset.cost; const {html, js} = await Templates.renderForPromise('core_payment/fee_breakdown', {fee: cost, surcharge}); Templates.replaceNodeContents(root.querySelector(Selectors.regions.costContainer), html, js); }; /** * Process payment using the selected gateway. * * @param {string} gateway The gateway to be used for payment * @param {string} component Name of the component that the itemId belongs to * @param {string} paymentArea Name of the area in the component that the itemId belongs to * @param {number} itemId An internal identifier that is used by the component * @param {string} description Description of the payment * @returns {Promise<string>} */ const processPayment = async(gateway, component, paymentArea, itemId, description) => { const paymentMethod = await import(`paygw_${gateway}/gateways_modal`); return paymentMethod.process(component, paymentArea, itemId, description); }; /** * Set up the payment actions. */ export const init = () => { if (!init.initialised) { // Event listeners should only be registered once. init.initialised = true; registerEventListeners(); } }; /** * Whether the init function was called before. * * @static * @type {boolean} */ init.initialised = false; amd/src/events.js 0000644 00000001723 15151162547 0007750 0 ustar 00 // 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/>. /** * Contain the events the payment modal can fire. * * @module core_payment/events * @copyright 2020 Shamim Rezaie <shamim@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ export default { proceed: 'core_payment-modal_gateways:proceed', }; manage_account.php 0000644 00000005014 15151162547 0010230 0 ustar 00 <?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); $restore = optional_param('restore', false, PARAM_BOOL); $pageurl = new moodle_url('/payment/manage_account.php'); admin_externalpage_setup('paymentaccounts', '', [], $pageurl); $enabledplugins = \core\plugininfo\paygw::get_enabled_plugins(); $account = new \core_payment\account($id); require_capability('moodle/payment:manageaccounts', $account->get_context()); if ($delete && !$account->get('archived') && confirm_sesskey()) { \core_payment\helper::delete_payment_account($account); redirect(new moodle_url('/payment/accounts.php')); } if ($restore && $account->get('archived') && confirm_sesskey()) { \core_payment\helper::restore_payment_account($account); redirect(new moodle_url('/payment/accounts.php')); } $PAGE->set_secondary_active_tab('siteadminnode'); $PAGE->set_primary_active_tab('siteadminnode'); if ($id == 0) { $PAGE->navbar->add(get_string('createaccount', 'payment'), $PAGE->url); } else { $PAGE->navbar->add(get_string('editpaymentaccount', 'payment'), $PAGE->url); } $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(); tests/generator_test.php 0000644 00000005464 15151162547 0011464 0 ustar 00 <?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/>. /** * Testing generator in payments API * * @package core_payment * @category test * @copyright 2020 Marina Glancy * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace core_payment; /** * Testing generator in payments API * * @package core_payment * @category test * @copyright 2020 Marina Glancy * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class generator_test extends \advanced_testcase { public function test_create_account() { global $DB; $this->resetAfterTest(); /** @var \core_payment_generator $generator */ $generator = $this->getDataGenerator()->get_plugin_generator('core_payment'); $this->assertTrue($generator instanceof \core_payment_generator); $account1 = $generator->create_payment_account(); $account2 = $generator->create_payment_account(['name' => 'My name', 'gateways' => 'paypal']); $record1 = $DB->get_record('payment_accounts', ['id' => $account1->get('id')]); $record2 = $DB->get_record('payment_accounts', ['id' => $account2->get('id')]); $this->assertEquals(1, $record1->enabled); $this->assertEquals('My name', $record2->name); // First account does not have gateways configurations. $this->assertEmpty($DB->get_records('payment_gateways', ['accountid' => $account1->get('id')])); // Second account has. $this->assertCount(1, $DB->get_records('payment_gateways', ['accountid' => $account2->get('id')])); } public function test_create_payment() { global $DB; $this->resetAfterTest(); /** @var \core_payment_generator $generator */ $generator = $this->getDataGenerator()->get_plugin_generator('core_payment'); $account = $generator->create_payment_account(['gateways' => 'paypal']); $user = $this->getDataGenerator()->create_user(); $paymentid = $generator->create_payment(['accountid' => $account->get('id'), 'amount' => 10, 'userid' => $user->id]); $this->assertEquals('testcomponent', $DB->get_field('payments', 'component', ['id' => $paymentid])); } } tests/generator/behat_core_payment_generator.php 0000644 00000004426 15151162547 0016320 0 ustar 00 <?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/>. /** * Behat data generator for core_payment. * * @package core_payment * @category test * @copyright 2020 Marina Glancy * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ /** * Behat data generator for core_payment. * * @package core_payment * @category test * @copyright 2020 Marina Glancy * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class behat_core_payment_generator extends behat_generator_base { /** * Get a list of the entities that can be created. * * @return array entity name => information about how to generate. */ protected function get_creatable_entities(): array { return [ 'payment accounts' => [ 'singular' => 'payment account', 'datagenerator' => 'payment_account', 'required' => ['name'], ], 'payments' => [ 'singular' => 'payment', 'datagenerator' => 'payment', 'required' => ['account', 'amount', 'user'], 'switchids' => ['account' => 'accountid', 'user' => 'userid'], ], ]; } /** * Look up the id of a account from its name. * * @param string $accountname * @return int corresponding id. */ protected function get_account_id(string $accountname): int { global $DB; if (!$id = $DB->get_field('payment_accounts', 'id', ['name' => $accountname])) { throw new Exception('There is no account with name "' . $accountname . '".'); } return $id; } } tests/generator/lib.php 0000644 00000005512 15151162547 0011165 0 ustar 00 <?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/>. /** * Payment module test data generator class * * @package core_payment * @category test * @copyright 2020 Marina Glancy * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class core_payment_generator extends component_generator_base { /** @var int */ protected $accountcounter = 0; /** * Create a payment account * * @param array $data account data (name, idnumber, enabled) and additionally field 'gateways' that can include * a list of gateways that should be mock-enabled for this account. */ public function create_payment_account(array $data = []): \core_payment\account { $this->accountcounter++; $gateways = []; if (!empty($data['gateways'])) { $gateways = preg_split('/,/', $data['gateways']); } unset($data['gateways']); $account = \core_payment\helper::save_payment_account( (object)($data + ['name' => 'Test '.$this->accountcounter, 'idnumber' => '', 'enabled' => 1])); foreach ($gateways as $gateway) { \core_payment\helper::save_payment_gateway( (object)['accountid' => $account->get('id'), 'gateway' => $gateway, 'enabled' => 1]); } return $account; } /** * Create a payment account * * @param array $data */ public function create_payment(array $data): int { global $DB; if (empty($data['accountid']) || !\core_payment\account::get_record(['id' => $data['accountid']])) { throw new coding_exception('Account id is not specified or does not exist'); } if (empty($data['amount'])) { throw new coding_exception('Amount must be specified'); } $gateways = \core\plugininfo\paygw::get_enabled_plugins(); if (empty($data['gateway'])) { $data['gateway'] = reset($gateways); } $id = $DB->insert_record('payments', $data + [ 'component' => 'testcomponent', 'paymentarea' => 'teatarea', 'itemid' => 0, 'currency' => 'AUD', ]); return $id; } } tests/helper_test.php 0000644 00000020575 15151162547 0010755 0 ustar 00 <?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/>. /** * Testing helper class methods in payments API * * @package core_payment * @category test * @copyright 2020 Marina Glancy * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace core_payment; use advanced_testcase; use core\plugininfo\paygw; /** * Testing helper class methods in payments API * * @package core_payment * @category test * @copyright 2020 Marina Glancy * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class helper_test extends advanced_testcase { protected function enable_paypal_gateway(): bool { if (!array_key_exists('paypal', \core_component::get_plugin_list('paygw'))) { return false; } return true; } public function test_create_account() { global $DB; $this->resetAfterTest(); $account = helper::save_payment_account((object)['name' => 'Test 1', 'idnumber' => '']); $this->assertNotEmpty($account->get('id')); $this->assertEquals('Test 1', $DB->get_field('payment_accounts', 'name', ['id' => $account->get('id')])); } public function test_update_account_details() { global $DB; $this->resetAfterTest(); $account = helper::save_payment_account((object)['name' => 'Test 1', 'idnumber' => '']); $record = $account->to_record(); $record->name = 'Edited name'; $editedaccount = helper::save_payment_account($record); $this->assertEquals($account->get('id'), $editedaccount->get('id')); $this->assertEquals('Edited name', $DB->get_field('payment_accounts', 'name', ['id' => $account->get('id')])); } public function test_update_account_gateways() { global $DB; if (!$this->enable_paypal_gateway()) { $this->markTestSkipped('Paypal payment gateway plugin not found'); } $this->resetAfterTest(); $account = helper::save_payment_account((object)['name' => 'Test 1', 'idnumber' => '']); $gateway = helper::save_payment_gateway( (object)['accountid' => $account->get('id'), 'gateway' => 'paypal', 'config' => 'T1']); $this->assertNotEmpty($gateway->get('id')); $this->assertEquals('T1', $DB->get_field('payment_gateways', 'config', ['id' => $gateway->get('id')])); // Update by id. $editedgateway = helper::save_payment_gateway( (object)['id' => $gateway->get('id'), 'accountid' => $account->get('id'), 'gateway' => 'paypal', 'config' => 'T2']); $this->assertEquals($gateway->get('id'), $editedgateway->get('id')); $this->assertEquals('T2', $DB->get_field('payment_gateways', 'config', ['id' => $gateway->get('id')])); // Update by account/gateway. $editedgateway = helper::save_payment_gateway( (object)['accountid' => $account->get('id'), 'gateway' => 'paypal', 'config' => 'T3']); $this->assertEquals($gateway->get('id'), $editedgateway->get('id')); $this->assertEquals('T3', $DB->get_field('payment_gateways', 'config', ['id' => $gateway->get('id')])); } public function test_delete_account() { global $DB; if (!$this->enable_paypal_gateway()) { $this->markTestSkipped('Paypal payment gateway plugin not found'); } $this->resetAfterTest(); // Delete account without payments, it will be deleted, gateways will also be deleted. $account = helper::save_payment_account((object)['name' => 'Test 1', 'idnumber' => '']); $gateway = helper::save_payment_gateway( (object)['accountid' => $account->get('id'), 'gateway' => 'paypal', 'config' => 'T1']); helper::delete_payment_account(account::get_record(['id' => $account->get('id')])); $this->assertEmpty($DB->get_records('payment_accounts', ['id' => $account->get('id')])); $this->assertEmpty($DB->get_records('payment_gateways', ['id' => $gateway->get('id')])); } public function test_archive_restore_account() { global $DB, $USER; $this->resetAfterTest(); // Delete account with payments - it will be archived. $this->setAdminUser(); $account = helper::save_payment_account((object)['name' => 'Test 1', 'idnumber' => '']); $DB->insert_record('payments', [ 'accountid' => $account->get('id'), 'component' => 'test', 'paymentarea' => 'test', 'itemid' => 1, 'userid' => $USER->id, ]); helper::delete_payment_account(account::get_record(['id' => $account->get('id')])); $this->assertEquals(1, $DB->get_field('payment_accounts', 'archived', ['id' => $account->get('id')])); // Restore account. helper::restore_payment_account(account::get_record(['id' => $account->get('id')])); $this->assertEquals(0, $DB->get_field('payment_accounts', 'archived', ['id' => $account->get('id')])); } /** * Provider for format_cost test * * @return array */ public function get_rounded_cost_provider(): array { return [ 'IRR 0 surcharge' => [5.345, 'IRR', 0, 5], 'IRR 12% surcharge' => [5.345, 'IRR', 12, 6], 'USD 0 surcharge' => [5.345, 'USD', 0, 5.34], 'USD 1% surcharge' => [5.345, 'USD', 1, 5.4], ]; } /** * Provider for test_get_cost_as_string * * @return array[] */ public function get_cost_as_string_provider(): array { return [ 'IRR 0 surcharge' => [5.345, 'IRR', 0, 'IRR'."\xc2\xa0".'5'], 'IRR 12% surcharge' => [5.345, 'IRR', 12, 'IRR'."\xc2\xa0".'6'], 'USD 0 surcharge' => [5.345, 'USD', 0, 'USD'."\xc2\xa0".'5.34'], 'USD 1% surcharge' => [5.345, 'USD', 1, 'USD'."\xc2\xa0".'5.40'], ]; } /** * Test for test_format_cost function * * @dataProvider get_rounded_cost_provider * @param float $amount * @param string $currency * @param float $surcharge * @param string $expected */ public function test_get_rounded_cost(float $amount, string $currency, float $surcharge, float $expected) { $this->assertEquals($expected, helper::get_rounded_cost($amount, $currency, $surcharge)); } /** * Test for get_cost_as_string function * * @dataProvider get_cost_as_string_provider * @param float $amount * @param string $currency * @param float $surcharge * @param string $expected */ public function test_get_cost_as_string(float $amount, string $currency, float $surcharge, string $expected) { // Some old ICU versions have a bug, where they don't follow the CLDR and they are // missing the non-breaking-space between the currency abbreviation and the value. // i.e. it returns AUD50 instead of AU\xc2\xa050). See the following issues @ ICU: // - https://unicode-org.atlassian.net/browse/ICU-6560 // - https://unicode-org.atlassian.net/browse/ICU-8853 // - https://unicode-org.atlassian.net/browse/ICU-8840 // It has been detected that versions prior to ICU-61.1 / ICU-62.1 come with this // problem. Noticeably Travis images (as of December 2021) use buggy ICU-60.1. // So, here, we are going to dynamically verify the behaviour and skip the // test when buggy one is found. No need to apply this to code as dar as the real // formatting is not critical for the functionality (just small glitch). if ('IRR5' === (new \NumberFormatter('en-AU', \NumberFormatter::CURRENCY))->formatCurrency(5, 'IRR')) { $this->markTestSkipped('Old ICU libraries behavior (ICU < 62), skipping this tests'); } $this->assertEquals($expected, helper::get_cost_as_string($amount, $currency, $surcharge)); } } tests/behat/siteadmin_accounts_breadcrumbs.feature 0000644 00000001661 15151162547 0016606 0 ustar 00 @core @core_payment @javascript Feature: Verify the breadcrumbs in payment accounts site administration pages Whenever I navigate to payment account page in site administration As an admin The breadcrumbs should be visible Background: Given I log in as "admin" Scenario: Verify the breadcrumbs in payment account page as an admin Given I navigate to "Payments > Payment accounts" in site administration And I click on "Create payment account" "button" And "Create payment account" "text" should exist in the ".breadcrumb" "css_element" And "Payment accounts" "link" should exist in the ".breadcrumb" "css_element" And "Payments" "link" should exist in the ".breadcrumb" "css_element" And I press "Cancel" When I click on "Show archived" "link" Then "Payment accounts" "text" should exist in the ".breadcrumb" "css_element" And "Payments" "link" should exist in the ".breadcrumb" "css_element" tests/behat/accounts.feature 0000644 00000006552 15151162547 0012204 0 ustar 00 @core @core_payment Feature: Manage payment accounts @javascript Scenario: Creating and editing payment account When I log in as "admin" And I navigate to "Payments > Payment accounts" in site administration And I follow "Manage payment gateways" Then "Australian Dollar" "text" should exist in the "PayPal" "table_row" And I follow "Payment accounts" And I press "Create payment account" And I set the field "Account name" to "TestAccount" And I press "Save changes" And I should see "PayPal" in the "TestAccount" "table_row" And I open the action menu in "TestAccount" "table_row" And I choose "Edit" in the open action menu And I set the field "Account name" to "NewName" And I press "Save changes" And I should see "PayPal" in the "NewName" "table_row" And I should not see "TestAccount" And I log out @javascript Scenario: Configuring gateways on payment accounts Given the following "core_payment > payment accounts" exist: | name | | Account1 | | Account2 | When I log in as "admin" And I navigate to "Payments > Payment accounts" in site administration Then I should see "Not available" in the "Account1" "table_row" And I click on "PayPal" "link" in the "Account1" "table_row" And I set the field "Brand name" to "Test paypal" And I set the following fields to these values: | Brand name | Test paypal | | Client ID | Test | | Secret | Test | | Enable | 1 | And I press "Save changes" And I should see "PayPal" in the "Account1" "table_row" And I should not see "Not available" in the "Account1" "table_row" And I log out @javascript Scenario: Deleting payment accounts Given the following "core_payment > payment accounts" exist: | name | | Account1 | | Account2 | When I log in as "admin" And I navigate to "Payments > Payment accounts" in site administration And I open the action menu in "Account1" "table_row" And I choose "Delete or archive" in the open action menu And I click on "Yes" "button" in the "Confirmation" "dialogue" Then I should not see "Account1" And I should see "Account2" And I log out @javascript Scenario: Archiving and restoring accounts Given the following "users" exist: | username | | user1 | And the following "core_payment > payment accounts" exist: | name | | Account1 | | Account2 | And the following "core_payment > payments" exist: | account | component | amount | user | | Account1 | test | 10 | user1 | | Account1 | test | 15 | user1 | When I log in as "admin" And I navigate to "Payments > Payment accounts" in site administration And I open the action menu in "Account1" "table_row" And I choose "Delete or archive" in the open action menu And I click on "Yes" "button" in the "Confirmation" "dialogue" Then I should not see "Account1" And I should see "Account2" And I follow "Show archived" And I should see "Archived" in the "Account1" "table_row" And I open the action menu in "Account1" "table_row" And I choose "Restore" in the open action menu And I should not see "Archived" in the "Account1" "table_row" And I log out templates/gateway.mustache 0000644 00000003333 15151162547 0011747 0 ustar 00 {{! 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/>. }} {{! @template core_payment/gateway This template will render the gateway option in the gateway selector modal. Classes required for JS: * none Data attributes required for JS: * none Context variables required for this template: * shortname * name * description * surcharge * image Example context (json): { "shortname": "paypal", "name": "PayPal", "description": "A description for PayPal.", "surcharge": "3" } }} <div class="custom-control custom-radio {{shortname}}"> <input class="custom-control-input" type="radio" name="payby" id="id-payby-{{uniqid}}-{{shortname}}" data-cost="{{cost}}" data-surcharge="{{surcharge}}" value="{{shortname}}" {{#checked}} checked="checked" {{/checked}} /> <label class="custom-control-label bg-light border p-3 my-3" for="id-payby-{{uniqid}}-{{shortname}}"> <p class="h3">{{name}}</p> <p class="content mb-2">{{{description}}}</p> {{#pix}} img, paygw_{{shortname}} {{/pix}} </label> </div>