mathp | f1a7a375 | 2017-03-15 11:23:37 | [diff] [blame] | 1 | // 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" |
mathp | eb8892ff | 2017-05-04 18:42:55 | [diff] [blame] | 10 | #include "base/strings/utf_string_conversions.h" |
mathp | b65623a | 2017-04-06 02:01:54 | [diff] [blame] | 11 | #include "components/payments/core/payment_method_data.h" |
| 12 | #include "components/payments/core/payment_request_data_util.h" |
mathp | eb8892ff | 2017-05-04 18:42:55 | [diff] [blame] | 13 | #include "components/strings/grit/components_strings.h" |
| 14 | #include "ui/base/l10n/l10n_util.h" |
mathp | f1a7a375 | 2017-03-15 11:23:37 | [diff] [blame] | 15 | |
| 16 | namespace payments { |
| 17 | |
mathp | b65623a | 2017-04-06 02:01:54 | [diff] [blame] | 18 | namespace { |
| 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. |
| 22 | std::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 | |
mathp | 600bab5 | 2017-03-26 03:47:59 | [diff] [blame] | 47 | const char kBasicCardMethodName[] = "basic-card"; |
mathp | f1a7a375 | 2017-03-15 11:23:37 | [diff] [blame] | 48 | |
| 49 | PaymentRequestSpec::PaymentRequestSpec( |
| 50 | mojom::PaymentOptionsPtr options, |
| 51 | mojom::PaymentDetailsPtr details, |
| 52 | std::vector<mojom::PaymentMethodDataPtr> method_data, |
mathp | c0d616a | 2017-03-15 14:09:33 | [diff] [blame] | 53 | Observer* observer, |
| 54 | const std::string& app_locale) |
| 55 | : options_(std::move(options)), |
| 56 | details_(std::move(details)), |
mathp | 151bd31e | 2017-04-03 21:07:24 | [diff] [blame] | 57 | app_locale_(app_locale), |
Anthony Vallee-Dubois | db030dd | 2017-05-19 18:04:51 | [diff] [blame^] | 58 | selected_shipping_option_(nullptr) { |
mathp | f1a7a375 | 2017-03-15 11:23:37 | [diff] [blame] | 59 | if (observer) |
| 60 | AddObserver(observer); |
mathp | b77b873 | 2017-05-11 15:26:42 | [diff] [blame] | 61 | UpdateSelectedShippingOption(/*after_update=*/false); |
mathp | f1a7a375 | 2017-03-15 11:23:37 | [diff] [blame] | 62 | PopulateValidatedMethodData(method_data); |
| 63 | } |
| 64 | PaymentRequestSpec::~PaymentRequestSpec() {} |
| 65 | |
mathp | 151bd31e | 2017-04-03 21:07:24 | [diff] [blame] | 66 | void PaymentRequestSpec::UpdateWith(mojom::PaymentDetailsPtr details) { |
| 67 | details_ = std::move(details); |
| 68 | // We reparse the |details_| and update the observers. |
mathp | b77b873 | 2017-05-11 15:26:42 | [diff] [blame] | 69 | UpdateSelectedShippingOption(/*after_update=*/true); |
mathp | 151bd31e | 2017-04-03 21:07:24 | [diff] [blame] | 70 | NotifyOnSpecUpdated(); |
Anthony Vallee-Dubois | db030dd | 2017-05-19 18:04:51 | [diff] [blame^] | 71 | current_update_reason_ = UpdateReason::NONE; |
mathp | 151bd31e | 2017-04-03 21:07:24 | [diff] [blame] | 72 | } |
| 73 | |
mathp | f1a7a375 | 2017-03-15 11:23:37 | [diff] [blame] | 74 | void PaymentRequestSpec::AddObserver(Observer* observer) { |
| 75 | CHECK(observer); |
| 76 | observers_.AddObserver(observer); |
| 77 | } |
| 78 | |
| 79 | void PaymentRequestSpec::RemoveObserver(Observer* observer) { |
| 80 | observers_.RemoveObserver(observer); |
| 81 | } |
| 82 | |
tmartino | 5f0912b8 | 2017-03-30 03:20:52 | [diff] [blame] | 83 | bool PaymentRequestSpec::request_shipping() const { |
| 84 | return options_->request_shipping; |
| 85 | } |
| 86 | bool PaymentRequestSpec::request_payer_name() const { |
| 87 | return options_->request_payer_name; |
| 88 | } |
| 89 | bool PaymentRequestSpec::request_payer_phone() const { |
| 90 | return options_->request_payer_phone; |
| 91 | } |
| 92 | bool PaymentRequestSpec::request_payer_email() const { |
| 93 | return options_->request_payer_email; |
| 94 | } |
| 95 | |
| 96 | PaymentShippingType 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 | |
mathp | 600bab5 | 2017-03-26 03:47:59 | [diff] [blame] | 112 | bool PaymentRequestSpec::IsMethodSupportedThroughBasicCard( |
| 113 | const std::string& method_name) { |
| 114 | return basic_card_specified_networks_.count(method_name) > 0; |
| 115 | } |
| 116 | |
mathp | c0d616a | 2017-03-15 14:09:33 | [diff] [blame] | 117 | base::string16 PaymentRequestSpec::GetFormattedCurrencyAmount( |
Anthony Vallee-Dubois | 080d5b7 | 2017-05-11 22:34:04 | [diff] [blame] | 118 | const mojom::PaymentCurrencyAmountPtr& currency_amount) { |
mathp | c0d616a | 2017-03-15 14:09:33 | [diff] [blame] | 119 | CurrencyFormatter* formatter = GetOrCreateCurrencyFormatter( |
Anthony Vallee-Dubois | 080d5b7 | 2017-05-11 22:34:04 | [diff] [blame] | 120 | currency_amount->currency, currency_amount->currency_system, app_locale_); |
| 121 | return formatter->Format(currency_amount->value); |
mathp | c0d616a | 2017-03-15 14:09:33 | [diff] [blame] | 122 | } |
| 123 | |
Anthony Vallee-Dubois | 080d5b7 | 2017-05-11 22:34:04 | [diff] [blame] | 124 | std::string PaymentRequestSpec::GetFormattedCurrencyCode( |
| 125 | const mojom::PaymentCurrencyAmountPtr& currency_amount) { |
mathp | c0d616a | 2017-03-15 14:09:33 | [diff] [blame] | 126 | CurrencyFormatter* formatter = GetOrCreateCurrencyFormatter( |
Anthony Vallee-Dubois | 080d5b7 | 2017-05-11 22:34:04 | [diff] [blame] | 127 | currency_amount->currency, currency_amount->currency_system, app_locale_); |
mathp | c0d616a | 2017-03-15 14:09:33 | [diff] [blame] | 128 | |
| 129 | return formatter->formatted_currency_code(); |
| 130 | } |
| 131 | |
anthonyvd | 2f30baa1 | 2017-04-13 22:30:50 | [diff] [blame] | 132 | void PaymentRequestSpec::StartWaitingForUpdateWith( |
| 133 | PaymentRequestSpec::UpdateReason reason) { |
Anthony Vallee-Dubois | db030dd | 2017-05-19 18:04:51 | [diff] [blame^] | 134 | current_update_reason_ = reason; |
anthonyvd | 2f30baa1 | 2017-04-13 22:30:50 | [diff] [blame] | 135 | for (auto& observer : observers_) { |
| 136 | observer.OnStartUpdating(reason); |
| 137 | } |
| 138 | } |
| 139 | |
Anthony Vallee-Dubois | 080d5b7 | 2017-05-11 22:34:04 | [diff] [blame] | 140 | bool 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 | |
mathp | f1a7a375 | 2017-03-15 11:23:37 | [diff] [blame] | 149 | void PaymentRequestSpec::PopulateValidatedMethodData( |
mathp | b65623a | 2017-04-06 02:01:54 | [diff] [blame] | 150 | const std::vector<mojom::PaymentMethodDataPtr>& method_data_mojom) { |
mathp | b65623a | 2017-04-06 02:01:54 | [diff] [blame] | 151 | 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) { |
rouslan | 69099768 | 2017-05-09 18:07:39 | [diff] [blame] | 155 | for (const std::string& method : method_data_entry->supported_methods) { |
| 156 | stringified_method_data_[method].insert( |
| 157 | method_data_entry->stringified_data); |
| 158 | } |
| 159 | |
mathp | b65623a | 2017-04-06 02:01:54 | [diff] [blame] | 160 | 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)); |
mathp | f1a7a375 | 2017-03-15 11:23:37 | [diff] [blame] | 167 | } |
mathp | b65623a | 2017-04-06 02:01:54 | [diff] [blame] | 168 | method_data.supported_networks = std::move(supported_networks); |
mathp | f1a7a375 | 2017-03-15 11:23:37 | [diff] [blame] | 169 | |
mathp | b65623a | 2017-04-06 02:01:54 | [diff] [blame] | 170 | // TODO(crbug.com/708603): Add browser-side support for |
| 171 | // |method_data.supported_types|. |
| 172 | method_data_vector.push_back(std::move(method_data)); |
mathp | f1a7a375 | 2017-03-15 11:23:37 | [diff] [blame] | 173 | } |
mathp | 363735b | 2017-03-16 18:08:05 | [diff] [blame] | 174 | |
rouslan | 6e3cf7c6 | 2017-04-17 21:23:28 | [diff] [blame] | 175 | data_util::ParseBasicCardSupportedNetworks(method_data_vector, |
| 176 | &supported_card_networks_, |
| 177 | &basic_card_specified_networks_); |
mathp | 363735b | 2017-03-16 18:08:05 | [diff] [blame] | 178 | supported_card_networks_set_.insert(supported_card_networks_.begin(), |
| 179 | supported_card_networks_.end()); |
mathp | f1a7a375 | 2017-03-15 11:23:37 | [diff] [blame] | 180 | } |
| 181 | |
mathp | b77b873 | 2017-05-11 15:26:42 | [diff] [blame] | 182 | void PaymentRequestSpec::UpdateSelectedShippingOption(bool after_update) { |
mathp | 151bd31e | 2017-04-03 21:07:24 | [diff] [blame] | 183 | if (!request_shipping()) |
| 184 | return; |
| 185 | |
mathp | b77b873 | 2017-05-11 15:26:42 | [diff] [blame] | 186 | selected_shipping_option_ = nullptr; |
mathp | eb8892ff | 2017-05-04 18:42:55 | [diff] [blame] | 187 | selected_shipping_option_error_.clear(); |
mathp | b77b873 | 2017-05-11 15:26:42 | [diff] [blame] | 188 | if (details().shipping_options.empty()) { |
| 189 | // No options are provided by the merchant. |
| 190 | if (after_update) { |
Mathieu Perreault | 2c1f319 | 2017-05-18 14:45:28 | [diff] [blame] | 191 | // This is after an update, which means that the selected address is not |
mathp | b77b873 | 2017-05-11 15:26:42 | [diff] [blame] | 192 | // 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 Perreault | 2c1f319 | 2017-05-18 14:45:28 | [diff] [blame] | 197 | // 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 | } |
mathp | b77b873 | 2017-05-11 15:26:42 | [diff] [blame] | 212 | } |
| 213 | } |
| 214 | return; |
| 215 | } |
| 216 | |
mathp | 151bd31e | 2017-04-03 21:07:24 | [diff] [blame] | 217 | // As per the spec, the selected shipping option should initially be the last |
mathp | b77b873 | 2017-05-11 15:26:42 | [diff] [blame] | 218 | // 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. |
mathp | 151bd31e | 2017-04-03 21:07:24 | [diff] [blame] | 220 | 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 | |
mathp | 151bd31e | 2017-04-03 21:07:24 | [diff] [blame] | 230 | void PaymentRequestSpec::NotifyOnSpecUpdated() { |
| 231 | for (auto& observer : observers_) |
| 232 | observer.OnSpecUpdated(); |
mathp | f1a7a375 | 2017-03-15 11:23:37 | [diff] [blame] | 233 | } |
| 234 | |
mathp | c0d616a | 2017-03-15 14:09:33 | [diff] [blame] | 235 | CurrencyFormatter* PaymentRequestSpec::GetOrCreateCurrencyFormatter( |
| 236 | const std::string& currency_code, |
| 237 | const std::string& currency_system, |
| 238 | const std::string& locale_name) { |
Anthony Vallee-Dubois | 080d5b7 | 2017-05-11 22:34:04 | [diff] [blame] | 239 | // 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); |
mathp | c0d616a | 2017-03-15 14:09:33 | [diff] [blame] | 247 | } |
| 248 | |
mathp | f1a7a375 | 2017-03-15 11:23:37 | [diff] [blame] | 249 | } // namespace payments |