| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/payments/core/autofill_payment_app.h" |
| |
| #include <algorithm> |
| #include <memory> |
| |
| #include "base/bind.h" |
| #include "base/json/json_writer.h" |
| #include "base/metrics/histogram_functions.h" |
| #include "base/stl_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/values.h" |
| #include "components/autofill/core/browser/autofill_data_util.h" |
| #include "components/autofill/core/browser/autofill_type.h" |
| #include "components/autofill/core/browser/field_types.h" |
| #include "components/autofill/core/browser/geo/autofill_country.h" |
| #include "components/autofill/core/browser/personal_data_manager.h" |
| #include "components/autofill/core/browser/validation.h" |
| #include "components/autofill/core/common/autofill_clock.h" |
| #include "components/payments/core/autofill_card_validation.h" |
| #include "components/payments/core/basic_card_response.h" |
| #include "components/payments/core/features.h" |
| #include "components/payments/core/method_strings.h" |
| #include "components/payments/core/payment_request_base_delegate.h" |
| #include "components/payments/core/payment_request_data_util.h" |
| #include "components/payments/core/payments_experimental_features.h" |
| |
| namespace payments { |
| |
| AutofillPaymentApp::AutofillPaymentApp( |
| const std::string& method_name, |
| const autofill::CreditCard& card, |
| bool matches_merchant_card_type_exactly, |
| const std::vector<autofill::AutofillProfile*>& billing_profiles, |
| const std::string& app_locale, |
| PaymentRequestBaseDelegate* payment_request_delegate) |
| : PaymentApp(autofill::data_util::GetPaymentRequestData(card.network()) |
| .icon_resource_id, |
| PaymentApp::Type::AUTOFILL), |
| method_name_(method_name), |
| credit_card_(card), |
| matches_merchant_card_type_exactly_(matches_merchant_card_type_exactly), |
| billing_profiles_(billing_profiles), |
| app_locale_(app_locale), |
| delegate_(nullptr), |
| payment_request_delegate_(payment_request_delegate) { |
| app_method_names_.insert(methods::kBasicCard); |
| } |
| |
| AutofillPaymentApp::~AutofillPaymentApp() {} |
| |
| void AutofillPaymentApp::InvokePaymentApp(PaymentApp::Delegate* delegate) { |
| DCHECK(delegate); |
| // There can be only one FullCardRequest going on at a time. If |delegate_| is |
| // not null, there's already an active request, which shouldn't happen. |
| // |delegate_| is reset to nullptr when the request succeeds or fails. |
| DCHECK(!delegate_); |
| delegate_ = delegate; |
| |
| // Get the billing address. |
| if (!credit_card_.billing_address_id().empty()) { |
| autofill::AutofillProfile* billing_address = |
| autofill::PersonalDataManager::GetProfileFromProfilesByGUID( |
| credit_card_.billing_address_id(), billing_profiles_); |
| if (billing_address) |
| billing_address_ = *billing_address; |
| } |
| |
| is_waiting_for_billing_address_normalization_ = true; |
| is_waiting_for_card_unmask_ = true; |
| |
| // Start the normalization of the billing address. |
| payment_request_delegate_->GetAddressNormalizer()->NormalizeAddressAsync( |
| billing_address_, /*timeout_seconds=*/5, |
| base::BindOnce(&AutofillPaymentApp::OnAddressNormalized, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| payment_request_delegate_->DoFullCardRequest(credit_card_, |
| weak_ptr_factory_.GetWeakPtr()); |
| } |
| |
| bool AutofillPaymentApp::IsCompleteForPayment() const { |
| // COMPLETE or EXPIRED cards are considered valid for payment. The user will |
| // be prompted to enter the new expiration at the CVC step. |
| return GetCompletionStatusForCard(credit_card_, app_locale_, |
| billing_profiles_) <= CREDIT_CARD_EXPIRED; |
| } |
| |
| uint32_t AutofillPaymentApp::GetCompletenessScore() const { |
| return ::payments::GetCompletenessScore(credit_card_, app_locale_, |
| billing_profiles_); |
| } |
| |
| bool AutofillPaymentApp::CanPreselect() const { |
| return IsCompleteForPayment() && matches_merchant_card_type_exactly_; |
| } |
| |
| bool AutofillPaymentApp::IsExactlyMatchingMerchantRequest() const { |
| return matches_merchant_card_type_exactly_; |
| } |
| |
| base::string16 AutofillPaymentApp::GetMissingInfoLabel() const { |
| return GetCompletionMessageForCard( |
| GetCompletionStatusForCard(credit_card_, app_locale_, billing_profiles_)); |
| } |
| |
| bool AutofillPaymentApp::IsValidForCanMakePayment() const { |
| CreditCardCompletionStatus status = |
| GetCompletionStatusForCard(credit_card_, app_locale_, billing_profiles_); |
| if (PaymentsExperimentalFeatures::IsEnabled( |
| features::kStrictHasEnrolledAutofillInstrument)) { |
| return status == CREDIT_CARD_COMPLETE && |
| is_requested_autofill_data_available_; |
| } |
| |
| // Card has to have a cardholder name and number for the purposes of |
| // CanMakePayment. An expired card is still valid at this stage. |
| return !(status & CREDIT_CARD_NO_CARDHOLDER || |
| status & CREDIT_CARD_NO_NUMBER); |
| } |
| |
| void AutofillPaymentApp::RecordUse() { |
| // Record the use of the credit card. |
| payment_request_delegate_->GetPersonalDataManager()->RecordUseOf( |
| credit_card_); |
| } |
| |
| base::string16 AutofillPaymentApp::GetLabel() const { |
| return credit_card_.NetworkAndLastFourDigits(); |
| } |
| |
| base::string16 AutofillPaymentApp::GetSublabel() const { |
| return credit_card_.GetInfo( |
| autofill::AutofillType(autofill::CREDIT_CARD_NAME_FULL), app_locale_); |
| } |
| |
| bool AutofillPaymentApp::IsValidForModifier( |
| const std::string& method, |
| bool supported_networks_specified, |
| const std::set<std::string>& supported_networks, |
| bool supported_types_specified, |
| const std::set<autofill::CreditCard::CardType>& supported_types) const { |
| bool is_valid = false; |
| IsValidForPaymentMethodIdentifier(method, &is_valid); |
| if (!is_valid) |
| return false; |
| |
| // If supported_types is not specified and this instrument matches the method, |
| // the modifier is applicable. If supported_types is populated, it must |
| // contain this card's type to be applicable. The same is true for |
| // supported_networks. |
| if (supported_types_specified) { |
| // supported_types may contain CARD_TYPE_UNKNOWN because of the parsing |
| // function so the local card only matches if it's because the website |
| // didn't specify types (meaning they don't care). |
| if (credit_card_.card_type() == |
| autofill::CreditCard::CardType::CARD_TYPE_UNKNOWN) { |
| return false; |
| } |
| |
| if (supported_types.find(credit_card_.card_type()) == supported_types.end()) |
| return false; |
| } |
| |
| if (supported_networks_specified) { |
| std::string basic_card_network = |
| autofill::data_util::GetPaymentRequestData(credit_card_.network()) |
| .basic_card_issuer_network; |
| if (supported_networks.find(basic_card_network) == supported_networks.end()) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| base::WeakPtr<PaymentApp> AutofillPaymentApp::AsWeakPtr() { |
| return weak_ptr_factory_.GetWeakPtr(); |
| } |
| |
| bool AutofillPaymentApp::HandlesShippingAddress() const { |
| return false; |
| } |
| |
| bool AutofillPaymentApp::HandlesPayerName() const { |
| return false; |
| } |
| |
| bool AutofillPaymentApp::HandlesPayerEmail() const { |
| return false; |
| } |
| |
| bool AutofillPaymentApp::HandlesPayerPhone() const { |
| return false; |
| } |
| |
| void AutofillPaymentApp::OnFullCardRequestSucceeded( |
| const autofill::payments::FullCardRequest& /* full_card_request */, |
| const autofill::CreditCard& card, |
| const base::string16& cvc) { |
| DCHECK(delegate_); |
| credit_card_ = card; |
| cvc_ = cvc; |
| is_waiting_for_card_unmask_ = false; |
| |
| if (!is_waiting_for_billing_address_normalization_) |
| GenerateBasicCardResponse(); |
| } |
| |
| void AutofillPaymentApp::OnFullCardRequestFailed() { |
| // The user may have cancelled the unmask or something has gone wrong (e.g., |
| // the network request failed). In all cases, reset the |delegate_| so another |
| // request can start. |
| delegate_ = nullptr; |
| } |
| |
| void AutofillPaymentApp::RecordMissingFieldsForApp() const { |
| CreditCardCompletionStatus completion_status = |
| GetCompletionStatusForCard(credit_card_, app_locale_, billing_profiles_); |
| if (completion_status == CREDIT_CARD_COMPLETE && |
| matches_merchant_card_type_exactly_) { |
| return; |
| } |
| |
| // Record cases that the card type does not match the requested type(s) in |
| // addititon to missing fields from card completion status. |
| base::UmaHistogramSparse( |
| "PaymentRequest.MissingPaymentFields", |
| completion_status | |
| (matches_merchant_card_type_exactly_ ? 0 |
| : CREDIT_CARD_TYPE_MISMATCH)); |
| } |
| |
| void AutofillPaymentApp::GenerateBasicCardResponse() { |
| DCHECK(!is_waiting_for_billing_address_normalization_); |
| DCHECK(!is_waiting_for_card_unmask_); |
| DCHECK(delegate_); |
| |
| std::unique_ptr<base::DictionaryValue> response_value = |
| payments::data_util::GetBasicCardResponseFromAutofillCreditCard( |
| credit_card_, cvc_, billing_address_, app_locale_) |
| ->ToDictionaryValue(); |
| std::string stringified_details; |
| base::JSONWriter::Write(*response_value, &stringified_details); |
| delegate_->OnInstrumentDetailsReady(method_name_, stringified_details, |
| PayerData()); |
| |
| delegate_ = nullptr; |
| cvc_ = base::UTF8ToUTF16(""); |
| } |
| |
| void AutofillPaymentApp::OnAddressNormalized( |
| bool success, |
| const autofill::AutofillProfile& normalized_profile) { |
| DCHECK(is_waiting_for_billing_address_normalization_); |
| |
| billing_address_ = normalized_profile; |
| is_waiting_for_billing_address_normalization_ = false; |
| |
| if (!is_waiting_for_card_unmask_) |
| GenerateBasicCardResponse(); |
| } |
| |
| } // namespace payments |