"use strict";
var wrapPromise = require("@braintree/wrap-promise");
var BraintreeError = require("../../lib/braintree-error");
var sepaErrors = require("../shared/errors");
var constants = require("../shared/constants");
var mandates = require("./mandate");
var hasMissingOption = require("../shared/has-missing-option");
var analytics = require("../../lib/analytics");
var VERSION = process.env.npm_package_version;
var assign = require("../../lib/assign").assign;
/**
* @class
* @param {object} options see {@link module:braintree-web/sepa.create|sepa.create}
* @description <strong>Do not use this constructor directly. Use {@link module:braintree-web/sepa.create|braintree-web.sepa.create} instead.</strong>
* @classdesc This class represents a SEPA component produced by {@link module:braintree-web/sepa.create|braintree-web.sepa.create}. Instances provide methods for tokenizing SEPA payments.
*/
function SEPA(options) {
var getConfiguration = options.client.getConfiguration();
this._client = options.client;
this._assetsUrl =
getConfiguration.gatewayConfiguration.assetsUrl + "/web/" + VERSION;
this._isDebug = getConfiguration.isDebug;
if (options.redirectUrl) {
this._returnUrl = options.redirectUrl;
this._cancelUrl = options.redirectUrl + "?cancel=1";
this._isRedirectFlow = true;
} else {
this._returnUrl = this._assetsUrl + "/html/redirect-frame.html?success=1";
this._cancelUrl = this._assetsUrl + "/html/redirect-frame.html?cancel=1";
}
if (options.tokenizePayload) {
this.tokenizePayload = options.tokenizePayload;
}
analytics.sendEvent(this._client, "sepa.component.initialized");
}
/**
* SEPA tokenize payload.
* @typedef SEPA~tokenizePayload
* @property {string} nonce The payment nonce.
* @property {string} ibanLastFour The last four digits of the customer's IBAN.
* @property {string} mandateType The specified mandateType used.
* @property {string} customerId The provided customer id.
*/
/**
* @public
* @param {object} options All options for intiating the SEPA payment flow.
* @param {string} [options.accountHolderName] The account holder name.
* @param {string} [options.customerId] The customer's id.
* @param {string} [options.iban] The customer's International Bank Account Number.
* @param {string} [options.mandateType] Specify ONE_OFF or RECURRENT payment.
* @param {string} [options.countryCode] The customer's country code.
* @param {string} [options.merchantAccountId] The merchant's account id.
* @param {callback} [callback] The first argument is an error object, where the second is a {@link SEPA~tokenizePayload|tokenizePayload}
* @returns {(Promise<tokenizePayload|error>)} Returns a promise if no callback is provided.
*
* @example
* button.addEventListener('click', function () {
* var tokenizeInputs = {
* accountHolderName: "some-accnt-holder-name",
* customerId: "a-customer-id",
* iban: "a-full-iban",
* mandateType: "ONE_OFF",
* countryCode: "LI",
* merchantAccountId: "a-merchant-account-id"
* }
* sepaInstance.tokenize(tokenizeInputs).then(function (payload) {
* // Submit payload.nonce to your server
* }).catch(function(tokenizationErr) {
* // Handle errors in the flow
* })
* })
*/
SEPA.prototype.tokenize = function (options) {
var self = this;
var popupPromise;
var createMandateOptions = assign(
{ cancelUrl: self._cancelUrl, returnUrl: self._returnUrl },
options
);
if (!options || hasMissingOption(options, constants.REQUIRED_OPTIONS)) {
analytics.sendEvent(self._client, "sepa.input-validation.missing-options");
return Promise.reject(
new BraintreeError(sepaErrors.SEPA_TOKENIZE_MISSING_REQUIRED_OPTION)
);
}
if (!constants.MANDATE_TYPE_ENUM.includes(options.mandateType)) {
analytics.sendEvent(self._client, "sepa.input-validation.invalid-mandate");
return Promise.reject(
new BraintreeError(sepaErrors.SEPA_INVALID_MANDATE_TYPE)
);
}
popupPromise = mandates
.createMandate(self._client, createMandateOptions)
.then(function (mandateResponse) {
analytics.sendEvent(self._client, "sepa.create-mandate.success");
if (self._isRedirectFlow) {
return mandates.redirectPage(mandateResponse.approvalUrl);
}
options.last4 = mandateResponse.last4;
options.bankReferenceToken = mandateResponse.bankReferenceToken;
return mandates.openPopup(self._client, {
approvalUrl: mandateResponse.approvalUrl,
assetsUrl: self._assetsUrl,
});
});
// Must be outside of .then() to return from top-level function
if (self._isRedirectFlow) {
return Promise.resolve();
}
// At this point, we know the promise came from the popup flow
return popupPromise
.then(function () {
analytics.sendEvent(self._client, "sepa.mandate.approved");
return mandates.handleApproval(self._client, {
bankReferenceToken: options.bankReferenceToken,
last4: options.last4,
customerId: options.customerId,
mandateType: options.mandateType,
merchantAccountId: options.merchantAccountId,
});
})
.then(function (approval) {
analytics.sendEvent(self._client, "sepa.tokenization.success");
return Promise.resolve(approval);
})
.catch(function (err) {
analytics.sendEvent(self._client, "sepa." + err.details + ".failed");
return Promise.reject(err);
});
};
module.exports = wrapPromise.wrapPrototype(SEPA);