blob: 252fe150417bd1e1b887d813a1a307e3e2f2fdc4 [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
9#include "base/logging.h"
mathpeb8892ff2017-05-04 18:42:5510#include "base/strings/utf_string_conversions.h"
mathpb65623a2017-04-06 02:01:5411#include "components/payments/core/payment_method_data.h"
12#include "components/payments/core/payment_request_data_util.h"
mathpeb8892ff2017-05-04 18:42:5513#include "components/strings/grit/components_strings.h"
14#include "ui/base/l10n/l10n_util.h"
mathpf1a7a3752017-03-15 11:23:3715
16namespace payments {
17
mathpb65623a2017-04-06 02:01:5418namespace {
19
20// Returns the card network name associated with a given BasicCardNetwork. Names
21// are inspired by https://www.w3.org/Payments/card-network-ids.
22std::string GetBasicCardNetworkName(const mojom::BasicCardNetwork& network) {
23 switch (network) {
24 case mojom::BasicCardNetwork::AMEX:
25 return "amex";
26 case mojom::BasicCardNetwork::DINERS:
27 return "diners";
28 case mojom::BasicCardNetwork::DISCOVER:
29 return "discover";
30 case mojom::BasicCardNetwork::JCB:
31 return "jcb";
32 case mojom::BasicCardNetwork::MASTERCARD:
33 return "mastercard";
34 case mojom::BasicCardNetwork::MIR:
35 return "mir";
36 case mojom::BasicCardNetwork::UNIONPAY:
37 return "unionpay";
38 case mojom::BasicCardNetwork::VISA:
39 return "visa";
40 }
41 NOTREACHED();
42 return std::string();
43}
44
45} // namespace
46
mathp600bab52017-03-26 03:47:5947const char kBasicCardMethodName[] = "basic-card";
mathpf1a7a3752017-03-15 11:23:3748
49PaymentRequestSpec::PaymentRequestSpec(
50 mojom::PaymentOptionsPtr options,
51 mojom::PaymentDetailsPtr details,
52 std::vector<mojom::PaymentMethodDataPtr> method_data,
mathpc0d616a2017-03-15 14:09:3353 Observer* observer,
54 const std::string& app_locale)
55 : options_(std::move(options)),
56 details_(std::move(details)),
mathp151bd31e2017-04-03 21:07:2457 app_locale_(app_locale),
Anthony Vallee-Duboisdb030dd2017-05-19 18:04:5158 selected_shipping_option_(nullptr) {
mathpf1a7a3752017-03-15 11:23:3759 if (observer)
60 AddObserver(observer);
mathpb77b8732017-05-11 15:26:4261 UpdateSelectedShippingOption(/*after_update=*/false);
mathpf1a7a3752017-03-15 11:23:3762 PopulateValidatedMethodData(method_data);
63}
64PaymentRequestSpec::~PaymentRequestSpec() {}
65
mathp151bd31e2017-04-03 21:07:2466void PaymentRequestSpec::UpdateWith(mojom::PaymentDetailsPtr details) {
67 details_ = std::move(details);
68 // We reparse the |details_| and update the observers.
mathpb77b8732017-05-11 15:26:4269 UpdateSelectedShippingOption(/*after_update=*/true);
mathp151bd31e2017-04-03 21:07:2470 NotifyOnSpecUpdated();
Anthony Vallee-Duboisdb030dd2017-05-19 18:04:5171 current_update_reason_ = UpdateReason::NONE;
mathp151bd31e2017-04-03 21:07:2472}
73
mathpf1a7a3752017-03-15 11:23:3774void PaymentRequestSpec::AddObserver(Observer* observer) {
75 CHECK(observer);
76 observers_.AddObserver(observer);
77}
78
79void PaymentRequestSpec::RemoveObserver(Observer* observer) {
80 observers_.RemoveObserver(observer);
81}
82
tmartino5f0912b82017-03-30 03:20:5283bool PaymentRequestSpec::request_shipping() const {
84 return options_->request_shipping;
85}
86bool PaymentRequestSpec::request_payer_name() const {
87 return options_->request_payer_name;
88}
89bool PaymentRequestSpec::request_payer_phone() const {
90 return options_->request_payer_phone;
91}
92bool PaymentRequestSpec::request_payer_email() const {
93 return options_->request_payer_email;
94}
95
96PaymentShippingType PaymentRequestSpec::shipping_type() const {
97 // Transform Mojo-specific enum into platform-agnostic equivalent.
98 switch (options_->shipping_type) {
99 case mojom::PaymentShippingType::DELIVERY:
100 return PaymentShippingType::DELIVERY;
101 case payments::mojom::PaymentShippingType::PICKUP:
102 return PaymentShippingType::PICKUP;
103 case payments::mojom::PaymentShippingType::SHIPPING:
104 return PaymentShippingType::SHIPPING;
105 default:
106 NOTREACHED();
107 }
108 // Needed for compilation on some platforms.
109 return PaymentShippingType::SHIPPING;
110}
111
mathp600bab52017-03-26 03:47:59112bool PaymentRequestSpec::IsMethodSupportedThroughBasicCard(
113 const std::string& method_name) {
114 return basic_card_specified_networks_.count(method_name) > 0;
115}
116
mathpc0d616a2017-03-15 14:09:33117base::string16 PaymentRequestSpec::GetFormattedCurrencyAmount(
Anthony Vallee-Dubois080d5b72017-05-11 22:34:04118 const mojom::PaymentCurrencyAmountPtr& currency_amount) {
mathpc0d616a2017-03-15 14:09:33119 CurrencyFormatter* formatter = GetOrCreateCurrencyFormatter(
Anthony Vallee-Dubois080d5b72017-05-11 22:34:04120 currency_amount->currency, currency_amount->currency_system, app_locale_);
121 return formatter->Format(currency_amount->value);
mathpc0d616a2017-03-15 14:09:33122}
123
Anthony Vallee-Dubois080d5b72017-05-11 22:34:04124std::string PaymentRequestSpec::GetFormattedCurrencyCode(
125 const mojom::PaymentCurrencyAmountPtr& currency_amount) {
mathpc0d616a2017-03-15 14:09:33126 CurrencyFormatter* formatter = GetOrCreateCurrencyFormatter(
Anthony Vallee-Dubois080d5b72017-05-11 22:34:04127 currency_amount->currency, currency_amount->currency_system, app_locale_);
mathpc0d616a2017-03-15 14:09:33128
129 return formatter->formatted_currency_code();
130}
131
anthonyvd2f30baa12017-04-13 22:30:50132void PaymentRequestSpec::StartWaitingForUpdateWith(
133 PaymentRequestSpec::UpdateReason reason) {
Anthony Vallee-Duboisdb030dd2017-05-19 18:04:51134 current_update_reason_ = reason;
anthonyvd2f30baa12017-04-13 22:30:50135 for (auto& observer : observers_) {
136 observer.OnStartUpdating(reason);
137 }
138}
139
Anthony Vallee-Dubois080d5b72017-05-11 22:34:04140bool PaymentRequestSpec::IsMixedCurrency() const {
141 const std::string& total_currency = details_->total->amount->currency;
142 return std::any_of(details_->display_items.begin(),
143 details_->display_items.end(),
144 [&total_currency](const mojom::PaymentItemPtr& item) {
145 return item->amount->currency != total_currency;
146 });
147}
148
mathpf1a7a3752017-03-15 11:23:37149void PaymentRequestSpec::PopulateValidatedMethodData(
mathpb65623a2017-04-06 02:01:54150 const std::vector<mojom::PaymentMethodDataPtr>& method_data_mojom) {
mathpb65623a2017-04-06 02:01:54151 std::vector<PaymentMethodData> method_data_vector;
152 method_data_vector.reserve(method_data_mojom.size());
153 for (const mojom::PaymentMethodDataPtr& method_data_entry :
154 method_data_mojom) {
rouslan690997682017-05-09 18:07:39155 for (const std::string& method : method_data_entry->supported_methods) {
156 stringified_method_data_[method].insert(
157 method_data_entry->stringified_data);
158 }
159
mathpb65623a2017-04-06 02:01:54160 PaymentMethodData method_data;
161 method_data.supported_methods = method_data_entry->supported_methods;
162 // Transfer the supported basic card networks.
163 std::vector<std::string> supported_networks;
164 for (const mojom::BasicCardNetwork& network :
165 method_data_entry->supported_networks) {
166 supported_networks.push_back(GetBasicCardNetworkName(network));
mathpf1a7a3752017-03-15 11:23:37167 }
mathpb65623a2017-04-06 02:01:54168 method_data.supported_networks = std::move(supported_networks);
mathpf1a7a3752017-03-15 11:23:37169
mathpb65623a2017-04-06 02:01:54170 // TODO(crbug.com/708603): Add browser-side support for
171 // |method_data.supported_types|.
172 method_data_vector.push_back(std::move(method_data));
mathpf1a7a3752017-03-15 11:23:37173 }
mathp363735b2017-03-16 18:08:05174
rouslan6e3cf7c62017-04-17 21:23:28175 data_util::ParseBasicCardSupportedNetworks(method_data_vector,
176 &supported_card_networks_,
177 &basic_card_specified_networks_);
mathp363735b2017-03-16 18:08:05178 supported_card_networks_set_.insert(supported_card_networks_.begin(),
179 supported_card_networks_.end());
mathpf1a7a3752017-03-15 11:23:37180}
181
mathpb77b8732017-05-11 15:26:42182void PaymentRequestSpec::UpdateSelectedShippingOption(bool after_update) {
mathp151bd31e2017-04-03 21:07:24183 if (!request_shipping())
184 return;
185
mathpb77b8732017-05-11 15:26:42186 selected_shipping_option_ = nullptr;
mathpeb8892ff2017-05-04 18:42:55187 selected_shipping_option_error_.clear();
mathpb77b8732017-05-11 15:26:42188 if (details().shipping_options.empty()) {
189 // No options are provided by the merchant.
190 if (after_update) {
Mathieu Perreault2c1f3192017-05-18 14:45:28191 // This is after an update, which means that the selected address is not
mathpb77b8732017-05-11 15:26:42192 // supported. The merchant may have customized the error string, or a
193 // generic one is used.
194 if (!details().error.empty()) {
195 selected_shipping_option_error_ = base::UTF8ToUTF16(details().error);
196 } else {
Mathieu Perreault2c1f3192017-05-18 14:45:28197 // The generic error string depends on the shipping type.
198 switch (shipping_type()) {
199 case PaymentShippingType::DELIVERY:
200 selected_shipping_option_error_ = l10n_util::GetStringUTF16(
201 IDS_PAYMENTS_UNSUPPORTED_DELIVERY_ADDRESS);
202 break;
203 case PaymentShippingType::PICKUP:
204 selected_shipping_option_error_ = l10n_util::GetStringUTF16(
205 IDS_PAYMENTS_UNSUPPORTED_PICKUP_ADDRESS);
206 break;
207 case PaymentShippingType::SHIPPING:
208 selected_shipping_option_error_ = l10n_util::GetStringUTF16(
209 IDS_PAYMENTS_UNSUPPORTED_SHIPPING_ADDRESS);
210 break;
211 }
mathpb77b8732017-05-11 15:26:42212 }
213 }
214 return;
215 }
216
mathp151bd31e2017-04-03 21:07:24217 // As per the spec, the selected shipping option should initially be the last
mathpb77b8732017-05-11 15:26:42218 // one in the array that has its selected field set to true. If none are
219 // selected by the merchant, |selected_shipping_option_| stays nullptr.
mathp151bd31e2017-04-03 21:07:24220 auto selected_shipping_option_it = std::find_if(
221 details().shipping_options.rbegin(), details().shipping_options.rend(),
222 [](const payments::mojom::PaymentShippingOptionPtr& element) {
223 return element->selected;
224 });
225 if (selected_shipping_option_it != details().shipping_options.rend()) {
226 selected_shipping_option_ = selected_shipping_option_it->get();
227 }
228}
229
mathp151bd31e2017-04-03 21:07:24230void PaymentRequestSpec::NotifyOnSpecUpdated() {
231 for (auto& observer : observers_)
232 observer.OnSpecUpdated();
mathpf1a7a3752017-03-15 11:23:37233}
234
mathpc0d616a2017-03-15 14:09:33235CurrencyFormatter* PaymentRequestSpec::GetOrCreateCurrencyFormatter(
236 const std::string& currency_code,
237 const std::string& currency_system,
238 const std::string& locale_name) {
Anthony Vallee-Dubois080d5b72017-05-11 22:34:04239 // Create a currency formatter for |currency_code|, or if already created
240 // return the cached version.
241 std::pair<std::map<std::string, CurrencyFormatter>::iterator, bool>
242 emplace_result = currency_formatters_.emplace(
243 std::piecewise_construct, std::forward_as_tuple(currency_code),
244 std::forward_as_tuple(currency_code, currency_system, locale_name));
245
246 return &(emplace_result.first->second);
mathpc0d616a2017-03-15 14:09:33247}
248
mathpf1a7a3752017-03-15 11:23:37249} // namespace payments