blob: 5f1de1797297dca8dcc6b502ce53407121877536 [file] [log] [blame]
mathpf1a7a3752017-03-15 11:23:371// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "components/payments/content/payment_request_spec.h"
6
7#include <utility>
8
Mathieu Perreault51339b82017-07-20 17:06:059#include "base/feature_list.h"
mathpf1a7a3752017-03-15 11:23:3710#include "base/logging.h"
mathpeb8892ff2017-05-04 18:42:5511#include "base/strings/utf_string_conversions.h"
Mohamad Ahmadif5544bb2017-09-01 21:48:2212#include "components/payments/content/payment_request_converter.h"
Mathieu Perreault51339b82017-07-20 17:06:0513#include "components/payments/core/features.h"
Anthony Vallee-Dubois059d59a2017-07-07 15:05:4914#include "components/payments/core/payment_instrument.h"
mathpb65623a2017-04-06 02:01:5415#include "components/payments/core/payment_method_data.h"
16#include "components/payments/core/payment_request_data_util.h"
mathpeb8892ff2017-05-04 18:42:5517#include "components/strings/grit/components_strings.h"
18#include "ui/base/l10n/l10n_util.h"
mathpf1a7a3752017-03-15 11:23:3719
20namespace payments {
21
mathpb65623a2017-04-06 02:01:5422namespace {
23
Anthony Vallee-Dubois059d59a2017-07-07 15:05:4924// Validates the |method_data| and fills |supported_card_networks_|,
Randall Raymondec4e0852017-07-14 01:30:4525// |supported_card_networks_set_|, |basic_card_specified_networks_|,
26// and |url_payment_method_identifiers_|.
Anthony Vallee-Dubois059d59a2017-07-07 15:05:4927void PopulateValidatedMethodData(
28 const std::vector<PaymentMethodData>& method_data_vector,
29 std::vector<std::string>* supported_card_networks,
30 std::set<std::string>* basic_card_specified_networks,
31 std::set<std::string>* supported_card_networks_set,
32 std::set<autofill::CreditCard::CardType>* supported_card_types_set,
Randall Raymond6a85ba0ab2017-08-04 23:11:5433 std::vector<GURL>* url_payment_method_identifiers,
Anthony Vallee-Dubois059d59a2017-07-07 15:05:4934 std::map<std::string, std::set<std::string>>* stringified_method_data) {
Randall Raymondec4e0852017-07-14 01:30:4535 data_util::ParseSupportedMethods(method_data_vector, supported_card_networks,
36 basic_card_specified_networks,
37 url_payment_method_identifiers);
Anthony Vallee-Dubois059d59a2017-07-07 15:05:4938 supported_card_networks_set->insert(supported_card_networks->begin(),
39 supported_card_networks->end());
40
41 data_util::ParseSupportedCardTypes(method_data_vector,
42 supported_card_types_set);
43}
44
45void PopulateValidatedMethodData(
46 const std::vector<mojom::PaymentMethodDataPtr>& method_data_mojom,
47 std::vector<std::string>* supported_card_networks,
48 std::set<std::string>* basic_card_specified_networks,
49 std::set<std::string>* supported_card_networks_set,
50 std::set<autofill::CreditCard::CardType>* supported_card_types_set,
Randall Raymond6a85ba0ab2017-08-04 23:11:5451 std::vector<GURL>* url_payment_method_identifiers,
Anthony Vallee-Dubois059d59a2017-07-07 15:05:4952 std::map<std::string, std::set<std::string>>* stringified_method_data) {
53 std::vector<PaymentMethodData> method_data_vector;
54 method_data_vector.reserve(method_data_mojom.size());
55 for (const mojom::PaymentMethodDataPtr& method_data_entry :
56 method_data_mojom) {
57 for (const std::string& method : method_data_entry->supported_methods) {
58 (*stringified_method_data)[method].insert(
59 method_data_entry->stringified_data);
60 }
61
Mohamad Ahmadif5544bb2017-09-01 21:48:2262 method_data_vector.push_back(ConvertPaymentMethodData(method_data_entry));
Anthony Vallee-Dubois059d59a2017-07-07 15:05:4963 }
64
65 PopulateValidatedMethodData(
66 method_data_vector, supported_card_networks,
67 basic_card_specified_networks, supported_card_networks_set,
Randall Raymondec4e0852017-07-14 01:30:4568 supported_card_types_set, url_payment_method_identifiers,
69 stringified_method_data);
Anthony Vallee-Dubois059d59a2017-07-07 15:05:4970}
71
mathpb65623a2017-04-06 02:01:5472} // namespace
73
mathp600bab52017-03-26 03:47:5974const char kBasicCardMethodName[] = "basic-card";
Mathieu Perreault627b97c2017-08-12 00:44:2275const char kGooglePayMethodName[] = "https://google.com/pay";
76const char kAndroidPayMethodName[] = "https://android.com/pay";
mathpf1a7a3752017-03-15 11:23:3777
78PaymentRequestSpec::PaymentRequestSpec(
79 mojom::PaymentOptionsPtr options,
80 mojom::PaymentDetailsPtr details,
81 std::vector<mojom::PaymentMethodDataPtr> method_data,
mathpc0d616a2017-03-15 14:09:3382 Observer* observer,
83 const std::string& app_locale)
84 : options_(std::move(options)),
85 details_(std::move(details)),
gogerald7a0cc3e2017-09-19 03:35:4886 method_data_(std::move(method_data)),
mathp151bd31e2017-04-03 21:07:2487 app_locale_(app_locale),
Anthony Vallee-Duboisdb030dd2017-05-19 18:04:5188 selected_shipping_option_(nullptr) {
mathpf1a7a3752017-03-15 11:23:3789 if (observer)
90 AddObserver(observer);
mathpb77b8732017-05-11 15:26:4291 UpdateSelectedShippingOption(/*after_update=*/false);
Anthony Vallee-Dubois059d59a2017-07-07 15:05:4992 PopulateValidatedMethodData(
gogerald7a0cc3e2017-09-19 03:35:4893 method_data_, &supported_card_networks_, &basic_card_specified_networks_,
Anthony Vallee-Dubois059d59a2017-07-07 15:05:4994 &supported_card_networks_set_, &supported_card_types_set_,
Randall Raymondec4e0852017-07-14 01:30:4595 &url_payment_method_identifiers_, &stringified_method_data_);
mathpf1a7a3752017-03-15 11:23:3796}
97PaymentRequestSpec::~PaymentRequestSpec() {}
98
mathp151bd31e2017-04-03 21:07:2499void PaymentRequestSpec::UpdateWith(mojom::PaymentDetailsPtr details) {
100 details_ = std::move(details);
101 // We reparse the |details_| and update the observers.
mathpb77b8732017-05-11 15:26:42102 UpdateSelectedShippingOption(/*after_update=*/true);
mathp151bd31e2017-04-03 21:07:24103 NotifyOnSpecUpdated();
Anthony Vallee-Duboisdb030dd2017-05-19 18:04:51104 current_update_reason_ = UpdateReason::NONE;
mathp151bd31e2017-04-03 21:07:24105}
106
mathpf1a7a3752017-03-15 11:23:37107void PaymentRequestSpec::AddObserver(Observer* observer) {
108 CHECK(observer);
109 observers_.AddObserver(observer);
110}
111
112void PaymentRequestSpec::RemoveObserver(Observer* observer) {
113 observers_.RemoveObserver(observer);
114}
115
tmartino5f0912b82017-03-30 03:20:52116bool PaymentRequestSpec::request_shipping() const {
117 return options_->request_shipping;
118}
119bool PaymentRequestSpec::request_payer_name() const {
120 return options_->request_payer_name;
121}
122bool PaymentRequestSpec::request_payer_phone() const {
123 return options_->request_payer_phone;
124}
125bool PaymentRequestSpec::request_payer_email() const {
126 return options_->request_payer_email;
127}
128
129PaymentShippingType PaymentRequestSpec::shipping_type() const {
130 // Transform Mojo-specific enum into platform-agnostic equivalent.
131 switch (options_->shipping_type) {
132 case mojom::PaymentShippingType::DELIVERY:
133 return PaymentShippingType::DELIVERY;
134 case payments::mojom::PaymentShippingType::PICKUP:
135 return PaymentShippingType::PICKUP;
136 case payments::mojom::PaymentShippingType::SHIPPING:
137 return PaymentShippingType::SHIPPING;
138 default:
139 NOTREACHED();
140 }
141 // Needed for compilation on some platforms.
142 return PaymentShippingType::SHIPPING;
143}
144
mathp600bab52017-03-26 03:47:59145bool PaymentRequestSpec::IsMethodSupportedThroughBasicCard(
146 const std::string& method_name) {
147 return basic_card_specified_networks_.count(method_name) > 0;
148}
149
mathpc0d616a2017-03-15 14:09:33150base::string16 PaymentRequestSpec::GetFormattedCurrencyAmount(
Anthony Vallee-Dubois080d5b72017-05-11 22:34:04151 const mojom::PaymentCurrencyAmountPtr& currency_amount) {
mathpc0d616a2017-03-15 14:09:33152 CurrencyFormatter* formatter = GetOrCreateCurrencyFormatter(
Anthony Vallee-Dubois080d5b72017-05-11 22:34:04153 currency_amount->currency, currency_amount->currency_system, app_locale_);
154 return formatter->Format(currency_amount->value);
mathpc0d616a2017-03-15 14:09:33155}
156
Anthony Vallee-Dubois080d5b72017-05-11 22:34:04157std::string PaymentRequestSpec::GetFormattedCurrencyCode(
158 const mojom::PaymentCurrencyAmountPtr& currency_amount) {
mathpc0d616a2017-03-15 14:09:33159 CurrencyFormatter* formatter = GetOrCreateCurrencyFormatter(
Anthony Vallee-Dubois080d5b72017-05-11 22:34:04160 currency_amount->currency, currency_amount->currency_system, app_locale_);
mathpc0d616a2017-03-15 14:09:33161
162 return formatter->formatted_currency_code();
163}
164
anthonyvd2f30baa12017-04-13 22:30:50165void PaymentRequestSpec::StartWaitingForUpdateWith(
166 PaymentRequestSpec::UpdateReason reason) {
Anthony Vallee-Duboisdb030dd2017-05-19 18:04:51167 current_update_reason_ = reason;
anthonyvd2f30baa12017-04-13 22:30:50168 for (auto& observer : observers_) {
169 observer.OnStartUpdating(reason);
170 }
171}
172
Anthony Vallee-Dubois080d5b72017-05-11 22:34:04173bool PaymentRequestSpec::IsMixedCurrency() const {
174 const std::string& total_currency = details_->total->amount->currency;
175 return std::any_of(details_->display_items.begin(),
176 details_->display_items.end(),
177 [&total_currency](const mojom::PaymentItemPtr& item) {
178 return item->amount->currency != total_currency;
179 });
180}
181
Anthony Vallee-Dubois059d59a2017-07-07 15:05:49182const mojom::PaymentItemPtr& PaymentRequestSpec::GetTotal(
183 PaymentInstrument* selected_instrument) const {
184 const mojom::PaymentDetailsModifierPtr* modifier =
185 GetApplicableModifier(selected_instrument);
gogerald7a0cc3e2017-09-19 03:35:48186 return modifier ? (*modifier)->total : details_->total;
Anthony Vallee-Dubois059d59a2017-07-07 15:05:49187}
rouslan690997682017-05-09 18:07:39188
Anthony Vallee-Dubois059d59a2017-07-07 15:05:49189std::vector<const mojom::PaymentItemPtr*> PaymentRequestSpec::GetDisplayItems(
190 PaymentInstrument* selected_instrument) const {
191 std::vector<const mojom::PaymentItemPtr*> display_items;
192 const mojom::PaymentDetailsModifierPtr* modifier =
193 GetApplicableModifier(selected_instrument);
gogerald7a0cc3e2017-09-19 03:35:48194 for (const auto& item : details_->display_items) {
Anthony Vallee-Dubois059d59a2017-07-07 15:05:49195 display_items.push_back(&item);
mathpf1a7a3752017-03-15 11:23:37196 }
mathp363735b2017-03-16 18:08:05197
Anthony Vallee-Dubois059d59a2017-07-07 15:05:49198 if (modifier) {
199 for (const auto& additional_item : (*modifier)->additional_display_items) {
200 display_items.push_back(&additional_item);
201 }
202 }
203 return display_items;
204}
Rouslan Solomakhin25d708b2017-06-23 17:12:03205
Anthony Vallee-Dubois059d59a2017-07-07 15:05:49206const std::vector<mojom::PaymentShippingOptionPtr>&
207PaymentRequestSpec::GetShippingOptions() const {
gogerald7a0cc3e2017-09-19 03:35:48208 return details_->shipping_options;
Anthony Vallee-Dubois059d59a2017-07-07 15:05:49209}
210
211const mojom::PaymentDetailsModifierPtr*
212PaymentRequestSpec::GetApplicableModifier(
213 PaymentInstrument* selected_instrument) const {
Mathieu Perreault51339b82017-07-20 17:06:05214 if (!selected_instrument ||
215 !base::FeatureList::IsEnabled(features::kWebPaymentsModifiers))
Anthony Vallee-Dubois059d59a2017-07-07 15:05:49216 return nullptr;
217
gogerald7a0cc3e2017-09-19 03:35:48218 for (const auto& modifier : details_->modifiers) {
Anthony Vallee-Dubois059d59a2017-07-07 15:05:49219 std::vector<std::string> supported_networks;
220 std::set<autofill::CreditCard::CardType> supported_types;
Randall Raymondec4e0852017-07-14 01:30:45221 // The following 4 are unused but required by PopulateValidatedMethodData.
Anthony Vallee-Dubois059d59a2017-07-07 15:05:49222 std::set<std::string> basic_card_specified_networks;
223 std::set<std::string> supported_card_networks_set;
Randall Raymond6a85ba0ab2017-08-04 23:11:54224 std::vector<GURL> url_payment_method_identifiers;
Anthony Vallee-Dubois059d59a2017-07-07 15:05:49225 std::map<std::string, std::set<std::string>> stringified_method_data;
226 PopulateValidatedMethodData(
Mohamad Ahmadif5544bb2017-09-01 21:48:22227 {ConvertPaymentMethodData(modifier->method_data)}, &supported_networks,
Anthony Vallee-Dubois059d59a2017-07-07 15:05:49228 &basic_card_specified_networks, &supported_card_networks_set,
Randall Raymondec4e0852017-07-14 01:30:45229 &supported_types, &url_payment_method_identifiers,
230 &stringified_method_data);
Anthony Vallee-Dubois059d59a2017-07-07 15:05:49231
232 if (selected_instrument->IsValidForModifier(
Anthony Vallee-Dubois6fae0472017-08-07 16:51:35233 modifier->method_data->supported_methods, supported_networks,
234 supported_types, !modifier->method_data->supported_types.empty())) {
Anthony Vallee-Dubois059d59a2017-07-07 15:05:49235 return &modifier;
236 }
237 }
238 return nullptr;
mathpf1a7a3752017-03-15 11:23:37239}
240
mathpb77b8732017-05-11 15:26:42241void PaymentRequestSpec::UpdateSelectedShippingOption(bool after_update) {
mathp151bd31e2017-04-03 21:07:24242 if (!request_shipping())
243 return;
244
mathpb77b8732017-05-11 15:26:42245 selected_shipping_option_ = nullptr;
mathpeb8892ff2017-05-04 18:42:55246 selected_shipping_option_error_.clear();
gogerald7a0cc3e2017-09-19 03:35:48247 if (details_->shipping_options.empty()) {
mathpb77b8732017-05-11 15:26:42248 // No options are provided by the merchant.
249 if (after_update) {
Mathieu Perreault2c1f3192017-05-18 14:45:28250 // This is after an update, which means that the selected address is not
mathpb77b8732017-05-11 15:26:42251 // supported. The merchant may have customized the error string, or a
252 // generic one is used.
gogerald7a0cc3e2017-09-19 03:35:48253 if (!details_->error.empty()) {
254 selected_shipping_option_error_ = base::UTF8ToUTF16(details_->error);
mathpb77b8732017-05-11 15:26:42255 } else {
Mathieu Perreault2c1f3192017-05-18 14:45:28256 // The generic error string depends on the shipping type.
257 switch (shipping_type()) {
258 case PaymentShippingType::DELIVERY:
259 selected_shipping_option_error_ = l10n_util::GetStringUTF16(
260 IDS_PAYMENTS_UNSUPPORTED_DELIVERY_ADDRESS);
261 break;
262 case PaymentShippingType::PICKUP:
263 selected_shipping_option_error_ = l10n_util::GetStringUTF16(
264 IDS_PAYMENTS_UNSUPPORTED_PICKUP_ADDRESS);
265 break;
266 case PaymentShippingType::SHIPPING:
267 selected_shipping_option_error_ = l10n_util::GetStringUTF16(
268 IDS_PAYMENTS_UNSUPPORTED_SHIPPING_ADDRESS);
269 break;
270 }
mathpb77b8732017-05-11 15:26:42271 }
272 }
273 return;
274 }
275
mathp151bd31e2017-04-03 21:07:24276 // As per the spec, the selected shipping option should initially be the last
mathpb77b8732017-05-11 15:26:42277 // one in the array that has its selected field set to true. If none are
278 // selected by the merchant, |selected_shipping_option_| stays nullptr.
mathp151bd31e2017-04-03 21:07:24279 auto selected_shipping_option_it = std::find_if(
gogerald7a0cc3e2017-09-19 03:35:48280 details_->shipping_options.rbegin(), details_->shipping_options.rend(),
mathp151bd31e2017-04-03 21:07:24281 [](const payments::mojom::PaymentShippingOptionPtr& element) {
282 return element->selected;
283 });
gogerald7a0cc3e2017-09-19 03:35:48284 if (selected_shipping_option_it != details_->shipping_options.rend()) {
mathp151bd31e2017-04-03 21:07:24285 selected_shipping_option_ = selected_shipping_option_it->get();
286 }
287}
288
mathp151bd31e2017-04-03 21:07:24289void PaymentRequestSpec::NotifyOnSpecUpdated() {
290 for (auto& observer : observers_)
291 observer.OnSpecUpdated();
mathpf1a7a3752017-03-15 11:23:37292}
293
mathpc0d616a2017-03-15 14:09:33294CurrencyFormatter* PaymentRequestSpec::GetOrCreateCurrencyFormatter(
295 const std::string& currency_code,
296 const std::string& currency_system,
297 const std::string& locale_name) {
Anthony Vallee-Dubois080d5b72017-05-11 22:34:04298 // Create a currency formatter for |currency_code|, or if already created
299 // return the cached version.
300 std::pair<std::map<std::string, CurrencyFormatter>::iterator, bool>
301 emplace_result = currency_formatters_.emplace(
302 std::piecewise_construct, std::forward_as_tuple(currency_code),
303 std::forward_as_tuple(currency_code, currency_system, locale_name));
304
305 return &(emplace_result.first->second);
mathpc0d616a2017-03-15 14:09:33306}
307
mathpf1a7a3752017-03-15 11:23:37308} // namespace payments