Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(414)

Side by Side Diff: components/payments/core/profile_util.cc

Issue 2847503002: [WebPayments] Show labels on incomplete profiles (Closed)
Patch Set: add missing changes Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/payments/core/profile_util.h" 5 #include "components/payments/core/profile_util.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <memory>
8 9
10 #include "base/strings/utf_string_conversions.h"
11 #include "components/autofill/core/browser/address_i18n.h"
12 #include "components/autofill/core/browser/autofill_country.h"
9 #include "components/autofill/core/browser/autofill_profile.h" 13 #include "components/autofill/core/browser/autofill_profile.h"
10 #include "components/autofill/core/browser/field_types.h" 14 #include "components/autofill/core/browser/field_types.h"
15 #include "components/autofill/core/browser/validation.h"
11 #include "components/payments/core/payment_options_provider.h" 16 #include "components/payments/core/payment_options_provider.h"
17 #include "components/payments/core/payment_request_data_util.h"
18 #include "components/strings/grit/components_strings.h"
19 #include "third_party/libaddressinput/chromium/addressinput_util.h"
20 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_da ta.h"
21 #include "ui/base/l10n/l10n_util.h"
12 22
13 namespace payments { 23 namespace payments {
14 namespace profile_util {
15 24
16 std::vector<autofill::AutofillProfile*> FilterProfilesForContact( 25 PaymentsProfileComparator::PaymentsProfileComparator(
17 const std::vector<autofill::AutofillProfile*>& profiles,
18 const std::string& app_locale, 26 const std::string& app_locale,
19 const PaymentOptionsProvider& options) { 27 const PaymentOptionsProvider& options)
28 : autofill::AutofillProfileComparator(app_locale), options_(options) {}
29
30 PaymentsProfileComparator::~PaymentsProfileComparator() {}
31
32 PaymentsProfileComparator::ProfileFields
33 PaymentsProfileComparator::GetMissingProfileFields(
34 const autofill::AutofillProfile* profile) const {
35 if (!profile)
36 return kName | kPhone | kEmail | kAddress;
37
38 if (!cache_.count(profile->guid())) {
39 cache_[profile->guid()] = ComputeMissingFields(profile);
40 } else {
41 // Cache hit. In debug mode, recompute and check that invalidation has
42 // occurred where necessary.
43 DCHECK_EQ(cache_[profile->guid()], ComputeMissingFields(profile))
44 << "Profiles must be invalidated when their contents change.";
45 }
46
47 return cache_[profile->guid()];
48 }
49
50 std::vector<autofill::AutofillProfile*>
51 PaymentsProfileComparator::FilterProfilesForContact(
52 const std::vector<autofill::AutofillProfile*>& profiles) const {
20 // We will be removing profiles, so we operate on a copy. 53 // We will be removing profiles, so we operate on a copy.
21 std::vector<autofill::AutofillProfile*> processed = profiles; 54 std::vector<autofill::AutofillProfile*> processed = profiles;
22 55
23 PaymentsProfileComparator comparator(app_locale, options);
24
25 // Stable sort, since profiles are expected to be passed in frecency order. 56 // Stable sort, since profiles are expected to be passed in frecency order.
26 std::stable_sort( 57 std::stable_sort(
27 processed.begin(), processed.end(), 58 processed.begin(), processed.end(),
28 std::bind(&PaymentsProfileComparator::IsContactMoreComplete, &comparator, 59 std::bind(&PaymentsProfileComparator::IsContactMoreComplete, this,
29 std::placeholders::_1, std::placeholders::_2)); 60 std::placeholders::_1, std::placeholders::_2));
30 61
31 auto it = processed.begin(); 62 auto it = processed.begin();
32 while (it != processed.end()) { 63 while (it != processed.end()) {
33 if (comparator.GetContactCompletenessScore(*it) == 0) { 64 if (GetContactCompletenessScore(*it) == 0) {
34 // Since profiles are sorted by completeness, this and any further 65 // Since profiles are sorted by completeness, this and any further
35 // profiles can be discarded. 66 // profiles can be discarded.
36 processed.erase(it, processed.end()); 67 processed.erase(it, processed.end());
37 break; 68 break;
38 } 69 }
39 70
40 // Attempt to find a matching element in the vector before the current. 71 // Attempt to find a matching element in the vector before the current.
41 // This is quadratic, but the number of elements is generally small 72 // This is quadratic, but the number of elements is generally small
42 // (< 10), so a more complicated algorithm would be overkill. 73 // (< 10), so a more complicated algorithm would be overkill.
43 if (std::find_if(processed.begin(), it, 74 if (std::find_if(processed.begin(), it,
44 [&](autofill::AutofillProfile* prior) { 75 [&](autofill::AutofillProfile* prior) {
45 return comparator.IsContactEqualOrSuperset(*prior, **it); 76 return IsContactEqualOrSuperset(*prior, **it);
46 }) != it) { 77 }) != it) {
47 // Remove the subset profile. |it| will point to the next element after 78 // Remove the subset profile. |it| will point to the next element after
48 // erasure. 79 // erasure.
49 it = processed.erase(it); 80 it = processed.erase(it);
50 } else { 81 } else {
51 it++; 82 it++;
52 } 83 }
53 } 84 }
54 85
55 return processed; 86 return processed;
56 } 87 }
57 88
58 PaymentsProfileComparator::PaymentsProfileComparator(
59 const std::string& app_locale,
60 const PaymentOptionsProvider& options)
61 : autofill::AutofillProfileComparator(app_locale), options_(options) {}
62
63 PaymentsProfileComparator::~PaymentsProfileComparator() {}
64
65 bool PaymentsProfileComparator::IsContactEqualOrSuperset( 89 bool PaymentsProfileComparator::IsContactEqualOrSuperset(
66 const autofill::AutofillProfile& super, 90 const autofill::AutofillProfile& super,
67 const autofill::AutofillProfile& sub) { 91 const autofill::AutofillProfile& sub) const {
68 if (options_.request_payer_name()) { 92 if (options_.request_payer_name()) {
69 if (sub.HasInfo(autofill::NAME_FULL) && 93 if (sub.HasInfo(autofill::NAME_FULL) &&
70 !super.HasInfo(autofill::NAME_FULL)) { 94 !super.HasInfo(autofill::NAME_FULL)) {
71 return false; 95 return false;
72 } 96 }
73 if (!HaveMergeableNames(super, sub)) 97 if (!HaveMergeableNames(super, sub))
74 return false; 98 return false;
75 } 99 }
76 if (options_.request_payer_phone()) { 100 if (options_.request_payer_phone()) {
77 if (sub.HasInfo(autofill::PHONE_HOME_WHOLE_NUMBER) && 101 if (sub.HasInfo(autofill::PHONE_HOME_WHOLE_NUMBER) &&
78 !super.HasInfo(autofill::PHONE_HOME_WHOLE_NUMBER)) { 102 !super.HasInfo(autofill::PHONE_HOME_WHOLE_NUMBER)) {
79 return false; 103 return false;
80 } 104 }
81 if (!HaveMergeablePhoneNumbers(super, sub)) 105 if (!HaveMergeablePhoneNumbers(super, sub))
82 return false; 106 return false;
83 } 107 }
84 if (options_.request_payer_email()) { 108 if (options_.request_payer_email()) {
85 if (sub.HasInfo(autofill::EMAIL_ADDRESS) && 109 if (sub.HasInfo(autofill::EMAIL_ADDRESS) &&
86 !super.HasInfo(autofill::EMAIL_ADDRESS)) { 110 !super.HasInfo(autofill::EMAIL_ADDRESS)) {
87 return false; 111 return false;
88 } 112 }
89 if (!HaveMergeableEmailAddresses(super, sub)) 113 if (!HaveMergeableEmailAddresses(super, sub))
90 return false; 114 return false;
91 } 115 }
92 return true; 116 return true;
93 } 117 }
94 118
95 int PaymentsProfileComparator::GetContactCompletenessScore( 119 int PaymentsProfileComparator::GetContactCompletenessScore(
96 const autofill::AutofillProfile* profile) { 120 const autofill::AutofillProfile* profile) const {
97 if (!profile) 121 if (!profile)
98 return 0; 122 return 0;
99 123
100 return (options_.request_payer_name() && 124 // Create a bitmask of the fields that are both present and required.
101 profile->HasInfo(autofill::NAME_FULL)) + 125 ProfileFields present =
102 (options_.request_payer_phone() && 126 ~GetMissingProfileFields(profile) & GetRequiredProfileFieldsForContact();
103 profile->HasInfo(autofill::PHONE_HOME_WHOLE_NUMBER)) + 127
104 (options_.request_payer_email() && 128 // Count how many are set.
105 profile->HasInfo(autofill::EMAIL_ADDRESS)); 129 return !!(present & kName) + !!(present & kPhone) + !!(present & kEmail);
106 } 130 }
107 131
108 bool PaymentsProfileComparator::IsContactInfoComplete( 132 bool PaymentsProfileComparator::IsContactInfoComplete(
109 const autofill::AutofillProfile* profile) { 133 const autofill::AutofillProfile* profile) const {
110 int desired_score = options_.request_payer_name() + 134 // Mask the fields that are missing with those that are requried. If any bits
111 options_.request_payer_phone() + 135 // are set (i.e., the result is nonzero), then contact info is incomplete.
112 options_.request_payer_email(); 136 return !(GetMissingProfileFields(profile) &
113 return GetContactCompletenessScore(profile) == desired_score; 137 GetRequiredProfileFieldsForContact());
114 } 138 }
115 139
116 bool PaymentsProfileComparator::IsContactMoreComplete( 140 bool PaymentsProfileComparator::IsContactMoreComplete(
117 const autofill::AutofillProfile* p1, 141 const autofill::AutofillProfile* p1,
118 const autofill::AutofillProfile* p2) { 142 const autofill::AutofillProfile* p2) const {
119 return GetContactCompletenessScore(p1) > GetContactCompletenessScore(p2); 143 return GetContactCompletenessScore(p1) > GetContactCompletenessScore(p2);
120 } 144 }
121 145
122 } // namespace profile_util 146 base::string16 PaymentsProfileComparator::GetStringForMissingContactFields(
147 const autofill::AutofillProfile& profile) const {
148 return GetStringForMissingFields(GetMissingProfileFields(&profile) &
149 GetRequiredProfileFieldsForContact());
150 }
151
152 bool PaymentsProfileComparator::IsShippingComplete(
153 const autofill::AutofillProfile* profile) const {
154 // Mask the fields that are missing with those that are requried. If any bits
155 // are set (i.e., the result is nonzero), then shipping is incomplete.
156 return !(GetMissingProfileFields(profile) &
157 GetRequiredProfileFieldsForShipping());
158 }
159
160 base::string16 PaymentsProfileComparator::GetStringForMissingShippingFields(
161 const autofill::AutofillProfile& profile) const {
162 return GetStringForMissingFields(GetMissingProfileFields(&profile) &
163 GetRequiredProfileFieldsForShipping());
164 }
165
166 void PaymentsProfileComparator::Invalidate(
167 const autofill::AutofillProfile& profile) {
168 cache_.erase(profile.guid());
169 }
170
171 PaymentsProfileComparator::ProfileFields
172 PaymentsProfileComparator::ComputeMissingFields(
173 const autofill::AutofillProfile* profile) const {
174 ProfileFields missing = 0;
175
176 if (!profile->HasInfo(autofill::NAME_FULL))
177 missing |= kName;
178
179 // Determine the country code to use when validating the phone number. Use
180 // the profile's country if it has one, or the code for the app locale
181 // otherwise. Note that international format numbers will always work--this
182 // is just the region that will be used to check if the number is
183 // potentially in a local format.
184 std::string country =
185 data_util::GetCountryCodeWithFallback(profile, app_locale());
186
187 base::string16 phone = profile->GetInfo(
188 autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER), app_locale());
189 if (!autofill::IsValidPhoneNumber(phone, country))
190 missing |= kPhone;
191
192 base::string16 email = profile->GetInfo(
193 autofill::AutofillType(autofill::EMAIL_ADDRESS), app_locale());
194 if (!autofill::IsValidEmailAddress(email))
195 missing |= kEmail;
196
197 if (!AreRequiredAddressFieldsPresent(*profile))
198 missing |= kAddress;
199
200 return missing;
201 }
202
203 PaymentsProfileComparator::ProfileFields
204 PaymentsProfileComparator::GetRequiredProfileFieldsForContact() const {
205 ProfileFields required = 0;
206 if (options_.request_payer_name())
207 required |= kName;
208 if (options_.request_payer_phone())
209 required |= kPhone;
210 if (options_.request_payer_email())
211 required |= kEmail;
212 return required;
213 }
214
215 PaymentsProfileComparator::ProfileFields
216 PaymentsProfileComparator::GetRequiredProfileFieldsForShipping() const {
217 return options_.request_shipping() ? (kAddress | kName | kPhone) : 0;
218 }
219
220 base::string16 PaymentsProfileComparator::GetStringForMissingFields(
221 PaymentsProfileComparator::ProfileFields fields) const {
222 switch (fields) {
223 case 0:
224 // No bits are set, so no fields are missing.
225 return base::string16();
226 case kName:
227 return l10n_util::GetStringUTF16(IDS_PAYMENTS_NAME_REQUIRED);
228 case kPhone:
229 return l10n_util::GetStringUTF16(IDS_PAYMENTS_PHONE_NUMBER_REQUIRED);
230 case kEmail:
231 return l10n_util::GetStringUTF16(IDS_PAYMENTS_EMAIL_REQUIRED);
232 case kAddress:
233 return l10n_util::GetStringUTF16(IDS_PAYMENTS_INVALID_ADDRESS);
234 default:
235 // Either multiple bits are set (likely) or one bit that doesn't
236 // correspond to a named constant is set (shouldn't happen). Return a
237 // generic "More information" message.
238 return l10n_util::GetStringUTF16(IDS_PAYMENTS_MORE_INFORMATION_REQUIRED);
239 }
240 }
241
242 bool PaymentsProfileComparator::AreRequiredAddressFieldsPresent(
243 const autofill::AutofillProfile& profile) const {
244 std::unique_ptr<::i18n::addressinput::AddressData> data =
245 autofill::i18n::CreateAddressDataFromAutofillProfile(profile,
246 app_locale());
247
248 return autofill::addressinput::HasAllRequiredFields(*data);
249 }
250
123 } // namespace payments 251 } // namespace payments
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698