Skip to content

Commit 3fdaad5

Browse files
authored
Merge branch 'trunk' into woomob-771-shipping-label-optimize-country-fetches
2 parents eeea591 + f689348 commit 3fdaad5

File tree

26 files changed

+348
-75
lines changed

26 files changed

+348
-75
lines changed

Modules/Sources/Experiments/DefaultFeatureFlagService.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ public struct DefaultFeatureFlagService: FeatureFlagService {
9999
return buildConfig == .localDeveloper || buildConfig == .alpha
100100
case .pointOfSaleOrdersi1:
101101
return buildConfig == .localDeveloper || buildConfig == .alpha
102+
case .pointOfSaleOrdersi2:
103+
return buildConfig == .localDeveloper || buildConfig == .alpha
102104
default:
103105
return true
104106
}

Modules/Sources/Experiments/FeatureFlag.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,4 +203,8 @@ public enum FeatureFlag: Int {
203203
/// Enables displaying Point Of Sale details in order list and order details
204204
///
205205
case pointOfSaleOrdersi1
206+
207+
/// Enables displaying Point Of Sale as a filter in order list
208+
///
209+
case pointOfSaleOrdersi2
206210
}

Modules/Sources/Yosemite/Stores/WooShippingStore.swift

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,17 @@ private extension WooShippingStore {
192192

193193
func loadAccountSettings(siteID: Int64,
194194
completion: @escaping (Result<WooShippingAccountSettings, Error>) -> Void) {
195-
remote.loadAccountSettings(siteID: siteID, completion: completion)
195+
remote.loadAccountSettings(siteID: siteID, completion: { [weak self] result in
196+
guard let self else { return }
197+
switch result {
198+
case .success(let settings):
199+
upsertShippingLabelAccountSettingsInBackground(siteID: siteID, accountSettings: settings.accountSettings) {
200+
completion(.success(settings))
201+
}
202+
case .failure(let error):
203+
completion(.failure(error))
204+
}
205+
})
196206
}
197207

198208
func updateAccountSettings(siteID: Int64,
@@ -732,6 +742,29 @@ private extension WooShippingStore {
732742
storageShippingLabel.refund = nil
733743
}
734744
}
745+
746+
/// Updates/inserts the specified readonly shipping label account settings entity *in a background thread*.
747+
/// `onCompletion` will be called on the main thread!
748+
///
749+
func upsertShippingLabelAccountSettingsInBackground(siteID: Int64,
750+
accountSettings: ShippingLabelAccountSettings,
751+
onCompletion: @escaping () -> Void) {
752+
storageManager.performAndSave({ storage in
753+
let storageAccountSettings = storage.loadShippingLabelAccountSettings(siteID: siteID) ??
754+
storage.insertNewObject(ofType: Storage.ShippingLabelAccountSettings.self)
755+
storageAccountSettings.update(with: accountSettings)
756+
757+
// Remove all previous payment methods
758+
storageAccountSettings.paymentMethods?.removeAll()
759+
760+
// Insert the payment methods from the read-only account settings
761+
for paymentMethod in accountSettings.paymentMethods {
762+
let newStoragePaymentMethod = storage.insertNewObject(ofType: Storage.ShippingLabelPaymentMethod.self)
763+
newStoragePaymentMethod.update(with: paymentMethod)
764+
storageAccountSettings.addToPaymentMethods(newStoragePaymentMethod)
765+
}
766+
}, completion: onCompletion, on: .main)
767+
}
735768
}
736769

737770
/// Represents errors that can be returned when purchasing a shipping label

Modules/Tests/YosemiteTests/Stores/WooShippingStoreTests.swift

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import XCTest
22
@testable import Yosemite
33
@testable import Networking
44
import protocol Storage.StorageType
5+
import class Storage.ShippingLabelPaymentMethod
56

67
final class WooShippingStoreTests: XCTestCase {
78

@@ -365,6 +366,90 @@ final class WooShippingStoreTests: XCTestCase {
365366
XCTAssertEqual(receivedValue, [samplePackage])
366367
}
367368

369+
// MARK: `loadAccountSettings`
370+
371+
func test_loadAccountSettings_returns_success_response() throws {
372+
// Given
373+
let remote = MockWooShippingRemote()
374+
let expectedSettings = WooShippingAccountSettings.fake()
375+
remote.whenLoadAccountSettings(siteID: sampleSiteID, thenReturn: .success(expectedSettings))
376+
let store = WooShippingStore(dispatcher: dispatcher, storageManager: storageManager, network: network, remote: remote)
377+
378+
// When
379+
let result: Result<WooShippingAccountSettings, Error> = waitFor { promise in
380+
let action = WooShippingAction.loadAccountSettings(siteID: self.sampleSiteID) { result in
381+
promise(result)
382+
}
383+
store.onAction(action)
384+
}
385+
386+
// Then
387+
XCTAssertTrue(result.isSuccess)
388+
let actualSettings = try result.get()
389+
XCTAssertEqual(actualSettings, expectedSettings)
390+
}
391+
392+
func test_loadAccountSettings_returns_error_on_failure() throws {
393+
// Given
394+
let remote = MockWooShippingRemote()
395+
let expectedError = NetworkError.notFound()
396+
remote.whenLoadAccountSettings(siteID: sampleSiteID, thenReturn: .failure(expectedError))
397+
let store = WooShippingStore(dispatcher: dispatcher, storageManager: storageManager, network: network, remote: remote)
398+
399+
// When
400+
let result: Result<WooShippingAccountSettings, Error> = waitFor { promise in
401+
let action = WooShippingAction.loadAccountSettings(siteID: self.sampleSiteID) { result in
402+
promise(result)
403+
}
404+
store.onAction(action)
405+
}
406+
407+
// Then
408+
XCTAssertTrue(result.isFailure)
409+
let error = try XCTUnwrap(result.failure)
410+
XCTAssertEqual(error as? NetworkError, expectedError)
411+
}
412+
413+
func test_loadAccountSettings_when_successful_then_upserts_settings_into_storage() throws {
414+
// Given
415+
let remote = MockWooShippingRemote()
416+
let paymentMethod = Yosemite.ShippingLabelPaymentMethod(
417+
paymentMethodID: 1434,
418+
name: "James Dean",
419+
cardType: .visa,
420+
cardDigits: "2352",
421+
expiry: DateFormatter.Defaults.yearMonthDayDateFormatter.date(from: "2030-12-31")
422+
)
423+
let accountSettings = ShippingLabelAccountSettings.fake().copy(
424+
siteID: sampleSiteID,
425+
paymentMethods: [paymentMethod],
426+
isEmailReceiptsEnabled: true,
427+
paperSize: .a4
428+
)
429+
let expectedSettings = WooShippingAccountSettings.fake().copy(accountSettings: accountSettings)
430+
remote.whenLoadAccountSettings(siteID: sampleSiteID, thenReturn: .success(expectedSettings))
431+
let store = WooShippingStore(dispatcher: dispatcher, storageManager: storageManager, network: network, remote: remote)
432+
433+
// Confidence check
434+
XCTAssertEqual(storageManager.viewStorage.countObjects(ofType: StorageShippingLabelAccountSettings.self), 0)
435+
436+
// When
437+
let onSuccess: Bool = waitFor { promise in
438+
let action = WooShippingAction.loadAccountSettings(siteID: self.sampleSiteID) { result in
439+
promise(result.isSuccess)
440+
}
441+
store.onAction(action)
442+
}
443+
444+
// Then
445+
XCTAssertTrue(onSuccess)
446+
XCTAssertEqual(storageManager.viewStorage.countObjects(ofType: StorageShippingLabelAccountSettings.self), 1)
447+
let storedSettings = try XCTUnwrap(storageManager.viewStorage.loadShippingLabelAccountSettings(siteID: sampleSiteID))
448+
XCTAssertEqual(storedSettings.siteID, sampleSiteID)
449+
XCTAssertEqual(storedSettings.toReadOnly(), accountSettings)
450+
XCTAssertEqual(storageManager.viewStorage.countObjects(ofType: Storage.ShippingLabelPaymentMethod.self), 1)
451+
}
452+
368453
// MARK: `loadPackages`
369454

370455
func test_loadPackages_returns_success_response_with_rates() throws {

RELEASE-NOTES.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
- [*] POS: icon button with confirmation step used for clearing the cart [https://github.com/woocommerce/woocommerce-ios/pull/15829]
88
- [*] Shipping Labels: Fixed a portion of layout issues caused by bigger accessibility content size categories. [https://github.com/woocommerce/woocommerce-ios/pull/15844]
99
- [*] Shipping Labels: Enable the confirm button on the payment method sheet even when there are no changes. [https://github.com/woocommerce/woocommerce-ios/pull/15856]
10+
- [*] POS: start a new cart by scanning a barcode on the payment success screen [https://github.com/woocommerce/woocommerce-ios/pull/15870]
1011
- [*] Watch app: Fixed connection issue upon fresh install [https://github.com/woocommerce/woocommerce-ios/pull/15867]
1112
- [Internal] Shipping Labels: Optimize requests for syncing countries [https://github.com/woocommerce/woocommerce-ios/pull/15875]
13+
- [*] Shipping Labels: Display label size from account settings as default [https://github.com/woocommerce/woocommerce-ios/pull/15873]
1214

1315
22.7
1416
-----

WooCommerce/Classes/POS/Presentation/CardReaderConnection/UI States/Reader Messages/PointOfSalePaymentSuccessView.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import SwiftUI
44
struct PointOfSalePaymentSuccessView: View {
55
let viewModel: PointOfSalePaymentSuccessViewModel
66
@Environment(\.dynamicTypeSize) var dynamicTypeSize
7+
@Environment(PointOfSaleAggregateModel.self) private var posModel
78

89
@State private var isShowingSendReceiptView: Bool = false
910
@State private var isShowingReceiptNotEligibleBanner: Bool = false
@@ -24,6 +25,10 @@ struct PointOfSalePaymentSuccessView: View {
2425
}
2526
.padding([.leading, .trailing], dynamicTypeSize.isAccessibilitySize ? nil : POSPadding.small)
2627
.background(Color.posSurfaceBright)
28+
.barcodeScanning { barcode in
29+
posModel.startNewCart()
30+
posModel.barcodeScanned(barcode)
31+
}
2732
}
2833
}
2934
.onAppear {

WooCommerce/Classes/Tools/BackgroundTasks/OrderListSyncBackgroundTask.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ private struct CurrentOrderListSyncUseCase {
7777
dateRange: settings.dateRangeFilter,
7878
product: settings.productFilter,
7979
customer: settings.customerFilter,
80+
salesChannel: nil, // TODO: Filter persistence WOOMOB-712
8081
numberOfActiveFilters: settings.numberOfActiveFilters())
8182
continuation.resume(returning: filters)
8283
case .failure:

WooCommerce/Classes/ViewRelated/Filters/FilterListViewController.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ enum FilterListValueSelectorConfig {
9292
case products(siteID: Int64)
9393
// Filter list selector for customer
9494
case customer(siteID: Int64)
95+
// Filter list selector for sales channel
96+
case salesChannel
9597

9698
}
9799

@@ -297,6 +299,10 @@ private extension FilterListViewController {
297299
self.listSelector.reloadData()
298300
}
299301
self.listSelector.navigationController?.pushViewController(statusesFilterVC, animated: true)
302+
case .salesChannel:
303+
// TODO: Make OrderSalesChannelFilterViewController, and handle filtering selection WOOMOB-711
304+
let emptyViewController = EmptyStateViewController(style: .list)
305+
self.listSelector.navigationController?.pushViewController(emptyViewController, animated: true)
300306
case .ordersDateRange:
301307
let selectedOrderFilter = selected.selectedValue as? OrderDateRangeFilter
302308
let datesFilterVC = OrderDatesFilterViewController(selected: selectedOrderFilter) { dateRangeFilter in

WooCommerce/Classes/ViewRelated/Orders/Order Details/Shipping Labels/WooShipping Create Shipping Labels/WooShipping Post-Purchase/WooShippingPostPurchaseViewModel.swift

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import Foundation
33
import UIKit
44
import Yosemite
55
import WooFoundation
6+
import protocol Storage.StorageManagerType
67

78
final class WooShippingPostPurchaseViewModel: ObservableObject {
89
private let stores: StoresManager
10+
private let storageManager: StorageManagerType
911
private let siteID: Int64
1012
private let labelID: Int64
1113

@@ -26,14 +28,27 @@ final class WooShippingPostPurchaseViewModel: ObservableObject {
2628
/// Customs form URL for the shipping label
2729
let commercialInvoiceURL: URL?
2830

31+
/// Shipping Label Account Settings ResultsController
32+
///
33+
private lazy var accountSettingsResultsController: ResultsController<StorageShippingLabelAccountSettings> = {
34+
let predicate = NSPredicate(format: "siteID == %lld", siteID)
35+
return ResultsController<StorageShippingLabelAccountSettings>(
36+
storageManager: storageManager,
37+
matching: predicate,
38+
fetchLimit: 1,
39+
sortedBy: []
40+
)
41+
}()
42+
2943
init(siteID: Int64,
3044
labelID: Int64,
3145
labelSizes: [ShippingLabelPaperSize],
3246
isRefundable: Bool,
3347
trackingURL: URL?,
3448
pickupURL: URL?,
3549
commercialInvoiceURL: URL?,
36-
stores: StoresManager = ServiceLocator.stores) {
50+
stores: StoresManager = ServiceLocator.stores,
51+
storageManager: StorageManagerType = ServiceLocator.storageManager) {
3752
self.siteID = siteID
3853
self.labelID = labelID
3954
self.labelSizes = labelSizes
@@ -42,15 +57,20 @@ final class WooShippingPostPurchaseViewModel: ObservableObject {
4257
self.pickupURL = pickupURL
4358
self.commercialInvoiceURL = commercialInvoiceURL
4459
self.stores = stores
60+
self.storageManager = storageManager
61+
62+
configureAccountSettingsResultsController()
4563
}
4664

4765
convenience init(shippingLabel: ShippingLabel,
4866
siteAddress: SiteAddress = SiteAddress(),
49-
stores: StoresManager = ServiceLocator.stores) {
67+
stores: StoresManager = ServiceLocator.stores,
68+
storageManager: StorageManagerType = ServiceLocator.storageManager) {
5069
// Label sizes aren't provided by the API, so we can hard-code them to match the extension behavior:
70+
// Ref: https://github.com/woocommerce/woocommerce-shipping/blob/trunk/client/components/label-purchase/label/utils.ts
5171
let labelSizes = {
5272
var availableLabelSizes: [ShippingLabelPaperSize] = [.label, .letter]
53-
if [.US, .CA, .MX, .DO].contains(siteAddress.countryCode) {
73+
if [.US, .CA, .MX, .DO].contains(siteAddress.countryCode) == false {
5474
availableLabelSizes.append(.a4)
5575
}
5676
return availableLabelSizes
@@ -71,7 +91,8 @@ final class WooShippingPostPurchaseViewModel: ObservableObject {
7191
trackingURL: trackingURL,
7292
pickupURL: pickupURL,
7393
commercialInvoiceURL: commercialInvoiceURL,
74-
stores: stores)
94+
stores: stores,
95+
storageManager: storageManager)
7596
}
7697

7798
/// Fetches the shipping label in the selected paper size and presents the print dialog.
@@ -89,6 +110,26 @@ final class WooShippingPostPurchaseViewModel: ObservableObject {
89110
}
90111

91112
private extension WooShippingPostPurchaseViewModel {
113+
/// Shipping Label Account Settings ResultsController monitoring
114+
///
115+
func configureAccountSettingsResultsController() {
116+
accountSettingsResultsController.onDidChangeContent = { [weak self] in
117+
self?.updateSelectedLabelSize()
118+
}
119+
120+
accountSettingsResultsController.onDidResetContent = { [weak self] in
121+
self?.updateSelectedLabelSize()
122+
}
123+
124+
try? accountSettingsResultsController.performFetch()
125+
updateSelectedLabelSize()
126+
}
127+
128+
func updateSelectedLabelSize() {
129+
guard let fetchedAccountSettings = accountSettingsResultsController.fetchedObjects.first else { return }
130+
selectedLabelSize = fetchedAccountSettings.paperSize
131+
}
132+
92133
/// Requests the shipping label data for printing.
93134
@MainActor
94135
func requestPrintData() async throws -> ShippingLabelPrintData {

0 commit comments

Comments
 (0)