-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathitero-sample.js
173 lines (156 loc) · 7.7 KB
/
itero-sample.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
'use strict';
/// The modal for the 3D-Secure popup needs a simple controller to pass along some data.
var ModalInstanceCtrl = function ($scope, $modalInstance, url, params, onclose) {
$scope.url = url;
$scope.params = params;
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
onclose();
};
};
var SignupController = function ($scope, $http, $modal) {
var self = this;
$scope.order = null;
// Some default data so we don't have to enter a ton of info every time
$scope.customerData = { firstName: "Marcellus", lastName: "Wallace", emailAddress: "[email protected]" };
$scope.paymentData = { bearer: "CreditCard:FakePSP", "cardNumber": "5169147129584558", cardHolder: "Marcellus Wallace", cvc: "911", expiryMonth: "12", expiryYear: "2017" };
$scope.paymentMethods = {};
$scope.paymentMethodEnum = [];
$scope.paymentReady = false;
// A lookup table for 'friendly' payment provider names
// FIXME: This isn't pretty, and having the PSP's name in the strings for direct debit and credit card seems nonsensical
$scope.paymentMethodNames = { "CreditCard:Paymill": "Credit Card", "Debit:Paymill": "Direct Debit", "PayPal": "PayPal", "Debit:FakePSP" : "Direct Debit", "CreditCard:FakePSP" : "Credit Card" };
// The signup method that is called when the user submits the form
$scope.signUp = function () {
// To indicate that the site is working and to disable the signup button, we're setting a flag
$scope.signupRunning = true;
// pass the order, customerData and payment data to subscriptionJS
// DTO: PaymentData
self.iteroInstance.subscribe(self.subscriptionJSPayment, $scope.order, $scope.customerData, $scope.paymentData, function (data) {
// This callback will be invoked when the signup succeeded (or failed)
// Note that the callback must use $apply, otherwise angularjs won't notice we changed something:
$scope.$apply(function () {
$scope.signupRunning = false;
if (!data.Url)
$scope.isSuccess = true; //done
else
window.location = data.Url; // redirect required, e.g. paypal, skrill
});
}, function (error) { alert("an error occurred during signup!"); console.log(error); });
};
$scope.preview = function () {
// ask subscriptionJS to update the expected total. preview() will internally use a timeout so it doesn't
// send a ton of requests and we don't need to bother with timeouts here.
self.iteroInstance.preview($scope.order, $scope.customerData, function (data) {
// use $scope.$apply so angular knows we're messing around with the scope's state again
$scope.$apply(function () {
// DTO: PreviewResponse
// DTO: OrderPost, CustomerDataPost
$scope.order = data.Order;
});
}, function () {});
};
var modalInstance = null;
// TODO: Maybe use a different DTO
var tdsInit = function tdsInit(redirect, cancelCallback) {
var url = redirect.url;
var params = redirect.params;
// Open the modal to show the bank's 3d-secure iframe
modalInstance = $modal.open({
templateUrl: '3ds-modal.html',
controller: ModalInstanceCtrl,
windowClass: "fade in",
resolve: {
url: function () {
return redirect.url;
},
params: function () {
return redirect.params;
},
onclose: function () {
return function () {
// Tell subscription we're no longer trying to sign up:
self.iteroInstance.abort();
};
}
}
});
modalInstance.result.then(function (result) {
}, function () {
// if the modal was dimissed, we can enable the signup button again
$scope.signupRunning = false;
});
};
var tdsCleanup = function () {
// tdsCleanup will be called if paymill wants us to close the modal, i.e. the process was successful
// TODO: It's not clear from the documentation if that's always true, 3DS frame contents depend on the
// issuer bank.
modalInstance.close('external cleanup');
};
var paymentConfig = {
// REQUIRED. The initial order to be displayed. This will be requested immediately upon load
publicApiKey: "5331a0751d8dd00c4466c9be",
// REQUIRED. After payment user will be redirected to this URL.
providerReturnUrl: "https://developer.billwerk.io/Docs/subscriptionJS_Introduction",
// OPTIONAL. Overwrite the handling of the 3d-secure iframes. Comment out these
// two lines to see what happens without (essentially the same, but not customizable).
// Only applies to paymill. You might want to read paymill's documentation on the subject.
"popupCreate": tdsInit,
"popupClose": tdsCleanup
};
self.subscriptionJSPayment = new subscriptionJS.Payment(paymentConfig, function () {
$scope.$apply(function () {
// When subscriptionJS is ready, copy the payment methods and initial order
$scope.paymentReady = true;
$scope.paymentMethods = self.subscriptionJSPayment.getAvailablePaymentMethods();
$scope.paymentMethodEnum = self.subscriptionJSPayment.getAvailablePaymentMethodEnum();
$scope.paymentData.bearer = $scope.paymentMethodEnum[0];
});
}, function (errorData) {
alert("error initializing payment!");
console.log(errorData);
});
var initialCart = { planVariantId: "5331a27f1d8dd00c4466c9dd", componentSubscriptions: [{ componentId: "537f6fb31d8dd000588fc677", quantity: 1}] };
self.iteroInstance = new subscriptionJS.Signup();
self.iteroInstance.preview(initialCart, $scope.customerData, function (success) {
$scope.$apply(function () {
$scope.order = success.Order;
});
}, function (error) {
alert("an error occured!"); console.log(error);
});
};
// This directive encapsulates the DOM modifications required to intialize the 3DS
// iframe. The core of this code is from paymill's own js bridge, but the directive
// bindings are a little intricate
angular.module('iteroAngular.directives', []).directive("3dsModal", function ($parse) {
return {
restrict: "A",
scope: {
params: "@",
url: "@"
},
link: function (scope, element, attrs) {
var url = scope.url;
var params = JSON.parse(scope.params);
var iframe = element[0];
var iframeDoc = iframe.contentWindow || iframe.contentDocument;
if (iframeDoc.document) iframeDoc = iframeDoc.document;
var form = iframeDoc.createElement('form');
form.method = 'post';
form.action = url;
for (var k in params) {
var input = iframeDoc.createElement('input');
input.type = 'hidden';
input.name = k;
input.value = decodeURIComponent(params[k]);
form.appendChild(input);
}
if (iframeDoc.body) iframeDoc.body.appendChild(form);
else iframeDoc.appendChild(form);
form.submit();
}
};
});
// angularjs dependency injection
angular.module('iteroAngular', ['iteroAngular.directives', 'ui.bootstrap.modal']);