blob: 52867d08ba432dab7b4682b501aef37d095a6fd9 [file] [log] [blame]
// Copyright 2016 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 "ios/web/public/payments/payment_request.h"
#include "base/json/json_reader.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
namespace {
// All of these are defined here (even though most are only used once each) so
// the format details are easy to locate and update or compare to the spec doc.
// (https://w3c.github.io/browser-payment-api/).
static const char kPaymentCurrencyAmountCurrencySystemISO4217[] =
"urn:iso:std:iso:4217";
static const char kPaymentCurrencyAmountCurrencySystem[] = "currencySystem";
static const char kPaymentCurrencyAmountCurrency[] = "currency";
static const char kPaymentCurrencyAmountValue[] = "value";
static const char kPaymentDetailsId[] = "id";
static const char kPaymentDetailsDisplayItems[] = "displayItems";
static const char kPaymentDetailsError[] = "error";
static const char kPaymentDetailsShippingOptions[] = "shippingOptions";
static const char kPaymentDetailsTotal[] = "total";
static const char kPaymentItemAmount[] = "amount";
static const char kPaymentItemLabel[] = "label";
static const char kPaymentItemPending[] = "pending";
static const char kPaymentOptionsRequestPayerEmail[] = "requestPayerEmail";
static const char kPaymentOptionsRequestPayerName[] = "requestPayerName";
static const char kPaymentOptionsRequestPayerPhone[] = "requestPayerPhone";
static const char kPaymentOptionsRequestShipping[] = "requestShipping";
static const char kPaymentOptionsShippingTypeDelivery[] = "delivery";
static const char kPaymentOptionsShippingTypePickup[] = "pickup";
static const char kPaymentOptionsShippingType[] = "shippingType";
static const char kPaymentRequestDetails[] = "details";
static const char kPaymentRequestId[] = "id";
static const char kPaymentRequestMethodData[] = "methodData";
static const char kPaymentRequestOptions[] = "options";
static const char kPaymentResponseId[] = "requestId";
static const char kPaymentResponseDetails[] = "details";
static const char kPaymentResponseMethodName[] = "methodName";
static const char kPaymentResponsePayerEmail[] = "payerEmail";
static const char kPaymentResponsePayerName[] = "payerName";
static const char kPaymentResponsePayerPhone[] = "payerPhone";
static const char kPaymentResponseShippingAddress[] = "shippingAddress";
static const char kPaymentResponseShippingOption[] = "shippingOption";
static const char kPaymentShippingOptionAmount[] = "amount";
static const char kPaymentShippingOptionId[] = "id";
static const char kPaymentShippingOptionLabel[] = "label";
static const char kPaymentShippingOptionSelected[] = "selected";
} // namespace
namespace web {
PaymentCurrencyAmount::PaymentCurrencyAmount()
// By default, the currency is defined by [ISO4217]. For example, USD for
// US Dollars.
: currency_system(
base::ASCIIToUTF16(kPaymentCurrencyAmountCurrencySystemISO4217)) {}
PaymentCurrencyAmount::~PaymentCurrencyAmount() = default;
bool PaymentCurrencyAmount::operator==(
const PaymentCurrencyAmount& other) const {
return this->currency == other.currency && this->value == other.value;
}
bool PaymentCurrencyAmount::operator!=(
const PaymentCurrencyAmount& other) const {
return !(*this == other);
}
bool PaymentCurrencyAmount::FromDictionaryValue(
const base::DictionaryValue& value) {
if (!value.GetString(kPaymentCurrencyAmountCurrency, &this->currency)) {
return false;
}
if (!value.GetString(kPaymentCurrencyAmountValue, &this->value)) {
return false;
}
// Currency_system is optional
value.GetString(kPaymentCurrencyAmountCurrencySystem, &this->currency_system);
return true;
}
PaymentItem::PaymentItem() : pending(false) {}
PaymentItem::~PaymentItem() = default;
bool PaymentItem::operator==(const PaymentItem& other) const {
return this->label == other.label && this->amount == other.amount &&
this->pending == other.pending;
}
bool PaymentItem::operator!=(const PaymentItem& other) const {
return !(*this == other);
}
bool PaymentItem::FromDictionaryValue(const base::DictionaryValue& value) {
if (!value.GetString(kPaymentItemLabel, &this->label)) {
return false;
}
const base::DictionaryValue* amount_dict = nullptr;
if (!value.GetDictionary(kPaymentItemAmount, &amount_dict)) {
return false;
}
if (!this->amount.FromDictionaryValue(*amount_dict)) {
return false;
}
// Pending is optional.
value.GetBoolean(kPaymentItemPending, &this->pending);
return true;
}
PaymentShippingOption::PaymentShippingOption() : selected(false) {}
PaymentShippingOption::PaymentShippingOption(
const PaymentShippingOption& other) = default;
PaymentShippingOption::~PaymentShippingOption() = default;
bool PaymentShippingOption::operator==(
const PaymentShippingOption& other) const {
return this->id == other.id && this->label == other.label &&
this->amount == other.amount && this->selected == other.selected;
}
bool PaymentShippingOption::operator!=(
const PaymentShippingOption& other) const {
return !(*this == other);
}
bool PaymentShippingOption::FromDictionaryValue(
const base::DictionaryValue& value) {
if (!value.GetString(kPaymentShippingOptionId, &this->id)) {
return false;
}
if (!value.GetString(kPaymentShippingOptionLabel, &this->label)) {
return false;
}
const base::DictionaryValue* amount_dict = nullptr;
if (!value.GetDictionary(kPaymentShippingOptionAmount, &amount_dict)) {
return false;
}
if (!this->amount.FromDictionaryValue(*amount_dict)) {
return false;
}
// Selected is optional.
value.GetBoolean(kPaymentShippingOptionSelected, &this->selected);
return true;
}
PaymentDetailsModifier::PaymentDetailsModifier() {}
PaymentDetailsModifier::PaymentDetailsModifier(
const PaymentDetailsModifier& other) = default;
PaymentDetailsModifier::~PaymentDetailsModifier() = default;
bool PaymentDetailsModifier::operator==(
const PaymentDetailsModifier& other) const {
return this->supported_methods == other.supported_methods &&
this->total == other.total &&
this->additional_display_items == other.additional_display_items;
}
bool PaymentDetailsModifier::operator!=(
const PaymentDetailsModifier& other) const {
return !(*this == other);
}
PaymentDetails::PaymentDetails() {}
PaymentDetails::PaymentDetails(const PaymentDetails& other) = default;
PaymentDetails::~PaymentDetails() = default;
bool PaymentDetails::operator==(const PaymentDetails& other) const {
return this->id == other.id && this->total == other.total &&
this->display_items == other.display_items &&
this->shipping_options == other.shipping_options &&
this->modifiers == other.modifiers && this->error == other.error;
}
bool PaymentDetails::operator!=(const PaymentDetails& other) const {
return !(*this == other);
}
bool PaymentDetails::FromDictionaryValue(const base::DictionaryValue& value,
bool requires_total) {
this->display_items.clear();
this->shipping_options.clear();
this->modifiers.clear();
// ID is optional.
value.GetString(kPaymentDetailsId, &this->id);
const base::DictionaryValue* total_dict = nullptr;
if (!value.GetDictionary(kPaymentDetailsTotal, &total_dict) &&
requires_total) {
return false;
}
if (total_dict && !this->total.FromDictionaryValue(*total_dict)) {
return false;
}
const base::ListValue* display_items_list = nullptr;
if (value.GetList(kPaymentDetailsDisplayItems, &display_items_list)) {
for (size_t i = 0; i < display_items_list->GetSize(); ++i) {
const base::DictionaryValue* payment_item_dict;
if (!display_items_list->GetDictionary(i, &payment_item_dict)) {
return false;
}
PaymentItem payment_item;
if (!payment_item.FromDictionaryValue(*payment_item_dict)) {
return false;
}
this->display_items.push_back(payment_item);
}
}
const base::ListValue* shipping_options_list = nullptr;
if (value.GetList(kPaymentDetailsShippingOptions, &shipping_options_list)) {
for (size_t i = 0; i < shipping_options_list->GetSize(); ++i) {
const base::DictionaryValue* shipping_option_dict;
if (!shipping_options_list->GetDictionary(i, &shipping_option_dict)) {
return false;
}
PaymentShippingOption shipping_option;
if (!shipping_option.FromDictionaryValue(*shipping_option_dict)) {
return false;
}
this->shipping_options.push_back(shipping_option);
}
}
// Error is optional.
value.GetString(kPaymentDetailsError, &this->error);
return true;
}
PaymentOptions::PaymentOptions()
: request_payer_name(false),
request_payer_email(false),
request_payer_phone(false),
request_shipping(false),
shipping_type(payments::PaymentShippingType::SHIPPING) {}
PaymentOptions::~PaymentOptions() = default;
bool PaymentOptions::operator==(const PaymentOptions& other) const {
return this->request_payer_name == other.request_payer_name &&
this->request_payer_email == other.request_payer_email &&
this->request_payer_phone == other.request_payer_phone &&
this->request_shipping == other.request_shipping &&
this->shipping_type == other.shipping_type;
}
bool PaymentOptions::operator!=(const PaymentOptions& other) const {
return !(*this == other);
}
bool PaymentOptions::FromDictionaryValue(const base::DictionaryValue& value) {
value.GetBoolean(kPaymentOptionsRequestPayerName, &this->request_payer_name);
value.GetBoolean(kPaymentOptionsRequestPayerEmail,
&this->request_payer_email);
value.GetBoolean(kPaymentOptionsRequestPayerPhone,
&this->request_payer_phone);
value.GetBoolean(kPaymentOptionsRequestShipping, &this->request_shipping);
base::string16 shipping_type;
value.GetString(kPaymentOptionsShippingType, &shipping_type);
if (shipping_type ==
base::ASCIIToUTF16(kPaymentOptionsShippingTypeDelivery)) {
this->shipping_type = payments::PaymentShippingType::DELIVERY;
} else if (shipping_type ==
base::ASCIIToUTF16(kPaymentOptionsShippingTypePickup)) {
this->shipping_type = payments::PaymentShippingType::PICKUP;
} else {
this->shipping_type = payments::PaymentShippingType::SHIPPING;
}
return true;
}
PaymentRequest::PaymentRequest() {}
PaymentRequest::PaymentRequest(const PaymentRequest& other) = default;
PaymentRequest::~PaymentRequest() = default;
bool PaymentRequest::operator==(const PaymentRequest& other) const {
return this->payment_request_id == other.payment_request_id &&
this->shipping_address == other.shipping_address &&
this->shipping_option == other.shipping_option &&
this->method_data == other.method_data &&
this->details == other.details && this->options == other.options;
}
bool PaymentRequest::operator!=(const PaymentRequest& other) const {
return !(*this == other);
}
bool PaymentRequest::FromDictionaryValue(const base::DictionaryValue& value) {
this->method_data.clear();
if (!value.GetString(kPaymentRequestId, &this->payment_request_id)) {
return false;
}
// Parse the payment method data.
const base::ListValue* method_data_list = nullptr;
// At least one method is required.
if (!value.GetList(kPaymentRequestMethodData, &method_data_list) ||
method_data_list->GetSize() == 0) {
return false;
}
for (size_t i = 0; i < method_data_list->GetSize(); ++i) {
const base::DictionaryValue* method_data_dict;
if (!method_data_list->GetDictionary(i, &method_data_dict))
return false;
payments::PaymentMethodData method_data;
if (!method_data.FromDictionaryValue(*method_data_dict))
return false;
this->method_data.push_back(method_data);
}
// Parse the payment details.
const base::DictionaryValue* payment_details_dict = nullptr;
if (!value.GetDictionary(kPaymentRequestDetails, &payment_details_dict) ||
!this->details.FromDictionaryValue(*payment_details_dict,
/*requires_total=*/true)) {
return false;
}
// Parse the payment options.
const base::DictionaryValue* payment_options = nullptr;
// Options field is optional.
if (value.GetDictionary(kPaymentRequestOptions, &payment_options))
if (!this->options.FromDictionaryValue(*payment_options))
return false;
return true;
}
PaymentResponse::PaymentResponse() {}
PaymentResponse::PaymentResponse(const PaymentResponse& other) = default;
PaymentResponse::~PaymentResponse() = default;
bool PaymentResponse::operator==(const PaymentResponse& other) const {
return this->payment_request_id == other.payment_request_id &&
this->method_name == other.method_name &&
this->details == other.details &&
this->shipping_address == other.shipping_address &&
this->shipping_option == other.shipping_option &&
this->payer_name == other.payer_name &&
this->payer_email == other.payer_email &&
this->payer_phone == other.payer_phone;
}
bool PaymentResponse::operator!=(const PaymentResponse& other) const {
return !(*this == other);
}
std::unique_ptr<base::DictionaryValue> PaymentResponse::ToDictionaryValue()
const {
std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue());
result->SetString(kPaymentResponseId, this->payment_request_id);
result->SetString(kPaymentResponseMethodName, this->method_name);
// |this.details| is a json-serialized string. Parse it to a base::Value so
// that when |this| is converted to a JSON string, |this.details| won't get
// json-escaped.
std::unique_ptr<base::Value> details =
base::JSONReader().ReadToValue(this->details);
if (details)
result->Set(kPaymentResponseDetails, std::move(details));
if (!this->shipping_address.ToDictionaryValue()->empty()) {
result->Set(kPaymentResponseShippingAddress,
this->shipping_address.ToDictionaryValue());
}
if (!this->shipping_option.empty())
result->SetString(kPaymentResponseShippingOption, this->shipping_option);
if (!this->payer_name.empty())
result->SetString(kPaymentResponsePayerName, this->payer_name);
if (!this->payer_email.empty())
result->SetString(kPaymentResponsePayerEmail, this->payer_email);
if (!this->payer_phone.empty())
result->SetString(kPaymentResponsePayerPhone, this->payer_phone);
return result;
}
} // namespace web