Skip to content

Commit 72c3a98

Browse files
authored
POS cash payment: prefill order amount and update analytics tracking (#16058)
2 parents 58c6ebd + 15e4a27 commit 72c3a98

File tree

7 files changed

+297
-116
lines changed

7 files changed

+297
-116
lines changed

RELEASE-NOTES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
23.2
55
-----
6+
- [*] POS: Enhanced cash payment experience with pre-filled amounts. [https://github.com/woocommerce/woocommerce-ios/pull/16058]
67
- [*] POS: Point of Sale settings are now accessible in POS mode [https://github.com/woocommerce/woocommerce-ios/pull/16067]
78

89
23.1

WooCommerce/Classes/Analytics/TracksProvider.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ private extension TracksProvider {
139139
WooAnalyticsStat.pointOfSaleViewDocsTapped,
140140
WooAnalyticsStat.pointOfSaleReaderReadyForCardPayment,
141141
WooAnalyticsStat.pointOfSaleCashCollectPaymentSuccess,
142+
WooAnalyticsStat.pointOfSaleCheckoutCashPaymentTapped,
142143
WooAnalyticsStat.pointOfSaleCashPaymentTapped,
143144
WooAnalyticsStat.pointOfSaleCashPaymentFailed,
144145
WooAnalyticsStat.pointOfSaleItemsHeaderTapped,

WooCommerce/Classes/Analytics/WooAnalyticsStat.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1258,6 +1258,7 @@ enum WooAnalyticsStat: String {
12581258
case pointOfSaleItemRemovedFromCart = "item_removed_from_cart"
12591259
case pointOfSaleCheckoutTapped = "checkout_tapped"
12601260
case pointOfSaleBackToCartTapped = "back_to_cart_tapped"
1261+
case pointOfSaleCheckoutCashPaymentTapped = "checkout_cash_payment_tapped"
12611262
case pointOfSaleCashPaymentTapped = "cash_payment_tapped"
12621263
case pointOfSaleCashPaymentFailed = "cash_payment_failed"
12631264
case pointOfSaleBackToCheckoutFromCashTapped = "back_to_checkout_from_cash"

WooCommerce/Classes/POS/Models/PointOfSaleAggregateModel.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ extension PointOfSaleAggregateModel {
368368
// Once we get the callback from the card service, we switch to cash collection state
369369
@MainActor
370370
func startCashPayment() async {
371-
analytics.track(.pointOfSaleCashPaymentTapped)
371+
analytics.track(.pointOfSaleCheckoutCashPaymentTapped)
372372
try? await cardPresentPaymentService.cancelPayment()
373373
paymentState.cash = .collectingCash
374374
}

WooCommerce/Classes/POS/Presentation/PointOfSaleCollectCashView.swift

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ struct PointOfSaleCollectCashView: View {
2525
String.localizedStringWithFormat(Localization.backNavigationSubtitle, orderTotal)
2626
}
2727

28+
private var isButtonEnabled: Bool {
29+
viewHelper.isPaymentButtonEnabled(orderTotal: orderTotal,
30+
textFieldAmountInput: textFieldAmountInput,
31+
isLoading: isLoading)
32+
}
33+
2834
@StateObject private var textFieldViewModel = FormattableAmountTextFieldViewModel(size: .extraLarge,
2935
locale: Locale.autoupdatingCurrent,
3036
storeCurrencySettings: ServiceLocator.currencySettings,
@@ -89,7 +95,7 @@ struct PointOfSaleCollectCashView: View {
8995
.buttonStyle(POSFilledButtonStyle(size: .normal, isLoading: isLoading))
9096
.frame(maxWidth: .infinity)
9197
.dynamicTypeSize(...DynamicTypeSize.accessibility1)
92-
.disabled(isLoading)
98+
.disabled(!isButtonEnabled)
9399
}
94100
.padding([.horizontal])
95101
.padding(.bottom, max(keyboardFrame.height - geometry.safeAreaInsets.bottom,
@@ -110,6 +116,9 @@ struct PointOfSaleCollectCashView: View {
110116
}
111117
}
112118
.frame(maxWidth: .infinity, maxHeight: .infinity)
119+
.onAppear {
120+
prefillOrderTotal()
121+
}
113122
}
114123

115124
private func markComplete() async throws {
@@ -121,9 +130,7 @@ struct PointOfSaleCollectCashView: View {
121130

122131
private extension PointOfSaleCollectCashView {
123132
private func submitCashAmount() async {
124-
guard validateAmountOnSubmit() else {
125-
return
126-
}
133+
ServiceLocator.analytics.track(.pointOfSaleCashPaymentTapped)
127134
isLoading = true
128135
do {
129136
try await markComplete()
@@ -140,14 +147,12 @@ private extension PointOfSaleCollectCashView {
140147
textFieldAmountInput: textFieldAmountInput)
141148
}
142149

143-
private func validateAmountOnSubmit() -> Bool {
144-
viewHelper.validateAmountOnSubmit(
145-
orderTotal: orderTotal,
146-
textFieldAmountInput: textFieldAmountInput,
147-
onError: { error in
148-
errorMessage = error
149-
})
150+
private func prefillOrderTotal() {
151+
if let orderDecimal = viewHelper.parseCurrency(orderTotal) {
152+
textFieldViewModel.presetAmount(orderDecimal)
150153
}
154+
isTextFieldFocused = true
155+
}
151156
}
152157

153158
private extension PointOfSaleCollectCashView {

WooCommerce/Classes/POS/ViewHelpers/CollectCashViewHelper.swift

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -54,25 +54,22 @@ final class CollectCashViewHelper {
5454
}
5555
}
5656

57-
func validateAmountOnSubmit(orderTotal: String,
57+
func isPaymentButtonEnabled(orderTotal: String,
5858
textFieldAmountInput: String,
59-
onError: (String) -> Void) -> Bool {
60-
let userInput = textFieldAmountInput.isNotEmpty ? textFieldAmountInput : "0"
61-
62-
guard let orderDecimal = parseCurrency(orderTotal),
63-
let inputDecimal = parseCurrency(userInput) else {
64-
onError(Localization.failedToCollectCashPayment)
59+
isLoading: Bool) -> Bool {
60+
guard !isLoading else {
6561
return false
6662
}
6763

68-
if inputDecimal < orderDecimal {
69-
onError(Localization.cashPaymentAmountNotEnough)
64+
let inputAmount = textFieldAmountInput.isNotEmpty ? textFieldAmountInput : "0"
65+
guard let orderDecimal = parseCurrency(orderTotal),
66+
let inputDecimal = parseCurrency(inputAmount) else {
7067
return false
7168
}
72-
return true
69+
return inputDecimal >= orderDecimal
7370
}
7471

75-
private func parseCurrency(_ amountString: String) -> Decimal? {
72+
func parseCurrency(_ amountString: String) -> Decimal? {
7673
// Removes all leading/trailing whitespace, if any
7774
let sanitized = amountString.trimmingCharacters(in: .whitespacesAndNewlines)
7875

@@ -101,16 +98,6 @@ private extension CollectCashViewHelper {
10198
comment: "Change due when the cash amount entered exceeds the order total." +
10299
"Reads as 'Change due: $1.23'"
103100
)
104-
static let failedToCollectCashPayment = NSLocalizedString(
105-
"collectcashviewhelper.failedtocollectcashpayment.errormessage",
106-
value: "Error trying to process payment. Try again.",
107-
comment: "Error message when the system fails to collect a cash payment."
108-
)
109-
static let cashPaymentAmountNotEnough = NSLocalizedString(
110-
"collectcashviewhelper.cashpaymentamountnotenough.errormessage",
111-
value: "Amount must be more or equal to total.",
112-
comment: "Error message when the cash amount entered is less than the order total."
113-
)
114101
}
115102
}
116103

0 commit comments

Comments
 (0)