Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
// This file is part of Moodle - http://moodle.org/
2
//
3
// Moodle is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, either version 3 of the License, or
6
// (at your option) any later version.
7
//
8
// Moodle is distributed in the hope that it will be useful,
9
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
// GNU General Public License for more details.
12
//
13
// You should have received a copy of the GNU General Public License
14
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
15
 
16
/**
17
 * This module is responsible for PayPal content in the gateways modal.
18
 *
19
 * @module     paygw_paypal/gateways_modal
20
 * @copyright  2020 Shamim Rezaie <shamim@moodle.com>
21
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22
 */
23
 
24
import * as Repository from './repository';
25
import Templates from 'core/templates';
26
import Truncate from 'core/truncate';
27
import Modal from 'core/modal';
28
import ModalEvents from 'core/modal_events';
29
import {getString} from 'core/str';
30
 
31
/**
32
 * Creates and shows a modal that contains a placeholder.
33
 *
34
 * @returns {Promise<Modal>}
35
 */
36
const showModalWithPlaceholder = async() => await Modal.create({
37
    body: await Templates.render('paygw_paypal/paypal_button_placeholder', {}),
38
    show: true,
39
    removeOnClose: true,
40
});
41
 
42
/**
43
 * Process the payment.
44
 *
45
 * @param {string} component Name of the component that the itemId belongs to
46
 * @param {string} paymentArea The area of the component that the itemId belongs to
47
 * @param {number} itemId An internal identifier that is used by the component
48
 * @param {string} description Description of the payment
49
 * @returns {Promise<string>}
50
 */
51
export const process = (component, paymentArea, itemId, description) => {
52
    return Promise.all([
53
        showModalWithPlaceholder(),
54
        Repository.getConfigForJs(component, paymentArea, itemId),
55
    ])
56
    .then(([modal, paypalConfig]) => {
57
        return Promise.all([
58
            modal,
59
            paypalConfig,
60
            switchSdk(paypalConfig.clientid, paypalConfig.currency),
61
        ]);
62
    })
63
    .then(([modal, paypalConfig]) => {
64
        // We have to clear the body. The render method in paypal.Buttons will render everything.
65
        modal.setBody('');
66
 
67
        return new Promise(resolve => {
68
            window.paypal.Buttons({
69
                // Set up the transaction.
70
                createOrder: function(data, actions) {
71
                    return actions.order.create({
72
                        purchase_units: [{ // eslint-disable-line
73
                            amount: {
74
                                currency_code: paypalConfig.currency_code, // eslint-disable-line
75
                                value: paypalConfig.cost,
76
                            },
77
                            description: Truncate.truncate(description, {length: 127, stripTags: true}),
78
                        }],
79
                        application_context: { // eslint-disable-line
80
                            shipping_preference: 'NO_SHIPPING', // eslint-disable-line
81
                            brand_name: Truncate.truncate(paypalConfig.brandname, {length: 127, stripTags: true}), // eslint-disable-line
82
                        },
83
                    });
84
                },
85
                // Finalise the transaction.
86
                onApprove: function(data) {
87
                    modal.getRoot().on(ModalEvents.outsideClick, (e) => {
88
                        // Prevent closing the modal when clicking outside of it.
89
                        e.preventDefault();
90
                    });
91
 
92
                    modal.setBody(getString('authorising', 'paygw_paypal'));
93
 
94
                    Repository.markTransactionComplete(component, paymentArea, itemId, data.orderID)
95
                    .then(res => {
96
                        modal.hide();
97
                        return res;
98
                    })
99
                    .then(resolve);
100
                }
101
            }).render(modal.getBody()[0]);
102
        });
103
    })
104
    .then(res => {
105
        if (res.success) {
106
            return Promise.resolve(res.message);
107
        }
108
 
109
        return Promise.reject(res.message);
110
    });
111
};
112
 
113
/**
114
 * Unloads the previously loaded PayPal JavaScript SDK, and loads a new one.
115
 *
116
 * @param {string} clientId PayPal client ID
117
 * @param {string} currency The currency
118
 * @returns {Promise}
119
 */
120
const switchSdk = (clientId, currency) => {
121
    const sdkUrl = `https://www.paypal.com/sdk/js?client-id=${clientId}&currency=${currency}`;
122
 
123
    // Check to see if this file has already been loaded. If so just go straight to the func.
124
    if (switchSdk.currentlyloaded === sdkUrl) {
125
        return Promise.resolve();
126
    }
127
 
128
    // PayPal can only work with one currency at the same time. We have to unload the previously loaded script
129
    // if it was loaded for a different currency. Weird way indeed, but the only way.
130
    // See: https://github.com/paypal/paypal-checkout-components/issues/1180
131
    if (switchSdk.currentlyloaded) {
132
        const suspectedScript = document.querySelector(`script[src="${switchSdk.currentlyloaded}"]`);
133
        if (suspectedScript) {
134
            suspectedScript.parentNode.removeChild(suspectedScript);
135
        }
136
    }
137
 
138
    const script = document.createElement('script');
139
 
140
    return new Promise(resolve => {
141
        if (script.readyState) {
142
            script.onreadystatechange = function() {
143
                if (this.readyState == 'complete' || this.readyState == 'loaded') {
144
                    this.onreadystatechange = null;
145
                    resolve();
146
                }
147
            };
148
        } else {
149
            script.onload = function() {
150
                resolve();
151
            };
152
        }
153
 
154
        script.setAttribute('src', sdkUrl);
155
        document.head.appendChild(script);
156
 
157
        switchSdk.currentlyloaded = sdkUrl;
158
    });
159
};
160
 
161
/**
162
 * Holds the full url of loaded PayPal JavaScript SDK.
163
 *
164
 * @static
165
 * @type {string}
166
 */
167
switchSdk.currentlyloaded = '';