[Apple Pay] Add new ApplePayInstallmentConfiguration members
authoraestes@apple.com <aestes@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 22 May 2020 20:10:01 +0000 (20:10 +0000)
committeraestes@apple.com <aestes@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 22 May 2020 20:10:01 +0000 (20:10 +0000)
https://bugs.webkit.org/show_bug.cgi?id=212160
<rdar://problem/60703650>

Reviewed by Alex Christensen.

Source/WebCore:

Test: http/tests/ssl/applepay/ApplePayInstallmentItems.https.html

* DerivedSources-input.xcfilelist:
* DerivedSources-output.xcfilelist:
* DerivedSources.make:
* SourcesCocoa.txt:
* WebCore.xcodeproj/project.pbxproj: Added IDLs, headers, and derived sources for
ApplePayInstallment{Item,ItemType,RetailChannel}.

* Modules/applepay/ApplePayInstallmentConfiguration.idl:
* Modules/applepay/ApplePayInstallmentConfigurationWebCore.h: Added items,
applicationMetadata, and retailChannel members. Added missing conditionals to
merchantIdentifier and referrerIdentifier.

* Modules/applepay/ApplePayInstallmentItem.h:
* Modules/applepay/ApplePayInstallmentItem.idl:
* Modules/applepay/ApplePayInstallmentItemType.h:
* Modules/applepay/ApplePayInstallmentItemType.idl:
* Modules/applepay/ApplePayInstallmentRetailChannel.h:
* Modules/applepay/ApplePayInstallmentRetailChannel.idl: Added.

* Modules/applepay/ApplePayRequestBase.cpp:
(WebCore::convertAndValidate): Changed to call PaymentInstallmentConfiguration::create,
returning an exception if present.

* Modules/applepay/PaymentInstallmentConfiguration.mm:
(WebCore::fromDecimalNumber): Allowed for a large maximum number of fractional digits to
support formatting high-precision currency and APRs (note that this formatter is only used
for test support).

(WebCore::applePayItemType):
(WebCore::platformItemType): Added to convert between PKInstallmentItemType and
ApplePayInstallmentItemType.

(WebCore::applePayRetailChannel):
(WebCore::platformRetailChannel): Added to convert between PKInstallmentRetailChannel and
ApplePayInstallmentRetailChannel.

(WebCore::makeNSArrayElement):
(WebCore::makeVectorElement): Added to convert between NSArray<PKPaymentInstallmentItem *>
and Vector<ApplePayInstallmentItem>.

(WebCore::createPlatformConfiguration): Added a parameter for passing in applicationMetadata
as an NSDictionary. Set properties on PKPaymentInstallmentConfiguration for new
ApplePayInstallmentConfiguration members.
(WebCore::PaymentInstallmentConfiguration::create): Added; converts the applicationMetadata
JSON string (if present) to an NSDictionary, returning a TypeError if the JSON string does
not deserialize to an NSDictionary (as PassKit requires).
(WebCore::PaymentInstallmentConfiguration::PaymentInstallmentConfiguration): Added a
parameter for passing in applicationMetadata as an NSDictionary. Made private.
(WebCore::PaymentInstallmentConfiguration::applePayInstallmentConfiguration const): Set
members on ApplePayInstallmentConfiguration for new PKPaymentInstallmentConfiguration
properties.

* Modules/applepay/PaymentInstallmentConfigurationWebCore.h:

Source/WebCore/PAL:

* pal/cocoa/PassKitSoftLink.h:
* pal/cocoa/PassKitSoftLink.mm: Added soft-linking macros for PKPaymentInstallmentItem.

Source/WTF:

* wtf/PlatformEnableCocoa.h: Defined ENABLE_APPLE_PAY_INSTALLMENT_IDENTIFIERS.

LayoutTests:

* http/tests/ssl/applepay/ApplePayInstallmentItems.https-expected.txt:
* http/tests/ssl/applepay/ApplePayInstallmentItems.https.html: Added.
* platform/mac-wk2/TestExpectations: Skipped test on Mojave and Catalina.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@262069 268f45cc-cd09-0410-ab3c-d52691b4dbfc

26 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/ssl/applepay/ApplePayInstallmentItems.https-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/ssl/applepay/ApplePayInstallmentItems.https.html [new file with mode: 0644]
LayoutTests/platform/mac-wk2/TestExpectations
Source/WTF/ChangeLog
Source/WTF/wtf/PlatformEnableCocoa.h
Source/WebCore/ChangeLog
Source/WebCore/DerivedSources-input.xcfilelist
Source/WebCore/DerivedSources-output.xcfilelist
Source/WebCore/DerivedSources.make
Source/WebCore/Modules/applepay/ApplePayInstallmentConfiguration.idl
Source/WebCore/Modules/applepay/ApplePayInstallmentConfigurationWebCore.h
Source/WebCore/Modules/applepay/ApplePayInstallmentItem.h [new file with mode: 0644]
Source/WebCore/Modules/applepay/ApplePayInstallmentItem.idl [new file with mode: 0644]
Source/WebCore/Modules/applepay/ApplePayInstallmentItemType.h [new file with mode: 0644]
Source/WebCore/Modules/applepay/ApplePayInstallmentItemType.idl [new file with mode: 0644]
Source/WebCore/Modules/applepay/ApplePayInstallmentRetailChannel.h [new file with mode: 0644]
Source/WebCore/Modules/applepay/ApplePayInstallmentRetailChannel.idl [new file with mode: 0644]
Source/WebCore/Modules/applepay/ApplePayRequestBase.cpp
Source/WebCore/Modules/applepay/PaymentInstallmentConfiguration.mm
Source/WebCore/Modules/applepay/PaymentInstallmentConfigurationWebCore.h
Source/WebCore/PAL/ChangeLog
Source/WebCore/PAL/pal/cocoa/PassKitSoftLink.h
Source/WebCore/PAL/pal/cocoa/PassKitSoftLink.mm
Source/WebCore/SourcesCocoa.txt
Source/WebCore/WebCore.xcodeproj/project.pbxproj

index e0a9a99..a5b9e52 100644 (file)
@@ -1,3 +1,15 @@
+2020-05-22  Andy Estes  <aestes@apple.com>
+
+        [Apple Pay] Add new ApplePayInstallmentConfiguration members
+        https://bugs.webkit.org/show_bug.cgi?id=212160
+        <rdar://problem/60703650>
+
+        Reviewed by Alex Christensen.
+
+        * http/tests/ssl/applepay/ApplePayInstallmentItems.https-expected.txt:
+        * http/tests/ssl/applepay/ApplePayInstallmentItems.https.html: Added.
+        * platform/mac-wk2/TestExpectations: Skipped test on Mojave and Catalina.
+
 2020-05-22  Carlos Alberto Lopez Perez  <clopez@igalia.com>
 
         Gardening after r262056
diff --git a/LayoutTests/http/tests/ssl/applepay/ApplePayInstallmentItems.https-expected.txt b/LayoutTests/http/tests/ssl/applepay/ApplePayInstallmentItems.https-expected.txt
new file mode 100644 (file)
index 0000000..7813c7a
--- /dev/null
@@ -0,0 +1,61 @@
+Test ApplePayInstallmentItem and friends.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Test installmentConfiguration.items
+PASS request = validRequest(); request.installmentConfiguration.items = 4; new ApplePaySession(apiVersion, request) threw exception TypeError: Value is not a sequence.
+PASS request = validRequest(); request.installmentConfiguration.items = ""; new ApplePaySession(apiVersion, request) threw exception TypeError: Value is not a sequence.
+PASS request = validRequest(); request.installmentConfiguration.items = null; new ApplePaySession(apiVersion, request) threw exception TypeError: Value is not a sequence.
+PASS request = validRequest(); request.installmentConfiguration.items = true; new ApplePaySession(apiVersion, request) threw exception TypeError: Value is not a sequence.
+PASS request = validRequest(); request.installmentConfiguration.items = new Date(); new ApplePaySession(apiVersion, request) threw exception TypeError: Type error.
+PASS request = validRequest(); request.installmentConfiguration.items = ["a", "b"]; new ApplePaySession(apiVersion, request) threw exception TypeError: Type error.
+PASS request = validRequest(); request.installmentConfiguration.items = [{type: 4}]; new ApplePaySession(apiVersion, request) threw exception TypeError: Type error.
+PASS request = validRequest(); request.installmentConfiguration.items = [{type: "invalid"}]; new ApplePaySession(apiVersion, request) threw exception TypeError: Type error.
+PASS request = validRequest(); request.installmentConfiguration.items = undefined; new ApplePaySession(apiVersion, request) did not throw exception.
+PASS request = validRequest(); request.installmentConfiguration.items = []; new ApplePaySession(apiVersion, request) did not throw exception.
+PASS request = validRequest(); request.installmentConfiguration.items = [{}]; new ApplePaySession(apiVersion, request) did not throw exception.
+PASS request = validRequest(); request.installmentConfiguration.items = [{type: undefined}]; new ApplePaySession(apiVersion, request) did not throw exception.
+PASS request = validRequest(); request.installmentConfiguration.items = [{type: "generic"}]; new ApplePaySession(apiVersion, request) did not throw exception.
+PASS request = validRequest(); request.installmentConfiguration.items = [{type: "phone"}]; new ApplePaySession(apiVersion, request) did not throw exception.
+PASS request = validRequest(); request.installmentConfiguration.items = [{type: "pad"}]; new ApplePaySession(apiVersion, request) did not throw exception.
+PASS request = validRequest(); request.installmentConfiguration.items = [{type: "watch"}]; new ApplePaySession(apiVersion, request) did not throw exception.
+PASS request = validRequest(); request.installmentConfiguration.items = [{type: "mac"}]; new ApplePaySession(apiVersion, request) did not throw exception.
+
+Test installmentConfiguration.applicationMetadata
+PASS request = validRequest(); request.installmentConfiguration.applicationMetadata = 4; new ApplePaySession(apiVersion, request) threw exception TypeError: applicationMetadata must be a JSON object.
+PASS request = validRequest(); request.installmentConfiguration.applicationMetadata = ""; new ApplePaySession(apiVersion, request) threw exception TypeError: applicationMetadata must be a JSON object.
+PASS request = validRequest(); request.installmentConfiguration.applicationMetadata = null; new ApplePaySession(apiVersion, request) threw exception TypeError: applicationMetadata must be a JSON object.
+PASS request = validRequest(); request.installmentConfiguration.applicationMetadata = true; new ApplePaySession(apiVersion, request) threw exception TypeError: applicationMetadata must be a JSON object.
+PASS request = validRequest(); request.installmentConfiguration.applicationMetadata = new Date(); new ApplePaySession(apiVersion, request) threw exception TypeError: applicationMetadata must be a JSON object.
+PASS request = validRequest(); request.installmentConfiguration.applicationMetadata = ["a", "b"]; new ApplePaySession(apiVersion, request) threw exception TypeError: applicationMetadata must be a JSON object.
+PASS request = validRequest(); request.installmentConfiguration.applicationMetadata = undefined; new ApplePaySession(apiVersion, request) did not throw exception.
+PASS request = validRequest(); request.installmentConfiguration.applicationMetadata = {}; new ApplePaySession(apiVersion, request) did not throw exception.
+PASS request = validRequest(); request.installmentConfiguration.applicationMetadata = {"foo": "bar"}; new ApplePaySession(apiVersion, request) did not throw exception.
+
+Test installmentConfiguration.retailChannel
+PASS request = validRequest(); request.installmentConfiguration.retailChannel = null; new ApplePaySession(apiVersion, request) threw exception TypeError: Type error.
+PASS request = validRequest(); request.installmentConfiguration.retailChannel = 4; new ApplePaySession(apiVersion, request) threw exception TypeError: Type error.
+PASS request = validRequest(); request.installmentConfiguration.retailChannel = ""; new ApplePaySession(apiVersion, request) threw exception TypeError: Type error.
+PASS request = validRequest(); request.installmentConfiguration.retailChannel = "invalid"; new ApplePaySession(apiVersion, request) threw exception TypeError: Type error.
+PASS request = validRequest(); request.installmentConfiguration.retailChannel = undefined; new ApplePaySession(apiVersion, request) did not throw exception.
+PASS request = validRequest(); request.installmentConfiguration.retailChannel = "unknown"; new ApplePaySession(apiVersion, request) did not throw exception.
+PASS request = validRequest(); request.installmentConfiguration.retailChannel = "app"; new ApplePaySession(apiVersion, request) did not throw exception.
+PASS request = validRequest(); request.installmentConfiguration.retailChannel = "web"; new ApplePaySession(apiVersion, request) did not throw exception.
+PASS request = validRequest(); request.installmentConfiguration.retailChannel = "inStore"; new ApplePaySession(apiVersion, request) did not throw exception.
+
+Test platform conversion
+PASS internals.mockPaymentCoordinator.installmentConfiguration.items.length is 2
+PASS internals.mockPaymentCoordinator.installmentConfiguration.items[0].type is expectedItemType
+PASS internals.mockPaymentCoordinator.installmentConfiguration.items[0].amount is expectedItemAmount
+PASS internals.mockPaymentCoordinator.installmentConfiguration.items[0].currencyCode is expectedCurrencyCode
+PASS internals.mockPaymentCoordinator.installmentConfiguration.items[0].programIdentifier is expectedProgramIdentifier
+PASS internals.mockPaymentCoordinator.installmentConfiguration.items[0].apr is expectedAPR
+PASS internals.mockPaymentCoordinator.installmentConfiguration.items[0].programTerms is expectedProgramTerms
+PASS internals.mockPaymentCoordinator.installmentConfiguration.items[1].type is "generic"
+PASS JSON.stringify(internals.mockPaymentCoordinator.installmentConfiguration.applicationMetadata) is JSON.stringify(expectedApplicationMetadata, Object.keys(expectedApplicationMetadata).sort())
+PASS internals.mockPaymentCoordinator.installmentConfiguration.retailChannel is expectedRetailChannel
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/ssl/applepay/ApplePayInstallmentItems.https.html b/LayoutTests/http/tests/ssl/applepay/ApplePayInstallmentItems.https.html
new file mode 100644 (file)
index 0000000..eb75c43
--- /dev/null
@@ -0,0 +1,129 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset='utf-8'>
+<script src='/js-test-resources/ui-helper.js'></script>
+<script src='/resources/js-test-pre.js'></script>
+<script src='/resources/payment-request.js'></script>
+</head>
+<body>
+<script>
+
+description('Test ApplePayInstallmentItem and friends.');
+
+jsTestIsAsync = true;
+
+apiVersion = 9;
+
+expectedAPR = '3.875';
+expectedApplicationMetadata = { integer: 1, float: 2.1, string: 'string', date: new Date(), bool: true, array: ['a', 'b'], null: null };
+expectedBindingTotalAmount = '1.00';
+expectedCurrencyCode = 'USD';
+expectedFeatureType = 'appleCard';
+expectedIsInStorePurchase = false;
+expectedItemAmount = '31.45';
+expectedItemType = "mac";
+expectedMerchandisingImageData = 'dGVzdA==';
+expectedMerchantIdentifier = 'merchant';
+expectedOpenToBuyThresholdAmount = '2.50';
+expectedProgramIdentifier = 'programIdentifier';
+expectedProgramTerms = 'programTerms';
+expectedReferrerIdentifier = 'referrer';
+expectedRetailChannel = 'web';
+
+let validRequest = () => {
+    return {
+        countryCode: 'US',
+        currencyCode: 'USD',
+        supportedNetworks: ['visa', 'masterCard'],
+        merchantCapabilities: ['supports3DS'],
+        total: { label: 'Your Label', amount: '10.00' },
+        installmentConfiguration: {
+            bindingTotalAmount: expectedBindingTotalAmount,
+            currencyCode: expectedCurrencyCode,
+            merchandisingImageData: expectedMerchandisingImageData,
+            merchantIdentifier: expectedMerchantIdentifier,
+            openToBuyThresholdAmount: expectedOpenToBuyThresholdAmount,
+            referrerIdentifier: expectedReferrerIdentifier,
+            items: [{
+                type: expectedItemType,
+                amount: expectedItemAmount,
+                currencyCode: expectedCurrencyCode,
+                programIdentifier: expectedProgramIdentifier,
+                apr: expectedAPR,
+                programTerms: expectedProgramTerms,
+            }, {
+            }],
+            applicationMetadata: expectedApplicationMetadata,
+            retailChannel: expectedRetailChannel,
+        },
+    };
+};
+
+activateThen(() => {
+
+    debug('Test installmentConfiguration.items');
+    shouldThrow('request = validRequest(); request.installmentConfiguration.items = 4; new ApplePaySession(apiVersion, request)');
+    shouldThrow('request = validRequest(); request.installmentConfiguration.items = ""; new ApplePaySession(apiVersion, request)');
+    shouldThrow('request = validRequest(); request.installmentConfiguration.items = null; new ApplePaySession(apiVersion, request)');
+    shouldThrow('request = validRequest(); request.installmentConfiguration.items = true; new ApplePaySession(apiVersion, request)');
+    shouldThrow('request = validRequest(); request.installmentConfiguration.items = new Date(); new ApplePaySession(apiVersion, request)');
+    shouldThrow('request = validRequest(); request.installmentConfiguration.items = ["a", "b"]; new ApplePaySession(apiVersion, request)');
+    shouldThrow('request = validRequest(); request.installmentConfiguration.items = [{type: 4}]; new ApplePaySession(apiVersion, request)');
+    shouldThrow('request = validRequest(); request.installmentConfiguration.items = [{type: "invalid"}]; new ApplePaySession(apiVersion, request)');
+    shouldNotThrow('request = validRequest(); request.installmentConfiguration.items = undefined; new ApplePaySession(apiVersion, request)');
+    shouldNotThrow('request = validRequest(); request.installmentConfiguration.items = []; new ApplePaySession(apiVersion, request)');
+    shouldNotThrow('request = validRequest(); request.installmentConfiguration.items = [{}]; new ApplePaySession(apiVersion, request)');
+    shouldNotThrow('request = validRequest(); request.installmentConfiguration.items = [{type: undefined}]; new ApplePaySession(apiVersion, request)');
+    shouldNotThrow('request = validRequest(); request.installmentConfiguration.items = [{type: "generic"}]; new ApplePaySession(apiVersion, request)');
+    shouldNotThrow('request = validRequest(); request.installmentConfiguration.items = [{type: "phone"}]; new ApplePaySession(apiVersion, request)');
+    shouldNotThrow('request = validRequest(); request.installmentConfiguration.items = [{type: "pad"}]; new ApplePaySession(apiVersion, request)');
+    shouldNotThrow('request = validRequest(); request.installmentConfiguration.items = [{type: "watch"}]; new ApplePaySession(apiVersion, request)');
+    shouldNotThrow('request = validRequest(); request.installmentConfiguration.items = [{type: "mac"}]; new ApplePaySession(apiVersion, request)');
+    debug('');
+
+    debug('Test installmentConfiguration.applicationMetadata');
+    shouldThrow('request = validRequest(); request.installmentConfiguration.applicationMetadata = 4; new ApplePaySession(apiVersion, request)');
+    shouldThrow('request = validRequest(); request.installmentConfiguration.applicationMetadata = ""; new ApplePaySession(apiVersion, request)');
+    shouldThrow('request = validRequest(); request.installmentConfiguration.applicationMetadata = null; new ApplePaySession(apiVersion, request)');
+    shouldThrow('request = validRequest(); request.installmentConfiguration.applicationMetadata = true; new ApplePaySession(apiVersion, request)');
+    shouldThrow('request = validRequest(); request.installmentConfiguration.applicationMetadata = new Date(); new ApplePaySession(apiVersion, request)');
+    shouldThrow('request = validRequest(); request.installmentConfiguration.applicationMetadata = ["a", "b"]; new ApplePaySession(apiVersion, request)');
+    shouldNotThrow('request = validRequest(); request.installmentConfiguration.applicationMetadata = undefined; new ApplePaySession(apiVersion, request)');
+    shouldNotThrow('request = validRequest(); request.installmentConfiguration.applicationMetadata = {}; new ApplePaySession(apiVersion, request)');
+    shouldNotThrow('request = validRequest(); request.installmentConfiguration.applicationMetadata = {"foo": "bar"}; new ApplePaySession(apiVersion, request)');
+    debug('');
+
+    debug('Test installmentConfiguration.retailChannel');
+    shouldThrow('request = validRequest(); request.installmentConfiguration.retailChannel = null; new ApplePaySession(apiVersion, request)');
+    shouldThrow('request = validRequest(); request.installmentConfiguration.retailChannel = 4; new ApplePaySession(apiVersion, request)');
+    shouldThrow('request = validRequest(); request.installmentConfiguration.retailChannel = ""; new ApplePaySession(apiVersion, request)');
+    shouldThrow('request = validRequest(); request.installmentConfiguration.retailChannel = "invalid"; new ApplePaySession(apiVersion, request)');
+    shouldNotThrow('request = validRequest(); request.installmentConfiguration.retailChannel = undefined; new ApplePaySession(apiVersion, request)');
+    shouldNotThrow('request = validRequest(); request.installmentConfiguration.retailChannel = "unknown"; new ApplePaySession(apiVersion, request)');
+    shouldNotThrow('request = validRequest(); request.installmentConfiguration.retailChannel = "app"; new ApplePaySession(apiVersion, request)');
+    shouldNotThrow('request = validRequest(); request.installmentConfiguration.retailChannel = "web"; new ApplePaySession(apiVersion, request)');
+    shouldNotThrow('request = validRequest(); request.installmentConfiguration.retailChannel = "inStore"; new ApplePaySession(apiVersion, request)');
+    debug('');
+
+    debug('Test platform conversion');
+    let session = new ApplePaySession(apiVersion, validRequest());
+    session.begin();
+    shouldBe('internals.mockPaymentCoordinator.installmentConfiguration.items.length', '2');
+    shouldBe('internals.mockPaymentCoordinator.installmentConfiguration.items[0].type', 'expectedItemType');
+    shouldBe('internals.mockPaymentCoordinator.installmentConfiguration.items[0].amount', 'expectedItemAmount');
+    shouldBe('internals.mockPaymentCoordinator.installmentConfiguration.items[0].currencyCode', 'expectedCurrencyCode');
+    shouldBe('internals.mockPaymentCoordinator.installmentConfiguration.items[0].programIdentifier', 'expectedProgramIdentifier');
+    shouldBe('internals.mockPaymentCoordinator.installmentConfiguration.items[0].apr', 'expectedAPR');
+    shouldBe('internals.mockPaymentCoordinator.installmentConfiguration.items[0].programTerms', 'expectedProgramTerms');
+    shouldBe('internals.mockPaymentCoordinator.installmentConfiguration.items[1].type', '"generic"');
+    shouldBe('JSON.stringify(internals.mockPaymentCoordinator.installmentConfiguration.applicationMetadata)', 'JSON.stringify(expectedApplicationMetadata, Object.keys(expectedApplicationMetadata).sort())');
+    shouldBe('internals.mockPaymentCoordinator.installmentConfiguration.retailChannel', 'expectedRetailChannel');
+
+    finishJSTest();
+});
+
+</script>
+<script src="/resources/js-test-post.js"></script>
+</body>
+</html>
index e5f3e0a..cda8adf 100644 (file)
@@ -39,6 +39,9 @@ http/tests/ssl/applepay/ [ Pass ]
 # ApplePayInstallmentConfiguration was first available in Catalina.
 [ Mojave ] http/tests/ssl/applepay/ApplePayInstallmentConfiguration.https.html [ Skip ]
 
+# ApplePayInstallmentItem is not available in Mojave or Catalina.
+[ Mojave Catalina ] http/tests/ssl/applepay/ApplePayInstallmentItems.https.html [ Skip ]
+
 fast/visual-viewport/rubberbanding-viewport-rects.html [ Pass ]
 fast/visual-viewport/rubberbanding-viewport-rects-header-footer.html  [ Pass ]
 
index f83d72e..3cf8340 100644 (file)
@@ -1,3 +1,13 @@
+2020-05-22  Andy Estes  <aestes@apple.com>
+
+        [Apple Pay] Add new ApplePayInstallmentConfiguration members
+        https://bugs.webkit.org/show_bug.cgi?id=212160
+        <rdar://problem/60703650>
+
+        Reviewed by Alex Christensen.
+
+        * wtf/PlatformEnableCocoa.h: Defined ENABLE_APPLE_PAY_INSTALLMENT_IDENTIFIERS.
+
 2020-05-21  Robin Morisset  <rmorisset@apple.com>
 
         Various compile-time boolean flags could/should be marked constexpr
index 73bb0c7..49555b6 100644 (file)
 #define ENABLE_AIRPLAY_PICKER 1
 #endif
 
+#if HAVE(PASSKIT_INSTALLMENT_IDENTIFIERS)
+#if !defined(ENABLE_APPLE_PAY_INSTALLMENT_IDENTIFIERS)
+#define ENABLE_APPLE_PAY_INSTALLMENT_IDENTIFIERS 1
+#endif
+#endif
+
 #if HAVE(PASSKIT_INSTALLMENT_ITEMS)
 #if !defined(ENABLE_APPLE_PAY_INSTALLMENT_ITEMS)
 #define ENABLE_APPLE_PAY_INSTALLMENT_ITEMS 1
@@ -56,7 +62,6 @@
 #if !defined(ENABLE_APPLE_PAY_SESSION_V8)
 #define ENABLE_APPLE_PAY_SESSION_V8 1
 #endif
-
 #endif
 
 #if !defined(ENABLE_APPLE_PAY_REMOTE_UI) && (PLATFORM(IOS_FAMILY) && !PLATFORM(APPLETV) && !PLATFORM(MACCATALYST) && !PLATFORM(WATCHOS))
index ef3b406..b605374 100644 (file)
@@ -1,3 +1,67 @@
+2020-05-22  Andy Estes  <aestes@apple.com>
+
+        [Apple Pay] Add new ApplePayInstallmentConfiguration members
+        https://bugs.webkit.org/show_bug.cgi?id=212160
+        <rdar://problem/60703650>
+
+        Reviewed by Alex Christensen.
+
+        Test: http/tests/ssl/applepay/ApplePayInstallmentItems.https.html
+
+        * DerivedSources-input.xcfilelist:
+        * DerivedSources-output.xcfilelist:
+        * DerivedSources.make:
+        * SourcesCocoa.txt:
+        * WebCore.xcodeproj/project.pbxproj: Added IDLs, headers, and derived sources for
+        ApplePayInstallment{Item,ItemType,RetailChannel}.
+
+        * Modules/applepay/ApplePayInstallmentConfiguration.idl:
+        * Modules/applepay/ApplePayInstallmentConfigurationWebCore.h: Added items,
+        applicationMetadata, and retailChannel members. Added missing conditionals to
+        merchantIdentifier and referrerIdentifier.
+
+        * Modules/applepay/ApplePayInstallmentItem.h:
+        * Modules/applepay/ApplePayInstallmentItem.idl:
+        * Modules/applepay/ApplePayInstallmentItemType.h:
+        * Modules/applepay/ApplePayInstallmentItemType.idl:
+        * Modules/applepay/ApplePayInstallmentRetailChannel.h:
+        * Modules/applepay/ApplePayInstallmentRetailChannel.idl: Added.
+
+        * Modules/applepay/ApplePayRequestBase.cpp:
+        (WebCore::convertAndValidate): Changed to call PaymentInstallmentConfiguration::create,
+        returning an exception if present.
+
+        * Modules/applepay/PaymentInstallmentConfiguration.mm:
+        (WebCore::fromDecimalNumber): Allowed for a large maximum number of fractional digits to
+        support formatting high-precision currency and APRs (note that this formatter is only used
+        for test support).
+
+        (WebCore::applePayItemType):
+        (WebCore::platformItemType): Added to convert between PKInstallmentItemType and
+        ApplePayInstallmentItemType.
+
+        (WebCore::applePayRetailChannel):
+        (WebCore::platformRetailChannel): Added to convert between PKInstallmentRetailChannel and
+        ApplePayInstallmentRetailChannel.
+
+        (WebCore::makeNSArrayElement):
+        (WebCore::makeVectorElement): Added to convert between NSArray<PKPaymentInstallmentItem *>
+        and Vector<ApplePayInstallmentItem>.
+
+        (WebCore::createPlatformConfiguration): Added a parameter for passing in applicationMetadata
+        as an NSDictionary. Set properties on PKPaymentInstallmentConfiguration for new
+        ApplePayInstallmentConfiguration members.
+        (WebCore::PaymentInstallmentConfiguration::create): Added; converts the applicationMetadata
+        JSON string (if present) to an NSDictionary, returning a TypeError if the JSON string does
+        not deserialize to an NSDictionary (as PassKit requires).
+        (WebCore::PaymentInstallmentConfiguration::PaymentInstallmentConfiguration): Added a
+        parameter for passing in applicationMetadata as an NSDictionary. Made private.
+        (WebCore::PaymentInstallmentConfiguration::applePayInstallmentConfiguration const): Set
+        members on ApplePayInstallmentConfiguration for new PKPaymentInstallmentConfiguration
+        properties.
+
+        * Modules/applepay/PaymentInstallmentConfigurationWebCore.h:
+
 2020-05-22  Alex Christensen  <achristensen@webkit.org>
 
         Add SPI to unblock third party cookies from WKWebViews with ResourceLoadStatistics turned on
index 5a8da6a..3f299f3 100644 (file)
@@ -25,6 +25,9 @@ $(PROJECT_DIR)/Modules/applepay/ApplePayError.idl
 $(PROJECT_DIR)/Modules/applepay/ApplePayErrorCode.idl
 $(PROJECT_DIR)/Modules/applepay/ApplePayErrorContactField.idl
 $(PROJECT_DIR)/Modules/applepay/ApplePayInstallmentConfiguration.idl
+$(PROJECT_DIR)/Modules/applepay/ApplePayInstallmentItem.idl
+$(PROJECT_DIR)/Modules/applepay/ApplePayInstallmentItemType.idl
+$(PROJECT_DIR)/Modules/applepay/ApplePayInstallmentRetailChannel.idl
 $(PROJECT_DIR)/Modules/applepay/ApplePayLineItem.idl
 $(PROJECT_DIR)/Modules/applepay/ApplePayMerchantCapability.idl
 $(PROJECT_DIR)/Modules/applepay/ApplePayPayment.idl
index f3e9762..2a1313c 100644 (file)
@@ -79,6 +79,12 @@ $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSApplePayErrorContactField.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSApplePayErrorContactField.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSApplePayInstallmentConfiguration.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSApplePayInstallmentConfiguration.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSApplePayInstallmentItem.cpp
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSApplePayInstallmentItem.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSApplePayInstallmentItemType.cpp
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSApplePayInstallmentItemType.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSApplePayInstallmentRetailChannel.cpp
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSApplePayInstallmentRetailChannel.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSApplePayLineItem.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSApplePayLineItem.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSApplePayMerchantCapability.cpp
index 2a3ef90..ecfa32a 100644 (file)
@@ -104,6 +104,9 @@ JS_BINDING_IDLS = \
     $(WebCore)/Modules/applepay/ApplePayErrorCode.idl \
     $(WebCore)/Modules/applepay/ApplePayErrorContactField.idl \
     $(WebCore)/Modules/applepay/ApplePayInstallmentConfiguration.idl \
+       $(WebCore)/Modules/applepay/ApplePayInstallmentItem.idl \
+       $(WebCore)/Modules/applepay/ApplePayInstallmentItemType.idl \
+       $(WebCore)/Modules/applepay/ApplePayInstallmentRetailChannel.idl \
     $(WebCore)/Modules/applepay/ApplePayLineItem.idl \
     $(WebCore)/Modules/applepay/ApplePayMerchantCapability.idl \
     $(WebCore)/Modules/applepay/ApplePayPayment.idl \
index 068c28a..f3dc178 100644 (file)
     DOMString openToBuyThresholdAmount;
     DOMString bindingTotalAmount;
     DOMString currencyCode;
-    DOMString merchantIdentifier;
-    DOMString referrerIdentifier;
     boolean isInStorePurchase;
+    [Conditional=APPLE_PAY_INSTALLMENT_IDENTIFIERS] DOMString merchantIdentifier;
+    [Conditional=APPLE_PAY_INSTALLMENT_IDENTIFIERS] DOMString referrerIdentifier;
+    [Conditional=APPLE_PAY_INSTALLMENT_ITEMS] sequence<ApplePayInstallmentItem> items;
+    [Conditional=APPLE_PAY_INSTALLMENT_ITEMS] JSON applicationMetadata;
+    [Conditional=APPLE_PAY_INSTALLMENT_ITEMS] ApplePayInstallmentRetailChannel retailChannel = "unknown";
 };
index 202015b..7c3131b 100644 (file)
 
 #if ENABLE(APPLE_PAY_INSTALLMENTS)
 
+#include "ApplePayInstallmentItem.h"
+#include "ApplePayInstallmentRetailChannel.h"
 #include "ApplePaySetupFeatureTypeWebCore.h"
+#include <wtf/Vector.h>
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
@@ -38,9 +41,16 @@ struct ApplePayInstallmentConfiguration {
     String openToBuyThresholdAmount;
     String bindingTotalAmount;
     String currencyCode;
+    bool isInStorePurchase { false };
+#if ENABLE(APPLE_PAY_INSTALLMENT_IDENTIFIERS)
     String merchantIdentifier;
     String referrerIdentifier;
-    bool isInStorePurchase { false };
+#endif
+#if ENABLE(APPLE_PAY_INSTALLMENT_ITEMS)
+    Vector<ApplePayInstallmentItem> items;
+    String applicationMetadata;
+    ApplePayInstallmentRetailChannel retailChannel { ApplePayInstallmentRetailChannel::Unknown };
+#endif
 };
 
 } // namespace WebCore
diff --git a/Source/WebCore/Modules/applepay/ApplePayInstallmentItem.h b/Source/WebCore/Modules/applepay/ApplePayInstallmentItem.h
new file mode 100644 (file)
index 0000000..e6caa2a
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(APPLE_PAY_INSTALLMENT_ITEMS)
+
+#include "ApplePayInstallmentItemType.h"
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+struct ApplePayInstallmentItem {
+    ApplePayInstallmentItemType type { ApplePayInstallmentItemType::Generic };
+    String amount;
+    String currencyCode;
+    String programIdentifier;
+    String apr;
+    String programTerms;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(APPLE_PAY_INSTALLMENT_ITEMS)
diff --git a/Source/WebCore/Modules/applepay/ApplePayInstallmentItem.idl b/Source/WebCore/Modules/applepay/ApplePayInstallmentItem.idl
new file mode 100644 (file)
index 0000000..155a6d6
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+[
+    Conditional=APPLE_PAY_INSTALLMENT_ITEMS,
+    JSGenerateToJSObject,
+] dictionary ApplePayInstallmentItem {
+    ApplePayInstallmentItemType type = "generic";
+    DOMString amount;
+    DOMString currencyCode;
+    DOMString programIdentifier;
+    DOMString apr;
+    DOMString programTerms;
+};
diff --git a/Source/WebCore/Modules/applepay/ApplePayInstallmentItemType.h b/Source/WebCore/Modules/applepay/ApplePayInstallmentItemType.h
new file mode 100644 (file)
index 0000000..2dcfbe6
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(APPLE_PAY_INSTALLMENT_ITEMS)
+
+namespace WebCore {
+
+enum class ApplePayInstallmentItemType : uint8_t {
+    Generic,
+    Phone,
+    Pad,
+    Watch,
+    Mac,
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(APPLE_PAY_INSTALLMENT_ITEMS)
diff --git a/Source/WebCore/Modules/applepay/ApplePayInstallmentItemType.idl b/Source/WebCore/Modules/applepay/ApplePayInstallmentItemType.idl
new file mode 100644 (file)
index 0000000..7363257
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+[
+    Conditional=APPLE_PAY_INSTALLMENT_ITEMS,
+] enum ApplePayInstallmentItemType {
+    "generic",
+    "phone",
+    "pad",
+    "watch",
+    "mac"
+};
diff --git a/Source/WebCore/Modules/applepay/ApplePayInstallmentRetailChannel.h b/Source/WebCore/Modules/applepay/ApplePayInstallmentRetailChannel.h
new file mode 100644 (file)
index 0000000..38cb9db
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(APPLE_PAY_INSTALLMENT_ITEMS)
+
+namespace WebCore {
+
+enum class ApplePayInstallmentRetailChannel : uint8_t {
+    Unknown,
+    App,
+    Web,
+    InStore,
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(APPLE_PAY_INSTALLMENT_ITEMS)
diff --git a/Source/WebCore/Modules/applepay/ApplePayInstallmentRetailChannel.idl b/Source/WebCore/Modules/applepay/ApplePayInstallmentRetailChannel.idl
new file mode 100644 (file)
index 0000000..d08b103
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+[
+    Conditional=APPLE_PAY_INSTALLMENT_ITEMS,
+] enum ApplePayInstallmentRetailChannel {
+    "unknown",
+    "app",
+    "web",
+    "inStore"
+};
index 1ea567e..7270b20 100644 (file)
@@ -106,8 +106,12 @@ ExceptionOr<ApplePaySessionPaymentRequest> convertAndValidate(Document& document
         result.setSupportedCountries(WTFMove(request.supportedCountries));
 
 #if ENABLE(APPLE_PAY_INSTALLMENTS)
-    if (request.installmentConfiguration)
-        result.setInstallmentConfiguration(WTFMove(*request.installmentConfiguration));
+    if (request.installmentConfiguration) {
+        auto installmentConfiguration = PaymentInstallmentConfiguration::create(*request.installmentConfiguration);
+        if (installmentConfiguration.hasException())
+            return installmentConfiguration.releaseException();
+        result.setInstallmentConfiguration(installmentConfiguration.releaseReturnValue());
+    }
 #endif
 
     return WTFMove(result);
index fc084f9..c679b5c 100644 (file)
 #if HAVE(PASSKIT_INSTALLMENTS)
 
 #import "ApplePayInstallmentConfigurationWebCore.h"
+#import "ApplePayInstallmentItemType.h"
+#import "ApplePayInstallmentRetailChannel.h"
+#import "ExceptionOr.h"
+#import <wtf/cocoa/VectorCocoa.h>
+
 #import <pal/cocoa/PassKitSoftLink.h>
 
 namespace WebCore {
@@ -47,10 +52,23 @@ static String fromDecimalNumber(NSDecimalNumber *number)
     [numberFormatter setNumberStyle:NSNumberFormatterNoStyle];
     [numberFormatter setMinimumIntegerDigits:1];
     [numberFormatter setMinimumFractionDigits:2];
+    [numberFormatter setMaximumFractionDigits:[numberFormatter maximumIntegerDigits]];
     return [numberFormatter stringFromNumber:number];
 }
 
-static PKPaymentSetupFeatureType platformFeatureType(const ApplePaySetupFeatureType& featureType)
+static ApplePaySetupFeatureType applePaySetupFeatureType(PKPaymentSetupFeatureType featureType)
+{
+    switch (featureType) {
+    case PKPaymentSetupFeatureTypeApplePay:
+        return ApplePaySetupFeatureType::ApplePay;
+    ALLOW_DEPRECATED_DECLARATIONS_BEGIN
+    case PKPaymentSetupFeatureTypeApplePay_X:
+    ALLOW_DEPRECATED_DECLARATIONS_END
+        return ApplePaySetupFeatureType::AppleCard;
+    }
+}
+
+static PKPaymentSetupFeatureType platformFeatureType(ApplePaySetupFeatureType featureType)
 {
     switch (featureType) {
     case ApplePaySetupFeatureType::ApplePay:
@@ -62,19 +80,95 @@ static PKPaymentSetupFeatureType platformFeatureType(const ApplePaySetupFeatureT
     }
 }
 
-static ApplePaySetupFeatureType applePaySetupFeatureType(PKPaymentSetupFeatureType featureType)
+static ApplePayInstallmentItemType applePayItemType(PKInstallmentItemType itemType)
 {
-    switch (featureType) {
-    case PKPaymentSetupFeatureTypeApplePay:
-        return ApplePaySetupFeatureType::ApplePay;
-    ALLOW_DEPRECATED_DECLARATIONS_BEGIN
-    case PKPaymentSetupFeatureTypeApplePay_X:
-    ALLOW_DEPRECATED_DECLARATIONS_END
-        return ApplePaySetupFeatureType::AppleCard;
+    switch (itemType) {
+    case PKInstallmentItemTypeGeneric:
+        return ApplePayInstallmentItemType::Generic;
+    case PKInstallmentItemTypePhone:
+        return ApplePayInstallmentItemType::Phone;
+    case PKInstallmentItemTypePad:
+        return ApplePayInstallmentItemType::Pad;
+    case PKInstallmentItemTypeWatch:
+        return ApplePayInstallmentItemType::Watch;
+    case PKInstallmentItemTypeMac:
+        return ApplePayInstallmentItemType::Mac;
+    }
+}
+
+static PKInstallmentItemType platformItemType(ApplePayInstallmentItemType itemType)
+{
+    switch (itemType) {
+    case ApplePayInstallmentItemType::Generic:
+        return PKInstallmentItemTypeGeneric;
+    case ApplePayInstallmentItemType::Phone:
+        return PKInstallmentItemTypePhone;
+    case ApplePayInstallmentItemType::Pad:
+        return PKInstallmentItemTypePad;
+    case ApplePayInstallmentItemType::Watch:
+        return PKInstallmentItemTypeWatch;
+    case ApplePayInstallmentItemType::Mac:
+        return PKInstallmentItemTypeMac;
+    }
+}
+
+static ApplePayInstallmentRetailChannel applePayRetailChannel(PKInstallmentRetailChannel retailChannel)
+{
+    switch (retailChannel) {
+    case PKInstallmentRetailChannelUnknown:
+        return ApplePayInstallmentRetailChannel::Unknown;
+    case PKInstallmentRetailChannelApp:
+        return ApplePayInstallmentRetailChannel::App;
+    case PKInstallmentRetailChannelWeb:
+        return ApplePayInstallmentRetailChannel::Web;
+    case PKInstallmentRetailChannelInStore:
+        return ApplePayInstallmentRetailChannel::InStore;
+    }
+}
+
+static PKInstallmentRetailChannel platformRetailChannel(ApplePayInstallmentRetailChannel retailChannel)
+{
+    switch (retailChannel) {
+    case ApplePayInstallmentRetailChannel::Unknown:
+        return PKInstallmentRetailChannelUnknown;
+    case ApplePayInstallmentRetailChannel::App:
+        return PKInstallmentRetailChannelApp;
+    case ApplePayInstallmentRetailChannel::Web:
+        return PKInstallmentRetailChannelWeb;
+    case ApplePayInstallmentRetailChannel::InStore:
+        return PKInstallmentRetailChannelInStore;
     }
 }
 
-static RetainPtr<PKPaymentInstallmentConfiguration> createPlatformConfiguration(const ApplePayInstallmentConfiguration& coreConfiguration)
+static RetainPtr<id> makeNSArrayElement(const ApplePayInstallmentItem& item)
+{
+    auto installmentItem = adoptNS([PAL::allocPKPaymentInstallmentItemInstance() init]);
+    [installmentItem setInstallmentItemType:platformItemType(item.type)];
+    [installmentItem setAmount:toDecimalNumber(item.amount)];
+    [installmentItem setCurrencyCode:item.currencyCode];
+    [installmentItem setProgramIdentifier:item.programIdentifier];
+    [installmentItem setApr:toDecimalNumber(item.apr)];
+    [installmentItem setProgramTerms:item.programTerms];
+    return installmentItem;
+}
+
+static Optional<ApplePayInstallmentItem> makeVectorElement(const ApplePayInstallmentItem*, id arrayElement)
+{
+    if (![arrayElement isKindOfClass:PAL::getPKPaymentInstallmentItemClass()])
+        return WTF::nullopt;
+
+    PKPaymentInstallmentItem *item = arrayElement;
+    return ApplePayInstallmentItem {
+        applePayItemType([item installmentItemType]),
+        fromDecimalNumber([item amount]),
+        [item currencyCode],
+        [item programIdentifier],
+        fromDecimalNumber([item apr]),
+        [item programTerms],
+    };
+}
+
+static RetainPtr<PKPaymentInstallmentConfiguration> createPlatformConfiguration(const ApplePayInstallmentConfiguration& coreConfiguration, NSDictionary *applicationMetadata)
 {
     auto configuration = adoptNS([PAL::allocPKPaymentInstallmentConfigurationInstance() init]);
 
@@ -96,12 +190,41 @@ static RetainPtr<PKPaymentInstallmentConfiguration> createPlatformConfiguration(
     [configuration setInstallmentMerchantIdentifier:coreConfiguration.merchantIdentifier];
     [configuration setReferrerIdentifier:coreConfiguration.referrerIdentifier];
 #endif
+    
+#if HAVE(PASSKIT_INSTALLMENT_ITEMS)
+#if PLATFORM(MAC)
+    if (![configuration respondsToSelector:@selector(setInstallmentItems:)]
+        || ![configuration respondsToSelector:@selector(setApplicationMetadata:)]
+        || ![configuration respondsToSelector:@selector(setRetailChannel:)])
+        return configuration;
+#endif
+    [configuration setInstallmentItems:createNSArray(coreConfiguration.items).get()];
+    [configuration setApplicationMetadata:applicationMetadata];
+    [configuration setRetailChannel:platformRetailChannel(coreConfiguration.retailChannel)];
+#else
+    UNUSED_PARAM(applicationMetadata);
+#endif
 
     return configuration;
 }
 
-PaymentInstallmentConfiguration::PaymentInstallmentConfiguration(const ApplePayInstallmentConfiguration& configuration)
-    : m_configuration { createPlatformConfiguration(configuration) }
+ExceptionOr<PaymentInstallmentConfiguration> PaymentInstallmentConfiguration::create(const ApplePayInstallmentConfiguration& configuration)
+{
+    NSDictionary *applicationMetadataDictionary = nil;
+#if ENABLE(APPLE_PAY_INSTALLMENT_ITEMS)
+    if (!configuration.applicationMetadata.isNull()) {
+        NSData *applicationMetadata = [configuration.applicationMetadata dataUsingEncoding:NSUTF8StringEncoding];
+        applicationMetadataDictionary = dynamic_objc_cast<NSDictionary>([NSJSONSerialization JSONObjectWithData:applicationMetadata options:0 error:nil]);
+        if (!applicationMetadataDictionary)
+            return Exception { TypeError, "applicationMetadata must be a JSON object" };
+    }
+#endif
+
+    return PaymentInstallmentConfiguration(configuration, applicationMetadataDictionary);
+}
+
+PaymentInstallmentConfiguration::PaymentInstallmentConfiguration(const ApplePayInstallmentConfiguration& configuration, NSDictionary *applicationMetadata)
+    : m_configuration { createPlatformConfiguration(configuration, applicationMetadata) }
 {
 }
 
@@ -136,7 +259,25 @@ ApplePayInstallmentConfiguration PaymentInstallmentConfiguration::applePayInstal
     installmentConfiguration.merchantIdentifier = [m_configuration installmentMerchantIdentifier];
     installmentConfiguration.referrerIdentifier = [m_configuration referrerIdentifier];
 #endif
-    
+
+#if ENABLE(APPLE_PAY_INSTALLMENT_ITEMS)
+#if PLATFORM(MAC)
+    if (![m_configuration respondsToSelector:@selector(installmentItems)]
+        || ![m_configuration respondsToSelector:@selector(applicationMetadata)]
+        || ![m_configuration respondsToSelector:@selector(retailChannel)])
+        return installmentConfiguration;
+#endif
+    RetainPtr<NSString> applicationMetadataString;
+    if (NSDictionary *applicationMetadataDictionary = [m_configuration applicationMetadata]) {
+        if (NSData *applicationMetadata = [NSJSONSerialization dataWithJSONObject:applicationMetadataDictionary options:NSJSONWritingSortedKeys error:nil])
+            applicationMetadataString = adoptNS([[NSString alloc] initWithData:applicationMetadata encoding:NSUTF8StringEncoding]);
+    }
+
+    installmentConfiguration.items = makeVector<ApplePayInstallmentItem>([m_configuration installmentItems]);
+    installmentConfiguration.applicationMetadata = applicationMetadataString.get();
+    installmentConfiguration.retailChannel = applePayRetailChannel([m_configuration retailChannel]);
+#endif
+
     return installmentConfiguration;
 }
 
index 3bf176a..3971aaa 100644 (file)
 
 #include <wtf/RetainPtr.h>
 
+OBJC_CLASS NSDictionary;
 OBJC_CLASS PKPaymentInstallmentConfiguration;
 
 namespace WebCore {
 
+class Document;
 struct ApplePayInstallmentConfiguration;
+template<typename> class ExceptionOr;
 
 class WEBCORE_EXPORT PaymentInstallmentConfiguration {
 public:
+    static ExceptionOr<PaymentInstallmentConfiguration> create(const ApplePayInstallmentConfiguration&);
+
     PaymentInstallmentConfiguration() = default;
-    PaymentInstallmentConfiguration(const ApplePayInstallmentConfiguration&);
     PaymentInstallmentConfiguration(RetainPtr<PKPaymentInstallmentConfiguration>&&);
 
     PKPaymentInstallmentConfiguration *platformConfiguration() const;
     ApplePayInstallmentConfiguration applePayInstallmentConfiguration() const;
 
 private:
+    PaymentInstallmentConfiguration(const ApplePayInstallmentConfiguration&, NSDictionary *applicationMetadata);
+
     RetainPtr<PKPaymentInstallmentConfiguration> m_configuration;
 };
 
index 0ce5bb6..6ceb9b6 100644 (file)
@@ -1,3 +1,14 @@
+2020-05-22  Andy Estes  <aestes@apple.com>
+
+        [Apple Pay] Add new ApplePayInstallmentConfiguration members
+        https://bugs.webkit.org/show_bug.cgi?id=212160
+        <rdar://problem/60703650>
+
+        Reviewed by Alex Christensen.
+
+        * pal/cocoa/PassKitSoftLink.h:
+        * pal/cocoa/PassKitSoftLink.mm: Added soft-linking macros for PKPaymentInstallmentItem.
+
 2020-05-20  Andy Estes  <aestes@apple.com>
 
         [Mac] UI processes spin when creating the "Share" context menu item
index 24e9d23..eaf1d9b 100644 (file)
@@ -51,6 +51,10 @@ SOFT_LINK_CLASS_FOR_HEADER(PAL, PKShippingMethod)
 SOFT_LINK_CLASS_FOR_HEADER(PAL, PKPaymentInstallmentConfiguration)
 #endif
 
+#if HAVE(PASSKIT_INSTALLMENT_ITEMS)
+SOFT_LINK_CLASS_FOR_HEADER(PAL, PKPaymentInstallmentItem)
+#endif
+
 #if PLATFORM(IOS_FAMILY)
 SOFT_LINK_CLASS_FOR_HEADER(PAL, PKPaymentAuthorizationController)
 #endif
index 0747622..c1fff90 100644 (file)
@@ -42,6 +42,10 @@ SOFT_LINK_CLASS_FOR_SOURCE_OPTIONAL_WITH_EXPORT(PAL, PassKit, PKPaymentSetupRequ
 SOFT_LINK_CLASS_FOR_SOURCE_OPTIONAL_WITH_EXPORT(PAL, PassKit, PKPaymentInstallmentConfiguration, PAL_EXPORT)
 #endif
 
+#if HAVE(PASSKIT_INSTALLMENT_ITEMS)
+SOFT_LINK_CLASS_FOR_SOURCE_OPTIONAL_WITH_EXPORT(PAL, PassKit, PKPaymentInstallmentItem, PAL_EXPORT)
+#endif
+
 #else // PLATFORM(MAC)
 
 SOFT_LINK_FRAMEWORK_FOR_SOURCE_WITH_EXPORT(PAL, PassKit, PAL_EXPORT)
@@ -56,6 +60,10 @@ SOFT_LINK_CLASS_FOR_SOURCE_WITH_EXPORT(PAL, PassKit, PKPaymentSetupViewControlle
 SOFT_LINK_CLASS_FOR_SOURCE_WITH_EXPORT(PAL, PassKit, PKPaymentInstallmentConfiguration, PAL_EXPORT)
 #endif
 
+#if HAVE(PASSKIT_INSTALLMENT_ITEMS)
+SOFT_LINK_CLASS_FOR_SOURCE_WITH_EXPORT(PAL, PassKit, PKPaymentInstallmentItem, PAL_EXPORT)
+#endif
+
 #endif // PLATFORM(MAC)
 
 SOFT_LINK_CLASS_FOR_SOURCE_WITH_EXPORT(PAL, PassKit, PKContact, PAL_EXPORT)
index dbf7f63..b85ad66 100644 (file)
@@ -623,6 +623,9 @@ WHLSLStandardLibraryFunctionMap.cpp
     JSApplePayErrorCode.cpp
     JSApplePayErrorContactField.cpp
     JSApplePayInstallmentConfiguration.cpp
+    JSApplePayInstallmentItem.cpp
+    JSApplePayInstallmentItemType.cpp
+    JSApplePayInstallmentRetailChannel.cpp
     JSApplePayLineItem.cpp
     JSApplePayMerchantCapability.cpp
     JSApplePayModifier.cpp
index 2308d03..0489ae4 100644 (file)
                A110DB9B14F5DF7700A03B93 /* StyleGridItemData.h in Headers */ = {isa = PBXBuildFile; fileRef = A110DB9A14F5DF7700A03B93 /* StyleGridItemData.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A113E02823318293009C33A0 /* PaymentSessionError.h in Headers */ = {isa = PBXBuildFile; fileRef = A113E02723318293009C33A0 /* PaymentSessionError.h */; settings = {ATTRIBUTES = (Private, ); }; };
                A113E02E2331A134009C33A0 /* ApplePayCancelEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = A113E02B2331A0E4009C33A0 /* ApplePayCancelEvent.h */; };
+               A117509A247468D600D4D26C /* ApplePayInstallmentConfigurationWebCore.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C53DCD02446449A00A93124 /* ApplePayInstallmentConfigurationWebCore.h */; };
+               A11750A0247468F300D4D26C /* ApplePayInstallmentItem.h in Headers */ = {isa = PBXBuildFile; fileRef = A117509C247468E500D4D26C /* ApplePayInstallmentItem.h */; };
+               A11750A1247468F700D4D26C /* ApplePayInstallmentItemType.h in Headers */ = {isa = PBXBuildFile; fileRef = A117509D247468E600D4D26C /* ApplePayInstallmentItemType.h */; };
                A11AE0CC1FFD60530047348B /* MerchantValidationEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = A11AE0C91FFD60530047348B /* MerchantValidationEvent.h */; };
                A11AE0D31FFD61DF0047348B /* JSMerchantValidationEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = A11AE0D11FFD61DF0047348B /* JSMerchantValidationEvent.h */; };
                A11E8C051B1E28F40003A7C7 /* copyCursor.png in Resources */ = {isa = PBXBuildFile; fileRef = A11E8C001B1E28BE0003A7C7 /* copyCursor.png */; };
                A12C59FD20360B3E0012236B /* JSApplePayShippingContactUpdate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ADFDFE81E71DCA0008F5D34 /* JSApplePayShippingContactUpdate.h */; };
                A12C59FE20360B4A0012236B /* JSApplePayShippingMethodUpdate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ADFDFEA1E71DCA0008F5D34 /* JSApplePayShippingMethodUpdate.h */; };
                A136A00D1134DBD200CC8D50 /* XMLHttpRequestProgressEventThrottle.h in Headers */ = {isa = PBXBuildFile; fileRef = A136A00B1134DBD200CC8D50 /* XMLHttpRequestProgressEventThrottle.h */; };
+               A13B616B2475E04800BBE6DE /* ApplePayInstallmentRetailChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = A13B61672475DFC500BBE6DE /* ApplePayInstallmentRetailChannel.h */; };
+               A13B61742475E34200BBE6DE /* JSApplePayInstallmentConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = A13B61722475E31500BBE6DE /* JSApplePayInstallmentConfiguration.h */; };
+               A13B61752475E35F00BBE6DE /* JSApplePayInstallmentItem.h in Headers */ = {isa = PBXBuildFile; fileRef = A13B61712475E31400BBE6DE /* JSApplePayInstallmentItem.h */; };
+               A13B61762475E37A00BBE6DE /* JSApplePayInstallmentItemType.h in Headers */ = {isa = PBXBuildFile; fileRef = A13B616E2475E31100BBE6DE /* JSApplePayInstallmentItemType.h */; };
+               A13B61772475E3A300BBE6DE /* JSApplePayInstallmentRetailChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = A13B616F2475E31200BBE6DE /* JSApplePayInstallmentRetailChannel.h */; };
                A140618B1E2ECA0A0032B34E /* MockPreviewLoaderClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A14061891E2ECA0A0032B34E /* MockPreviewLoaderClient.cpp */; };
                A140618C1E2ECA0A0032B34E /* MockPreviewLoaderClient.h in Headers */ = {isa = PBXBuildFile; fileRef = A140618A1E2ECA0A0032B34E /* MockPreviewLoaderClient.h */; };
                A14090FB1AA51E1D0091191A /* ContentFilterUnblockHandlerCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = A14090FA1AA51E1D0091191A /* ContentFilterUnblockHandlerCocoa.mm */; };
                A113E02A23318EBC009C33A0 /* PaymentSessionErrorCocoa.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PaymentSessionErrorCocoa.mm; sourceTree = "<group>"; };
                A113E02B2331A0E4009C33A0 /* ApplePayCancelEvent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ApplePayCancelEvent.h; sourceTree = "<group>"; };
                A113E02C2331A0E4009C33A0 /* ApplePayCancelEvent.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ApplePayCancelEvent.cpp; sourceTree = "<group>"; };
+               A117509C247468E500D4D26C /* ApplePayInstallmentItem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ApplePayInstallmentItem.h; sourceTree = "<group>"; };
+               A117509D247468E600D4D26C /* ApplePayInstallmentItemType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ApplePayInstallmentItemType.h; sourceTree = "<group>"; };
+               A117509E247468E600D4D26C /* ApplePayInstallmentItemType.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = ApplePayInstallmentItemType.idl; sourceTree = "<group>"; };
+               A117509F247468E700D4D26C /* ApplePayInstallmentItem.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = ApplePayInstallmentItem.idl; sourceTree = "<group>"; };
                A11AE0C91FFD60530047348B /* MerchantValidationEvent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MerchantValidationEvent.h; sourceTree = "<group>"; };
                A11AE0CA1FFD60530047348B /* MerchantValidationEvent.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MerchantValidationEvent.cpp; sourceTree = "<group>"; };
                A11AE0CB1FFD60530047348B /* MerchantValidationEvent.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = MerchantValidationEvent.idl; sourceTree = "<group>"; };
                A12A104E166444DC008FA311 /* GridTrackSize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GridTrackSize.h; sourceTree = "<group>"; };
                A136A00A1134DBD200CC8D50 /* XMLHttpRequestProgressEventThrottle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = XMLHttpRequestProgressEventThrottle.cpp; sourceTree = "<group>"; };
                A136A00B1134DBD200CC8D50 /* XMLHttpRequestProgressEventThrottle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XMLHttpRequestProgressEventThrottle.h; sourceTree = "<group>"; };
+               A13B61672475DFC500BBE6DE /* ApplePayInstallmentRetailChannel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ApplePayInstallmentRetailChannel.h; sourceTree = "<group>"; };
+               A13B61692475DFC500BBE6DE /* ApplePayInstallmentRetailChannel.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = ApplePayInstallmentRetailChannel.idl; sourceTree = "<group>"; };
+               A13B616C2475E31000BBE6DE /* JSApplePayInstallmentRetailChannel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSApplePayInstallmentRetailChannel.cpp; sourceTree = "<group>"; };
+               A13B616D2475E31000BBE6DE /* JSApplePayInstallmentConfiguration.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSApplePayInstallmentConfiguration.cpp; sourceTree = "<group>"; };
+               A13B616E2475E31100BBE6DE /* JSApplePayInstallmentItemType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSApplePayInstallmentItemType.h; sourceTree = "<group>"; };
+               A13B616F2475E31200BBE6DE /* JSApplePayInstallmentRetailChannel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSApplePayInstallmentRetailChannel.h; sourceTree = "<group>"; };
+               A13B61702475E31300BBE6DE /* JSApplePayInstallmentItem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSApplePayInstallmentItem.cpp; sourceTree = "<group>"; };
+               A13B61712475E31400BBE6DE /* JSApplePayInstallmentItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSApplePayInstallmentItem.h; sourceTree = "<group>"; };
+               A13B61722475E31500BBE6DE /* JSApplePayInstallmentConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSApplePayInstallmentConfiguration.h; sourceTree = "<group>"; };
+               A13B61732475E31600BBE6DE /* JSApplePayInstallmentItemType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSApplePayInstallmentItemType.cpp; sourceTree = "<group>"; };
                A14061891E2ECA0A0032B34E /* MockPreviewLoaderClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MockPreviewLoaderClient.cpp; sourceTree = "<group>"; };
                A140618A1E2ECA0A0032B34E /* MockPreviewLoaderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MockPreviewLoaderClient.h; sourceTree = "<group>"; };
                A14090FA1AA51E1D0091191A /* ContentFilterUnblockHandlerCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ContentFilterUnblockHandlerCocoa.mm; sourceTree = "<group>"; };
                                A1BB85A22159AF570067E07D /* ApplePayErrorContactField.idl */,
                                5C53DCD52446449B00A93124 /* ApplePayInstallmentConfiguration.idl */,
                                5C53DCD02446449A00A93124 /* ApplePayInstallmentConfigurationWebCore.h */,
+                               A117509C247468E500D4D26C /* ApplePayInstallmentItem.h */,
+                               A117509F247468E700D4D26C /* ApplePayInstallmentItem.idl */,
+                               A117509D247468E600D4D26C /* ApplePayInstallmentItemType.h */,
+                               A117509E247468E600D4D26C /* ApplePayInstallmentItemType.idl */,
+                               A13B61672475DFC500BBE6DE /* ApplePayInstallmentRetailChannel.h */,
+                               A13B61692475DFC500BBE6DE /* ApplePayInstallmentRetailChannel.idl */,
                                7C6579E21E00827000E3A27A /* ApplePayLineItem.h */,
                                7C6579E41E0082C800E3A27A /* ApplePayLineItem.idl */,
                                A1DF5AA81F8070D40058A477 /* ApplePayMerchantCapability.cpp */,
                                A1BB85AE2159B1A00067E07D /* JSApplePayErrorCode.h */,
                                A1BB85AC2159B19F0067E07D /* JSApplePayErrorContactField.cpp */,
                                A1BB85AF2159B1A00067E07D /* JSApplePayErrorContactField.h */,
+                               A13B616D2475E31000BBE6DE /* JSApplePayInstallmentConfiguration.cpp */,
+                               A13B61722475E31500BBE6DE /* JSApplePayInstallmentConfiguration.h */,
+                               A13B61702475E31300BBE6DE /* JSApplePayInstallmentItem.cpp */,
+                               A13B61712475E31400BBE6DE /* JSApplePayInstallmentItem.h */,
+                               A13B61732475E31600BBE6DE /* JSApplePayInstallmentItemType.cpp */,
+                               A13B616E2475E31100BBE6DE /* JSApplePayInstallmentItemType.h */,
+                               A13B616C2475E31000BBE6DE /* JSApplePayInstallmentRetailChannel.cpp */,
+                               A13B616F2475E31200BBE6DE /* JSApplePayInstallmentRetailChannel.h */,
                                7C6579E91E00856600E3A27A /* JSApplePayLineItem.cpp */,
                                7C6579EA1E00856600E3A27A /* JSApplePayLineItem.h */,
                                A1DF5A891F7EC0000058A477 /* JSApplePayMerchantCapability.cpp */,
                                A12C59EE2035FC9B0012236B /* ApplePayError.h in Headers */,
                                A1BB859C2159AEA10067E07D /* ApplePayErrorCode.h in Headers */,
                                A1BB85A32159AF570067E07D /* ApplePayErrorContactField.h in Headers */,
+                               A117509A247468D600D4D26C /* ApplePayInstallmentConfigurationWebCore.h in Headers */,
+                               A11750A0247468F300D4D26C /* ApplePayInstallmentItem.h in Headers */,
+                               A11750A1247468F700D4D26C /* ApplePayInstallmentItemType.h in Headers */,
+                               A13B616B2475E04800BBE6DE /* ApplePayInstallmentRetailChannel.h in Headers */,
                                7C6579E31E00827000E3A27A /* ApplePayLineItem.h in Headers */,
                                A1DF5A861F7EBDF20058A477 /* ApplePayMerchantCapability.h in Headers */,
                                A1F6CFFF1FE096210018078C /* ApplePayModifier.h in Headers */,
                                A12C59F920360ACB0012236B /* JSApplePayError.h in Headers */,
                                A1BB85B22159B1A10067E07D /* JSApplePayErrorCode.h in Headers */,
                                A1BB85B32159B1A10067E07D /* JSApplePayErrorContactField.h in Headers */,
+                               A13B61742475E34200BBE6DE /* JSApplePayInstallmentConfiguration.h in Headers */,
+                               A13B61752475E35F00BBE6DE /* JSApplePayInstallmentItem.h in Headers */,
+                               A13B61762475E37A00BBE6DE /* JSApplePayInstallmentItemType.h in Headers */,
+                               A13B61772475E3A300BBE6DE /* JSApplePayInstallmentRetailChannel.h in Headers */,
                                7C6579F01E00856600E3A27A /* JSApplePayLineItem.h in Headers */,
                                A1DF5A8E1F7EC0020058A477 /* JSApplePayMerchantCapability.h in Headers */,
                                A1F6D0121FE099B40018078C /* JSApplePayModifier.h in Headers */,