blob: e0eebe5ae2c67b3c608a8c410a1c72820b6f59c0 [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 Solomakhin2039a342020-05-21 19:21:0421#include "components/payments/content/autofill_payment_app.h"
Rouslan Solomakhin6d4c1c272019-11-22 17:09:2722#include "components/payments/content/autofill_payment_app_factory.h"
Rouslan Solomakhin4eea9bc22017-10-10 15:18:5123#include "components/payments/content/content_payment_request_delegate.h"
Rouslan Solomakhin2039a342020-05-21 19:21:0424#include "components/payments/content/payment_app.h"
Rouslan Solomakhin6d4c1c272019-11-22 17:09:2725#include "components/payments/content/payment_app_service.h"
26#include "components/payments/content/payment_app_service_factory.h"
Rouslan Solomakhin4eea9bc22017-10-10 15:18:5127#include "components/payments/content/payment_manifest_web_data_service.h"
sebsgad86bd002017-03-29 16:39:1228#include "components/payments/content/payment_response_helper.h"
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:3929#include "components/payments/content/service_worker_payment_app.h"
Sahel Sharify13331e82019-07-12 01:00:3030#include "components/payments/core/autofill_card_validation.h"
Rouslan Solomakhin1dca2a922019-09-06 22:25:0731#include "components/payments/core/error_strings.h"
Mathieu Perreault157f3992018-06-29 18:48:0632#include "components/payments/core/features.h"
Rouslan Solomakhin85b10da2019-11-05 20:03:1733#include "components/payments/core/method_strings.h"
tmartino01c3eb82017-04-29 15:18:3934#include "components/payments/core/payment_request_data_util.h"
Danyao Wang761739b2019-06-27 23:59:3235#include "components/payments/core/payments_experimental_features.h"
Danyao Wang4f2ba632020-03-11 13:56:5436#include "content/public/browser/render_frame_host.h"
gogerald8189d522017-09-15 17:52:1837#include "content/public/common/content_features.h"
mathpf1a7a3752017-03-15 11:23:3738
39namespace payments {
Rouslan Solomakhin1dca2a922019-09-06 22:25:0740namespace {
41
Rouslan Solomakhin1dca2a922019-09-06 22:25:0742// Invokes the |callback| with |status|.
43void CallStatusCallback(PaymentRequestState::StatusCallback callback,
44 bool status) {
45 std::move(callback).Run(status);
46}
47
48// Posts the |callback| to be invoked with |status| asynchronously.
49void PostStatusCallback(PaymentRequestState::StatusCallback callback,
50 bool status) {
51 base::ThreadTaskRunnerHandle::Get()->PostTask(
52 FROM_HERE,
53 base::BindOnce(&CallStatusCallback, std::move(callback), status));
54}
55
56} // namespace
mathpf1a7a3752017-03-15 11:23:3757
mathpc0d616a2017-03-15 14:09:3358PaymentRequestState::PaymentRequestState(
Rouslan Solomakhindbf593d92017-11-21 19:20:5759 content::WebContents* web_contents,
Danyao Wang4f2ba632020-03-11 13:56:5460 content::RenderFrameHost* initiator_render_frame_host,
gogerald7a0cc3e2017-09-19 03:35:4861 const GURL& top_level_origin,
62 const GURL& frame_origin,
Rouslan Solomakhinc71cca622020-01-31 22:15:3563 const url::Origin& frame_security_origin,
mathpc0d616a2017-03-15 14:09:3364 PaymentRequestSpec* spec,
65 Delegate* delegate,
66 const std::string& app_locale,
anthonyvdd23ed702017-04-05 15:29:0067 autofill::PersonalDataManager* personal_data_manager,
Rouslan Solomakhin4eea9bc22017-10-10 15:18:5168 ContentPaymentRequestDelegate* payment_request_delegate,
Rouslan Solomakhin6d4c1c272019-11-22 17:09:2769 const ServiceWorkerPaymentApp::IdentityCallback& sw_identity_callback,
sebsgc6719b32017-07-05 19:54:4770 JourneyLogger* journey_logger)
Rouslan Solomakhin6d4c1c272019-11-22 17:09:2771 : web_contents_(web_contents),
Danyao Wang4f2ba632020-03-11 13:56:5472 initiator_render_frame_host_(initiator_render_frame_host),
Rouslan Solomakhin6d4c1c272019-11-22 17:09:2773 top_origin_(top_level_origin),
74 frame_origin_(frame_origin),
Rouslan Solomakhinc71cca622020-01-31 22:15:3575 frame_security_origin_(frame_security_origin),
mathpc0d616a2017-03-15 14:09:3376 app_locale_(app_locale),
mathpf1a7a3752017-03-15 11:23:3777 spec_(spec),
78 delegate_(delegate),
mathpc0d616a2017-03-15 14:09:3379 personal_data_manager_(personal_data_manager),
sebsgc6719b32017-07-05 19:54:4780 journey_logger_(journey_logger),
Rouslan Solomakhind2cae95a2018-08-09 00:16:1081 are_requested_methods_supported_(
82 !spec_->supported_card_networks().empty()),
tmartino01c3eb82017-04-29 15:18:3983 payment_request_delegate_(payment_request_delegate),
Rouslan Solomakhin6d4c1c272019-11-22 17:09:2784 sw_identity_callback_(sw_identity_callback),
Jeremy Roman5c341f6d2019-07-15 15:56:1085 profile_comparator_(app_locale, *spec) {
Rouslan Solomakhin6d4c1c272019-11-22 17:09:2786 PopulateProfileCache();
Danyao Wang761739b2019-06-27 23:59:3287
Rouslan Solomakhin6d4c1c272019-11-22 17:09:2788 // |web_contents_| is null in unit tests.
Danyao Wange865a302020-04-01 18:35:1489 PaymentAppService* service = PaymentAppServiceFactory::GetForContext(
90 web_contents_ ? web_contents_->GetBrowserContext() : nullptr);
91 number_of_payment_app_factories_ = service->GetNumberOfFactories();
92 service->Create(weak_ptr_factory_.GetWeakPtr());
Rouslan Solomakhin6d4c1c272019-11-22 17:09:2793
sebsg7e619132017-04-27 16:07:1094 spec_->AddObserver(this);
mathpf1a7a3752017-03-15 11:23:3795}
Rouslan Solomakhin4eea9bc22017-10-10 15:18:5196
mathp151bd31e2017-04-03 21:07:2497PaymentRequestState::~PaymentRequestState() {}
mathpf1a7a3752017-03-15 11:23:3798
Rouslan Solomakhin6d4c1c272019-11-22 17:09:2799content::WebContents* PaymentRequestState::GetWebContents() {
100 return web_contents_;
gogeraldac15d2362017-11-15 01:04:19101}
102
Danyao Wangaed5b0a92020-04-01 22:43:14103ContentPaymentRequestDelegate* PaymentRequestState::GetPaymentRequestDelegate()
104 const {
Rouslan Solomakhin6d4c1c272019-11-22 17:09:27105 return payment_request_delegate_;
106}
Rouslan Solomakhin1dca2a922019-09-06 22:25:07107
Danyao Wangaed5b0a92020-04-01 22:43:14108PaymentRequestSpec* PaymentRequestState::GetSpec() const {
Rouslan Solomakhin6d4c1c272019-11-22 17:09:27109 return spec_;
110}
gogeraldac15d2362017-11-15 01:04:19111
Rouslan Solomakhin6d4c1c272019-11-22 17:09:27112const GURL& PaymentRequestState::GetTopOrigin() {
113 return top_origin_;
114}
115
116const GURL& PaymentRequestState::GetFrameOrigin() {
117 return frame_origin_;
118}
119
Rouslan Solomakhinc71cca622020-01-31 22:15:35120const url::Origin& PaymentRequestState::GetFrameSecurityOrigin() {
121 return frame_security_origin_;
122}
123
Danyao Wang4f2ba632020-03-11 13:56:54124content::RenderFrameHost* PaymentRequestState::GetInitiatorRenderFrameHost()
125 const {
126 return initiator_render_frame_host_;
127}
128
Danyao Wangaed5b0a92020-04-01 22:43:14129const std::vector<mojom::PaymentMethodDataPtr>&
130PaymentRequestState::GetMethodData() const {
131 return GetSpec()->method_data();
132}
133
134scoped_refptr<PaymentManifestWebDataService>
135PaymentRequestState::GetPaymentManifestWebDataService() const {
136 return GetPaymentRequestDelegate()->GetPaymentManifestWebDataService();
137}
138
Rouslan Solomakhin6d4c1c272019-11-22 17:09:27139const std::vector<autofill::AutofillProfile*>&
140PaymentRequestState::GetBillingProfiles() {
141 return shipping_profiles_;
142}
143
144bool PaymentRequestState::IsRequestedAutofillDataAvailable() {
145 return is_requested_autofill_data_available_;
146}
147
148bool PaymentRequestState::MayCrawlForInstallablePaymentApps() {
149 return PaymentsExperimentalFeatures::IsEnabled(
150 features::kAlwaysAllowJustInTimePaymentApp) ||
151 !spec_->supports_basic_card();
152}
153
154void PaymentRequestState::OnPaymentAppInstalled(const url::Origin& origin,
155 int64_t registration_id) {
156 sw_identity_callback_.Run(origin, registration_id);
157}
158
159void PaymentRequestState::OnPaymentAppCreated(std::unique_ptr<PaymentApp> app) {
160 if (app->type() == PaymentApp::Type::AUTOFILL) {
161 journey_logger_->SetEventOccurred(
162 JourneyLogger::EVENT_AVAILABLE_METHOD_BASIC_CARD);
163 } else if (base::Contains(app->GetAppMethodNames(), methods::kGooglePay) ||
164 base::Contains(app->GetAppMethodNames(), methods::kAndroidPay)) {
Danyao Wang25f72dc2019-10-18 05:11:32165 journey_logger_->SetEventOccurred(
166 JourneyLogger::EVENT_AVAILABLE_METHOD_GOOGLE);
167 } else {
168 journey_logger_->SetEventOccurred(
169 JourneyLogger::EVENT_AVAILABLE_METHOD_OTHER);
170 }
Rouslan Solomakhin6d4c1c272019-11-22 17:09:27171 available_apps_.emplace_back(std::move(app));
gogeraldac15d2362017-11-15 01:04:19172}
173
Rouslan Solomakhin6d4c1c272019-11-22 17:09:27174void PaymentRequestState::OnPaymentAppCreationError(
175 const std::string& error_message) {
176 get_all_payment_apps_error_ = error_message;
177}
178
Danyao Wangaed5b0a92020-04-01 22:43:14179bool PaymentRequestState::SkipCreatingNativePaymentApps() const {
180 return false;
181}
182
183void PaymentRequestState::OnCreatingNativePaymentAppsSkipped(
Danyao Wanga6b37162020-04-16 14:31:19184 content::PaymentAppProvider::PaymentApps unused_apps,
185 ServiceWorkerPaymentAppFinder::InstallablePaymentApps
Danyao Wangaed5b0a92020-04-01 22:43:14186 unused_installable_apps) {
187 NOTREACHED();
188}
189
Rouslan Solomakhin6d4c1c272019-11-22 17:09:27190void PaymentRequestState::OnDoneCreatingPaymentApps() {
191 DCHECK_NE(0U, number_of_payment_app_factories_);
192 if (--number_of_payment_app_factories_ > 0U)
193 return;
194
gogerald8189d522017-09-15 17:52:18195 SetDefaultProfileSelections();
196
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39197 get_all_apps_finished_ = true;
Danyao Wang5a14e982020-02-12 21:34:09198 has_enrolled_instrument_ =
199 std::any_of(available_apps_.begin(), available_apps_.end(),
200 [](const auto& app) { return app->HasEnrolledInstrument(); });
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39201 are_requested_methods_supported_ |= !available_apps_.empty();
202 NotifyOnGetAllPaymentAppsFinished();
Rouslan Solomakhin9788d4b2019-04-09 13:10:23203 NotifyInitialized();
gogerald8189d522017-09-15 17:52:18204
Danyao Wang4bc0606a2018-12-27 16:54:53205 // Fulfill the pending CanMakePayment call.
Rouslan Solomakhin1dca2a922019-09-06 22:25:07206 if (can_make_payment_callback_)
207 std::move(can_make_payment_callback_).Run(are_requested_methods_supported_);
Danyao Wang4bc0606a2018-12-27 16:54:53208
Danyao Wangce175bf2018-12-21 22:35:58209 // Fulfill the pending HasEnrolledInstrument call.
210 if (has_enrolled_instrument_callback_)
Rouslan Solomakhin1dca2a922019-09-06 22:25:07211 std::move(has_enrolled_instrument_callback_).Run(has_enrolled_instrument_);
gogerald0a7ee6c2017-11-13 18:23:19212
Danyao Wangce175bf2018-12-21 22:35:58213 // Fulfill the pending AreRequestedMethodsSupported call.
gogerald0a7ee6c2017-11-13 18:23:19214 if (are_requested_methods_supported_callback_)
215 CheckRequestedMethodsSupported(
216 std::move(are_requested_methods_supported_callback_));
gogerald8189d522017-09-15 17:52:18217}
218
sebsg695799a2017-04-11 16:29:06219void PaymentRequestState::OnPaymentResponseReady(
220 mojom::PaymentResponsePtr payment_response) {
221 delegate_->OnPaymentResponseAvailable(std::move(payment_response));
222}
223
Rouslan Solomakhin68429b72019-06-27 15:12:39224void PaymentRequestState::OnPaymentResponseError(
225 const std::string& error_message) {
226 delegate_->OnPaymentResponseError(error_message);
227}
228
sebsg7e619132017-04-27 16:07:10229void PaymentRequestState::OnSpecUpdated() {
Jinho Bangcac8d9a02018-08-23 19:47:22230 autofill::AutofillProfile* selected_shipping_profile =
231 selected_shipping_profile_;
232 autofill::AutofillProfile* selected_contact_profile =
233 selected_contact_profile_;
234
235 if (spec_->current_update_reason() ==
236 PaymentRequestSpec::UpdateReason::RETRY) {
237 if (spec_->has_shipping_address_error() && selected_shipping_profile) {
238 invalid_shipping_profile_ = selected_shipping_profile;
239 selected_shipping_profile_ = nullptr;
240 }
Jinho Bang092e7162018-09-06 23:41:19241
Jinho Bangcac8d9a02018-08-23 19:47:22242 if (spec_->has_payer_error() && selected_contact_profile) {
243 invalid_contact_profile_ = selected_contact_profile;
244 selected_contact_profile_ = nullptr;
245 }
246 }
247
Mathieu Perreault04b4c662017-06-02 13:35:13248 if (spec_->selected_shipping_option_error().empty()) {
249 selected_shipping_option_error_profile_ = nullptr;
250 } else {
Jinho Bangcac8d9a02018-08-23 19:47:22251 selected_shipping_option_error_profile_ = selected_shipping_profile;
Mathieu Perreault04b4c662017-06-02 13:35:13252 selected_shipping_profile_ = nullptr;
Jinho Bang092e7162018-09-06 23:41:19253 if (spec_->has_shipping_address_error() && selected_shipping_profile) {
254 invalid_shipping_profile_ = selected_shipping_profile;
255 }
Mathieu Perreault04b4c662017-06-02 13:35:13256 }
Jinho Bangcac8d9a02018-08-23 19:47:22257
sebsg7e619132017-04-27 16:07:10258 is_waiting_for_merchant_validation_ = false;
259 UpdateIsReadyToPayAndNotifyObservers();
260}
261
Danyao Wang03a4cbd2019-08-15 23:47:11262void PaymentRequestState::CanMakePayment(StatusCallback callback) {
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39263 if (!get_all_apps_finished_) {
Danyao Wang4bc0606a2018-12-27 16:54:53264 DCHECK(!can_make_payment_callback_);
265 can_make_payment_callback_ = std::move(callback);
266 return;
267 }
268
Rouslan Solomakhin1dca2a922019-09-06 22:25:07269 PostStatusCallback(std::move(callback), are_requested_methods_supported_);
Danyao Wangce175bf2018-12-21 22:35:58270}
271
272void PaymentRequestState::HasEnrolledInstrument(StatusCallback callback) {
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39273 if (!get_all_apps_finished_) {
Danyao Wang4bc0606a2018-12-27 16:54:53274 DCHECK(!has_enrolled_instrument_callback_);
Danyao Wangce175bf2018-12-21 22:35:58275 has_enrolled_instrument_callback_ = std::move(callback);
gogerald8189d522017-09-15 17:52:18276 return;
277 }
278
Rouslan Solomakhin1dca2a922019-09-06 22:25:07279 PostStatusCallback(std::move(callback), has_enrolled_instrument_);
mathp1a5be4f2017-03-24 18:09:19280}
281
gogerald0a7ee6c2017-11-13 18:23:19282void PaymentRequestState::AreRequestedMethodsSupported(
Rouslan Solomakhind5dcc322019-07-11 21:47:20283 MethodsSupportedCallback callback) {
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39284 if (!get_all_apps_finished_) {
gogerald0a7ee6c2017-11-13 18:23:19285 are_requested_methods_supported_callback_ = std::move(callback);
286 return;
287 }
288
289 base::ThreadTaskRunnerHandle::Get()->PostTask(
290 FROM_HERE,
291 base::BindOnce(&PaymentRequestState::CheckRequestedMethodsSupported,
292 weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
293}
294
Sahel Sharifyd3418222020-02-19 21:50:02295void PaymentRequestState::OnAbort() {
296 // Reset supported method callback when the merchant calls abort before
297 // OnDoneCreatingPaymentApps().
298 if (are_requested_methods_supported_callback_)
299 are_requested_methods_supported_callback_.Reset();
300}
301
gogerald0a7ee6c2017-11-13 18:23:19302void PaymentRequestState::CheckRequestedMethodsSupported(
Rouslan Solomakhind5dcc322019-07-11 21:47:20303 MethodsSupportedCallback callback) {
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39304 DCHECK(get_all_apps_finished_);
gogerald0a7ee6c2017-11-13 18:23:19305
Rouslan Solomakhin1dca2a922019-09-06 22:25:07306 // Don't modify the value of |are_requested_methods_supported_|, because it's
307 // used for canMakePayment().
308 bool supported = are_requested_methods_supported_;
309 if (supported && is_show_user_gesture_ &&
Rouslan Solomakhin85b10da2019-11-05 20:03:17310 base::Contains(spec_->payment_method_identifiers_set(),
311 methods::kBasicCard) &&
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39312 !has_non_autofill_app_ && !has_enrolled_instrument_ &&
Rouslan Solomakhin1dca2a922019-09-06 22:25:07313 PaymentsExperimentalFeatures::IsEnabled(
314 features::kStrictHasEnrolledAutofillInstrument)) {
315 supported = false;
316 get_all_payment_apps_error_ = errors::kStrictBasicCardShowReject;
317 }
318
319 std::move(callback).Run(supported, get_all_payment_apps_error_);
rouslan6e3cf7c62017-04-17 21:23:28320}
321
anthonyvd6a43b932017-05-11 18:39:27322std::string PaymentRequestState::GetAuthenticatedEmail() const {
323 return payment_request_delegate_->GetAuthenticatedEmail();
324}
325
mathpf1a7a3752017-03-15 11:23:37326void PaymentRequestState::AddObserver(Observer* observer) {
327 CHECK(observer);
328 observers_.AddObserver(observer);
329}
mathpf1a7a3752017-03-15 11:23:37330
331void PaymentRequestState::RemoveObserver(Observer* observer) {
332 observers_.RemoveObserver(observer);
333}
334
mathpf1a7a3752017-03-15 11:23:37335void PaymentRequestState::GeneratePaymentResponse() {
mathp363735b2017-03-16 18:08:05336 DCHECK(is_ready_to_pay());
sebsg695799a2017-04-11 16:29:06337
338 // Once the response is ready, will call back into OnPaymentResponseReady.
Rouslan Solomakhin4eea9bc22017-10-10 15:18:51339 response_helper_ = std::make_unique<PaymentResponseHelper>(
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39340 app_locale_, spec_, selected_app_, payment_request_delegate_,
sebsg8a9c2342017-04-21 17:05:15341 selected_shipping_profile_, selected_contact_profile_, this);
mathpf1a7a3752017-03-15 11:23:37342}
343
Rouslan Solomakhin761d65eb2019-04-29 20:08:01344void PaymentRequestState::OnPaymentAppWindowClosed() {
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39345 DCHECK(selected_app_);
Rouslan Solomakhin761d65eb2019-04-29 20:08:01346 response_helper_.reset();
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39347 selected_app_->OnPaymentAppWindowClosed();
Rouslan Solomakhin761d65eb2019-04-29 20:08:01348}
349
sebsg8a93b272017-05-11 19:30:22350void PaymentRequestState::RecordUseStats() {
Sahel Sharifyfef3d922019-09-11 01:41:22351 if (ShouldShowShippingSection()) {
sebsg8a93b272017-05-11 19:30:22352 DCHECK(selected_shipping_profile_);
353 personal_data_manager_->RecordUseOf(*selected_shipping_profile_);
354 }
355
Sahel Sharifyfef3d922019-09-11 01:41:22356 if (ShouldShowContactSection()) {
sebsg8a93b272017-05-11 19:30:22357 DCHECK(selected_contact_profile_);
358
359 // If the same address was used for both contact and shipping, the stats
360 // should only be updated once.
Sahel Sharifyfef3d922019-09-11 01:41:22361 if (!ShouldShowShippingSection() || (selected_shipping_profile_->guid() !=
362 selected_contact_profile_->guid())) {
sebsg8a93b272017-05-11 19:30:22363 personal_data_manager_->RecordUseOf(*selected_contact_profile_);
364 }
365 }
366
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39367 selected_app_->RecordUse();
sebsg8a93b272017-05-11 19:30:22368}
369
Sahel Sharifycf4e2132020-01-24 23:59:08370void PaymentRequestState::SetAvailablePaymentAppForRetry() {
371 DCHECK(selected_app_);
372 base::EraseIf(available_apps_, [this](const auto& payment_app) {
373 // Remove the app if it is not selected.
374 return payment_app.get() != selected_app_;
375 });
376 is_retry_called_ = true;
377}
378
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39379void PaymentRequestState::AddAutofillPaymentApp(
mathp24ce4cd2017-04-12 20:56:42380 bool selected,
381 const autofill::CreditCard& card) {
Rouslan Solomakhin6d4c1c272019-11-22 17:09:27382 auto app =
383 AutofillPaymentAppFactory::ConvertCardToPaymentAppIfSupportedNetwork(
384 card, weak_ptr_factory_.GetWeakPtr());
385 if (!app)
mathp24ce4cd2017-04-12 20:56:42386 return;
Rouslan Solomakhin25d708b2017-06-23 17:12:03387
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39388 available_apps_.push_back(std::move(app));
Danyao Wang25f72dc2019-10-18 05:11:32389 journey_logger_->SetEventOccurred(
390 JourneyLogger::EVENT_AVAILABLE_METHOD_BASIC_CARD);
mathp24ce4cd2017-04-12 20:56:42391
Sahel Sharifybc4173f2019-05-09 21:03:57392 if (selected) {
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39393 SetSelectedApp(available_apps_.back().get(),
394 SectionSelectionStatus::kAddedSelected);
Sahel Sharifybc4173f2019-05-09 21:03:57395 }
mathp24ce4cd2017-04-12 20:56:42396}
397
madf9904ea2017-04-25 18:39:12398void PaymentRequestState::AddAutofillShippingProfile(
399 bool selected,
400 const autofill::AutofillProfile& profile) {
401 profile_cache_.push_back(
Rouslan Solomakhin4eea9bc22017-10-10 15:18:51402 std::make_unique<autofill::AutofillProfile>(profile));
madf9904ea2017-04-25 18:39:12403 // TODO(tmartino): Implement deduplication rules specific to shipping
404 // profiles.
405 autofill::AutofillProfile* new_cached_profile = profile_cache_.back().get();
406 shipping_profiles_.push_back(new_cached_profile);
407
Sahel Sharifybc4173f2019-05-09 21:03:57408 if (selected) {
409 SetSelectedShippingProfile(new_cached_profile,
410 SectionSelectionStatus::kAddedSelected);
411 }
madf9904ea2017-04-25 18:39:12412}
413
Anthony Vallee-Duboisf1e88b42017-05-15 15:09:23414void PaymentRequestState::AddAutofillContactProfile(
415 bool selected,
416 const autofill::AutofillProfile& profile) {
417 profile_cache_.push_back(
Rouslan Solomakhin4eea9bc22017-10-10 15:18:51418 std::make_unique<autofill::AutofillProfile>(profile));
Anthony Vallee-Duboisf1e88b42017-05-15 15:09:23419 autofill::AutofillProfile* new_cached_profile = profile_cache_.back().get();
420 contact_profiles_.push_back(new_cached_profile);
421
Sahel Sharifybc4173f2019-05-09 21:03:57422 if (selected) {
423 SetSelectedContactProfile(new_cached_profile,
424 SectionSelectionStatus::kAddedSelected);
425 }
Anthony Vallee-Duboisf1e88b42017-05-15 15:09:23426}
427
anthonyvd0116ce332017-03-21 21:29:01428void PaymentRequestState::SetSelectedShippingOption(
mathp151bd31e2017-04-03 21:07:24429 const std::string& shipping_option_id) {
anthonyvd2f30baa12017-04-13 22:30:50430 spec_->StartWaitingForUpdateWith(
431 PaymentRequestSpec::UpdateReason::SHIPPING_OPTION);
mathp151bd31e2017-04-03 21:07:24432 // This will inform the merchant and will lead to them calling updateWith with
433 // new PaymentDetails.
434 delegate_->OnShippingOptionIdSelected(shipping_option_id);
anthonyvd0116ce332017-03-21 21:29:01435}
436
mathpf1a7a3752017-03-15 11:23:37437void PaymentRequestState::SetSelectedShippingProfile(
Sahel Sharifybc4173f2019-05-09 21:03:57438 autofill::AutofillProfile* profile,
439 SectionSelectionStatus selection_status) {
anthonyvd2f30baa12017-04-13 22:30:50440 spec_->StartWaitingForUpdateWith(
441 PaymentRequestSpec::UpdateReason::SHIPPING_ADDRESS);
mathpf1a7a3752017-03-15 11:23:37442 selected_shipping_profile_ = profile;
sebsg7e619132017-04-27 16:07:10443
Jinho Bangcac8d9a02018-08-23 19:47:22444 // Changing the shipping address clears shipping address validation errors
445 // from retry().
446 invalid_shipping_profile_ = nullptr;
447
sebsg7e619132017-04-27 16:07:10448 // The user should not be able to click on pay until the callback from the
449 // merchant.
450 is_waiting_for_merchant_validation_ = true;
sebsg7e619132017-04-27 16:07:10451
452 // Start the normalization of the shipping address.
Mathieu Perreaultc94700f112017-10-23 20:28:39453 payment_request_delegate_->GetAddressNormalizer()->NormalizeAddressAsync(
Mathieu Perreault9b40d5102017-11-21 20:51:29454 *selected_shipping_profile_, /*timeout_seconds=*/2,
Mathieu Perreault17c1ae92017-10-20 17:16:00455 base::BindOnce(&PaymentRequestState::OnAddressNormalized,
456 weak_ptr_factory_.GetWeakPtr()));
Sahel Sharifybc4173f2019-05-09 21:03:57457 IncrementSelectionStatus(JourneyLogger::Section::SECTION_SHIPPING_ADDRESS,
458 selection_status);
mathpf1a7a3752017-03-15 11:23:37459}
460
461void PaymentRequestState::SetSelectedContactProfile(
Sahel Sharifybc4173f2019-05-09 21:03:57462 autofill::AutofillProfile* profile,
463 SectionSelectionStatus selection_status) {
mathpf1a7a3752017-03-15 11:23:37464 selected_contact_profile_ = profile;
Jinho Bangcac8d9a02018-08-23 19:47:22465
466 // Changing the contact information clears contact information validation
467 // errors from retry().
468 invalid_contact_profile_ = nullptr;
469
mathpf1a7a3752017-03-15 11:23:37470 UpdateIsReadyToPayAndNotifyObservers();
Jinho Bangbb178152018-09-13 09:44:43471
472 if (IsPaymentAppInvoked()) {
Jinho Bang21d6be92018-12-18 15:30:31473 delegate_->OnPayerInfoSelected(
474 response_helper_->GeneratePayerDetail(profile));
Jinho Bangbb178152018-09-13 09:44:43475 }
Sahel Sharifybc4173f2019-05-09 21:03:57476 IncrementSelectionStatus(JourneyLogger::Section::SECTION_CONTACT_INFO,
477 selection_status);
mathpf1a7a3752017-03-15 11:23:37478}
479
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39480void PaymentRequestState::SetSelectedApp(
481 PaymentApp* app,
Sahel Sharifybc4173f2019-05-09 21:03:57482 SectionSelectionStatus selection_status) {
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39483 selected_app_ = app;
mathpf1a7a3752017-03-15 11:23:37484 UpdateIsReadyToPayAndNotifyObservers();
Sahel Sharifybc4173f2019-05-09 21:03:57485 IncrementSelectionStatus(JourneyLogger::Section::SECTION_PAYMENT_METHOD,
486 selection_status);
487}
488
489void PaymentRequestState::IncrementSelectionStatus(
490 JourneyLogger::Section section,
491 SectionSelectionStatus selection_status) {
492 switch (selection_status) {
493 case SectionSelectionStatus::kSelected:
494 journey_logger_->IncrementSelectionChanges(section);
495 break;
496 case SectionSelectionStatus::kEditedSelected:
497 journey_logger_->IncrementSelectionEdits(section);
498 break;
499 case SectionSelectionStatus::kAddedSelected:
500 journey_logger_->IncrementSelectionAdds(section);
501 break;
502 default:
503 NOTREACHED();
504 }
mathpf1a7a3752017-03-15 11:23:37505}
506
mathpc0d616a2017-03-15 14:09:33507const std::string& PaymentRequestState::GetApplicationLocale() {
508 return app_locale_;
509}
510
511autofill::PersonalDataManager* PaymentRequestState::GetPersonalDataManager() {
512 return personal_data_manager_;
513}
514
mad763ed2b2017-04-24 20:28:47515autofill::RegionDataLoader* PaymentRequestState::GetRegionDataLoader() {
516 return payment_request_delegate_->GetRegionDataLoader();
mad45271932017-04-13 16:07:38517}
518
Anthony Vallee-Dubois6813c1442017-05-17 19:32:56519bool PaymentRequestState::IsPaymentAppInvoked() const {
520 return !!response_helper_;
521}
522
Mathieu Perreaulteea046d12017-09-28 15:51:21523autofill::AddressNormalizer* PaymentRequestState::GetAddressNormalizer() {
Anthony Vallee-Dubois71bf349462017-07-20 23:56:45524 return payment_request_delegate_->GetAddressNormalizer();
525}
526
Rouslan Solomakhin48fd6e872019-02-22 17:23:10527bool PaymentRequestState::IsInitialized() const {
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39528 return get_all_apps_finished_;
Rouslan Solomakhin48fd6e872019-02-22 17:23:10529}
530
Rouslan Solomakhin9788d4b2019-04-09 13:10:23531void PaymentRequestState::SelectDefaultShippingAddressAndNotifyObservers() {
532 // Only pre-select an address if the merchant provided at least one selected
533 // shipping option, and the top profile is complete. Assumes that profiles
534 // have already been sorted for completeness and frecency.
535 if (!shipping_profiles().empty() && spec_->selected_shipping_option() &&
536 profile_comparator()->IsShippingComplete(shipping_profiles_[0])) {
537 selected_shipping_profile_ = shipping_profiles()[0];
538 }
Sahel Sharify6efdfb32019-07-02 16:12:16539 // Record the missing required fields (if any) of the most complete shipping
540 // profile.
541 profile_comparator()->RecordMissingFieldsOfShippingProfile(
542 shipping_profiles().empty() ? nullptr : shipping_profiles()[0]);
Rouslan Solomakhin9788d4b2019-04-09 13:10:23543 UpdateIsReadyToPayAndNotifyObservers();
544}
545
Sahel Sharifyfef3d922019-09-11 01:41:22546bool PaymentRequestState::ShouldShowShippingSection() const {
547 if (!spec_->request_shipping())
548 return false;
549
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39550 return selected_app_ ? !selected_app_->HandlesShippingAddress() : true;
Sahel Sharifyfef3d922019-09-11 01:41:22551}
552
553bool PaymentRequestState::ShouldShowContactSection() const {
554 if (spec_->request_payer_name() &&
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39555 (!selected_app_ || !selected_app_->HandlesPayerName())) {
Sahel Sharifyfef3d922019-09-11 01:41:22556 return true;
557 }
558 if (spec_->request_payer_email() &&
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39559 (!selected_app_ || !selected_app_->HandlesPayerEmail())) {
Sahel Sharifyfef3d922019-09-11 01:41:22560 return true;
561 }
562 if (spec_->request_payer_phone() &&
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39563 (!selected_app_ || !selected_app_->HandlesPayerPhone())) {
Sahel Sharifyfef3d922019-09-11 01:41:22564 return true;
565 }
566
567 return false;
568}
569
Rouslan Solomakhin65552292019-08-29 17:28:21570base::WeakPtr<PaymentRequestState> PaymentRequestState::AsWeakPtr() {
571 return weak_ptr_factory_.GetWeakPtr();
572}
573
mathpf1a7a3752017-03-15 11:23:37574void PaymentRequestState::PopulateProfileCache() {
mathpf1a7a3752017-03-15 11:23:37575 std::vector<autofill::AutofillProfile*> profiles =
mathpc0d616a2017-03-15 14:09:33576 personal_data_manager_->GetProfilesToSuggest();
mathpf1a7a3752017-03-15 11:23:37577
tmartinocd131b32017-05-24 19:40:59578 std::vector<autofill::AutofillProfile*> raw_profiles_for_filtering;
579 raw_profiles_for_filtering.reserve(profiles.size());
580
mathpf1a7a3752017-03-15 11:23:37581 // PaymentRequest may outlive the Profiles returned by the Data Manager.
582 // Thus, we store copies, and return a vector of pointers to these copies
mathpf14c1e32017-05-12 16:37:30583 // whenever Profiles are requested.
mathpf1a7a3752017-03-15 11:23:37584 for (size_t i = 0; i < profiles.size(); i++) {
585 profile_cache_.push_back(
Rouslan Solomakhin4eea9bc22017-10-10 15:18:51586 std::make_unique<autofill::AutofillProfile>(*profiles[i]));
tmartinocd131b32017-05-24 19:40:59587 raw_profiles_for_filtering.push_back(profile_cache_.back().get());
mathpf1a7a3752017-03-15 11:23:37588 }
589
tmartino01c3eb82017-04-29 15:18:39590 contact_profiles_ = profile_comparator()->FilterProfilesForContact(
591 raw_profiles_for_filtering);
tmartinocd131b32017-05-24 19:40:59592 shipping_profiles_ = profile_comparator()->FilterProfilesForShipping(
593 raw_profiles_for_filtering);
tmartinoa6eb22f2017-04-06 20:16:24594
sebsgc6719b32017-07-05 19:54:47595 // Set the number of suggestions shown for the sections requested by the
596 // merchant.
Sahel Sharifyfef3d922019-09-11 01:41:22597 if (ShouldShowContactSection()) {
sebsgce700484d2017-07-19 23:25:38598 bool has_complete_contact =
599 contact_profiles_.empty()
600 ? false
601 : profile_comparator()->IsContactInfoComplete(contact_profiles_[0]);
Rouslan Solomakhincb29c4f2019-08-16 22:49:39602 is_requested_autofill_data_available_ &= has_complete_contact;
sebsgc6719b32017-07-05 19:54:47603 journey_logger_->SetNumberOfSuggestionsShown(
sebsgce700484d2017-07-19 23:25:38604 JourneyLogger::Section::SECTION_CONTACT_INFO, contact_profiles_.size(),
605 has_complete_contact);
sebsgc6719b32017-07-05 19:54:47606 }
Sahel Sharifyfef3d922019-09-11 01:41:22607 if (ShouldShowShippingSection()) {
sebsgce700484d2017-07-19 23:25:38608 bool has_complete_shipping =
609 shipping_profiles_.empty()
610 ? false
611 : profile_comparator()->IsShippingComplete(shipping_profiles_[0]);
Rouslan Solomakhincb29c4f2019-08-16 22:49:39612 is_requested_autofill_data_available_ &= has_complete_shipping;
sebsgc6719b32017-07-05 19:54:47613 journey_logger_->SetNumberOfSuggestionsShown(
614 JourneyLogger::Section::SECTION_SHIPPING_ADDRESS,
sebsgce700484d2017-07-19 23:25:38615 shipping_profiles_.size(), has_complete_shipping);
sebsgc6719b32017-07-05 19:54:47616 }
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
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39631 // Sort apps.
632 PaymentApp::SortApps(&available_apps_);
Sahel Sharify13331e82019-07-12 01:00:30633
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39634 selected_app_ = nullptr;
Sahel Sharify90307872019-12-02 17:28:14635 if (!available_apps_.empty() && available_apps_[0]->CanPreselect()) {
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39636 selected_app_ = available_apps_[0].get();
Sahel Sharify9be7b292020-03-13 17:37:46637 UpdateIsReadyToPayAndNotifyObservers();
Sahel Sharify13331e82019-07-12 01:00:30638 }
Rouslan Solomakhin9788d4b2019-04-09 13:10:23639
Sahel Sharify6efdfb32019-07-02 16:12:16640 // Record the missing required payment fields when no complete payment
641 // info exists.
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39642 if (available_apps_.empty()) {
Sahel Sharify6efdfb32019-07-02 16:12:16643 if (spec_->supports_basic_card()) {
644 // All fields are missing when basic-card is requested but no card exits.
645 base::UmaHistogramSparse("PaymentRequest.MissingPaymentFields",
Sahel Sharify13331e82019-07-12 01:00:30646 CREDIT_CARD_EXPIRED | CREDIT_CARD_NO_CARDHOLDER |
647 CREDIT_CARD_NO_NUMBER |
648 CREDIT_CARD_NO_BILLING_ADDRESS);
Sahel Sharify6efdfb32019-07-02 16:12:16649 }
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39650 } else if (available_apps_[0]->type() == PaymentApp::Type::AUTOFILL) {
651 // Record the missing fields (if any) of the most complete app when
652 // it's autofill based. SW based apps are always complete.
653 static_cast<const AutofillPaymentApp*>(available_apps_[0].get())
654 ->RecordMissingFieldsForApp();
Sahel Sharify6efdfb32019-07-02 16:12:16655 }
gogerald8189d522017-09-15 17:52:18656
Sahel Sharify6efdfb32019-07-02 16:12:16657 SelectDefaultShippingAddressAndNotifyObservers();
gogerald8189d522017-09-15 17:52:18658
659 journey_logger_->SetNumberOfSuggestionsShown(
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39660 JourneyLogger::Section::SECTION_PAYMENT_METHOD, available_apps().size(),
661 selected_app_);
mathpf1a7a3752017-03-15 11:23:37662}
663
664void PaymentRequestState::UpdateIsReadyToPayAndNotifyObservers() {
665 is_ready_to_pay_ =
666 ArePaymentDetailsSatisfied() && ArePaymentOptionsSatisfied();
667 NotifyOnSelectedInformationChanged();
668}
669
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39670void PaymentRequestState::NotifyOnGetAllPaymentAppsFinished() {
gogerald8189d522017-09-15 17:52:18671 for (auto& observer : observers_)
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39672 observer.OnGetAllPaymentAppsFinished();
gogerald8189d522017-09-15 17:52:18673}
674
mathpf1a7a3752017-03-15 11:23:37675void PaymentRequestState::NotifyOnSelectedInformationChanged() {
676 for (auto& observer : observers_)
677 observer.OnSelectedInformationChanged();
678}
679
680bool PaymentRequestState::ArePaymentDetailsSatisfied() {
mathp363735b2017-03-16 18:08:05681 // There is no need to check for supported networks, because only supported
Rouslan Solomakhin5d15cb1f2019-11-11 18:11:39682 // apps are listed/created in the flow.
683 return selected_app_ != nullptr && selected_app_->IsCompleteForPayment();
mathpf1a7a3752017-03-15 11:23:37684}
685
686bool PaymentRequestState::ArePaymentOptionsSatisfied() {
sebsg7e619132017-04-27 16:07:10687 if (is_waiting_for_merchant_validation_)
688 return false;
689
Sahel Sharifyfef3d922019-09-11 01:41:22690 if (ShouldShowShippingSection() &&
691 (!spec_->selected_shipping_option() ||
692 !profile_comparator()->IsShippingComplete(selected_shipping_profile_))) {
tmartino01c3eb82017-04-29 15:18:39693 return false;
Sahel Sharifyfef3d922019-09-11 01:41:22694 }
tmartino01c3eb82017-04-29 15:18:39695
Sahel Sharifyfef3d922019-09-11 01:41:22696 if (ShouldShowContactSection() &&
697 !profile_comparator()->IsContactInfoComplete(selected_contact_profile_)) {
Anthony Vallee-Duboisa8814672017-06-01 18:43:20698 return false;
Sahel Sharifyfef3d922019-09-11 01:41:22699 }
Anthony Vallee-Duboisa8814672017-06-01 18:43:20700
Sahel Sharifyfef3d922019-09-11 01:41:22701 return true;
mathpf1a7a3752017-03-15 11:23:37702}
703
Mathieu Perreault17c1ae92017-10-20 17:16:00704void PaymentRequestState::OnAddressNormalized(
705 bool success,
706 const autofill::AutofillProfile& normalized_profile) {
707 delegate_->OnShippingAddressSelected(
Tommy Martino21d415f2018-01-12 20:08:22708 data_util::GetPaymentAddressFromAutofillProfile(normalized_profile,
709 app_locale_));
Mathieu Perreault17c1ae92017-10-20 17:16:00710}
711
mathpf1a7a3752017-03-15 11:23:37712} // namespace payments