Skip to content

Commit fbe4080

Browse files
authored
Fix orderTotalChanged error for 8dp vs 2dp amounts (#15980)
2 parents ab58d66 + f124f9f commit fbe4080

File tree

2 files changed

+66
-8
lines changed

2 files changed

+66
-8
lines changed

WooCommerce/Classes/ViewRelated/Orders/Collect Payments/CollectOrderPaymentUseCase.swift

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -261,15 +261,17 @@ private extension CollectOrderPaymentUseCase {
261261
guard let self = self else { return }
262262

263263
switch result {
264-
case .success(let order):
265-
guard order.total == self.order.total else {
266-
return onCheckCompletion(.failure(CollectOrderPaymentUseCaseError.orderTotalChanged))
267-
}
264+
case .success(let order):
265+
let orderTotal = currencyFormatter.convertToDecimal(order.total)
266+
let originalOrderTotal = currencyFormatter.convertToDecimal(self.order.total)
267+
guard orderTotal == originalOrderTotal else {
268+
return onCheckCompletion(.failure(CollectOrderPaymentUseCaseError.orderTotalChanged))
269+
}
268270

269-
self.order = order
270-
case .failure(let error):
271-
DDLogError("⛔️ Error synchronizing Order: \(error.localizedDescription)")
272-
return onCheckCompletion(.failure(CollectOrderPaymentUseCaseError.couldNotRefreshOrder(error)))
271+
self.order = order
272+
case .failure(let error):
273+
DDLogError("⛔️ Error synchronizing Order: \(error.localizedDescription)")
274+
return onCheckCompletion(.failure(CollectOrderPaymentUseCaseError.couldNotRefreshOrder(error)))
273275
}
274276

275277
guard self.isTotalAmountValid() else {

WooCommerce/WooCommerceTests/ViewModels/CardPresentPayments/CollectOrderPaymentUseCaseTests.swift

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,62 @@ final class CollectOrderPaymentUseCaseTests: XCTestCase {
410410
// Then ensure payment completion happens after alert presentation to avoid CollectOrderPaymentUseCase deinit before alert presentation
411411
XCTAssertEqual(eventOrder, [.receiptEligibilityCheck, .alertPresented, .paymentCompletion])
412412
}
413+
414+
func test_collectPayment_succeeds_when_order_total_precision_differs_between_initial_and_retrieved_order() throws {
415+
// Given an order with 2 decimal place precision
416+
let initialOrder = Order.fake().copy(siteID: defaultSiteID, orderID: defaultOrderID, total: "22.56")
417+
418+
// And the retrieved order has 8 decimal place precision (same value, different formatting)
419+
let retrievedOrder = Order.fake().copy(siteID: defaultSiteID, orderID: defaultOrderID, total: "22.56000000")
420+
421+
setUpUseCase(order: initialOrder)
422+
423+
// Mock the order retrieval to return the 8dp version
424+
stores.whenReceivingAction(ofType: OrderAction.self) { action in
425+
switch action {
426+
case .retrieveOrderRemotely(_, _, let completion):
427+
completion(.success(retrievedOrder))
428+
default:
429+
break
430+
}
431+
}
432+
433+
let paymentMethod = PaymentMethod.cardPresent(details: .fake())
434+
let intent = PaymentIntent.fake().copy(charges: [.fake().copy(paymentMethod: paymentMethod)])
435+
let capturedPaymentData = CardPresentCapturedPaymentData(paymentMethod: paymentMethod, receiptParameters: .fake())
436+
mockSuccessfulCardPresentPaymentActions(intent: intent, capturedPaymentData: capturedPaymentData)
437+
438+
// When collecting payment
439+
var paymentCompleted = false
440+
var paymentFailed = false
441+
442+
waitFor { promise in
443+
self.useCase.collectPayment(
444+
using: .bluetoothScan,
445+
channel: .storeManagement,
446+
onFailure: { error in
447+
paymentFailed = true
448+
// This should not happen with the decimal comparison fix
449+
XCTFail("Payment should not fail due to precision mismatch. Error: \(error)")
450+
promise(())
451+
},
452+
onCancel: {
453+
XCTFail("Payment should not be canceled")
454+
promise(())
455+
},
456+
onPaymentCompletion: {
457+
paymentCompleted = true
458+
promise(())
459+
},
460+
onCompleted: {}
461+
)
462+
self.mockPreflightController.completeConnection(reader: MockCardReader.wisePad3(), gatewayID: Mocks.paymentGatewayAccount)
463+
}
464+
465+
// Then payment should succeed (with decimal comparison, "22.56" equals "22.56000000")
466+
XCTAssertTrue(paymentCompleted)
467+
XCTAssertFalse(paymentFailed)
468+
}
413469
}
414470

415471
private extension CollectOrderPaymentUseCaseTests {

0 commit comments

Comments
 (0)