blob: 9ea28a891e564eff5c2fcc82fd7f0e9f186bb51d [file] [log] [blame]
mathpf709499d2017-01-09 20:48:361// 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/payment_request.h"
6
tmartino68c0a272017-01-19 17:44:087#include "base/memory/ptr_util.h"
mathpf709499d2017-01-09 20:48:368#include "components/payments/payment_details_validation.h"
mathpf709499d2017-01-09 20:48:369#include "components/payments/payment_request_web_contents_manager.h"
10#include "content/public/browser/browser_thread.h"
11#include "content/public/browser/web_contents.h"
12
mathpc2d07f962017-02-17 18:33:5113using payments::mojom::BasicCardNetwork;
14
mathpf709499d2017-01-09 20:48:3615namespace payments {
16
mathpc2d07f962017-02-17 18:33:5117namespace {
18
19// Identifier for the basic card payment method in the PaymentMethodData.
20const char* const kBasicCardMethodName = "basic-card";
21
22} // namespace
23
mathpf709499d2017-01-09 20:48:3624PaymentRequest::PaymentRequest(
25 content::WebContents* web_contents,
26 std::unique_ptr<PaymentRequestDelegate> delegate,
27 PaymentRequestWebContentsManager* manager,
28 mojo::InterfaceRequest<payments::mojom::PaymentRequest> request)
29 : web_contents_(web_contents),
30 delegate_(std::move(delegate)),
31 manager_(manager),
tmartino36405622017-01-26 16:23:0332 binding_(this, std::move(request)),
33 selected_shipping_profile_(nullptr),
34 selected_contact_profile_(nullptr) {
mathpf4bc50e2017-01-24 05:17:5035 // OnConnectionTerminated will be called when the Mojo pipe is closed. This
36 // will happen as a result of many renderer-side events (both successful and
37 // erroneous in nature).
38 // TODO(crbug.com/683636): Investigate using
39 // set_connection_error_with_reason_handler with Binding::CloseWithReason.
40 binding_.set_connection_error_handler(base::Bind(
41 &PaymentRequest::OnConnectionTerminated, base::Unretained(this)));
tmartino36405622017-01-26 16:23:0342
mathpf709499d2017-01-09 20:48:3643}
44
45PaymentRequest::~PaymentRequest() {}
46
47void PaymentRequest::Init(
48 payments::mojom::PaymentRequestClientPtr client,
mathpc2d07f962017-02-17 18:33:5149 std::vector<payments::mojom::PaymentMethodDataPtr> method_data,
mathpf709499d2017-01-09 20:48:3650 payments::mojom::PaymentDetailsPtr details,
51 payments::mojom::PaymentOptionsPtr options) {
52 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
53 std::string error;
54 if (!payments::validatePaymentDetails(details, &error)) {
55 LOG(ERROR) << error;
mathpf4bc50e2017-01-24 05:17:5056 OnConnectionTerminated();
mathpf709499d2017-01-09 20:48:3657 return;
58 }
59 client_ = std::move(client);
60 details_ = std::move(details);
mathpc2d07f962017-02-17 18:33:5161 PopulateValidatedMethodData(method_data);
tmartino36405622017-01-26 16:23:0362 PopulateProfileCache();
63 SetDefaultProfileSelections();
mathpf709499d2017-01-09 20:48:3664}
65
66void PaymentRequest::Show() {
tmartino8ce922852017-01-09 22:23:1067 if (!client_.is_bound() || !binding_.is_bound()) {
mathpf4bc50e2017-01-24 05:17:5068 LOG(ERROR) << "Attempted Show(), but binding(s) missing.";
69 OnConnectionTerminated();
tmartino8ce922852017-01-09 22:23:1070 return;
71 }
mathpf4bc50e2017-01-24 05:17:5072 delegate_->ShowDialog(this);
mathpf709499d2017-01-09 20:48:3673}
74
mathpf4bc50e2017-01-24 05:17:5075void PaymentRequest::Abort() {
76 // The API user has decided to abort. We return a successful abort message to
77 // the renderer, which closes the Mojo message pipe, which triggers
78 // PaymentRequest::OnConnectionTerminated, which destroys this object.
79 if (client_.is_bound())
80 client_->OnAbort(true /* aborted_successfully */);
81}
82
83void PaymentRequest::UserCancelled() {
84 // If |client_| is not bound, then the object is already being destroyed as
85 // a result of a renderer event.
86 if (!client_.is_bound())
87 return;
88
89 // This sends an error to the renderer, which informs the API user.
mathpf709499d2017-01-09 20:48:3690 client_->OnError(payments::mojom::PaymentErrorReason::USER_CANCEL);
mathpf4bc50e2017-01-24 05:17:5091
92 // We close all bindings and ask to be destroyed.
93 client_.reset();
94 binding_.Close();
95 manager_->DestroyRequest(this);
mathpf709499d2017-01-09 20:48:3696}
97
mathpf4bc50e2017-01-24 05:17:5098void PaymentRequest::OnConnectionTerminated() {
99 // We are here because of a browser-side error, or likely as a result of the
100 // connection_error_handler on |binding_|, which can mean that the renderer
101 // has decided to close the pipe for various reasons (see all uses of
102 // PaymentRequest::clearResolversAndCloseMojoConnection() in Blink). We close
103 // the binding and the dialog, and ask to be deleted.
104 client_.reset();
mathpf709499d2017-01-09 20:48:36105 binding_.Close();
mathpf4bc50e2017-01-24 05:17:50106 delegate_->CloseDialog();
mathpf709499d2017-01-09 20:48:36107 manager_->DestroyRequest(this);
108}
109
mathp6758be032017-01-13 04:49:50110CurrencyFormatter* PaymentRequest::GetOrCreateCurrencyFormatter(
111 const std::string& currency_code,
jinho.bang42764542017-01-24 14:42:56112 const std::string& currency_system,
mathp6758be032017-01-13 04:49:50113 const std::string& locale_name) {
114 if (!currency_formatter_) {
115 currency_formatter_.reset(
116 new CurrencyFormatter(currency_code, currency_system, locale_name));
117 }
mathp6758be032017-01-13 04:49:50118 return currency_formatter_.get();
119}
120
tmartino36405622017-01-26 16:23:03121const std::vector<autofill::AutofillProfile*>&
122 PaymentRequest::shipping_profiles() {
123 return shipping_profiles_;
124}
125
126const std::vector<autofill::AutofillProfile*>&
127 PaymentRequest::contact_profiles() {
128 return contact_profiles_;
tmartino68c0a272017-01-19 17:44:08129}
130
anthonyvd045303a2017-01-17 22:19:19131autofill::CreditCard* PaymentRequest::GetCurrentlySelectedCreditCard() {
132 // TODO(anthonyvd): Change this code to prioritize server cards and implement
133 // a way to modify this function's return value.
anthonyvd045303a2017-01-17 22:19:19134 const std::vector<autofill::CreditCard*> cards =
mathpd4cfd8f2017-02-09 21:16:53135 personal_data_manager()->GetCreditCardsToSuggest();
anthonyvd045303a2017-01-17 22:19:19136
137 auto first_complete_card = std::find_if(
138 cards.begin(),
139 cards.end(),
140 [] (autofill::CreditCard* card) {
141 return card->IsValid();
142 });
143
144 return first_complete_card == cards.end() ? nullptr : *first_complete_card;
145}
146
tmartino36405622017-01-26 16:23:03147void PaymentRequest::PopulateProfileCache() {
tmartino36405622017-01-26 16:23:03148 std::vector<autofill::AutofillProfile*> profiles =
mathpd4cfd8f2017-02-09 21:16:53149 personal_data_manager()->GetProfilesToSuggest();
tmartino36405622017-01-26 16:23:03150
151 // PaymentRequest may outlive the Profiles returned by the Data Manager.
152 // Thus, we store copies, and return a vector of pointers to these copies
153 // whenever Profiles are requested.
154 for (size_t i = 0; i < profiles.size(); i++) {
155 profile_cache_.push_back(
156 base::MakeUnique<autofill::AutofillProfile>(*profiles[i]));
157
158 // TODO(tmartino): Implement deduplication rules specific to shipping and
159 // contact profiles.
160 shipping_profiles_.push_back(profile_cache_[i].get());
161 contact_profiles_.push_back(profile_cache_[i].get());
162 }
163}
164
165void PaymentRequest::SetDefaultProfileSelections() {
166 if (!shipping_profiles().empty())
167 set_selected_shipping_profile(shipping_profiles()[0]);
168
169 if (!contact_profiles().empty())
170 set_selected_contact_profile(contact_profiles()[0]);
171}
172
mathpc2d07f962017-02-17 18:33:51173void PaymentRequest::PopulateValidatedMethodData(
174 const std::vector<payments::mojom::PaymentMethodDataPtr>& method_data) {
175 if (method_data.empty()) {
176 LOG(ERROR) << "Invalid payment methods or data";
177 OnConnectionTerminated();
178 return;
179 }
180
181 std::set<std::string> card_networks{"amex", "diners", "discover",
182 "jcb", "mastercard", "mir",
183 "unionpay", "visa"};
184 for (const payments::mojom::PaymentMethodDataPtr& method_data_entry :
185 method_data) {
186 std::vector<std::string> supported_methods =
187 method_data_entry->supported_methods;
188 if (supported_methods.empty()) {
189 LOG(ERROR) << "Invalid payment methods or data";
190 OnConnectionTerminated();
191 return;
192 }
193
194 for (const std::string& method : supported_methods) {
195 if (method.empty())
196 continue;
197
198 // If a card network is specified right in "supportedMethods", add it.
199 auto card_it = card_networks.find(method);
200 if (card_it != card_networks.end()) {
201 supported_card_networks_.push_back(method);
202 // |method| removed from |card_networks| so that it is not doubly added
203 // to |supported_card_networks_| if "basic-card" is specified with no
204 // supported networks.
205 card_networks.erase(card_it);
206 } else if (method == kBasicCardMethodName) {
207 // For the "basic-card" method, check "supportedNetworks".
208 if (method_data_entry->supported_networks.empty()) {
209 // Empty |supported_networks| means all networks are supported.
210 supported_card_networks_.insert(supported_card_networks_.end(),
211 card_networks.begin(),
212 card_networks.end());
213 // Clear the set so that no further networks are added to
214 // |supported_card_networks_|.
215 card_networks.clear();
216 } else {
217 // The merchant has specified a few basic card supported networks. Use
218 // the mapping to transform to known basic-card types.
219 std::unordered_map<BasicCardNetwork, std::string> networks = {
220 {BasicCardNetwork::AMEX, "amex"},
221 {BasicCardNetwork::DINERS, "diners"},
222 {BasicCardNetwork::DISCOVER, "discover"},
223 {BasicCardNetwork::JCB, "jcb"},
224 {BasicCardNetwork::MASTERCARD, "mastercard"},
225 {BasicCardNetwork::MIR, "mir"},
226 {BasicCardNetwork::UNIONPAY, "unionpay"},
227 {BasicCardNetwork::VISA, "visa"}};
228 for (const BasicCardNetwork& supported_network :
229 method_data_entry->supported_networks) {
230 // Make sure that the network was not already added to
231 // |supported_card_networks_|.
232 auto card_it = card_networks.find(networks[supported_network]);
233 if (card_it != card_networks.end()) {
234 supported_card_networks_.push_back(networks[supported_network]);
235 card_networks.erase(card_it);
236 }
237 }
238 }
239 }
240 }
241 }
242}
243
mathpf709499d2017-01-09 20:48:36244} // namespace payments