blob: e37422a29b5afde56cb0d64d326b375cf2faab20 [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
7#include "components/autofill/core/browser/autofill_data_util.h"
8#include "components/autofill/core/browser/autofill_profile.h"
9#include "components/autofill/core/browser/credit_card.h"
mathpc0d616a2017-03-15 14:09:3310#include "components/autofill/core/browser/personal_data_manager.h"
mathpf1a7a3752017-03-15 11:23:3711#include "components/payments/content/payment_request_spec.h"
12#include "components/payments/core/autofill_payment_instrument.h"
13
14namespace payments {
15
16namespace {
17// Identifier for the basic card payment method in the PaymentMethodData.
18static const char* const kBasicCardMethodName = "basic-card";
19} // namespace
20
mathpc0d616a2017-03-15 14:09:3321PaymentRequestState::PaymentRequestState(
22 PaymentRequestSpec* spec,
23 Delegate* delegate,
24 const std::string& app_locale,
25 autofill::PersonalDataManager* personal_data_manager)
mathpf1a7a3752017-03-15 11:23:3726 : is_ready_to_pay_(false),
mathpc0d616a2017-03-15 14:09:3327 app_locale_(app_locale),
mathpf1a7a3752017-03-15 11:23:3728 spec_(spec),
29 delegate_(delegate),
mathpc0d616a2017-03-15 14:09:3330 personal_data_manager_(personal_data_manager),
mathpf1a7a3752017-03-15 11:23:3731 selected_shipping_profile_(nullptr),
32 selected_contact_profile_(nullptr),
33 selected_credit_card_(nullptr),
34 selected_shipping_option_(nullptr) {
35 PopulateProfileCache();
36 UpdateSelectedShippingOption();
37 SetDefaultProfileSelections();
38}
39
40void PaymentRequestState::AddObserver(Observer* observer) {
41 CHECK(observer);
42 observers_.AddObserver(observer);
43}
44PaymentRequestState::~PaymentRequestState() {}
45
46void PaymentRequestState::RemoveObserver(Observer* observer) {
47 observers_.RemoveObserver(observer);
48}
49
50void PaymentRequestState::OnInstrumentDetailsReady(
51 const std::string& method_name,
52 const std::string& stringified_details) {
53 // TODO(mathp): Fill other fields in the PaymentResponsePtr object.
54 mojom::PaymentResponsePtr payment_response = mojom::PaymentResponse::New();
55
56 payment_response->method_name = method_name;
57 payment_response->stringified_details = stringified_details;
58 delegate_->OnPaymentResponseAvailable(std::move(payment_response));
59}
60
61void PaymentRequestState::GeneratePaymentResponse() {
62 // TODO(mathp): PaymentRequest should know about the currently selected
63 // instrument, and not |selected_credit_card_| which is too specific.
64 // TODO(mathp): The method_name should reflect what the merchant asked, and
65 // not necessarily basic-card.
66 selected_payment_instrument_.reset(new AutofillPaymentInstrument(
67 kBasicCardMethodName, *selected_credit_card_, shipping_profiles_,
mathpc0d616a2017-03-15 14:09:3368 app_locale_));
mathpf1a7a3752017-03-15 11:23:3769 // Fetch the instrument details, will call back into
70 // PaymentRequest::OnInstrumentsDetailsReady.
71 selected_payment_instrument_->InvokePaymentApp(this);
72}
73
74void PaymentRequestState::SetSelectedShippingProfile(
75 autofill::AutofillProfile* profile) {
76 selected_shipping_profile_ = profile;
77 UpdateIsReadyToPayAndNotifyObservers();
78}
79
80void PaymentRequestState::SetSelectedContactProfile(
81 autofill::AutofillProfile* profile) {
82 selected_contact_profile_ = profile;
83 UpdateIsReadyToPayAndNotifyObservers();
84}
85
86void PaymentRequestState::SetSelectedCreditCard(autofill::CreditCard* card) {
87 selected_credit_card_ = card;
88 UpdateIsReadyToPayAndNotifyObservers();
89}
90
mathpc0d616a2017-03-15 14:09:3391const std::string& PaymentRequestState::GetApplicationLocale() {
92 return app_locale_;
93}
94
95autofill::PersonalDataManager* PaymentRequestState::GetPersonalDataManager() {
96 return personal_data_manager_;
97}
98
mathpf1a7a3752017-03-15 11:23:3799void PaymentRequestState::PopulateProfileCache() {
mathpf1a7a3752017-03-15 11:23:37100 std::vector<autofill::AutofillProfile*> profiles =
mathpc0d616a2017-03-15 14:09:33101 personal_data_manager_->GetProfilesToSuggest();
mathpf1a7a3752017-03-15 11:23:37102
103 // PaymentRequest may outlive the Profiles returned by the Data Manager.
104 // Thus, we store copies, and return a vector of pointers to these copies
105 // whenever Profiles are requested. The same is true for credit cards.
106 for (size_t i = 0; i < profiles.size(); i++) {
107 profile_cache_.push_back(
108 base::MakeUnique<autofill::AutofillProfile>(*profiles[i]));
109
110 // TODO(tmartino): Implement deduplication rules specific to shipping and
111 // contact profiles.
112 shipping_profiles_.push_back(profile_cache_[i].get());
113 contact_profiles_.push_back(profile_cache_[i].get());
114 }
115
116 const std::vector<autofill::CreditCard*>& cards =
mathpc0d616a2017-03-15 14:09:33117 personal_data_manager_->GetCreditCardsToSuggest();
mathpf1a7a3752017-03-15 11:23:37118 for (autofill::CreditCard* card : cards) {
119 card_cache_.push_back(base::MakeUnique<autofill::CreditCard>(*card));
120 credit_cards_.push_back(card_cache_.back().get());
121 }
122}
123
124void PaymentRequestState::SetDefaultProfileSelections() {
125 if (!shipping_profiles().empty())
126 selected_shipping_profile_ = shipping_profiles()[0];
127
128 if (!contact_profiles().empty())
129 selected_contact_profile_ = contact_profiles()[0];
130
131 // TODO(anthonyvd): Change this code to prioritize server cards and implement
132 // a way to modify this function's return value.
133 const std::vector<autofill::CreditCard*> cards = credit_cards();
134 auto first_complete_card =
135 std::find_if(cards.begin(), cards.end(),
136 [](autofill::CreditCard* card) { return card->IsValid(); });
137
138 selected_credit_card_ =
139 first_complete_card == cards.end() ? nullptr : *first_complete_card;
140
141 UpdateIsReadyToPayAndNotifyObservers();
142}
143
144void PaymentRequestState::UpdateIsReadyToPayAndNotifyObservers() {
145 is_ready_to_pay_ =
146 ArePaymentDetailsSatisfied() && ArePaymentOptionsSatisfied();
147 NotifyOnSelectedInformationChanged();
148}
149
150void PaymentRequestState::NotifyOnSelectedInformationChanged() {
151 for (auto& observer : observers_)
152 observer.OnSelectedInformationChanged();
153}
154
155bool PaymentRequestState::ArePaymentDetailsSatisfied() {
156 // TODO(mathp): A masked card may not satisfy IsValid().
157 if (selected_credit_card_ == nullptr || !selected_credit_card_->IsValid())
158 return false;
159
160 const std::string basic_card_payment_type =
161 autofill::data_util::GetPaymentRequestData(selected_credit_card_->type())
162 .basic_card_payment_type;
163 return !spec_->supported_card_networks().empty() &&
164 std::find(spec_->supported_card_networks().begin(),
165 spec_->supported_card_networks().end(),
166 basic_card_payment_type) !=
167 spec_->supported_card_networks().end();
168}
169
170bool PaymentRequestState::ArePaymentOptionsSatisfied() {
171 // TODO(mathp): Have a measure of shipping address completeness.
172 if (spec_->request_shipping() && selected_shipping_profile_ == nullptr)
173 return false;
174
175 // TODO(mathp): Make an encompassing class to validate contact info.
mathpf1a7a3752017-03-15 11:23:37176 if (spec_->request_payer_name() &&
177 (selected_contact_profile_ == nullptr ||
178 selected_contact_profile_
mathpc0d616a2017-03-15 14:09:33179 ->GetInfo(autofill::AutofillType(autofill::NAME_FULL), app_locale_)
mathpf1a7a3752017-03-15 11:23:37180 .empty())) {
181 return false;
182 }
183 if (spec_->request_payer_email() &&
184 (selected_contact_profile_ == nullptr ||
185 selected_contact_profile_
186 ->GetInfo(autofill::AutofillType(autofill::EMAIL_ADDRESS),
mathpc0d616a2017-03-15 14:09:33187 app_locale_)
mathpf1a7a3752017-03-15 11:23:37188 .empty())) {
189 return false;
190 }
191 if (spec_->request_payer_phone() &&
192 (selected_contact_profile_ == nullptr ||
193 selected_contact_profile_
194 ->GetInfo(autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER),
mathpc0d616a2017-03-15 14:09:33195 app_locale_)
mathpf1a7a3752017-03-15 11:23:37196 .empty())) {
197 return false;
198 }
199
200 return true;
201}
202
203void PaymentRequestState::UpdateSelectedShippingOption() {
204 selected_shipping_option_ = nullptr;
205
206 // As per the spec, the selected shipping option should initially be the last
207 // one in the array that has its selected field set to true.
208 auto selected_shipping_option_it = std::find_if(
209 spec_->details().shipping_options.rbegin(),
210 spec_->details().shipping_options.rend(),
211 [](const payments::mojom::PaymentShippingOptionPtr& element) {
212 return element->selected;
213 });
214 if (selected_shipping_option_it != spec_->details().shipping_options.rend()) {
215 selected_shipping_option_ = selected_shipping_option_it->get();
216 }
217}
218
219} // namespace payments