Commit 363735b9 authored by mathp's avatar mathp Committed by Commit bot

[Payments] Use PaymentInstrument/AutofillPaymentInstrument throughout.

Limit the concept of CreditCard to PaymentRequestState (when creating
instruments) and the Credit Card editor.

BUG=702061
TEST=Existing

Review-Url: https://codereview.chromium.org/2757523002
Cr-Commit-Position: refs/heads/master@{#457491}
parent 3226ce85
......@@ -129,8 +129,10 @@ CreditCardEditorViewController::CreateHeaderView() {
const std::string autofill_card_type =
autofill::data_util::GetCardTypeForBasicCardPaymentType(
supported_network);
std::unique_ptr<views::ImageView> card_icon_view =
CreateCardIconView(autofill_card_type);
std::unique_ptr<views::ImageView> card_icon_view = CreateInstrumentIconView(
autofill::data_util::GetPaymentRequestData(autofill_card_type)
.icon_resource_id,
base::UTF8ToUTF16(supported_network));
card_icon_view->SetImageSize(kCardIconSize);
icons_row->AddChildView(card_icon_view.release());
......
......@@ -14,9 +14,8 @@
#include "chrome/browser/ui/views/payments/payment_request_row_view.h"
#include "chrome/browser/ui/views/payments/payment_request_views_util.h"
#include "chrome/grit/generated_resources.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/credit_card.h"
#include "components/payments/content/payment_request_state.h"
#include "components/payments/core/payment_instrument.h"
#include "components/strings/grit/components_strings.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/l10n/l10n_util.h"
......@@ -42,16 +41,16 @@ enum class PaymentMethodViewControllerTags : int {
class PaymentMethodListItem : public payments::PaymentRequestItemList::Item {
public:
// Does not take ownership of |card|, which should not be null and should
// outlive this object. |list| is the PaymentRequestItemList object that will
// own this.
PaymentMethodListItem(autofill::CreditCard* card,
// Does not take ownership of |instrument|, which should not be null and
// should outlive this object. |list| is the PaymentRequestItemList object
// that will own this.
PaymentMethodListItem(PaymentInstrument* instrument,
PaymentRequestSpec* spec,
PaymentRequestState* state,
PaymentRequestItemList* list,
bool selected)
: payments::PaymentRequestItemList::Item(spec, state, list, selected),
card_(card) {}
instrument_(instrument) {}
~PaymentMethodListItem() override {}
private:
......@@ -100,11 +99,9 @@ class PaymentMethodListItem : public payments::PaymentRequestItemList::Item {
views::BoxLayout::CROSS_AXIS_ALIGNMENT_START);
card_info_container->SetLayoutManager(box_layout.release());
card_info_container->AddChildView(new views::Label(instrument_->label()));
card_info_container->AddChildView(
new views::Label(card_->TypeAndLastFourDigits()));
card_info_container->AddChildView(new views::Label(
card_->GetInfo(autofill::AutofillType(autofill::CREDIT_CARD_NAME_FULL),
g_browser_process->GetApplicationLocale())));
new views::Label(instrument_->sublabel()));
// TODO(anthonyvd): Add the "card is incomplete" label once the
// completedness logic is implemented.
layout->AddView(card_info_container.release());
......@@ -112,8 +109,8 @@ class PaymentMethodListItem : public payments::PaymentRequestItemList::Item {
checkmark_ = CreateCheckmark(selected());
layout->AddView(checkmark_.get());
std::unique_ptr<views::ImageView> card_icon_view =
CreateCardIconView(card_->type());
std::unique_ptr<views::ImageView> card_icon_view = CreateInstrumentIconView(
instrument_->icon_resource_id(), instrument_->label());
card_icon_view->SetImageSize(gfx::Size(32, 20));
layout->AddView(card_icon_view.release());
......@@ -126,7 +123,7 @@ class PaymentMethodListItem : public payments::PaymentRequestItemList::Item {
if (checkmark_)
checkmark_->SetVisible(selected());
state()->SetSelectedCreditCard(card_);
state()->SetSelectedInstrument(instrument_);
}
// views::ButtonListener:
......@@ -145,7 +142,7 @@ class PaymentMethodListItem : public payments::PaymentRequestItemList::Item {
return true;
}
autofill::CreditCard* card_;
PaymentInstrument* instrument_;
std::unique_ptr<views::ImageView> checkmark_;
DISALLOW_COPY_AND_ASSIGN(PaymentMethodListItem);
......@@ -158,14 +155,15 @@ PaymentMethodViewController::PaymentMethodViewController(
PaymentRequestState* state,
PaymentRequestDialogView* dialog)
: PaymentRequestSheetController(spec, state, dialog) {
const std::vector<autofill::CreditCard*>& available_cards =
state->credit_cards();
const std::vector<std::unique_ptr<PaymentInstrument>>& available_instruments =
state->available_instruments();
for (autofill::CreditCard* card : available_cards) {
for (const std::unique_ptr<PaymentInstrument>& instrument :
available_instruments) {
std::unique_ptr<PaymentMethodListItem> item =
base::MakeUnique<PaymentMethodListItem>(
card, spec, state, &payment_method_list_,
card == state->selected_credit_card());
instrument.get(), spec, state, &payment_method_list_,
instrument.get() == state->selected_instrument());
payment_method_list_.AddItem(std::move(item));
}
}
......
......@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/views/payments/payment_request_browsertest_base.h"
#include "chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
......@@ -39,15 +40,16 @@ IN_PROC_BROWSER_TEST_F(PaymentMethodViewControllerTest, OneCardSelected) {
InvokePaymentRequestUI();
OpenPaymentMethodScreen();
PaymentRequest* request = GetPaymentRequests(GetActiveWebContents())[0];
EXPECT_EQ(1U, request->state()->credit_cards().size());
PaymentRequest* request = GetPaymentRequests(GetActiveWebContents()).front();
EXPECT_EQ(1U, request->state()->available_instruments().size());
views::View* list_view = dialog_view()->GetViewByID(
static_cast<int>(DialogViewID::PAYMENT_METHOD_SHEET_LIST_VIEW));
EXPECT_TRUE(list_view);
EXPECT_EQ(1, list_view->child_count());
EXPECT_EQ(card, *request->state()->selected_credit_card());
EXPECT_EQ(request->state()->available_instruments().front().get(),
request->state()->selected_instrument());
views::View* checkmark_view = list_view->child_at(0)->GetViewByID(
static_cast<int>(DialogViewID::CHECKMARK_VIEW));
EXPECT_TRUE(checkmark_view->visible());
......@@ -60,23 +62,27 @@ IN_PROC_BROWSER_TEST_F(PaymentMethodViewControllerTest,
card1.set_use_count(5U);
AddCreditCard(card1);
autofill::CreditCard card2 = autofill::test::GetCreditCard2();
// Slightly different visa.
autofill::CreditCard card2 = autofill::test::GetCreditCard();
card2.SetNumber(base::ASCIIToUTF16("4111111111111112"));
card2.set_use_count(1U);
AddCreditCard(card2);
InvokePaymentRequestUI();
OpenPaymentMethodScreen();
PaymentRequest* request = GetPaymentRequests(GetActiveWebContents())[0];
EXPECT_EQ(2U, request->state()->credit_cards().size());
EXPECT_EQ(card1, *request->state()->selected_credit_card());
PaymentRequest* request = GetPaymentRequests(GetActiveWebContents()).front();
EXPECT_EQ(2U, request->state()->available_instruments().size());
EXPECT_EQ(request->state()->available_instruments().front().get(),
request->state()->selected_instrument());
views::View* list_view = dialog_view()->GetViewByID(
static_cast<int>(DialogViewID::PAYMENT_METHOD_SHEET_LIST_VIEW));
EXPECT_TRUE(list_view);
EXPECT_EQ(2, list_view->child_count());
EXPECT_EQ(card1, *request->state()->selected_credit_card());
EXPECT_EQ(request->state()->available_instruments().front().get(),
request->state()->selected_instrument());
views::View* checkmark_view = list_view->child_at(0)->GetViewByID(
static_cast<int>(DialogViewID::CHECKMARK_VIEW));
EXPECT_TRUE(checkmark_view->visible());
......@@ -88,14 +94,16 @@ IN_PROC_BROWSER_TEST_F(PaymentMethodViewControllerTest,
// Simulate selecting the second card.
ClickOnDialogViewAndWait(list_view->child_at(1));
EXPECT_EQ(card2, *request->state()->selected_credit_card());
EXPECT_EQ(request->state()->available_instruments().back().get(),
request->state()->selected_instrument());
EXPECT_FALSE(checkmark_view->visible());
EXPECT_TRUE(checkmark_view2->visible());
// Clicking on the second card again should not modify any state.
ClickOnDialogViewAndWait(list_view->child_at(1));
EXPECT_EQ(card2, *request->state()->selected_credit_card());
EXPECT_EQ(request->state()->available_instruments().back().get(),
request->state()->selected_instrument());
EXPECT_FALSE(checkmark_view->visible());
EXPECT_TRUE(checkmark_view2->visible());
}
......
......@@ -170,18 +170,16 @@ std::unique_ptr<views::View> CreateSheetHeaderView(
return container;
}
std::unique_ptr<views::ImageView> CreateCardIconView(
const std::string& card_type) {
std::unique_ptr<views::ImageView> CreateInstrumentIconView(
int icon_resource_id,
const base::string16& tooltip_text) {
std::unique_ptr<views::ImageView> card_icon_view =
base::MakeUnique<views::ImageView>();
card_icon_view->set_can_process_events_within_subtree(false);
card_icon_view->SetImage(
ResourceBundle::GetSharedInstance()
.GetImageNamed(autofill::data_util::GetPaymentRequestData(card_type)
.icon_resource_id)
.AsImageSkia());
card_icon_view->SetTooltipText(
autofill::CreditCard::TypeForDisplay(card_type));
card_icon_view->SetImage(ResourceBundle::GetSharedInstance()
.GetImageNamed(icon_resource_id)
.AsImageSkia());
card_icon_view->SetTooltipText(tooltip_text);
card_icon_view->SetBorder(views::CreateRoundedRectBorder(
1, 3, card_icon_view->GetNativeTheme()->GetSystemColor(
ui::NativeTheme::kColorId_UnfocusedBorderColor)));
......
......@@ -55,10 +55,12 @@ std::unique_ptr<views::View> CreateSheetHeaderView(
const base::string16& title,
views::VectorIconButtonDelegate* delegate);
// Returns a card image view for the given |card_type|. Includes a rounded rect
// border. Callers need to set the size of the resulting ImageView.
std::unique_ptr<views::ImageView> CreateCardIconView(
const std::string& card_type);
// Returns an instrument image view for the given |icon_resource_id|. Includes
// a rounded rect border. Callers need to set the size of the resulting
// ImageView. Callers should set a |tooltip_text|.
std::unique_ptr<views::ImageView> CreateInstrumentIconView(
int icon_resource_id,
const base::string16& tooltip_text);
// Represents formatting options for each of the different contexts in which an
// Address label may be displayed.
......
......@@ -23,13 +23,12 @@
#include "chrome/grit/chromium_strings.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/grit/theme_resources.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/credit_card.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/payments/content/payment_request_spec.h"
#include "components/payments/content/payment_request_state.h"
#include "components/payments/core/currency_formatter.h"
#include "components/payments/core/payment_instrument.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/web_contents.h"
#include "ui/base/l10n/l10n_util.h"
......@@ -438,11 +437,11 @@ std::unique_ptr<views::Button> PaymentSheetViewController::CreateShippingRow() {
// +----------------------------------------------+
std::unique_ptr<views::Button>
PaymentSheetViewController::CreatePaymentMethodRow() {
autofill::CreditCard* selected_card = state()->selected_credit_card();
PaymentInstrument* selected_instrument = state()->selected_instrument();
std::unique_ptr<views::View> content_view;
std::unique_ptr<views::ImageView> card_icon_view;
if (selected_card) {
if (selected_instrument) {
content_view = base::MakeUnique<views::View>();
views::GridLayout* layout = new views::GridLayout(content_view.get());
......@@ -452,14 +451,12 @@ PaymentSheetViewController::CreatePaymentMethodRow() {
1, views::GridLayout::USE_PREF, 0, 0);
layout->StartRow(0, 0);
layout->AddView(new views::Label(selected_card->TypeAndLastFourDigits()));
layout->AddView(new views::Label(selected_instrument->label()));
layout->StartRow(0, 0);
layout->AddView(new views::Label(
selected_card->GetInfo(
autofill::AutofillType(autofill::CREDIT_CARD_NAME_FULL),
g_browser_process->GetApplicationLocale())));
layout->AddView(new views::Label(selected_instrument->sublabel()));
card_icon_view = CreateCardIconView(selected_card->type());
card_icon_view = CreateInstrumentIconView(
selected_instrument->icon_resource_id(), selected_instrument->label());
card_icon_view->SetImageSize(gfx::Size(32, 20));
}
......
......@@ -125,8 +125,6 @@ void PaymentRequest::OnConnectionTerminated() {
}
void PaymentRequest::Pay() {
DCHECK(state_->is_ready_to_pay());
state_->GeneratePaymentResponse();
}
......
......@@ -124,6 +124,9 @@ void PaymentRequestSpec::PopulateValidatedMethodData(
}
}
}
supported_card_networks_set_.insert(supported_card_networks_.begin(),
supported_card_networks_.end());
}
void PaymentRequestSpec::NotifyOnInvalidSpecProvided() {
......
......@@ -5,6 +5,7 @@
#ifndef COMPONENTS_PAYMENTS_CONTENT_PAYMENT_REQUEST_SPEC_H_
#define COMPONENTS_PAYMENTS_CONTENT_PAYMENT_REQUEST_SPEC_H_
#include <set>
#include <string>
#include <vector>
......@@ -46,9 +47,12 @@ class PaymentRequestSpec {
bool request_payer_phone() const { return options_->request_payer_phone; }
bool request_payer_email() const { return options_->request_payer_email; }
const std::vector<std::string>& supported_card_networks() {
const std::vector<std::string>& supported_card_networks() const {
return supported_card_networks_;
}
const std::set<std::string>& supported_card_networks_set() const {
return supported_card_networks_set_;
}
// Uses CurrencyFormatter to format |amount| with the currency symbol for this
// request's currency. Will use currency of the "total" display item, because
......@@ -85,9 +89,11 @@ class PaymentRequestSpec {
const std::string app_locale_;
std::unique_ptr<CurrencyFormatter> currency_formatter_;
// A list of supported basic card networks, in order that they were specified
// by the merchant.
// A list/set of supported basic card networks. The list is used to keep the
// order in which they were specified by the merchant. The set is used for
// fast lookup of supported methods.
std::vector<std::string> supported_card_networks_;
std::set<std::string> supported_card_networks_set_;
base::ObserverList<Observer> observers_;
......
......@@ -13,11 +13,6 @@
namespace payments {
namespace {
// Identifier for the basic card payment method in the PaymentMethodData.
static const char* const kBasicCardMethodName = "basic-card";
} // namespace
PaymentRequestState::PaymentRequestState(
PaymentRequestSpec* spec,
Delegate* delegate,
......@@ -30,7 +25,7 @@ PaymentRequestState::PaymentRequestState(
personal_data_manager_(personal_data_manager),
selected_shipping_profile_(nullptr),
selected_contact_profile_(nullptr),
selected_credit_card_(nullptr),
selected_instrument_(nullptr),
selected_shipping_option_(nullptr) {
PopulateProfileCache();
UpdateSelectedShippingOption();
......@@ -59,16 +54,10 @@ void PaymentRequestState::OnInstrumentDetailsReady(
}
void PaymentRequestState::GeneratePaymentResponse() {
// TODO(mathp): PaymentRequest should know about the currently selected
// instrument, and not |selected_credit_card_| which is too specific.
// TODO(mathp): The method_name should reflect what the merchant asked, and
// not necessarily basic-card.
selected_payment_instrument_.reset(new AutofillPaymentInstrument(
kBasicCardMethodName, *selected_credit_card_, shipping_profiles_,
app_locale_));
DCHECK(is_ready_to_pay());
// Fetch the instrument details, will call back into
// PaymentRequest::OnInstrumentsDetailsReady.
selected_payment_instrument_->InvokePaymentApp(this);
selected_instrument_->InvokePaymentApp(this);
}
void PaymentRequestState::SetSelectedShippingProfile(
......@@ -83,8 +72,8 @@ void PaymentRequestState::SetSelectedContactProfile(
UpdateIsReadyToPayAndNotifyObservers();
}
void PaymentRequestState::SetSelectedCreditCard(autofill::CreditCard* card) {
selected_credit_card_ = card;
void PaymentRequestState::SetSelectedInstrument(PaymentInstrument* instrument) {
selected_instrument_ = instrument;
UpdateIsReadyToPayAndNotifyObservers();
}
......@@ -113,11 +102,27 @@ void PaymentRequestState::PopulateProfileCache() {
contact_profiles_.push_back(profile_cache_[i].get());
}
// Create the list of available instruments.
const std::vector<autofill::CreditCard*>& cards =
personal_data_manager_->GetCreditCardsToSuggest();
const std::set<std::string>& supported_card_networks =
spec_->supported_card_networks_set();
for (autofill::CreditCard* card : cards) {
card_cache_.push_back(base::MakeUnique<autofill::CreditCard>(*card));
credit_cards_.push_back(card_cache_.back().get());
std::string basic_card_network =
autofill::data_util::GetPaymentRequestData(card->type())
.basic_card_payment_type;
if (!supported_card_networks.count(basic_card_network))
continue;
// TODO(crbug.com/701952): Should use the method name preferred by the
// merchant (either "basic-card" or the basic card network e.g. "visa").
// Copy the credit cards as part of AutofillPaymentInstrument so they are
// indirectly owned by this object.
std::unique_ptr<PaymentInstrument> instrument =
base::MakeUnique<AutofillPaymentInstrument>(
basic_card_network, *card, shipping_profiles_, app_locale_);
available_instruments_.push_back(std::move(instrument));
}
}
......@@ -128,15 +133,20 @@ void PaymentRequestState::SetDefaultProfileSelections() {
if (!contact_profiles().empty())
selected_contact_profile_ = contact_profiles()[0];
// TODO(anthonyvd): Change this code to prioritize server cards and implement
// a way to modify this function's return value.
const std::vector<autofill::CreditCard*> cards = credit_cards();
auto first_complete_card =
std::find_if(cards.begin(), cards.end(),
[](autofill::CreditCard* card) { return card->IsValid(); });
selected_credit_card_ =
first_complete_card == cards.end() ? nullptr : *first_complete_card;
// TODO(crbug.com/702063): Change this code to prioritize instruments by use
// count and other means, and implement a way to modify this function's return
// value.
const std::vector<std::unique_ptr<PaymentInstrument>>& instruments =
available_instruments();
auto first_complete_instrument =
std::find_if(instruments.begin(), instruments.end(),
[](const std::unique_ptr<PaymentInstrument>& instrument) {
return instrument->IsValid();
});
selected_instrument_ = first_complete_instrument == instruments.end()
? nullptr
: first_complete_instrument->get();
UpdateIsReadyToPayAndNotifyObservers();
}
......@@ -153,18 +163,10 @@ void PaymentRequestState::NotifyOnSelectedInformationChanged() {
}
bool PaymentRequestState::ArePaymentDetailsSatisfied() {
// TODO(mathp): A masked card may not satisfy IsValid().
if (selected_credit_card_ == nullptr || !selected_credit_card_->IsValid())
return false;
const std::string basic_card_payment_type =
autofill::data_util::GetPaymentRequestData(selected_credit_card_->type())
.basic_card_payment_type;
return !spec_->supported_card_networks().empty() &&
std::find(spec_->supported_card_networks().begin(),
spec_->supported_card_networks().end(),
basic_card_payment_type) !=
spec_->supported_card_networks().end();
// There is no need to check for supported networks, because only supported
// instruments are listed/created in the flow.
// TODO(crbug.com/702063): A masked card may not satisfy IsValid().
return selected_instrument_ != nullptr && selected_instrument_->IsValid();
}
bool PaymentRequestState::ArePaymentOptionsSatisfied() {
......
......@@ -12,7 +12,6 @@
namespace autofill {
class AutofillProfile;
class CreditCard;
class PersonalDataManager;
} // namespace autofill
......@@ -76,11 +75,11 @@ class PaymentRequestState : public PaymentInstrument::Delegate {
autofill::AutofillProfile* selected_contact_profile() const {
return selected_contact_profile_;
}
// Returns the currently selected credit card for this PaymentRequest flow.
// Returns the currently selected instrument for this PaymentRequest flow.
// It's not guaranteed to be complete. Returns nullptr if there is no selected
// card.
autofill::CreditCard* selected_credit_card() const {
return selected_credit_card_;
// instrument.
PaymentInstrument* selected_instrument() const {
return selected_instrument_;
}
mojom::PaymentShippingOption* selected_shipping_option() {
return selected_shipping_option_;
......@@ -94,15 +93,16 @@ class PaymentRequestState : public PaymentInstrument::Delegate {
const std::vector<autofill::AutofillProfile*>& contact_profiles() {
return contact_profiles_;
}
const std::vector<autofill::CreditCard*>& credit_cards() {
return credit_cards_;
const std::vector<std::unique_ptr<PaymentInstrument>>&
available_instruments() {
return available_instruments_;
}
// Setters to change the selected information. Will have the side effect of
// recomputing "is ready to pay" and notify observers.
void SetSelectedShippingProfile(autofill::AutofillProfile* profile);
void SetSelectedContactProfile(autofill::AutofillProfile* profile);
void SetSelectedCreditCard(autofill::CreditCard* card);
void SetSelectedInstrument(PaymentInstrument* instrument);
bool is_ready_to_pay() { return is_ready_to_pay_; }
......@@ -115,7 +115,7 @@ class PaymentRequestState : public PaymentInstrument::Delegate {
// profile_cache_.
void PopulateProfileCache();
// Sets the initial selections for credit card and profiles, and notifies
// Sets the initial selections for instruments and profiles, and notifies
// observers.
void SetDefaultProfileSelections();
......@@ -150,21 +150,19 @@ class PaymentRequestState : public PaymentInstrument::Delegate {
autofill::AutofillProfile* selected_shipping_profile_;
autofill::AutofillProfile* selected_contact_profile_;
autofill::CreditCard* selected_credit_card_;
PaymentInstrument* selected_instrument_;
// The shipping options (and thus this pointer) are owned by |spec_| which
// outlives this object.
mojom::PaymentShippingOption* selected_shipping_option_;
std::unique_ptr<PaymentInstrument> selected_payment_instrument_;
// Profiles may change due to (e.g.) sync events, so profiles are cached after
// loading and owned here. They are populated once only, and ordered by
// frecency.
std::vector<std::unique_ptr<autofill::AutofillProfile>> profile_cache_;
std::vector<autofill::AutofillProfile*> shipping_profiles_;
std::vector<autofill::AutofillProfile*> contact_profiles_;
std::vector<std::unique_ptr<autofill::CreditCard>> card_cache_;
std::vector<autofill::CreditCard*> credit_cards_;
// Credit cards are directly owned by the instruments in this list.
std::vector<std::unique_ptr<PaymentInstrument>> available_instruments_;
base::ObserverList<Observer> observers_;
......
......@@ -24,10 +24,15 @@ class PaymentRequestStateTest : public testing::Test,
PaymentRequestStateTest()
: num_on_selected_information_changed_called_(0),
address_(autofill::test::GetFullProfile()),
credit_card_(autofill::test::GetCreditCard()) {
credit_card_visa_(autofill::test::GetCreditCard()),
credit_card_amex_(autofill::test::GetCreditCard2()) {
test_personal_data_manager_.AddTestingProfile(&address_);
credit_card_.set_billing_address_id(address_.guid());
test_personal_data_manager_.AddTestingCreditCard(&credit_card_);
credit_card_visa_.set_billing_address_id(address_.guid());
credit_card_visa_.set_use_count(5u);
test_personal_data_manager_.AddTestingCreditCard(&credit_card_visa_);
credit_card_amex_.set_billing_address_id(address_.guid());
credit_card_amex_.set_use_count(1u);
test_personal_data_manager_.AddTestingCreditCard(&credit_card_amex_);
}
~PaymentRequestStateTest() override {}
......@@ -86,7 +91,6 @@ class PaymentRequestStateTest : public testing::Test,
}
autofill::AutofillProfile* test_address() { return &address_; }
autofill::CreditCard* test_credit_card() { return &credit_card_; }
private:
std::unique_ptr<PaymentRequestState> state_;
......@@ -97,7 +101,8 @@ class PaymentRequestStateTest : public testing::Test,
// Test data.
autofill::AutofillProfile address_;
autofill::CreditCard credit_card_;
autofill::CreditCard credit_card_visa_;
autofill::CreditCard credit_card_amex_;
};
// Test that the last shipping option is selected.
......@@ -133,28 +138,18 @@ TEST_F(PaymentRequestStateTest, ReadyToPay_DefaultSelections) {
EXPECT_TRUE(state()->is_ready_to_pay());
}
// Testing that the card is supported when determining "is ready to pay". In
// this test the merchant only supports Visa.
TEST_F(PaymentRequestStateTest, ReadyToPay_SelectUnsupportedCard) {
// Testing that only supported intruments are shown. In this test the merchant
// only supports Visa.
TEST_F(PaymentRequestStateTest, UnsupportedCardAreNotAvailable) {
// Default options.
RecreateStateWithOptions(mojom::PaymentOptions::New());
// Ready to pay because the default card is selected and supported.
// Ready to pay because the default instrument is selected and supported.
EXPECT_TRUE(state()->is_ready_to_pay());
autofill::CreditCard amex_card = autofill::test::GetCreditCard2(); // Amex.
state()->SetSelectedCreditCard(&amex_card);
EXPECT_EQ(1, num_on_selected_information_changed_called());
// Not ready to pay because the card is not supported.
EXPECT_FALSE(state()->is_ready_to_pay());
// Go back to the Visa card.
state()->SetSelectedCreditCard(test_credit_card()); // Visa card.
EXPECT_EQ(2, num_on_selected_information_changed_called());
// Visa card is supported by the merchant.
EXPECT_TRUE(state()->is_ready_to_pay());
// There's only one instrument available, even though there's an Amex in
// PersonalDataManager.
EXPECT_EQ(1u, state()->available_instruments().size());
}
// Test selecting a contact info profile will make the user ready to pay.
......@@ -185,13 +180,13 @@ TEST_F(PaymentRequestStateTest, ReadyToPay_ContactInfo) {
TEST_F(PaymentRequestStateTest, GeneratePaymentResponse) {
// Default options (no shipping, no contact info).
RecreateStateWithOptions(mojom::PaymentOptions::New());
state()->SetSelectedCreditCard(test_credit_card());
state()->SetSelectedInstrument(state()->available_instruments()[0].get());
EXPECT_EQ(1, num_on_selected_information_changed_called());
EXPECT_TRUE(state()->is_ready_to_pay());
// TODO(mathp): Currently synchronous, when async will need a RunLoop.
state()->GeneratePaymentResponse();
EXPECT_EQ("basic-card", response()->method_name);
EXPECT_EQ("visa", response()->method_name);
EXPECT_EQ(
"{\"billingAddress\":"
"{\"addressLine\":[\"666 Erebus St.\",\"Apt 8\"],"
......
......@@ -14,6 +14,7 @@ static_library("core") {
"currency_formatter.h",
"payment_address.cc",
"payment_address.h",
"payment_instrument.cc",
"payment_instrument.h",
"payment_request_data_util.cc",
"payment_request_data_util.h",
......
......@@ -15,11 +15,18 @@ namespace payments {
AutofillPaymentInstrument::AutofillPaymentInstrument(
const std::string& method_name,
const autofill::CreditCard& credit_card,
const autofill::CreditCard& card,
const std::vector<autofill::AutofillProfile*>& billing_profiles,
const std::string& app_locale)
: PaymentInstrument(method_name),
credit_card_(credit_card),
: PaymentInstrument(
method_name,
/* label= */ card.TypeAndLastFourDigits(),
/* sublabel= */
card.GetInfo(autofill::AutofillType(autofill::CREDIT_CARD_NAME_FULL),
app_locale),
autofill::data_util::GetPaymentRequestData(card.type())
.icon_resource_id),
credit_card_(card),
billing_profiles_(billing_profiles),
app_locale_(app_locale) {}
AutofillPaymentInstrument::~AutofillPaymentInstrument() {}
......@@ -39,4 +46,8 @@ void AutofillPaymentInstrument::InvokePaymentApp(
delegate->OnInstrumentDetailsReady(method_name(), stringified_details);
}
bool AutofillPaymentInstrument::IsValid() {
return credit_card_.IsValid();
}
} // namespace payments
......@@ -26,17 +26,21 @@ class AutofillPaymentInstrument : public PaymentInstrument {
// |billing_profiles| is owned by the caller and should outlive this object.
AutofillPaymentInstrument(
const std::string& method_name,
const autofill::CreditCard& credit_card,
const autofill::CreditCard& card,
const std::vector<autofill::AutofillProfile*>& billing_profiles,
const std::string& app_locale);
~AutofillPaymentInstrument() override;
// PaymentInstrument:
void InvokePaymentApp(PaymentInstrument::Delegate* delegate) override;
bool IsValid() override;
private:
// A copy of the card is owned by this object.
const autofill::CreditCard credit_card_;
// Not owned by this object, should outlive this.
const std::vector<autofill::AutofillProfile*>& billing_profiles_;
const std::string app_locale_;
DISALLOW_COPY_AND_ASSIGN(AutofillPaymentInstrument);
......
// 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/payment_instrument.h"
namespace payments {
PaymentInstrument::PaymentInstrument(const std::string& method_name,
const base::string16& label,
const base::string16& sublabel,
int icon_resource_id)
: method_name_(method_name),
label_(label),
sublabel_(sublabel),
icon_resource_id_(icon_resource_id) {}
PaymentInstrument::~PaymentInstrument() {}
} // namespace payments
......@@ -9,6 +9,7 @@
#include <string>
#include "base/macros.h"
#include "base/strings/string16.h"
namespace payments {
......@@ -28,19 +29,29 @@ class PaymentInstrument {
virtual void OnInstrumentDetailsError() = 0;
};
virtual ~PaymentInstrument() {}
virtual ~PaymentInstrument();
// Will call into the |delegate| (can't be null) on success or error.
virtual void InvokePaymentApp(Delegate* delegate) = 0;
// Returns true if the card is valid to be used as a payment method.
virtual bool IsValid() = 0;
const std::string& method_name() { return method_name_; }
const std::string& method_name() const { return method_name_; }
const base::string16& label() const { return label_; }
const base::string16& sublabel() const { return sublabel_; }
int icon_resource_id() const { return icon_resource_id_; }
protected:
explicit PaymentInstrument(const std::string& method_name)
: method_name_(method_name) {}
PaymentInstrument(const std::string& method_name,
const base::string16& label,
const base::string16& sublabel,
int icon_resource_id);
private:
const std::string method_name_;
const base::string16 label_;
const base::string16 sublabel_;
int icon_resource_id_;
DISALLOW_COPY_AND_ASSIGN(PaymentInstrument);
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment