Skip to content

Commit 5fdb9d5

Browse files
authored
Merge pull request #6208 from woocommerce/issue/6132-lazy-draft-order
Order Creation: Copy content of LocalOrderSynchronizer to RemoteOrderSynchronizer
2 parents aa4d818 + c96c854 commit 5fdb9d5

File tree

9 files changed

+383
-78
lines changed

9 files changed

+383
-78
lines changed

Fakes/Fakes/Networking.generated.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,7 @@ extension OrderStatusEnum {
542542
/// Returns a "ready to use" type filled with fake values.
543543
///
544544
public static func fake() -> OrderStatusEnum {
545-
.pending
545+
.autoDraft
546546
}
547547
}
548548
extension OrderTaxLine {

Networking/Networking/Model/Copiable/Models+Copiable.generated.swift

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1468,6 +1468,33 @@ extension ShippingLabelPurchase {
14681468
}
14691469
}
14701470

1471+
extension ShippingLine {
1472+
public func copy(
1473+
shippingID: CopiableProp<Int64> = .copy,
1474+
methodTitle: CopiableProp<String> = .copy,
1475+
methodID: NullableCopiableProp<String> = .copy,
1476+
total: CopiableProp<String> = .copy,
1477+
totalTax: CopiableProp<String> = .copy,
1478+
taxes: CopiableProp<[ShippingLineTax]> = .copy
1479+
) -> ShippingLine {
1480+
let shippingID = shippingID ?? self.shippingID
1481+
let methodTitle = methodTitle ?? self.methodTitle
1482+
let methodID = methodID ?? self.methodID
1483+
let total = total ?? self.total
1484+
let totalTax = totalTax ?? self.totalTax
1485+
let taxes = taxes ?? self.taxes
1486+
1487+
return ShippingLine(
1488+
shippingID: shippingID,
1489+
methodTitle: methodTitle,
1490+
methodID: methodID,
1491+
total: total,
1492+
totalTax: totalTax,
1493+
taxes: taxes
1494+
)
1495+
}
1496+
}
1497+
14711498
extension Site {
14721499
public func copy(
14731500
siteID: CopiableProp<Int64> = .copy,
@@ -1741,8 +1768,8 @@ extension WCPayCardPresentPaymentDetails {
17411768
extension WCPayCardPresentReceiptDetails {
17421769
public func copy(
17431770
accountType: CopiableProp<WCPayCardFunding> = .copy,
1744-
applicationPreferredName: CopiableProp<String> = .copy,
1745-
dedicatedFileName: CopiableProp<String> = .copy
1771+
applicationPreferredName: NullableCopiableProp<String> = .copy,
1772+
dedicatedFileName: NullableCopiableProp<String> = .copy
17461773
) -> WCPayCardPresentReceiptDetails {
17471774
let accountType = accountType ?? self.accountType
17481775
let applicationPreferredName = applicationPreferredName ?? self.applicationPreferredName

Networking/Networking/Model/ShippingLine.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Codegen
33

44
/// Represents a Shipping Line Entity.
55
///
6-
public struct ShippingLine: Codable, Equatable, GeneratedFakeable {
6+
public struct ShippingLine: Codable, Equatable, GeneratedFakeable, GeneratedCopiable {
77
public let shippingID: Int64
88
public let methodTitle: String
99

WooCommerce/Classes/ViewRelated/Orders/Order Creation/Synchronizer/LocalOrderSynchronizer.swift

Lines changed: 0 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -90,77 +90,3 @@ private extension LocalOrderSynchronizer {
9090
// TODO: Bind fees input
9191
}
9292
}
93-
94-
/// Helper to updates an `order` given an `OrderSyncInput` type.
95-
///
96-
private struct ProductInputTransformer {
97-
/// Type to help bundling order Items parameters.
98-
///
99-
struct OrderItemParameters {
100-
let quantity: Decimal
101-
let price: Decimal
102-
let productID: Int64
103-
let variationID: Int64?
104-
var subtotal: String {
105-
"\(price * quantity)"
106-
}
107-
}
108-
109-
/// Adds, deletes, or updates order items based on the given product input.
110-
///
111-
static func update(input: OrderSyncProductInput, on order: Order) -> Order {
112-
// If the input's quantity is 0 or less, delete the item if possible.
113-
guard input.quantity > 0 else {
114-
return remove(input: input, from: order)
115-
}
116-
117-
// Add or update the order items with the new input.
118-
let newItem = createOrderItem(using: input)
119-
var items = order.items
120-
if let itemIndex = order.items.firstIndex(where: { $0.itemID == newItem.itemID }) {
121-
items[itemIndex] = newItem
122-
} else {
123-
items.append(newItem)
124-
}
125-
126-
return order.copy(items: items)
127-
}
128-
129-
/// Removes an order item from an order when the `item.itemID` matches the `input.id`.
130-
///
131-
private static func remove(input: OrderSyncProductInput, from order: Order) -> Order {
132-
var items = order.items
133-
items.removeAll { $0.itemID == input.id }
134-
return order.copy(items: items)
135-
}
136-
137-
/// Creates and order item by using the `input.id` as the `item.itemID`.
138-
///
139-
private static func createOrderItem(using input: OrderSyncProductInput) -> OrderItem {
140-
let parameters: OrderItemParameters = {
141-
switch input.product {
142-
case .product(let product):
143-
let price = Decimal(string: product.price) ?? .zero
144-
return OrderItemParameters(quantity: input.quantity, price: price, productID: product.productID, variationID: nil)
145-
case .variation(let variation):
146-
let price = Decimal(string: variation.price) ?? .zero
147-
return OrderItemParameters(quantity: input.quantity, price: price, productID: variation.productID, variationID: variation.productVariationID)
148-
}
149-
}()
150-
151-
return OrderItem(itemID: input.id,
152-
name: "",
153-
productID: parameters.productID,
154-
variationID: parameters.variationID ?? 0,
155-
quantity: parameters.quantity,
156-
price: parameters.price as NSDecimalNumber,
157-
sku: nil,
158-
subtotal: parameters.subtotal,
159-
subtotalTax: "",
160-
taxClass: "",
161-
taxes: [],
162-
total: "",
163-
totalTax: "",
164-
attributes: [])
165-
}
166-
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import Foundation
2+
import Yosemite
3+
4+
/// Helper to updates an `order` given an `OrderSyncInput` type.
5+
///
6+
struct ProductInputTransformer {
7+
/// Type to help bundling order Items parameters.
8+
///
9+
struct OrderItemParameters {
10+
let quantity: Decimal
11+
let price: Decimal
12+
let productID: Int64
13+
let variationID: Int64?
14+
var subtotal: String {
15+
"\(price * quantity)"
16+
}
17+
}
18+
19+
/// Adds, deletes, or updates order items based on the given product input.
20+
///
21+
static func update(input: OrderSyncProductInput, on order: Order) -> Order {
22+
// If the input's quantity is 0 or less, delete the item if possible.
23+
guard input.quantity > 0 else {
24+
return remove(input: input, from: order)
25+
}
26+
27+
// Add or update the order items with the new input.
28+
let newItem = createOrderItem(using: input)
29+
var items = order.items
30+
if let itemIndex = order.items.firstIndex(where: { $0.itemID == newItem.itemID }) {
31+
items[itemIndex] = newItem
32+
} else {
33+
items.append(newItem)
34+
}
35+
36+
return order.copy(items: items)
37+
}
38+
39+
/// Removes an order item from an order when the `item.itemID` matches the `input.id`.
40+
///
41+
private static func remove(input: OrderSyncProductInput, from order: Order) -> Order {
42+
var items = order.items
43+
items.removeAll { $0.itemID == input.id }
44+
return order.copy(items: items)
45+
}
46+
47+
/// Creates and order item by using the `input.id` as the `item.itemID`.
48+
///
49+
private static func createOrderItem(using input: OrderSyncProductInput) -> OrderItem {
50+
let parameters: OrderItemParameters = {
51+
switch input.product {
52+
case .product(let product):
53+
let price = Decimal(string: product.price) ?? .zero
54+
return OrderItemParameters(quantity: input.quantity, price: price, productID: product.productID, variationID: nil)
55+
case .variation(let variation):
56+
let price = Decimal(string: variation.price) ?? .zero
57+
return OrderItemParameters(quantity: input.quantity, price: price, productID: variation.productID, variationID: variation.productVariationID)
58+
}
59+
}()
60+
61+
return OrderItem(itemID: input.id,
62+
name: "",
63+
productID: parameters.productID,
64+
variationID: parameters.variationID ?? 0,
65+
quantity: parameters.quantity,
66+
price: parameters.price as NSDecimalNumber,
67+
sku: nil,
68+
subtotal: parameters.subtotal,
69+
subtotalTax: "",
70+
taxClass: "",
71+
taxes: [],
72+
total: "",
73+
totalTax: "",
74+
attributes: [])
75+
}
76+
}

WooCommerce/Classes/ViewRelated/Orders/Order Creation/Synchronizer/RemoteOrderSynchronizer.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ final class RemoteOrderSynchronizer: OrderSynchronizer {
4949
self.stores = stores
5050

5151
updateBaseSyncOrderStatus()
52+
bindInputs()
5253
}
5354

5455
// MARK: Methods
@@ -72,4 +73,32 @@ private extension RemoteOrderSynchronizer {
7273
self?.baseSyncStatus = baseStatus
7374
}
7475
}
76+
77+
/// Updates the underlying order as inputs are received.
78+
///
79+
func bindInputs() {
80+
setStatus.withLatestFrom(orderPublisher)
81+
.map { newStatus, order in
82+
order.copy(status: newStatus)
83+
}
84+
.assign(to: &$order)
85+
86+
setProduct.withLatestFrom(orderPublisher)
87+
.map { productInput, order in
88+
ProductInputTransformer.update(input: productInput, on: order)
89+
}
90+
.assign(to: &$order)
91+
92+
setAddresses.withLatestFrom(orderPublisher)
93+
.map { addressesInput, order in
94+
order.copy(billingAddress: .some(addressesInput?.billing), shippingAddress: .some(addressesInput?.shipping))
95+
}
96+
.assign(to: &$order)
97+
98+
setShipping.withLatestFrom(orderPublisher)
99+
.map { shippingLineInput, order in
100+
order.copy(shippingLines: shippingLineInput.flatMap { [$0] } ?? [])
101+
}
102+
.assign(to: &$order)
103+
}
75104
}

WooCommerce/WooCommerce.xcodeproj/project.pbxproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,9 @@
422422
2602A63D27BD3C8C00B347F1 /* RemoteOrderSynchronizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2602A63C27BD3C8C00B347F1 /* RemoteOrderSynchronizer.swift */; };
423423
2602A63F27BD880A00B347F1 /* NewOrderInitialStatusResolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2602A63E27BD880A00B347F1 /* NewOrderInitialStatusResolver.swift */; };
424424
2602A64227BD89CE00B347F1 /* NewOrderInitialStatusResolverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2602A64127BD89CE00B347F1 /* NewOrderInitialStatusResolverTests.swift */; };
425+
2602A64627BDBEBA00B347F1 /* ProductInputTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2602A64527BDBEBA00B347F1 /* ProductInputTransformer.swift */; };
426+
2602A64827BDBF8000B347F1 /* ProductInputTransformerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2602A64727BDBF8000B347F1 /* ProductInputTransformerTests.swift */; };
427+
2602A64A27BDC80200B347F1 /* RemoteOrderSynchronizerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2602A64927BDC80200B347F1 /* RemoteOrderSynchronizerTests.swift */; };
425428
260C315E2523CC4000157BC2 /* RefundProductsTotalViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260C315D2523CC4000157BC2 /* RefundProductsTotalViewModel.swift */; };
426429
260C31602524ECA900157BC2 /* IssueRefundViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260C315F2524ECA900157BC2 /* IssueRefundViewController.swift */; };
427430
260C31622524EEB200157BC2 /* IssueRefundViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 260C31612524EEB200157BC2 /* IssueRefundViewController.xib */; };
@@ -2068,6 +2071,9 @@
20682071
2602A63C27BD3C8C00B347F1 /* RemoteOrderSynchronizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteOrderSynchronizer.swift; sourceTree = "<group>"; };
20692072
2602A63E27BD880A00B347F1 /* NewOrderInitialStatusResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewOrderInitialStatusResolver.swift; sourceTree = "<group>"; };
20702073
2602A64127BD89CE00B347F1 /* NewOrderInitialStatusResolverTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewOrderInitialStatusResolverTests.swift; sourceTree = "<group>"; };
2074+
2602A64527BDBEBA00B347F1 /* ProductInputTransformer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductInputTransformer.swift; sourceTree = "<group>"; };
2075+
2602A64727BDBF8000B347F1 /* ProductInputTransformerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductInputTransformerTests.swift; sourceTree = "<group>"; };
2076+
2602A64927BDC80200B347F1 /* RemoteOrderSynchronizerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteOrderSynchronizerTests.swift; sourceTree = "<group>"; };
20712077
260C315D2523CC4000157BC2 /* RefundProductsTotalViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefundProductsTotalViewModel.swift; sourceTree = "<group>"; };
20722078
260C315F2524ECA900157BC2 /* IssueRefundViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IssueRefundViewController.swift; sourceTree = "<group>"; };
20732079
260C31612524EEB200157BC2 /* IssueRefundViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = IssueRefundViewController.xib; sourceTree = "<group>"; };
@@ -4313,6 +4319,8 @@
43134319
isa = PBXGroup;
43144320
children = (
43154321
2602A64127BD89CE00B347F1 /* NewOrderInitialStatusResolverTests.swift */,
4322+
2602A64727BDBF8000B347F1 /* ProductInputTransformerTests.swift */,
4323+
2602A64927BDC80200B347F1 /* RemoteOrderSynchronizerTests.swift */,
43164324
);
43174325
path = Synchronizer;
43184326
sourceTree = "<group>";
@@ -4553,6 +4561,7 @@
45534561
26C6439427B9A1B300DD00D1 /* LocalOrderSynchronizer.swift */,
45544562
2602A63C27BD3C8C00B347F1 /* RemoteOrderSynchronizer.swift */,
45554563
2602A63E27BD880A00B347F1 /* NewOrderInitialStatusResolver.swift */,
4564+
2602A64527BDBEBA00B347F1 /* ProductInputTransformer.swift */,
45564565
);
45574566
path = Synchronizer;
45584567
sourceTree = "<group>";
@@ -9027,6 +9036,7 @@
90279036
021AEF9E2407F55C00029D28 /* PHAssetImageLoader.swift in Sources */,
90289037
DECE13FB27993F6500816ECD /* TitleAndSubtitleAndStatusTableViewCell.swift in Sources */,
90299038
26E0AE1926335AA900A5EB3B /* Survey.swift in Sources */,
9039+
2602A64627BDBEBA00B347F1 /* ProductInputTransformer.swift in Sources */,
90309040
AE77EA5027A47C99006A21BD /* View+AddingDividers.swift in Sources */,
90319041
0298430C259351F100979CAE /* ShippingLabelsTopBannerFactory.swift in Sources */,
90329042
020BE74D23B1F5EB007FE54C /* TitleAndTextFieldTableViewCell.swift in Sources */,
@@ -9300,6 +9310,7 @@
93009310
57B374B6245B331100D58BE0 /* EmptyStateViewControllerTests.swift in Sources */,
93019311
020BE76923B4A268007FE54C /* AztecItalicFormatBarCommandTests.swift in Sources */,
93029312
0271E1642509C66200633F7A /* DefaultProductFormTableViewModelTests.swift in Sources */,
9313+
2602A64827BDBF8000B347F1 /* ProductInputTransformerTests.swift in Sources */,
93039314
D802548726552E07001B2CC1 /* CardPresentModalNonRetryableErrorTests.swift in Sources */,
93049315
02BAB02924D13AA500F8B06E /* ProductVariationFormActionsFactoryTests.swift in Sources */,
93059316
B53A569B21123E8E000776C9 /* MockTableView.swift in Sources */,
@@ -9389,6 +9400,7 @@
93899400
020BE76B23B4A380007FE54C /* AztecUnderlineFormatBarCommandTests.swift in Sources */,
93909401
D83F5937225B402E00626E75 /* TitleAndEditableValueTableViewCellTests.swift in Sources */,
93919402
773077F3251E954300178696 /* ProductDownloadFileViewModelTests.swift in Sources */,
9403+
2602A64A27BDC80200B347F1 /* RemoteOrderSynchronizerTests.swift in Sources */,
93929404
DE4B3B2E269455D400EEF2D8 /* MockShipmentActionStoresManager.swift in Sources */,
93939405
0246405F258B122100C10A7D /* PrintShippingLabelCoordinatorTests.swift in Sources */,
93949406
576D9F2924DB81D3007B48F4 /* StoreStatsAndTopPerformersPeriodViewModelTests.swift in Sources */,

0 commit comments

Comments
 (0)