Skip to content

Commit c6f751d

Browse files
committed
Web Payments API update.
1) Build PR() object on page load, so that querying of slower payment apps does not result in showing a spinner when .show() is called. 2) Check if user has a payment instrument by calling .canMakePayment() in the new sample at paymentrequest/can-make-payment/. 3) Use the built-in serializer for PaymentResponse and PaymentAddress. 4) Add support for Basic Card payment method. 5) Add support for MIR credit card type. 6) Show 'Cannot ship outside of US' in the dynamic shipping example. 7) Make the shipping price "pending" until user selects a valid shipping address. 8) Warn that these tests work only on Android for now.
1 parent 516365d commit c6f751d

File tree

11 files changed

+541
-188
lines changed

11 files changed

+541
-188
lines changed

paymentrequest/README.md

+11-7
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,28 @@
11
# PaymentRequest Recipes
22

3-
- [Credit cards](https://googlechrome.github.io/samples/paymentrequest/credit-cards/index.html) -
3+
- [Credit cards](https://googlechrome.github.io/samples/paymentrequest/credit-cards/) -
44
a sample that accepts credit card payments and does not request shipping
55
information.
66

7-
- [Android Pay](https://googlechrome.github.io/samples/paymentrequest/android-pay/index.html) -
7+
- [Android Pay](https://googlechrome.github.io/samples/paymentrequest/android-pay/) -
88
a sample that accepts Android Pay payments and does not request shipping
99
information.
1010

11-
- [Free shipping](https://googlechrome.github.io/samples/paymentrequest/free-shipping/index.html) -
11+
- [Free shipping](https://googlechrome.github.io/samples/paymentrequest/free-shipping/) -
1212
a sample that accepts credit card payments and provides free shipping worldwide.
1313

14-
- [Shipping options](https://googlechrome.github.io/samples/paymentrequest/shipping-options/index.html) -
14+
- [Shipping options](https://googlechrome.github.io/samples/paymentrequest/shipping-options/) -
1515
a sample that accepts credit card payments and provides a couple of shipping
1616
options regardless of shipping address.
1717

18-
- [Dynamic shipping options](https://googlechrome.github.io/samples/paymentrequest/dynamic-shipping/index.html) -
18+
- [Dynamic shipping options](https://googlechrome.github.io/samples/paymentrequest/dynamic-shipping/) -
1919
a sample that accepts credit card payments and varies the availability and price
2020
of shipping options depending on the shipping address.
2121

22-
- [Contact info](https://googlechrome.github.io/samples/paymentrequest/contact-info/index.html) -
22+
- [Contact info](https://googlechrome.github.io/samples/paymentrequest/contact-info/) -
2323
a sample that accepts credit card payments and requests user's contact
24-
information: phone number and email address.
24+
information: name, phone number, and email address.
25+
26+
- [Can make payment](https://googlechrome.github.io/samples/paymentrequest/can-make-payment/) -
27+
a sample that accepts both Android Pay and credit card payments and checks
28+
whether the browser can make payment.

paymentrequest/android-pay/demo.js

+50-34
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
/**
2-
* Invokes PaymentRequest for Android Pay. If you encounter issues when running
3-
* your own copy of this sample, run 'adb logcat | grep Wallet' to see detailed
4-
* error messages.
2+
* Builds PaymentRequest for Android Pay, but does not show any UI yet. If you
3+
* encounter issues when running your own copy of this sample, run 'adb logcat |
4+
* grep Wallet' to see detailed error messages.
5+
*
6+
* @return {PaymentRequest} The PaymentRequest object.
57
*/
6-
function onBuyClicked() {
7-
var supportedInstruments = [{
8+
function initPaymentRequest() {
9+
let supportedInstruments = [{
810
supportedMethods: ['https://android.com/pay'],
911
data: {
1012
merchantName: 'Android Pay Demo',
@@ -21,34 +23,41 @@ function onBuyClicked() {
2123
// Place your own Stripe publishable key here. Use a matching Stripe
2224
// secret key on the server to initiate a transaction.
2325
'stripe:publishableKey': 'pk_live_lNk21zqKM2BENZENh3rzCUgo',
24-
'stripe:version': '2016-07-06'
25-
}
26-
}
27-
}
26+
'stripe:version': '2016-07-06',
27+
},
28+
},
29+
},
2830
}];
2931

30-
var details = {
32+
let details = {
3133
total: {label: 'Donation', amount: {currency: 'USD', value: '55.00'}},
3234
displayItems: [
3335
{
3436
label: 'Original donation amount',
35-
amount: {currency: 'USD', value: '65.00'}
37+
amount: {currency: 'USD', value: '65.00'},
3638
},
3739
{
3840
label: 'Friends and family discount',
39-
amount: {currency: 'USD', value: '-10.00'}
40-
}
41-
]
41+
amount: {currency: 'USD', value: '-10.00'},
42+
},
43+
],
4244
};
4345

44-
new PaymentRequest(supportedInstruments, details) // eslint-disable-line no-undef
45-
.show()
46-
.then(function(instrumentResponse) {
47-
sendPaymentToServer(instrumentResponse);
48-
})
49-
.catch(function(err) {
50-
ChromeSamples.setStatus(err);
51-
});
46+
return new PaymentRequest(supportedInstruments, details);
47+
}
48+
49+
/**
50+
* Invokes PaymentRequest for Android Pay.
51+
*
52+
* @param {PaymentRequest} request The PaymentRequest object.
53+
*/
54+
function onBuyClicked(request) {
55+
request.show().then(function(instrumentResponse) {
56+
sendPaymentToServer(instrumentResponse);
57+
})
58+
.catch(function(err) {
59+
ChromeSamples.setStatus(err);
60+
});
5261
}
5362

5463
/**
@@ -58,7 +67,7 @@ function onBuyClicked() {
5867
* process.
5968
*/
6069
function sendPaymentToServer(instrumentResponse) {
61-
// There's no server-side component of these samples. Not transactions are
70+
// There's no server-side component of these samples. No transactions are
6271
// processed and no money exchanged hands. Instantaneous transactions are not
6372
// realistic. Add a 2 second delay to make it seem more real.
6473
window.setTimeout(function() {
@@ -76,24 +85,31 @@ function sendPaymentToServer(instrumentResponse) {
7685
/**
7786
* Converts the payment instrument into a JSON string.
7887
*
79-
* @private
8088
* @param {PaymentResponse} instrument The instrument to convert.
8189
* @return {string} The JSON string representation of the instrument.
8290
*/
8391
function instrumentToJsonString(instrument) {
84-
// PaymentInsrument is an interface, but JSON.stringify works only on
85-
// dictionaries.
86-
return JSON.stringify({
87-
methodName: instrument.methodName,
88-
details: instrument.details
89-
}, undefined, 2);
92+
if (instrument.toJSON) {
93+
return JSON.stringify(instrument, undefined, 2);
94+
} else {
95+
return JSON.stringify({
96+
methodName: instrument.methodName,
97+
details: instrument.details,
98+
}, undefined, 2);
99+
}
90100
}
91101

92-
var buyButton = document.getElementById('buyButton');
93-
if ('PaymentRequest' in window) {
102+
const buyButton = document.getElementById('buyButton');
103+
buyButton.setAttribute('style', 'display: none;');
104+
if (!navigator.userAgent.match(/Android/i)) {
105+
ChromeSamples.setStatus('Supported only on Android for now.');
106+
} else if ('PaymentRequest' in window) {
107+
let request = initPaymentRequest();
94108
buyButton.setAttribute('style', 'display: inline;');
95-
buyButton.addEventListener('click', onBuyClicked);
109+
buyButton.addEventListener('click', function() {
110+
onBuyClicked(request);
111+
request = initPaymentRequest();
112+
});
96113
} else {
97-
buyButton.setAttribute('style', 'display: none;');
98114
ChromeSamples.setStatus('This browser does not support web payments');
99115
}
+180
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
/**
2+
* The callback for successful creation of PaymentRequest.
3+
*
4+
* @callback successCallback
5+
* @param {PaymentRequest} request The newly created instance of PaymentRequest
6+
* object.
7+
* @param {string} optionalWarning The optional warning message to be used, for
8+
* example, when unable to determine whether the browser can make payments.
9+
*/
10+
11+
/**
12+
* The callback for failed creation of PaymentRequest.
13+
*
14+
* @callback failureCallback
15+
* @param {string} error The message indicating the reason why an instance of
16+
* PaymentRequest was not created.
17+
*/
18+
19+
/**
20+
* Asynchronously builds PaymentRequest for both Android Pay and credit card
21+
* payments, but does not show any UI yet. Succeeds only if can make payments.
22+
* If you encounter issues when running your own copy of this sample, run 'adb
23+
* logcat | grep Wallet' to see detailed error messages.
24+
*
25+
* @param {successCallback} onSuccess The callback to invoke when this function
26+
* is finished successfully.
27+
* @param {failureCallback} onFailure The callback to invoke when this function
28+
* is finished with failure.
29+
*/
30+
function initPaymentRequest(onSuccess, onFailure) {
31+
if (!navigator.userAgent.match(/Android/i)) {
32+
onFailure('Supported only on Android for now.');
33+
return;
34+
}
35+
36+
if (!('PaymentRequest' in window)) {
37+
onFailure('This browser does not support web payments.');
38+
return;
39+
}
40+
41+
let networks = ['amex', 'diners', 'discover', 'jcb', 'mastercard', 'unionpay',
42+
'visa', 'mir'];
43+
let types = ['debit', 'credit', 'prepaid'];
44+
let supportedInstruments = [{
45+
supportedMethods: ['https://android.com/pay'],
46+
data: {
47+
merchantName: 'Android Pay Demo',
48+
// Place your own Android Pay merchant ID here. The merchant ID is tied to
49+
// the origin of the website.
50+
merchantId: '00184145120947117657',
51+
// If you do not yet have a merchant ID, uncomment the following line.
52+
// environment: 'TEST',
53+
allowedCardNetworks: ['AMEX', 'DISCOVER', 'MASTERCARD', 'VISA'],
54+
paymentMethodTokenizationParameters: {
55+
tokenizationType: 'GATEWAY_TOKEN',
56+
parameters: {
57+
'gateway': 'stripe',
58+
// Place your own Stripe publishable key here. Use a matching Stripe
59+
// secret key on the server to initiate a transaction.
60+
'stripe:publishableKey': 'pk_live_lNk21zqKM2BENZENh3rzCUgo',
61+
'stripe:version': '2016-07-06',
62+
},
63+
},
64+
},
65+
}, {
66+
supportedMethods: networks,
67+
}, {
68+
supportedMethods: ['basic-card'],
69+
data: {supportedNetworks: networks, supportedTypes: types},
70+
}];
71+
72+
let details = {
73+
total: {label: 'Donation', amount: {currency: 'USD', value: '55.00'}},
74+
displayItems: [
75+
{
76+
label: 'Original donation amount',
77+
amount: {currency: 'USD', value: '65.00'},
78+
},
79+
{
80+
label: 'Friends and family discount',
81+
amount: {currency: 'USD', value: '-10.00'},
82+
},
83+
],
84+
};
85+
86+
let request = new PaymentRequest(supportedInstruments, details);
87+
88+
if (request.canMakePayment) {
89+
request.canMakePayment().then(function(result) {
90+
if (result) {
91+
onSuccess(request);
92+
} else {
93+
onFailure('Cannot make payment');
94+
}
95+
}).catch(function(err) {
96+
onSuccess(request, err);
97+
});
98+
} else {
99+
onSuccess(
100+
request, 'This browser does not support "can make payment" query');
101+
}
102+
}
103+
104+
/**
105+
* Invokes PaymentRequest for Android Pay.
106+
*
107+
* @param {PaymentRequest} request The PaymentRequest object.
108+
*/
109+
function onBuyClicked(request) {
110+
request.show().then(function(instrumentResponse) {
111+
sendPaymentToServer(instrumentResponse);
112+
})
113+
.catch(function(err) {
114+
ChromeSamples.setStatus(err);
115+
});
116+
}
117+
118+
/**
119+
* Simulates processing the payment data on the server.
120+
*
121+
* @param {PaymentResponse} instrumentResponse The payment information to
122+
* process.
123+
*/
124+
function sendPaymentToServer(instrumentResponse) {
125+
// There's no server-side component of these samples. No transactions are
126+
// processed and no money exchanged hands. Instantaneous transactions are not
127+
// realistic. Add a 2 second delay to make it seem more real.
128+
window.setTimeout(function() {
129+
instrumentResponse.complete('success')
130+
.then(function() {
131+
document.getElementById('result').innerHTML =
132+
instrumentToJsonString(instrumentResponse);
133+
})
134+
.catch(function(err) {
135+
ChromeSamples.setStatus(err);
136+
});
137+
}, 2000);
138+
}
139+
140+
/**
141+
* Converts the payment instrument into a JSON string.
142+
*
143+
* @param {PaymentResponse} instrument The instrument to convert.
144+
* @return {string} The JSON string representation of the instrument.
145+
*/
146+
function instrumentToJsonString(instrument) {
147+
if (instrument.toJSON) {
148+
return JSON.stringify(instrument, undefined, 2);
149+
} else {
150+
return JSON.stringify({
151+
methodName: instrument.methodName,
152+
details: instrument.details,
153+
}, undefined, 2);
154+
}
155+
}
156+
157+
/**
158+
* Initializes the buy button.
159+
*
160+
* @param {HTMLElement} buyButton The "Buy" button to initialize.
161+
*/
162+
function initBuyButton(buyButton) {
163+
initPaymentRequest(function(request, optionalWarning) {
164+
buyButton.setAttribute('style', 'display: inline;');
165+
ChromeSamples.setStatus(optionalWarning ? optionalWarning : '');
166+
buyButton.addEventListener('click', function handleClick() {
167+
buyButton.removeEventListener('click', handleClick);
168+
onBuyClicked(request);
169+
initBuyButton(buyButton);
170+
});
171+
}, function(error) {
172+
buyButton.setAttribute('style', 'display: none;');
173+
ChromeSamples.setStatus(error);
174+
});
175+
}
176+
177+
const buyButton = document.getElementById('buyButton');
178+
buyButton.setAttribute('style', 'display: none;');
179+
ChromeSamples.setStatus('Checking...');
180+
initBuyButton(buyButton);
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
feature_name: PaymentRequest Can Make Payment
3+
chrome_version: 56
4+
feature_id: 5639348045217792
5+
---
6+
7+
<h3>Background</h3>
8+
<p>
9+
<a href="https://github.com/w3c/browser-payment-api">PaymentRequest</a> lets
10+
you accept payment from different payment methods.
11+
</p>
12+
13+
<p>
14+
This sample accepts both Android Pay and credit card payments and checks
15+
whether the browser can make payment.
16+
</p>
17+
18+
{% capture initial_output_content %}
19+
<div><button id="buyButton">Buy</button></div>
20+
<div><pre id="result"></pre></div>
21+
{% endcapture %}
22+
{% include output_helper.html initial_output_content=initial_output_content %}
23+
24+
{% include js_snippet.html filename='demo.js' %}

0 commit comments

Comments
 (0)