5ba6921377f6183316845b419f9870dcc973863f
[moodle.git] / payment / classes / helper.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Contains helper class for the payment subsystem.
19  *
20  * @package    core_payment
21  * @copyright  2019 Shamim Rezaie <shamim@moodle.com>
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 namespace core_payment;
27 defined('MOODLE_INTERNAL') || die();
29 /**
30  * Helper class for the payment subsystem.
31  *
32  * @copyright  2019 Shamim Rezaie <shamim@moodle.com>
33  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
34  */
35 class helper {
37     /**
38      * Returns an accumulated list of supported currencies by all payment gateways.
39      *
40      * @return string[] An array of the currency codes in the three-character ISO-4217 format
41      */
42     public static function get_supported_currencies(): array {
43         $currencies = [];
45         $plugins = \core_plugin_manager::instance()->get_enabled_plugins('pg');
46         foreach ($plugins as $plugin) {
47             /** @var \pg_paypal\gateway $classname */
48             $classname = '\pg_' . $plugin . '\gateway';
50             $currencies += $classname::get_supported_currencies();
51         }
53         $currencies = array_unique($currencies);
55         return $currencies;
56     }
58     /**
59      * Returns the list of gateways that can process payments in the given currency.
60      *
61      * @param string $currency The currency in the three-character ISO-4217 format.
62      * @param int $accountid
63      * @return string[]
64      */
65     public static function get_gateways_for_currency(string $currency, int $accountid): array {
66         $gateways = [];
68         $account = new account($accountid);
69         if (!$account->get('id') || !$account->get('enabled')) {
70             return $gateways;
71         }
73         foreach ($account->get_gateways() as $plugin => $gateway) {
74             if (!$gateway->get('enabled')) {
75                 continue;
76             }
77             /** @var gateway $classname */
78             $classname = '\pg_' . $plugin . '\gateway';
80             $currencies = $classname::get_supported_currencies();
81             if (in_array($currency, $currencies)) {
82                 $gateways[] = $plugin;
83             }
84         }
86         return $gateways;
87     }
89     /**
90      * Returns the percentage of surcharge that is applied when using a gateway
91      *
92      * @param string $gateway Name of the gateway
93      * @return int
94      */
95     public static function get_gateway_surcharge(string $gateway): int {
96         return get_config('pg_' . $gateway, 'surcharge') ?: 0;
97     }
99     /**
100      * Returns the attributes to place on a pay button.
101      *
102      * @param float $amount Amount of payment
103      * @param string $currency Currency of payment
104      * @param string $component Name of the component that the componentid belongs to
105      * @param int $componentid An internal identifier that is used by the component
106      * @param string $description Description of the payment
107      * @return array
108      */
109     public static function gateways_modal_link_params(float $amount, string $currency, string $component, int $componentid,
110             string $description): array {
111         return [
112             'id' => 'gateways-modal-trigger',
113             'role' => 'button',
114             'data-amount' => $amount,
115             'data-currency' => $currency,
116             'data-component' => $component,
117             'data-componentid' => $componentid,
118             'data-description' => $description,
119         ];
120     }
122     /**
123      * Asks the cost from the related component.
124      *
125      * @param string $component Name of the component that the componentid belongs to
126      * @param int $componentid An internal identifier that is used by the component
127      * @return array['amount' => float, 'currency' => string, 'accountid' => int]
128      * @throws \moodle_exception
129      */
130     public static function get_cost(string $component, int $componentid): array {
131         $cost = component_class_callback("$component\\payment\\provider", 'get_cost', [$componentid]);
133         if ($cost === null || !is_array($cost) || !array_key_exists('amount', $cost)
134                 || !array_key_exists('currency', $cost) || !array_key_exists('accountid', $cost) ) {
135             throw new \moodle_exception('callbacknotimplemented', 'core_payment', '', $component);
136         }
138         return $cost;
139     }
141     /**
142      * Returns the gateway configuration for given component and gateway
143      *
144      * @param string $component
145      * @param int $componentid
146      * @param string $gatewayname
147      * @return array
148      * @throws \moodle_exception
149      */
150     public static function get_gateway_configuration(string $component, int $componentid, string $gatewayname): array {
151         $x = self::get_cost($component, $componentid);
152         $gateway = null;
153         $account = new account($x['accountid']);
154         if ($account && $account->get('enabled')) {
155             $gateway = $account->get_gateways()[$gatewayname] ?? null;
156         }
157         if (!$gateway) {
158             throw new \moodle_exception('gatewaynotfound', 'payment');
159         }
160         return $gateway->get_configuration();
161     }
163     /**
164      * Delivers what the user paid for.
165      *
166      * @param string $component Name of the component that the componentid belongs to
167      * @param int $componentid An internal identifier that is used by the component
168      * @return bool Whether successful or not
169      * @throws \moodle_exception
170      */
171     public static function deliver_order(string $component, int $componentid): bool {
172         $result = component_class_callback("$component\\payment\\provider", 'deliver_order', [$componentid]);
174         if ($result === null) {
175             throw new \moodle_exception('callbacknotimplemented', 'core_payment', '', $component);
176         }
178         return $result;
179     }
181     /**
182      * Stores essential information about the payment and returns the "id" field of the payment record in DB.
183      * Each payment gateway may then store the additional information their way.
184      *
185      * @param string $component Name of the component that the componentid belongs to
186      * @param int $componentid An internal identifier that is used by the component
187      * @param int $userid Id of the user who is paying
188      * @param float $amount Amount of payment
189      * @param string $currency Currency of payment
190      * @param string $gateway The gateway that is used for the payment
191      * @return int
192      */
193     public static function save_payment(string $component, int $componentid, int $userid, float $amount, string $currency,
194             string $gateway): int {
195         global $DB;
197         $record = new \stdClass();
198         $record->component = $component;
199         $record->componentid = $componentid;
200         $record->userid = $userid;
201         $record->amount = $amount;
202         $record->currency = $currency;
203         $record->gateway = $gateway;
204         $record->timecreated = $record->timemodified = time();
206         $id = $DB->insert_record('payments', $record);
208         return $id;
209     }
211     /**
212      * This functions adds the settings that are common for all payment gateways.
213      *
214      * @param \admin_settingpage $settings The settings object
215      * @param string $gateway The gateway name prefic with pg_
216      */
217     public static function add_common_gateway_settings(\admin_settingpage $settings, string $gateway): void {
218         $settings->add(new \admin_setting_configtext($gateway . '/surcharge', get_string('surcharge', 'core_payment'),
219                 get_string('surcharge_desc', 'core_payment'), 0, PARAM_INT));
221     }
223     /**
224      * Save a new or edited payment account (used in management interface)
225      *
226      * @param \stdClass $data
227      */
228     public static function save_payment_account(\stdClass $data) {
230         if (empty($data->id)) {
231             $account = new account(0, $data);
232         } else {
233             $account = new account($data->id);
234             $account->from_record($data);
235         }
237         $account->save();
238         // TODO trigger event.
239     }
241     /**
242      * Delete a payment account (used in management interface)
243      *
244      * @param account $account
245      */
246     public static function delete_payment_account(account $account) {
247         foreach ($account->get_gateways(false) as $gateway) {
248             if ($gateway->get('id')) {
249                 $gateway->delete();
250             }
251         }
252         $account->delete();
253         // TODO trigger event.
254     }
256     /**
257      * Save a payment gateway linked to an existing account (used in management interface)
258      *
259      * @param \stdClass $data
260      */
261     public static function save_payment_gateway(\stdClass $data) {
262         if (empty($data->id)) {
263             $gateway = new account_gateway(0, $data);
264         } else {
265             $gateway = new account_gateway($data->id);
266             unset($data->accountid, $data->gateway, $data->id);
267             $gateway->from_record($data);
268         }
270         $gateway->save();
271         // TODO trigger event.
272     }
274     /**
275      * Returns the list of payment accounts in the given context (used in management interface)
276      *
277      * @param \context $context
278      * @return account[]
279      */
280     public static function get_payment_accounts_to_manage(\context $context): array {
281         return account::get_records(['contextid' => $context->id]);
282     }
284     /**
285      * Get list of accounts available in the given context
286      *
287      * @param \context $context
288      * @return array
289      */
290     public static function get_payment_accounts_menu(\context $context): array {
291         global $DB;
292         [$sql, $params] = $DB->get_in_or_equal($context->get_parent_context_ids(true));
293         $accounts = array_filter(account::get_records_select('contextid '.$sql, $params), function($account) {
294             return $account->is_available();
295         });
296         return array_map(function($account) {
297             return $account->get_formatted_name();
298         }, $accounts);
299     }