blob: 998704810c15a58ec6a19cd2d8f5cbff1a036d17 [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_state.h"
6
mad45271932017-04-13 16:07:387#include <algorithm>
anthonyvd0116ce332017-03-21 21:29:018#include <set>
mad45271932017-04-13 16:07:389#include <utility>
anthonyvd0116ce332017-03-21 21:29:0110
Sebastien Marchand53801a32019-01-25 16:26:1111#include "base/bind.h"
gogerald8189d522017-09-15 17:52:1812#include "base/feature_list.h"
Sahel Sharify6efdfb32019-07-02 16:12:1613#include "base/metrics/histogram_functions.h"
sebsgad86bd002017-03-29 16:39:1214#include "base/strings/utf_string_conversions.h"
mathpf1a7a3752017-03-15 11:23:3715#include "components/autofill/core/browser/autofill_data_util.h"
Dominic Battreaed20f9f2019-05-10 19:09:5216#include "components/autofill/core/browser/data_model/autofill_profile.h"
17#include "components/autofill/core/browser/data_model/credit_card.h"
Dominic Battredd73d262019-05-15 20:10:3818#include "components/autofill/core/browser/geo/autofill_country.h"
mathpc0d616a2017-03-15 14:09:3319#include "components/autofill/core/browser/personal_data_manager.h"
Sahel Sharify6efdfb32019-07-02 16:12:1620#include "components/autofill/core/browser/validation.h"
Rouslan Solomakhin4eea9bc22017-10-10 15:18:5121#include "components/payments/content/content_payment_request_delegate.h"
Rouslan Solomakhin4eea9bc22017-10-10 15:18:5122#include "components/payments/content/payment_manifest_web_data_service.h"
sebsgad86bd002017-03-29 16:39:1223#include "components/payments/content/payment_response_helper.h"
gogerald8189d522017-09-15 17:52:1824#include "components/payments/content/service_worker_payment_instrument.h"
Sahel Sharify13331e82019-07-12 01:00:3025#include "components/payments/core/autofill_card_validation.h"
mathpf1a7a3752017-03-15 11:23:3726#include "components/payments/core/autofill_payment_instrument.h"
Rouslan Solomakhin1dca2a922019-09-06 22:25:0727#include "components/payments/core/error_strings.h"
Mathieu Perreault157f3992018-06-29 18:48:0628#include "components/payments/core/features.h"
sebsg695799a2017-04-11 16:29:0629#include "components/payments/core/payment_instrument.h"
tmartino01c3eb82017-04-29 15:18:3930#include "components/payments/core/payment_request_data_util.h"
Danyao Wang761739b2019-06-27 23:59:3231#include "components/payments/core/payments_experimental_features.h"
gogerald8189d522017-09-15 17:52:1832#include "content/public/common/content_features.h"
mathpf1a7a3752017-03-15 11:23:3733
34namespace payments {
Rouslan Solomakhin1dca2a922019-09-06 22:25:0735namespace {
36
37// Checks whether any of the |instruments| return true in
38// IsValidForCanMakePayment().
39bool GetHasEnrolledInstrument(
40 const std::vector<std::unique_ptr<PaymentInstrument>>& instruments) {
41 return std::any_of(instruments.begin(), instruments.end(),
42 [](const auto& instrument) {
43 return instrument->IsValidForCanMakePayment();
44 });
45}
46
47// Invokes the |callback| with |status|.
48void CallStatusCallback(PaymentRequestState::StatusCallback callback,
49 bool status) {
50 std::move(callback).Run(status);
51}
52
53// Posts the |callback| to be invoked with |status| asynchronously.
54void PostStatusCallback(PaymentRequestState::StatusCallback callback,
55 bool status) {
56 base::ThreadTaskRunnerHandle::Get()->PostTask(
57 FROM_HERE,
58 base::BindOnce(&CallStatusCallback, std::move(callback), status));
59}
60
61} // namespace
mathpf1a7a3752017-03-15 11:23:3762
mathpc0d616a2017-03-15 14:09:3363PaymentRequestState::PaymentRequestState(
Rouslan Solomakhindbf593d92017-11-21 19:20:5764 content::WebContents* web_contents,
gogerald7a0cc3e2017-09-19 03:35:4865 const GURL& top_level_origin,
66 const GURL& frame_origin,
mathpc0d616a2017-03-15 14:09:3367 PaymentRequestSpec* spec,
68 Delegate* delegate,
69 const std::string& app_locale,
anthonyvdd23ed702017-04-05 15:29:0070 autofill::PersonalDataManager* personal_data_manager,
Rouslan Solomakhin4eea9bc22017-10-10 15:18:5171 ContentPaymentRequestDelegate* payment_request_delegate,
Rouslan Solomakhin65552292019-08-29 17:28:2172 base::WeakPtr<ServiceWorkerPaymentInstrument::IdentityObserver>
73 sw_identity_observer,
sebsgc6719b32017-07-05 19:54:4774 JourneyLogger* journey_logger)
mathpf1a7a3752017-03-15 11:23:3775 : is_ready_to_pay_(false),
sebsg7e619132017-04-27 16:07:1076 is_waiting_for_merchant_validation_(false),
mathpc0d616a2017-03-15 14:09:3377 app_locale_(app_locale),
mathpf1a7a3752017-03-15 11:23:3778 spec_(spec),
79 delegate_(delegate),
mathpc0d616a2017-03-15 14:09:3380 personal_data_manager_(personal_data_manager),
sebsgc6719b32017-07-05 19:54:4781 journey_logger_(journey_logger),
Rouslan Solomakhind2cae95a2018-08-09 00:16:1082 are_requested_methods_supported_(
83 !spec_->supported_card_networks().empty()),
mathpf1a7a3752017-03-15 11:23:3784 selected_shipping_profile_(nullptr),
Mathieu Perreault04b4c662017-06-02 13:35:1385 selected_shipping_option_error_profile_(nullptr),
mathpf1a7a3752017-03-15 11:23:3786 selected_contact_profile_(nullptr),
Jinho Bangcac8d9a02018-08-23 19:47:2287 invalid_shipping_profile_(nullptr),
88 invalid_contact_profile_(nullptr),
anthonyvdd23ed702017-04-05 15:29:0089 selected_instrument_(nullptr),
gogeraldac15d2362017-11-15 01:04:1990 number_of_pending_sw_payment_instruments_(0),
tmartino01c3eb82017-04-29 15:18:3991 payment_request_delegate_(payment_request_delegate),
Rouslan Solomakhin1f95f092019-08-09 12:28:5192 sw_identity_observer_(sw_identity_observer),
Jeremy Roman5c341f6d2019-07-15 15:56:1093 profile_comparator_(app_locale, *spec) {
Rouslan Solomakhin1f95f092019-08-09 12:28:5194 DCHECK(sw_identity_observer_);
Mathieu Perreault157f3992018-06-29 18:48:0695 if (base::FeatureList::IsEnabled(::features::kServiceWorkerPaymentApps)) {
gogerald12a4e4ff2018-08-08 12:16:2596 DCHECK(web_contents);
Danyao Wang761739b2019-06-27 23:59:3297 bool may_crawl_for_installable_payment_apps =
98 PaymentsExperimentalFeatures::IsEnabled(
99 features::kAlwaysAllowJustInTimePaymentApp) ||
100 !spec_->supports_basic_card();
101
gogerald97e1b3312017-11-21 23:31:10102 ServiceWorkerPaymentAppFactory::GetInstance()->GetAllPaymentApps(
Rouslan Solomakhindbf593d92017-11-21 19:20:57103 web_contents,
Rouslan Solomakhin438d8c92017-10-26 21:33:18104 payment_request_delegate_->GetPaymentManifestWebDataService(),
Danyao Wang761739b2019-06-27 23:59:32105 spec_->method_data(), may_crawl_for_installable_payment_apps,
Rouslan Solomakhin438d8c92017-10-26 21:33:18106 base::BindOnce(&PaymentRequestState::GetAllPaymentAppsCallback,
gogerald3f1cabf2018-02-08 14:19:18107 weak_ptr_factory_.GetWeakPtr(), web_contents,
108 top_level_origin, frame_origin),
gogerald97e1b3312017-11-21 23:31:10109 base::BindOnce([]() {
110 /* Nothing needs to be done after writing cache. This callback is used
111 * only in tests. */
112 }));
gogerald8189d522017-09-15 17:52:18113 } else {
114 PopulateProfileCache();
115 SetDefaultProfileSelections();
Rouslan Solomakhin1dca2a922019-09-06 22:25:07116 get_all_instruments_finished_ = true;
117 has_enrolled_instrument_ = GetHasEnrolledInstrument(available_instruments_);
gogerald8189d522017-09-15 17:52:18118 }
sebsg7e619132017-04-27 16:07:10119 spec_->AddObserver(this);
mathpf1a7a3752017-03-15 11:23:37120}
Rouslan Solomakhin4eea9bc22017-10-10 15:18:51121
mathp151bd31e2017-04-03 21:07:24122PaymentRequestState::~PaymentRequestState() {}
mathpf1a7a3752017-03-15 11:23:37123
gogerald8189d522017-09-15 17:52:18124void PaymentRequestState::GetAllPaymentAppsCallback(
gogerald3f1cabf2018-02-08 14:19:18125 content::WebContents* web_contents,
gogerald7a0cc3e2017-09-19 03:35:48126 const GURL& top_level_origin,
127 const GURL& frame_origin,
gogerald84ae6262018-02-06 06:21:46128 content::PaymentAppProvider::PaymentApps apps,
Rouslan Solomakhind5dcc322019-07-11 21:47:20129 ServiceWorkerPaymentAppFactory::InstallablePaymentApps installable_apps,
130 const std::string& error_message) {
gogerald3f1cabf2018-02-08 14:19:18131 number_of_pending_sw_payment_instruments_ =
132 apps.size() + installable_apps.size();
Rouslan Solomakhind5dcc322019-07-11 21:47:20133 get_all_payment_apps_error_ = error_message;
gogeraldac15d2362017-11-15 01:04:19134 if (number_of_pending_sw_payment_instruments_ == 0U) {
135 FinishedGetAllSWPaymentInstruments();
136 return;
gogerald8189d522017-09-15 17:52:18137 }
138
gogeraldac15d2362017-11-15 01:04:19139 for (auto& app : apps) {
140 std::unique_ptr<ServiceWorkerPaymentInstrument> instrument =
141 std::make_unique<ServiceWorkerPaymentInstrument>(
gogerald3f1cabf2018-02-08 14:19:18142 web_contents->GetBrowserContext(), top_level_origin, frame_origin,
Rouslan Solomakhin1f95f092019-08-09 12:28:51143 spec_, std::move(app.second), payment_request_delegate_,
144 sw_identity_observer_);
gogerald3f1cabf2018-02-08 14:19:18145 instrument->ValidateCanMakePayment(
146 base::BindOnce(&PaymentRequestState::OnSWPaymentInstrumentValidated,
147 weak_ptr_factory_.GetWeakPtr()));
148 available_instruments_.push_back(std::move(instrument));
149 }
150
151 for (auto& installable_app : installable_apps) {
152 std::unique_ptr<ServiceWorkerPaymentInstrument> instrument =
153 std::make_unique<ServiceWorkerPaymentInstrument>(
154 web_contents, top_level_origin, frame_origin, spec_,
155 std::move(installable_app.second), installable_app.first.spec(),
Rouslan Solomakhin1f95f092019-08-09 12:28:51156 payment_request_delegate_, sw_identity_observer_);
gogeraldac15d2362017-11-15 01:04:19157 instrument->ValidateCanMakePayment(
158 base::BindOnce(&PaymentRequestState::OnSWPaymentInstrumentValidated,
159 weak_ptr_factory_.GetWeakPtr()));
160 available_instruments_.push_back(std::move(instrument));
161 }
162}
163
164void PaymentRequestState::OnSWPaymentInstrumentValidated(
165 ServiceWorkerPaymentInstrument* instrument,
166 bool result) {
Rouslan Solomakhin1dca2a922019-09-06 22:25:07167 has_non_autofill_instrument_ |= result;
168
gogeraldac15d2362017-11-15 01:04:19169 // Remove service worker payment instruments failed on validation.
170 if (!result) {
171 for (size_t i = 0; i < available_instruments_.size(); i++) {
172 if (available_instruments_[i].get() == instrument) {
173 available_instruments_.erase(available_instruments_.begin() + i);
174 break;
175 }
176 }
177 }
178
179 if (--number_of_pending_sw_payment_instruments_ > 0)
180 return;
181
182 FinishedGetAllSWPaymentInstruments();
183}
184
185void PaymentRequestState::FinishedGetAllSWPaymentInstruments() {
gogerald8189d522017-09-15 17:52:18186 PopulateProfileCache();
187 SetDefaultProfileSelections();
188
189 get_all_instruments_finished_ = true;
Rouslan Solomakhin1dca2a922019-09-06 22:25:07190 has_enrolled_instrument_ = GetHasEnrolledInstrument(available_instruments_);
Rouslan Solomakhind2cae95a2018-08-09 00:16:10191 are_requested_methods_supported_ |= !available_instruments_.empty();
gogerald8189d522017-09-15 17:52:18192 NotifyOnGetAllPaymentInstrumentsFinished();
Rouslan Solomakhin9788d4b2019-04-09 13:10:23193 NotifyInitialized();
gogerald8189d522017-09-15 17:52:18194
Danyao Wang4bc0606a2018-12-27 16:54:53195 // Fulfill the pending CanMakePayment call.
Rouslan Solomakhin1dca2a922019-09-06 22:25:07196 if (can_make_payment_callback_)
197 std::move(can_make_payment_callback_).Run(are_requested_methods_supported_);
Danyao Wang4bc0606a2018-12-27 16:54:53198
Danyao Wangce175bf2018-12-21 22:35:58199 // Fulfill the pending HasEnrolledInstrument call.
200 if (has_enrolled_instrument_callback_)
Rouslan Solomakhin1dca2a922019-09-06 22:25:07201 std::move(has_enrolled_instrument_callback_).Run(has_enrolled_instrument_);
gogerald0a7ee6c2017-11-13 18:23:19202
Danyao Wangce175bf2018-12-21 22:35:58203 // Fulfill the pending AreRequestedMethodsSupported call.
gogerald0a7ee6c2017-11-13 18:23:19204 if (are_requested_methods_supported_callback_)
205 CheckRequestedMethodsSupported(
206 std::move(are_requested_methods_supported_callback_));
gogerald8189d522017-09-15 17:52:18207}
208
sebsg695799a2017-04-11 16:29:06209void PaymentRequestState::OnPaymentResponseReady(
210 mojom::PaymentResponsePtr payment_response) {
211 delegate_->OnPaymentResponseAvailable(std::move(payment_response));
212}
213
Rouslan Solomakhin68429b72019-06-27 15:12:39214void PaymentRequestState::OnPaymentResponseError(
215 const std::string& error_message) {
216 delegate_->OnPaymentResponseError(error_message);
217}
218
sebsg7e619132017-04-27 16:07:10219void PaymentRequestState::OnSpecUpdated() {
Jinho Bangcac8d9a02018-08-23 19:47:22220 autofill::AutofillProfile* selected_shipping_profile =
221 selected_shipping_profile_;
222 autofill::AutofillProfile* selected_contact_profile =
223 selected_contact_profile_;
224
225 if (spec_->current_update_reason() ==
226 PaymentRequestSpec::UpdateReason::RETRY) {
227 if (spec_->has_shipping_address_error() && selected_shipping_profile) {
228 invalid_shipping_profile_ = selected_shipping_profile;
229 selected_shipping_profile_ = nullptr;
230 }
Jinho Bang092e7162018-09-06 23:41:19231
Jinho Bangcac8d9a02018-08-23 19:47:22232 if (spec_->has_payer_error() && selected_contact_profile) {
233 invalid_contact_profile_ = selected_contact_profile;
234 selected_contact_profile_ = nullptr;
235 }
236 }
237
Mathieu Perreault04b4c662017-06-02 13:35:13238 if (spec_->selected_shipping_option_error().empty()) {
239 selected_shipping_option_error_profile_ = nullptr;
240 } else {
Jinho Bangcac8d9a02018-08-23 19:47:22241 selected_shipping_option_error_profile_ = selected_shipping_profile;
Mathieu Perreault04b4c662017-06-02 13:35:13242 selected_shipping_profile_ = nullptr;
Jinho Bang092e7162018-09-06 23:41:19243 if (spec_->has_shipping_address_error() && selected_shipping_profile) {
244 invalid_shipping_profile_ = selected_shipping_profile;
245 }
Mathieu Perreault04b4c662017-06-02 13:35:13246 }
Jinho Bangcac8d9a02018-08-23 19:47:22247
sebsg7e619132017-04-27 16:07:10248 is_waiting_for_merchant_validation_ = false;
249 UpdateIsReadyToPayAndNotifyObservers();
250}
251
Danyao Wang03a4cbd2019-08-15 23:47:11252void PaymentRequestState::CanMakePayment(StatusCallback callback) {
Danyao Wang4bc0606a2018-12-27 16:54:53253 if (!get_all_instruments_finished_) {
254 DCHECK(!can_make_payment_callback_);
255 can_make_payment_callback_ = std::move(callback);
256 return;
257 }
258
Rouslan Solomakhin1dca2a922019-09-06 22:25:07259 PostStatusCallback(std::move(callback), are_requested_methods_supported_);
Danyao Wangce175bf2018-12-21 22:35:58260}
261
262void PaymentRequestState::HasEnrolledInstrument(StatusCallback callback) {
gogerald8189d522017-09-15 17:52:18263 if (!get_all_instruments_finished_) {
Danyao Wang4bc0606a2018-12-27 16:54:53264 DCHECK(!has_enrolled_instrument_callback_);
Danyao Wangce175bf2018-12-21 22:35:58265 has_enrolled_instrument_callback_ = std::move(callback);
gogerald8189d522017-09-15 17:52:18266 return;
267 }
268
Rouslan Solomakhin1dca2a922019-09-06 22:25:07269 PostStatusCallback(std::move(callback), has_enrolled_instrument_);
mathp1a5be4f2017-03-24 18:09:19270}
271
gogerald0a7ee6c2017-11-13 18:23:19272void PaymentRequestState::AreRequestedMethodsSupported(
Rouslan Solomakhind5dcc322019-07-11 21:47:20273 MethodsSupportedCallback callback) {
gogerald0a7ee6c2017-11-13 18:23:19274 if (!get_all_instruments_finished_) {
275 are_requested_methods_supported_callback_ = std::move(callback);
276 return;
277 }
278
279 base::ThreadTaskRunnerHandle::Get()->PostTask(
280 FROM_HERE,
281 base::BindOnce(&PaymentRequestState::CheckRequestedMethodsSupported,
282 weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
283}
284
285void PaymentRequestState::CheckRequestedMethodsSupported(
Rouslan Solomakhind5dcc322019-07-11 21:47:20286 MethodsSupportedCallback callback) {
gogerald0a7ee6c2017-11-13 18:23:19287 DCHECK(get_all_instruments_finished_);
288
Rouslan Solomakhin1dca2a922019-09-06 22:25:07289 // Don't modify the value of |are_requested_methods_supported_|, because it's
290 // used for canMakePayment().
291 bool supported = are_requested_methods_supported_;
292 if (supported && is_show_user_gesture_ &&
293 base::Contains(spec_->payment_method_identifiers_set(), "basic-card") &&
294 !has_non_autofill_instrument_ && !has_enrolled_instrument_ &&
295 PaymentsExperimentalFeatures::IsEnabled(
296 features::kStrictHasEnrolledAutofillInstrument)) {
297 supported = false;
298 get_all_payment_apps_error_ = errors::kStrictBasicCardShowReject;
299 }
300
301 std::move(callback).Run(supported, get_all_payment_apps_error_);
rouslan6e3cf7c62017-04-17 21:23:28302}
303
anthonyvd6a43b932017-05-11 18:39:27304std::string PaymentRequestState::GetAuthenticatedEmail() const {
305 return payment_request_delegate_->GetAuthenticatedEmail();
306}
307
mathpf1a7a3752017-03-15 11:23:37308void PaymentRequestState::AddObserver(Observer* observer) {
309 CHECK(observer);
310 observers_.AddObserver(observer);
311}
mathpf1a7a3752017-03-15 11:23:37312
313void PaymentRequestState::RemoveObserver(Observer* observer) {
314 observers_.RemoveObserver(observer);
315}
316
mathpf1a7a3752017-03-15 11:23:37317void PaymentRequestState::GeneratePaymentResponse() {
mathp363735b2017-03-16 18:08:05318 DCHECK(is_ready_to_pay());
sebsg695799a2017-04-11 16:29:06319
320 // Once the response is ready, will call back into OnPaymentResponseReady.
Rouslan Solomakhin4eea9bc22017-10-10 15:18:51321 response_helper_ = std::make_unique<PaymentResponseHelper>(
sebsg8a9c2342017-04-21 17:05:15322 app_locale_, spec_, selected_instrument_, payment_request_delegate_,
323 selected_shipping_profile_, selected_contact_profile_, this);
mathpf1a7a3752017-03-15 11:23:37324}
325
Rouslan Solomakhin761d65eb2019-04-29 20:08:01326void PaymentRequestState::OnPaymentAppWindowClosed() {
327 DCHECK(selected_instrument_);
328 response_helper_.reset();
329 selected_instrument_->OnPaymentAppWindowClosed();
330}
331
sebsg8a93b272017-05-11 19:30:22332void PaymentRequestState::RecordUseStats() {
Sahel Sharifyfef3d922019-09-11 01:41:22333 if (ShouldShowShippingSection()) {
sebsg8a93b272017-05-11 19:30:22334 DCHECK(selected_shipping_profile_);
335 personal_data_manager_->RecordUseOf(*selected_shipping_profile_);
336 }
337
Sahel Sharifyfef3d922019-09-11 01:41:22338 if (ShouldShowContactSection()) {
sebsg8a93b272017-05-11 19:30:22339 DCHECK(selected_contact_profile_);
340
341 // If the same address was used for both contact and shipping, the stats
342 // should only be updated once.
Sahel Sharifyfef3d922019-09-11 01:41:22343 if (!ShouldShowShippingSection() || (selected_shipping_profile_->guid() !=
344 selected_contact_profile_->guid())) {
sebsg8a93b272017-05-11 19:30:22345 personal_data_manager_->RecordUseOf(*selected_contact_profile_);
346 }
347 }
348
349 selected_instrument_->RecordUse();
350}
351
mathp24ce4cd2017-04-12 20:56:42352void PaymentRequestState::AddAutofillPaymentInstrument(
353 bool selected,
354 const autofill::CreditCard& card) {
355 std::string basic_card_network =
rouslan4e981bd32017-05-01 17:49:16356 autofill::data_util::GetPaymentRequestData(card.network())
357 .basic_card_issuer_network;
Rouslan Solomakhin25d708b2017-06-23 17:12:03358 if (!spec_->supported_card_networks_set().count(basic_card_network) ||
359 !spec_->supported_card_types_set().count(card.card_type())) {
mathp24ce4cd2017-04-12 20:56:42360 return;
Rouslan Solomakhin25d708b2017-06-23 17:12:03361 }
362
363 // The total number of card types: credit, debit, prepaid, unknown.
364 constexpr size_t kTotalNumberOfCardTypes = 4U;
365
366 // Whether the card type (credit, debit, prepaid) matches thetype that the
367 // merchant has requested exactly. This should be false for unknown card
368 // types, if the merchant cannot accept some card types.
369 bool matches_merchant_card_type_exactly =
370 card.card_type() != autofill::CreditCard::CARD_TYPE_UNKNOWN ||
371 spec_->supported_card_types_set().size() == kTotalNumberOfCardTypes;
mathp24ce4cd2017-04-12 20:56:42372
373 // AutofillPaymentInstrument makes a copy of |card| so it is effectively
374 // owned by this object.
Rouslan Solomakhin4eea9bc22017-10-10 15:18:51375 auto instrument = std::make_unique<AutofillPaymentInstrument>(
Rouslan Solomakhin25d708b2017-06-23 17:12:03376 basic_card_network, card, matches_merchant_card_type_exactly,
377 shipping_profiles_, app_locale_, payment_request_delegate_);
Rouslan Solomakhincb29c4f2019-08-16 22:49:39378 instrument->set_is_requested_autofill_data_available(
379 is_requested_autofill_data_available_);
mathp24ce4cd2017-04-12 20:56:42380 available_instruments_.push_back(std::move(instrument));
381
Sahel Sharifybc4173f2019-05-09 21:03:57382 if (selected) {
383 SetSelectedInstrument(available_instruments_.back().get(),
384 SectionSelectionStatus::kAddedSelected);
385 }
mathp24ce4cd2017-04-12 20:56:42386}
387
madf9904ea2017-04-25 18:39:12388void PaymentRequestState::AddAutofillShippingProfile(
389 bool selected,
390 const autofill::AutofillProfile& profile) {
391 profile_cache_.push_back(
Rouslan Solomakhin4eea9bc22017-10-10 15:18:51392 std::make_unique<autofill::AutofillProfile>(profile));
madf9904ea2017-04-25 18:39:12393 // TODO(tmartino): Implement deduplication rules specific to shipping
394 // profiles.
395 autofill::AutofillProfile* new_cached_profile = profile_cache_.back().get();
396 shipping_profiles_.push_back(new_cached_profile);
397
Sahel Sharifybc4173f2019-05-09 21:03:57398 if (selected) {
399 SetSelectedShippingProfile(new_cached_profile,
400 SectionSelectionStatus::kAddedSelected);
401 }
madf9904ea2017-04-25 18:39:12402}
403
Anthony Vallee-Duboisf1e88b42017-05-15 15:09:23404void PaymentRequestState::AddAutofillContactProfile(
405 bool selected,
406 const autofill::AutofillProfile& profile) {
407 profile_cache_.push_back(
Rouslan Solomakhin4eea9bc22017-10-10 15:18:51408 std::make_unique<autofill::AutofillProfile>(profile));
Anthony Vallee-Duboisf1e88b42017-05-15 15:09:23409 autofill::AutofillProfile* new_cached_profile = profile_cache_.back().get();
410 contact_profiles_.push_back(new_cached_profile);
411
Sahel Sharifybc4173f2019-05-09 21:03:57412 if (selected) {
413 SetSelectedContactProfile(new_cached_profile,
414 SectionSelectionStatus::kAddedSelected);
415 }
Anthony Vallee-Duboisf1e88b42017-05-15 15:09:23416}
417
anthonyvd0116ce332017-03-21 21:29:01418void PaymentRequestState::SetSelectedShippingOption(
mathp151bd31e2017-04-03 21:07:24419 const std::string& shipping_option_id) {
anthonyvd2f30baa12017-04-13 22:30:50420 spec_->StartWaitingForUpdateWith(
421 PaymentRequestSpec::UpdateReason::SHIPPING_OPTION);
mathp151bd31e2017-04-03 21:07:24422 // This will inform the merchant and will lead to them calling updateWith with
423 // new PaymentDetails.
424 delegate_->OnShippingOptionIdSelected(shipping_option_id);
anthonyvd0116ce332017-03-21 21:29:01425}
426
mathpf1a7a3752017-03-15 11:23:37427void PaymentRequestState::SetSelectedShippingProfile(
Sahel Sharifybc4173f2019-05-09 21:03:57428 autofill::AutofillProfile* profile,
429 SectionSelectionStatus selection_status) {
anthonyvd2f30baa12017-04-13 22:30:50430 spec_->StartWaitingForUpdateWith(
431 PaymentRequestSpec::UpdateReason::SHIPPING_ADDRESS);
mathpf1a7a3752017-03-15 11:23:37432 selected_shipping_profile_ = profile;
sebsg7e619132017-04-27 16:07:10433
Jinho Bangcac8d9a02018-08-23 19:47:22434 // Changing the shipping address clears shipping address validation errors
435 // from retry().
436 invalid_shipping_profile_ = nullptr;
437
sebsg7e619132017-04-27 16:07:10438 // The user should not be able to click on pay until the callback from the
439 // merchant.
440 is_waiting_for_merchant_validation_ = true;
sebsg7e619132017-04-27 16:07:10441
442 // Start the normalization of the shipping address.
Mathieu Perreaultc94700f112017-10-23 20:28:39443 payment_request_delegate_->GetAddressNormalizer()->NormalizeAddressAsync(
Mathieu Perreault9b40d5102017-11-21 20:51:29444 *selected_shipping_profile_, /*timeout_seconds=*/2,
Mathieu Perreault17c1ae92017-10-20 17:16:00445 base::BindOnce(&PaymentRequestState::OnAddressNormalized,
446 weak_ptr_factory_.GetWeakPtr()));
Sahel Sharifybc4173f2019-05-09 21:03:57447 IncrementSelectionStatus(JourneyLogger::Section::SECTION_SHIPPING_ADDRESS,
448 selection_status);
mathpf1a7a3752017-03-15 11:23:37449}
450
451void PaymentRequestState::SetSelectedContactProfile(
Sahel Sharifybc4173f2019-05-09 21:03:57452 autofill::AutofillProfile* profile,
453 SectionSelectionStatus selection_status) {
mathpf1a7a3752017-03-15 11:23:37454 selected_contact_profile_ = profile;
Jinho Bangcac8d9a02018-08-23 19:47:22455
456 // Changing the contact information clears contact information validation
457 // errors from retry().
458 invalid_contact_profile_ = nullptr;
459
mathpf1a7a3752017-03-15 11:23:37460 UpdateIsReadyToPayAndNotifyObservers();
Jinho Bangbb178152018-09-13 09:44:43461
462 if (IsPaymentAppInvoked()) {
Jinho Bang21d6be92018-12-18 15:30:31463 delegate_->OnPayerInfoSelected(
464 response_helper_->GeneratePayerDetail(profile));
Jinho Bangbb178152018-09-13 09:44:43465 }
Sahel Sharifybc4173f2019-05-09 21:03:57466 IncrementSelectionStatus(JourneyLogger::Section::SECTION_CONTACT_INFO,
467 selection_status);
mathpf1a7a3752017-03-15 11:23:37468}
469
Sahel Sharifybc4173f2019-05-09 21:03:57470void PaymentRequestState::SetSelectedInstrument(
471 PaymentInstrument* instrument,
472 SectionSelectionStatus selection_status) {
mathp363735b2017-03-16 18:08:05473 selected_instrument_ = instrument;
mathpf1a7a3752017-03-15 11:23:37474 UpdateIsReadyToPayAndNotifyObservers();
Sahel Sharifybc4173f2019-05-09 21:03:57475 IncrementSelectionStatus(JourneyLogger::Section::SECTION_PAYMENT_METHOD,
476 selection_status);
477}
478
479void PaymentRequestState::IncrementSelectionStatus(
480 JourneyLogger::Section section,
481 SectionSelectionStatus selection_status) {
482 switch (selection_status) {
483 case SectionSelectionStatus::kSelected:
484 journey_logger_->IncrementSelectionChanges(section);
485 break;
486 case SectionSelectionStatus::kEditedSelected:
487 journey_logger_->IncrementSelectionEdits(section);
488 break;
489 case SectionSelectionStatus::kAddedSelected:
490 journey_logger_->IncrementSelectionAdds(section);
491 break;
492 default:
493 NOTREACHED();
494 }
mathpf1a7a3752017-03-15 11:23:37495}
496
mathpc0d616a2017-03-15 14:09:33497const std::string& PaymentRequestState::GetApplicationLocale() {
498 return app_locale_;
499}
500
501autofill::PersonalDataManager* PaymentRequestState::GetPersonalDataManager() {
502 return personal_data_manager_;
503}
504
mad763ed2b2017-04-24 20:28:47505autofill::RegionDataLoader* PaymentRequestState::GetRegionDataLoader() {
506 return payment_request_delegate_->GetRegionDataLoader();
mad45271932017-04-13 16:07:38507}
508
Anthony Vallee-Dubois6813c1442017-05-17 19:32:56509bool PaymentRequestState::IsPaymentAppInvoked() const {
510 return !!response_helper_;
511}
512
Mathieu Perreaulteea046d12017-09-28 15:51:21513autofill::AddressNormalizer* PaymentRequestState::GetAddressNormalizer() {
Anthony Vallee-Dubois71bf349462017-07-20 23:56:45514 return payment_request_delegate_->GetAddressNormalizer();
515}
516
Rouslan Solomakhin48fd6e872019-02-22 17:23:10517bool PaymentRequestState::IsInitialized() const {
518 return get_all_instruments_finished_;
519}
520
Rouslan Solomakhin9788d4b2019-04-09 13:10:23521void PaymentRequestState::SelectDefaultShippingAddressAndNotifyObservers() {
522 // Only pre-select an address if the merchant provided at least one selected
523 // shipping option, and the top profile is complete. Assumes that profiles
524 // have already been sorted for completeness and frecency.
525 if (!shipping_profiles().empty() && spec_->selected_shipping_option() &&
526 profile_comparator()->IsShippingComplete(shipping_profiles_[0])) {
527 selected_shipping_profile_ = shipping_profiles()[0];
528 }
Sahel Sharify6efdfb32019-07-02 16:12:16529 // Record the missing required fields (if any) of the most complete shipping
530 // profile.
531 profile_comparator()->RecordMissingFieldsOfShippingProfile(
532 shipping_profiles().empty() ? nullptr : shipping_profiles()[0]);
Rouslan Solomakhin9788d4b2019-04-09 13:10:23533 UpdateIsReadyToPayAndNotifyObservers();
534}
535
Sahel Sharifyfef3d922019-09-11 01:41:22536bool PaymentRequestState::ShouldShowShippingSection() const {
537 if (!spec_->request_shipping())
538 return false;
539
540 return selected_instrument_ ? !selected_instrument_->HandlesShippingAddress()
541 : true;
542}
543
544bool PaymentRequestState::ShouldShowContactSection() const {
545 if (spec_->request_payer_name() &&
546 (!selected_instrument_ || !selected_instrument_->HandlesPayerName())) {
547 return true;
548 }
549 if (spec_->request_payer_email() &&
550 (!selected_instrument_ || !selected_instrument_->HandlesPayerEmail())) {
551 return true;
552 }
553 if (spec_->request_payer_phone() &&
554 (!selected_instrument_ || !selected_instrument_->HandlesPayerPhone())) {
555 return true;
556 }
557
558 return false;
559}
560
Rouslan Solomakhin65552292019-08-29 17:28:21561base::WeakPtr<PaymentRequestState> PaymentRequestState::AsWeakPtr() {
562 return weak_ptr_factory_.GetWeakPtr();
563}
564
mathpf1a7a3752017-03-15 11:23:37565void PaymentRequestState::PopulateProfileCache() {
mathpf1a7a3752017-03-15 11:23:37566 std::vector<autofill::AutofillProfile*> profiles =
mathpc0d616a2017-03-15 14:09:33567 personal_data_manager_->GetProfilesToSuggest();
mathpf1a7a3752017-03-15 11:23:37568
tmartinocd131b32017-05-24 19:40:59569 std::vector<autofill::AutofillProfile*> raw_profiles_for_filtering;
570 raw_profiles_for_filtering.reserve(profiles.size());
571
mathpf1a7a3752017-03-15 11:23:37572 // PaymentRequest may outlive the Profiles returned by the Data Manager.
573 // Thus, we store copies, and return a vector of pointers to these copies
mathpf14c1e32017-05-12 16:37:30574 // whenever Profiles are requested.
mathpf1a7a3752017-03-15 11:23:37575 for (size_t i = 0; i < profiles.size(); i++) {
576 profile_cache_.push_back(
Rouslan Solomakhin4eea9bc22017-10-10 15:18:51577 std::make_unique<autofill::AutofillProfile>(*profiles[i]));
tmartinocd131b32017-05-24 19:40:59578 raw_profiles_for_filtering.push_back(profile_cache_.back().get());
mathpf1a7a3752017-03-15 11:23:37579 }
580
tmartino01c3eb82017-04-29 15:18:39581 contact_profiles_ = profile_comparator()->FilterProfilesForContact(
582 raw_profiles_for_filtering);
tmartinocd131b32017-05-24 19:40:59583 shipping_profiles_ = profile_comparator()->FilterProfilesForShipping(
584 raw_profiles_for_filtering);
tmartinoa6eb22f2017-04-06 20:16:24585
sebsgc6719b32017-07-05 19:54:47586 // Set the number of suggestions shown for the sections requested by the
587 // merchant.
Sahel Sharifyfef3d922019-09-11 01:41:22588 if (ShouldShowContactSection()) {
sebsgce700484d2017-07-19 23:25:38589 bool has_complete_contact =
590 contact_profiles_.empty()
591 ? false
592 : profile_comparator()->IsContactInfoComplete(contact_profiles_[0]);
Rouslan Solomakhincb29c4f2019-08-16 22:49:39593 is_requested_autofill_data_available_ &= has_complete_contact;
sebsgc6719b32017-07-05 19:54:47594 journey_logger_->SetNumberOfSuggestionsShown(
sebsgce700484d2017-07-19 23:25:38595 JourneyLogger::Section::SECTION_CONTACT_INFO, contact_profiles_.size(),
596 has_complete_contact);
sebsgc6719b32017-07-05 19:54:47597 }
Sahel Sharifyfef3d922019-09-11 01:41:22598 if (ShouldShowShippingSection()) {
sebsgce700484d2017-07-19 23:25:38599 bool has_complete_shipping =
600 shipping_profiles_.empty()
601 ? false
602 : profile_comparator()->IsShippingComplete(shipping_profiles_[0]);
Rouslan Solomakhincb29c4f2019-08-16 22:49:39603 is_requested_autofill_data_available_ &= has_complete_shipping;
sebsgc6719b32017-07-05 19:54:47604 journey_logger_->SetNumberOfSuggestionsShown(
605 JourneyLogger::Section::SECTION_SHIPPING_ADDRESS,
sebsgce700484d2017-07-19 23:25:38606 shipping_profiles_.size(), has_complete_shipping);
sebsgc6719b32017-07-05 19:54:47607 }
608
mathpf14c1e32017-05-12 16:37:30609 // Create the list of available instruments. A copy of each card will be made
610 // by their respective AutofillPaymentInstrument.
mathpf1a7a3752017-03-15 11:23:37611 const std::vector<autofill::CreditCard*>& cards =
Amirhossein Simjourd3b7ba4a2018-05-07 15:27:21612 personal_data_manager_->GetCreditCardsToSuggest(
Mathieu Perreault157f3992018-06-29 18:48:06613 /*include_server_cards=*/base::FeatureList::IsEnabled(
614 payments::features::kReturnGooglePayInBasicCard));
mathp24ce4cd2017-04-12 20:56:42615 for (autofill::CreditCard* card : cards)
616 AddAutofillPaymentInstrument(/*selected=*/false, *card);
mathpf1a7a3752017-03-15 11:23:37617}
618
619void PaymentRequestState::SetDefaultProfileSelections() {
mathpf14c1e32017-05-12 16:37:30620 // Contact profiles were ordered by completeness in addition to frecency;
621 // the first one is the best default selection.
tmartinocd131b32017-05-24 19:40:59622 if (!contact_profiles().empty() &&
623 profile_comparator()->IsContactInfoComplete(contact_profiles_[0]))
mathpf1a7a3752017-03-15 11:23:37624 selected_contact_profile_ = contact_profiles()[0];
625
Sahel Sharify6efdfb32019-07-02 16:12:16626 // Record the missing required fields (if any) of the most complete contact
627 // profile.
628 profile_comparator()->RecordMissingFieldsOfContactProfile(
629 contact_profiles().empty() ? nullptr : contact_profiles()[0]);
630
Sahel Sharify13331e82019-07-12 01:00:30631 // Sort instruments.
632 PaymentInstrument::SortInstruments(&available_instruments_);
633
634 selected_instrument_ = nullptr;
635 if (!available_instruments_.empty() &&
636 available_instruments_[0]->IsCompleteForPayment() &&
637 available_instruments_[0]->IsExactlyMatchingMerchantRequest()) {
638 selected_instrument_ = available_instruments_[0].get();
639 }
Rouslan Solomakhin9788d4b2019-04-09 13:10:23640
Sahel Sharify6efdfb32019-07-02 16:12:16641 // Record the missing required payment fields when no complete payment
642 // info exists.
Sahel Sharify13331e82019-07-12 01:00:30643 if (available_instruments_.empty()) {
Sahel Sharify6efdfb32019-07-02 16:12:16644 if (spec_->supports_basic_card()) {
645 // All fields are missing when basic-card is requested but no card exits.
646 base::UmaHistogramSparse("PaymentRequest.MissingPaymentFields",
Sahel Sharify13331e82019-07-12 01:00:30647 CREDIT_CARD_EXPIRED | CREDIT_CARD_NO_CARDHOLDER |
648 CREDIT_CARD_NO_NUMBER |
649 CREDIT_CARD_NO_BILLING_ADDRESS);
Sahel Sharify6efdfb32019-07-02 16:12:16650 }
Sahel Sharify13331e82019-07-12 01:00:30651 } else if (available_instruments_[0]->type() ==
652 PaymentInstrument::Type::AUTOFILL) {
653 // Record the missing fields (if any) of the most complete instrument when
654 // it's autofill based. SW based instruments are always complete.
655 static_cast<const AutofillPaymentInstrument*>(
656 available_instruments_[0].get())
Sahel Sharify6efdfb32019-07-02 16:12:16657 ->RecordMissingFieldsForInstrument();
658 }
gogerald8189d522017-09-15 17:52:18659
Sahel Sharify6efdfb32019-07-02 16:12:16660 SelectDefaultShippingAddressAndNotifyObservers();
gogerald8189d522017-09-15 17:52:18661
662 journey_logger_->SetNumberOfSuggestionsShown(
663 JourneyLogger::Section::SECTION_PAYMENT_METHOD,
Sahel Sharify6efdfb32019-07-02 16:12:16664 available_instruments().size(), selected_instrument_);
mathpf1a7a3752017-03-15 11:23:37665}
666
667void PaymentRequestState::UpdateIsReadyToPayAndNotifyObservers() {
668 is_ready_to_pay_ =
669 ArePaymentDetailsSatisfied() && ArePaymentOptionsSatisfied();
670 NotifyOnSelectedInformationChanged();
671}
672
gogerald8189d522017-09-15 17:52:18673void PaymentRequestState::NotifyOnGetAllPaymentInstrumentsFinished() {
674 for (auto& observer : observers_)
675 observer.OnGetAllPaymentInstrumentsFinished();
676}
677
mathpf1a7a3752017-03-15 11:23:37678void PaymentRequestState::NotifyOnSelectedInformationChanged() {
679 for (auto& observer : observers_)
680 observer.OnSelectedInformationChanged();
681}
682
683bool PaymentRequestState::ArePaymentDetailsSatisfied() {
mathp363735b2017-03-16 18:08:05684 // There is no need to check for supported networks, because only supported
685 // instruments are listed/created in the flow.
mathp4baea332017-04-10 21:42:29686 return selected_instrument_ != nullptr &&
687 selected_instrument_->IsCompleteForPayment();
mathpf1a7a3752017-03-15 11:23:37688}
689
690bool PaymentRequestState::ArePaymentOptionsSatisfied() {
sebsg7e619132017-04-27 16:07:10691 if (is_waiting_for_merchant_validation_)
692 return false;
693
Sahel Sharifyfef3d922019-09-11 01:41:22694 if (ShouldShowShippingSection() &&
695 (!spec_->selected_shipping_option() ||
696 !profile_comparator()->IsShippingComplete(selected_shipping_profile_))) {
tmartino01c3eb82017-04-29 15:18:39697 return false;
Sahel Sharifyfef3d922019-09-11 01:41:22698 }
tmartino01c3eb82017-04-29 15:18:39699
Sahel Sharifyfef3d922019-09-11 01:41:22700 if (ShouldShowContactSection() &&
701 !profile_comparator()->IsContactInfoComplete(selected_contact_profile_)) {
Anthony Vallee-Duboisa8814672017-06-01 18:43:20702 return false;
Sahel Sharifyfef3d922019-09-11 01:41:22703 }
Anthony Vallee-Duboisa8814672017-06-01 18:43:20704
Sahel Sharifyfef3d922019-09-11 01:41:22705 return true;
mathpf1a7a3752017-03-15 11:23:37706}
707
Mathieu Perreault17c1ae92017-10-20 17:16:00708void PaymentRequestState::OnAddressNormalized(
709 bool success,
710 const autofill::AutofillProfile& normalized_profile) {
711 delegate_->OnShippingAddressSelected(
Tommy Martino21d415f2018-01-12 20:08:22712 data_util::GetPaymentAddressFromAutofillProfile(normalized_profile,
713 app_locale_));
Mathieu Perreault17c1ae92017-10-20 17:16:00714}
715
mathpf1a7a3752017-03-15 11:23:37716} // namespace payments