Skip to content

Commit c0dba92

Browse files
committed
Merge branch 'trunk' into issue/6025-add-shipping-line-section
# Conflicts: # WooCommerce/Classes/ViewRelated/Coupons/CouponDetails/CouponDetails.swift
2 parents 085943d + d708c33 commit c0dba92

File tree

41 files changed

+1820
-92
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1820
-92
lines changed

Networking/Networking.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090
0359EA1F27AAE4680048DE2D /* WCPayChargeMapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0359EA1E27AAE4680048DE2D /* WCPayChargeMapperTests.swift */; };
9191
0359EA2127AAE58C0048DE2D /* wcpay-charge-card-present.json in Resources */ = {isa = PBXBuildFile; fileRef = 0359EA2027AAE58C0048DE2D /* wcpay-charge-card-present.json */; };
9292
0359EA2527AAF7D60048DE2D /* wcpay-charge-card.json in Resources */ = {isa = PBXBuildFile; fileRef = 0359EA2427AAF7D60048DE2D /* wcpay-charge-card.json */; };
93+
0359EA2927AC2AAD0048DE2D /* wcpay-charge-error.json in Resources */ = {isa = PBXBuildFile; fileRef = 0359EA2827AC2AAD0048DE2D /* wcpay-charge-error.json */; };
9394
03DCB72626244B9B00C8953D /* Coupon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03DCB72526244B9B00C8953D /* Coupon.swift */; };
9495
03DCB7402624AD7D00C8953D /* CouponListMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03DCB73F2624AD7D00C8953D /* CouponListMapper.swift */; };
9596
03DCB7442624AD9B00C8953D /* CouponListMapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03DCB7432624AD9A00C8953D /* CouponListMapperTests.swift */; };
@@ -100,6 +101,7 @@
100101
03DCB7822627394500C8953D /* CouponMapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03DCB7812627394500C8953D /* CouponMapperTests.swift */; };
101102
03DCB786262739D200C8953D /* CouponMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03DCB785262739D200C8953D /* CouponMapper.swift */; };
102103
03DCB796262741E000C8953D /* Coupon+Decoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03DCB795262741E000C8953D /* Coupon+Decoder.swift */; };
104+
03E8FEC427B40E3F00F5FC7D /* wcpay-charge-card-present-minimal.json in Resources */ = {isa = PBXBuildFile; fileRef = 03E8FEC327B40E3F00F5FC7D /* wcpay-charge-card-present-minimal.json */; };
103105
077F39C8269F2C7E00ABEADC /* SystemPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 077F39C7269F2C7E00ABEADC /* SystemPlugin.swift */; };
104106
077F39D426A58DE700ABEADC /* SystemStatusMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 077F39D326A58DE700ABEADC /* SystemStatusMapper.swift */; };
105107
077F39D626A58E4500ABEADC /* SystemStatusRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 077F39D526A58E4500ABEADC /* SystemStatusRemote.swift */; };
@@ -762,6 +764,7 @@
762764
0359EA1E27AAE4680048DE2D /* WCPayChargeMapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WCPayChargeMapperTests.swift; sourceTree = "<group>"; };
763765
0359EA2027AAE58C0048DE2D /* wcpay-charge-card-present.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "wcpay-charge-card-present.json"; sourceTree = "<group>"; };
764766
0359EA2427AAF7D60048DE2D /* wcpay-charge-card.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "wcpay-charge-card.json"; sourceTree = "<group>"; };
767+
0359EA2827AC2AAD0048DE2D /* wcpay-charge-error.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "wcpay-charge-error.json"; sourceTree = "<group>"; };
765768
03DCB72526244B9B00C8953D /* Coupon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Coupon.swift; sourceTree = "<group>"; };
766769
03DCB73F2624AD7D00C8953D /* CouponListMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CouponListMapper.swift; sourceTree = "<group>"; };
767770
03DCB7432624AD9A00C8953D /* CouponListMapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CouponListMapperTests.swift; sourceTree = "<group>"; };
@@ -772,6 +775,7 @@
772775
03DCB7812627394500C8953D /* CouponMapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CouponMapperTests.swift; sourceTree = "<group>"; };
773776
03DCB785262739D200C8953D /* CouponMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CouponMapper.swift; sourceTree = "<group>"; };
774777
03DCB795262741E000C8953D /* Coupon+Decoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Coupon+Decoder.swift"; sourceTree = "<group>"; };
778+
03E8FEC327B40E3F00F5FC7D /* wcpay-charge-card-present-minimal.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "wcpay-charge-card-present-minimal.json"; sourceTree = "<group>"; };
775779
077F39C7269F2C7E00ABEADC /* SystemPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SystemPlugin.swift; sourceTree = "<group>"; };
776780
077F39D326A58DE700ABEADC /* SystemStatusMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SystemStatusMapper.swift; sourceTree = "<group>"; };
777781
077F39D526A58E4500ABEADC /* SystemStatusRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SystemStatusRemote.swift; sourceTree = "<group>"; };
@@ -2017,6 +2021,8 @@
20172021
077F39D726A58EB600ABEADC /* systemStatus.json */,
20182022
0359EA2427AAF7D60048DE2D /* wcpay-charge-card.json */,
20192023
0359EA2027AAE58C0048DE2D /* wcpay-charge-card-present.json */,
2024+
03E8FEC327B40E3F00F5FC7D /* wcpay-charge-card-present-minimal.json */,
2025+
0359EA2827AC2AAD0048DE2D /* wcpay-charge-error.json */,
20202026
45CCFCE927A2E59B0012E8CB /* inbox-note-list.json */,
20212027
4513382727A96DE700AE5E78 /* inbox-note.json */,
20222028
);
@@ -2525,6 +2531,7 @@
25252531
45CCFCEA27A2E59B0012E8CB /* inbox-note-list.json in Resources */,
25262532
025CA2C8238F4FF400B05C81 /* product-shipping-classes-load-all.json in Resources */,
25272533
74046E21217A73D0007DD7BF /* settings-general.json in Resources */,
2534+
03E8FEC427B40E3F00F5FC7D /* wcpay-charge-card-present-minimal.json in Resources */,
25282535
31054724262E2FC600C5C02B /* wcpay-payment-intent-requires-capture.json in Resources */,
25292536
7492FAE3217FBDBC00ED2C69 /* settings-general-alt.json in Resources */,
25302537
93D8BBFF226BC1DA00AD2EB3 /* me-settings.json in Resources */,
@@ -2581,6 +2588,7 @@
25812588
B524194721AC643900D6FC0A /* device-settings.json in Resources */,
25822589
3158A49F2729F3F600C3CFA8 /* wcpay-account-live-live.json in Resources */,
25832590
318E8FD926C324D900F519D7 /* wcpay-customer-error.json in Resources */,
2591+
0359EA2927AC2AAD0048DE2D /* wcpay-charge-error.json in Resources */,
25842592
CEF88DAB233E911A00BED485 /* order-fully-refunded.json in Resources */,
25852593
02698CFA24C188E9005337C4 /* product-variations-load-all-alternative-types.json in Resources */,
25862594
CC0786632678F79500BA9AC1 /* shipping-label-purchase-success.json in Resources */,

Networking/Networking/Model/WCPayCardPresentReceiptDetails.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,18 @@ public struct WCPayCardPresentReceiptDetails: Codable, GeneratedCopiable, Genera
1414
public let accountType: WCPayCardFunding
1515

1616
/// The EMV Application Identifier (AID)
17-
public let applicationPreferredName: String
17+
/// Ideally these would not be optional, as they are required on the receipt. Stripe's simulated cards currently give `null` here.
18+
/// p1644486564027519-slack-C01G168NFC2
19+
public let applicationPreferredName: String?
1820

1921
/// The EMV Dedicated File (DF) Name
20-
public let dedicatedFileName: String
22+
/// Ideally these would not be optional, as they are required on the receipt. Stripe's simulated cards currently give `null` here.
23+
/// p1644486564027519-slack-C01G168NFC2
24+
public let dedicatedFileName: String?
2125

2226
public init(accountType: WCPayCardFunding,
23-
applicationPreferredName: String,
24-
dedicatedFileName: String) {
27+
applicationPreferredName: String?,
28+
dedicatedFileName: String?) {
2529
self.accountType = accountType
2630
self.applicationPreferredName = applicationPreferredName
2731
self.dedicatedFileName = dedicatedFileName

Networking/Networking/Remote/WCPayRemote.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,24 @@ public class WCPayRemote: Remote {
6060

6161
enqueue(request, mapper: mapper, completion: completion)
6262
}
63+
64+
/// Fetches the details of a charge, if available. See https://stripe.com/docs/api/charges/object
65+
/// Also note that the JSON returned by the WCPay endpoint is an abridged copy of Stripe's response.
66+
/// - Parameters:
67+
/// - siteID: Site for which we'll fetch the charge.
68+
/// - chargeID: ID of the charge to fetch
69+
/// - completion: Closure to be run on completion.
70+
public func fetchCharge(for siteID: Int64,
71+
chargeID: String,
72+
completion: @escaping (Result<WCPayCharge, Error>) -> Void) {
73+
let path = "\(Path.charges)/\(chargeID)"
74+
75+
let request = JetpackRequest(wooApiVersion: .mark3, method: .get, siteID: siteID, path: path, parameters: [:])
76+
77+
let mapper = WCPayChargeMapper(siteID: siteID)
78+
79+
enqueue(request, mapper: mapper, completion: completion)
80+
}
6381
}
6482

6583
// MARK: - CardReaderCapableRemote
@@ -104,6 +122,7 @@ private extension WCPayRemote {
104122
static let captureTerminalPayment = "capture_terminal_payment"
105123
static let createCustomer = "create_customer"
106124
static let locations = "payments/terminal/locations/store"
125+
static let charges = "payments/charges"
107126
}
108127

109128
enum AccountParameterKeys {

Networking/NetworkingTests/Mapper/WCPayChargeMapperTests.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,39 @@ class WCPayChargeMapperTests: XCTestCase {
5353
XCTAssertEqual(wcpayCharge, expectedWcpayCharge)
5454
}
5555

56+
/// Verifies that the fields are all parsed correctly for a card present payment
57+
///
58+
func test_WCPayCharge_map_parses_all_fields_in_result_for_card_present_with_nulls() throws {
59+
let wcpayCharge = try mapRetrieveWCPayChargeResponse(responseName: .cardPresentMinimal)
60+
61+
let expectedCreatedDate = Date.init(timeIntervalSince1970: 1643799478) //2022-02-02 10:57:58 UTC
62+
63+
let expectedPaymentMethodDetails = WCPayPaymentMethodDetails.cardPresent(
64+
details: .init(brand: .visa,
65+
last4: "4242",
66+
funding: .credit,
67+
receipt: .init(accountType: .credit,
68+
applicationPreferredName: nil,
69+
dedicatedFileName: nil)))
70+
71+
let expectedWcpayCharge = WCPayCharge(siteID: dummySiteID,
72+
id: "ch_3KOgX62EdyGr1FMV0CSW2k48",
73+
amount: 100,
74+
amountCaptured: 100,
75+
amountRefunded: 0,
76+
authorizationCode: "123456",
77+
captured: true,
78+
created: expectedCreatedDate,
79+
currency: "usd",
80+
paid: true,
81+
paymentIntentID: "pi_3KOgX62EdyGr1FMV0HpUJ10k",
82+
paymentMethodID: "pm_1KOgXB2EdyGr1FMVucJRZLpC",
83+
paymentMethodDetails: expectedPaymentMethodDetails,
84+
refunded: false,
85+
status: .succeeded)
86+
XCTAssertEqual(wcpayCharge, expectedWcpayCharge)
87+
}
88+
5689
/// Verifies that the fields are all parsed correctly for a card payment
5790
///
5891
func test_WCPayCharge_map_parses_all_fields_in_result_for_card() throws {
@@ -107,6 +140,7 @@ private extension WCPayChargeMapperTests {
107140

108141
enum ChargeResponse: String {
109142
case cardPresent = "wcpay-charge-card-present"
143+
case cardPresentMinimal = "wcpay-charge-card-present-minimal"
110144
case card = "wcpay-charge-card"
111145
}
112146
}

Networking/NetworkingTests/Remote/WCPayRemoteTests.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,4 +661,49 @@ final class WCPayRemoteTests: XCTestCase {
661661

662662
XCTAssertTrue(result.isFailure)
663663
}
664+
665+
func test_fetchCharge_properly_returns_charge_with_payment_method_details() throws {
666+
let remote = WCPayRemote(network: network)
667+
let chargeID = "ch_3KMVap2EdyGr1FMV1uKJEWtg"
668+
let expectedPaymentMethodDetails = WCPayPaymentMethodDetails.cardPresent(
669+
details: .init(brand: .visa,
670+
last4: "9969",
671+
funding: .credit,
672+
receipt: .init(accountType: .credit,
673+
applicationPreferredName: "Stripe Credit",
674+
dedicatedFileName: "A000000003101001")))
675+
676+
network.simulateResponse(
677+
requestUrlSuffix: "payments/charges/\(chargeID)",
678+
filename: "wcpay-charge-card-present"
679+
)
680+
681+
let result: Result<WCPayCharge, Error> = waitFor { promise in
682+
remote.fetchCharge(for: self.sampleSiteID, chargeID: chargeID) { result in
683+
promise(result)
684+
}
685+
}
686+
687+
XCTAssertTrue(result.isSuccess)
688+
let charge = try result.get()
689+
XCTAssertEqual(charge.paymentMethodDetails, expectedPaymentMethodDetails)
690+
}
691+
692+
func test_fetchCharge_properly_handles_error_response() throws {
693+
let remote = WCPayRemote(network: network)
694+
let chargeID = "ch_3KMVapErrorERROR"
695+
696+
network.simulateResponse(
697+
requestUrlSuffix: "payments/charges/\(chargeID)",
698+
filename: "wcpay-charge-error"
699+
)
700+
701+
let result: Result<WCPayCharge, Error> = waitFor { promise in
702+
remote.fetchCharge(for: self.sampleSiteID, chargeID: chargeID) { result in
703+
promise(result)
704+
}
705+
}
706+
707+
XCTAssertTrue(result.isFailure)
708+
}
664709
}
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
{
2+
"data": {
3+
"id": "ch_3KOgX62EdyGr1FMV0CSW2k48",
4+
"object": "charge",
5+
"amount": 100,
6+
"amount_captured": 100,
7+
"amount_refunded": 0,
8+
"application": "ca_Ex84e31yMTLaNU5ozQvi5woLclpIDVpX",
9+
"application_fee": "fee_1KOgXF2EdyGr1FMVtgiTktaZ",
10+
"application_fee_amount": 13,
11+
"authorization_code": "123456",
12+
"balance_transaction": {
13+
"id": "txn_3KOgX62EdyGr1FMV0EvyEIyd",
14+
"object": "balance_transaction",
15+
"amount": 100,
16+
"available_on": 1644364800,
17+
"created": 1643799481,
18+
"currency": "usd",
19+
"description": "In-Person Payment for Order #213 for My WordPress Site",
20+
"exchange_rate": null,
21+
"fee": 13,
22+
"fee_details": [
23+
{
24+
"amount": 13,
25+
"application": "ca_Ex84e31yMTLaNU5ozQvi5woLclpIDVpX",
26+
"currency": "usd",
27+
"description": "WooCommerce Payments application fee",
28+
"type": "application_fee"
29+
}
30+
],
31+
"net": 87,
32+
"reporting_category": "charge",
33+
"source": "ch_3KOgX62EdyGr1FMV0CSW2k48",
34+
"status": "available",
35+
"type": "charge"
36+
},
37+
"billing_details": {
38+
"address": {
39+
"city": null,
40+
"country": null,
41+
"line1": null,
42+
"line2": null,
43+
"postal_code": null,
44+
"state": null
45+
},
46+
"email": null,
47+
"name": null,
48+
"phone": null,
49+
"formatted_address": ""
50+
},
51+
"calculated_statement_descriptor": "TAXBUGCHECK.MYSTAGINGW",
52+
"captured": true,
53+
"created": 1643799478,
54+
"currency": "usd",
55+
"customer": "cus_L4qDnGQ8DjdMrb",
56+
"description": "In-Person Payment for Order #213 for My WordPress Site",
57+
"destination": null,
58+
"dispute": null,
59+
"disputed": false,
60+
"failure_code": null,
61+
"failure_message": null,
62+
"fraud_details": [],
63+
"invoice": null,
64+
"level3": {
65+
"customer_reference": "213",
66+
"line_items": [
67+
{
68+
"discount_amount": 0,
69+
"product_code": "simple-payme",
70+
"product_description": "Simple Payments",
71+
"quantity": 1,
72+
"tax_amount": 0,
73+
"unit_cost": 100
74+
}
75+
],
76+
"merchant_reference": "213",
77+
"shipping_amount": 0,
78+
"shipping_from_zip": "85120"
79+
},
80+
"livemode": false,
81+
"metadata": {
82+
"order_id": "213",
83+
"payment_type": "single",
84+
"paymentintent.storename": "My WordPress Site",
85+
"reader_ID": "CHB20SIMULATOR1",
86+
"reader_model": "CHIPPER_2X",
87+
"site_url": "https://store.example.com"
88+
},
89+
"on_behalf_of": null,
90+
"order": {
91+
"number": "213",
92+
"url": "https://store.example.com/wp-admin/post.php?post=213&action=edit",
93+
"customer_url": "admin.php?page=wc-admin&path=/customers&filter=single_customer&customers=0",
94+
"subscriptions": []
95+
},
96+
"outcome": {
97+
"network_status": "approved_by_network",
98+
"reason": null,
99+
"risk_level": "not_assessed",
100+
"seller_message": "Payment complete.",
101+
"type": "authorized"
102+
},
103+
"paid": true,
104+
"payment_intent": "pi_3KOgX62EdyGr1FMV0HpUJ10k",
105+
"payment_method": "pm_1KOgXB2EdyGr1FMVucJRZLpC",
106+
"payment_method_details": {
107+
"card_present": {
108+
"amount_authorized": 100,
109+
"brand": "visa",
110+
"cardholder_name": null,
111+
"country": "US",
112+
"emv_auth_data": "8A023030",
113+
"exp_month": 12,
114+
"exp_year": 2030,
115+
"fingerprint": "0SEufZLr8JkcLcfi",
116+
"funding": "credit",
117+
"generated_card": "pm_1KOgXB2EdyGr1FMVZ4GOElsc",
118+
"last4": "4242",
119+
"network": "visa",
120+
"overcapture_supported": false,
121+
"read_method": "contactless_emv",
122+
"receipt": {
123+
"account_type": "credit",
124+
"application_cryptogram": null,
125+
"application_preferred_name": null,
126+
"authorization_code": null,
127+
"authorization_response_code": "3030",
128+
"cardholder_verification_method": null,
129+
"dedicated_file_name": null,
130+
"terminal_verification_results": null,
131+
"transaction_status_information": null
132+
}
133+
},
134+
"type": "card_present"
135+
},
136+
"receipt_email": null,
137+
"receipt_number": null,
138+
"receipt_url": "https://pay.stripe.com/receipts/acct_1Jaefx2EdyGr1FMV/ch_3KOgX62EdyGr1FMV0CSW2k48/rcpt_L4qDOZ5aR8acdq5HxPDdO49rjeYBSgk",
139+
"refunded": false,
140+
"refunds": {
141+
"object": "list",
142+
"data": [],
143+
"has_more": false,
144+
"total_count": 0,
145+
"url": "/v1/charges/ch_3KOgX62EdyGr1FMV0CSW2k48/refunds"
146+
},
147+
"review": null,
148+
"shipping": null,
149+
"source": null,
150+
"source_transfer": null,
151+
"statement_descriptor": "TAXBUGCHECK.MYSTAGINGW",
152+
"statement_descriptor_suffix": null,
153+
"status": "succeeded",
154+
"transfer_data": null,
155+
"transfer_group": null
156+
}
157+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"error": "wcpay_get_charge",
3+
"message": "Error: No such charge: 'ch_3KMVapErrorERROR'"
4+
}

RELEASE-NOTES.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
8.6
44
-----
5+
- [*] Orders: In the experimental Order Creation feature, product variations added to a new order now show a list of their attributes. [https://github.com/woocommerce/woocommerce-ios/pull/6131]
56
- [*] Enlarged the tap area for the action button on the notice view. [https://github.com/woocommerce/woocommerce-ios/pull/6146]
67

7-
88
8.5
99
-----
1010
- [*] In-Person Payments: Inform the user when a card reader battery is so low that it needs to be charged before the reader can be connected. [https://github.com/woocommerce/woocommerce-ios/pull/5998]

0 commit comments

Comments
 (0)