Skip to content

Commit

Permalink
Show description for trial tap to pay line items
Browse files Browse the repository at this point in the history
When a merchant tries out tap to pay on iPhone, we make an order which will remain in their history, even though it gets refunded.

To help merchants identify the order, this adds a specific description rather than showing `Simple Payment` for these payments.
  • Loading branch information
joshheald committed Sep 23, 2024
1 parent bffaecf commit 74a25b0
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ final class SetUpTapToPayTryPaymentPromptViewModel: PaymentSettingsFlowPresented
self.summaryViewModel = TryAPaymentSummaryViewModel(
simplePaymentSummaryViewModel: SimplePaymentsSummaryViewModel(order: order,
providedAmount: order.total,
amountName: Localization.tryAPaymentAmountName,
presentNoticeSubject: self.presentNoticeSubject,
analyticsFlow: .tapToPayTryAPayment),
siteID: self.siteID,
Expand Down Expand Up @@ -236,6 +237,12 @@ extension SetUpTapToPayTryPaymentPromptViewModel {
value: "Trial Tap to Pay payment auto refund",
comment: "After a trial Tap to Pay payment, we attempt to automatically refund the test amount. When " +
"this is sent to the server, we provide a reason for later identification.")

static let tryAPaymentAmountName = NSLocalizedString(
"tap.to.pay.try.payment.amount.name",
value: "Try out Tap to Pay on iPhone",
comment: "On a trial Tap to Pay order, this is the name of the line item for the trial amount."
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@ struct SimplePaymentsSummary_Preview: PreviewProvider {
title: "State Tax (5.55%)",
value: taxAmount)
return .init(providedAmount: "40.0",
amountName: nil,
totalWithTaxes: "$42.3",
taxLines: [taxLine],
noteContent: noteContent)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ final class SimplePaymentsSummaryViewModel: ObservableObject {
///
let providedAmount: String

let amountName: String?

private let unformattedProvidedAmount: String

/// Store tax lines.
Expand Down Expand Up @@ -157,6 +159,7 @@ final class SimplePaymentsSummaryViewModel: ObservableObject {
lazy private(set) var noteViewModel = { SimplePaymentsNoteViewModel(analytics: analytics) }()

init(providedAmount: String,
amountName: String? = nil,
totalWithTaxes: String,
taxLines: [TaxLine],
noteContent: String? = nil,
Expand All @@ -183,6 +186,7 @@ final class SimplePaymentsSummaryViewModel: ObservableObject {
self.analytics = analytics
self.flow = analyticsFlow
self.providedAmount = currencyFormatter.formatAmount(providedAmount) ?? providedAmount
self.amountName = amountName
self.unformattedProvidedAmount = providedAmount
self.totalWithTaxes = currencyFormatter.formatAmount(totalWithTaxes) ?? totalWithTaxes
self.unformattedTotalWithTaxes = totalWithTaxes
Expand All @@ -205,6 +209,7 @@ final class SimplePaymentsSummaryViewModel: ObservableObject {

convenience init(order: Order,
providedAmount: String,
amountName: String? = nil,
presentNoticeSubject: PassthroughSubject<PaymentMethodsNotice, Never> = PassthroughSubject(),
currencyFormatter: CurrencyFormatter = CurrencyFormatter(currencySettings: ServiceLocator.currencySettings),
stores: StoresManager = ServiceLocator.stores,
Expand All @@ -217,6 +222,7 @@ final class SimplePaymentsSummaryViewModel: ObservableObject {
})

self.init(providedAmount: providedAmount,
amountName: amountName,
totalWithTaxes: order.total,
taxLines: taxLines,
siteID: order.siteID,
Expand Down Expand Up @@ -254,6 +260,7 @@ final class SimplePaymentsSummaryViewModel: ObservableObject {
feeID: feeID,
status: .pending, // Force .pending status to properly generate the payment link in the next screen.
amount: removeCurrencySymbolFromAmount(providedAmount),
amountName: amountName,
taxable: enableTaxes,
orderNote: noteContent,
email: email.isEmpty ? nil : email) { [weak self] result in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ final class SimplePaymentsSummaryViewModelTests: XCTestCase {
let _: String = waitFor { promise in
mockStores.whenReceivingAction(ofType: OrderAction.self) { action in
switch action {
case let .updateSimplePaymentsOrder(_, _, _, _, amount, _, _, _, _):
case let .updateSimplePaymentsOrder(_, _, _, _, amount, _, _, _, _, _):
promise(amount)
default:
XCTFail("Unexpected action: \(action)")
Expand Down Expand Up @@ -109,7 +109,7 @@ final class SimplePaymentsSummaryViewModelTests: XCTestCase {
let _: String = waitFor { promise in
mockStores.whenReceivingAction(ofType: OrderAction.self) { action in
switch action {
case let .updateSimplePaymentsOrder(_, _, _, _, amount, _, _, _, _):
case let .updateSimplePaymentsOrder(_, _, _, _, amount, _, _, _, _, _):
promise(amount)
default:
XCTFail("Unexpected action: \(action)")
Expand All @@ -132,7 +132,7 @@ final class SimplePaymentsSummaryViewModelTests: XCTestCase {
let updatedAmount: String = waitFor { promise in
mockStores.whenReceivingAction(ofType: OrderAction.self) { action in
switch action {
case let .updateSimplePaymentsOrder(_, _, _, _, amount, _, _, _, _):
case let .updateSimplePaymentsOrder(_, _, _, _, amount, _, _, _, _, _):
promise(amount)
default:
XCTFail("Unexpected action: \(action)")
Expand All @@ -147,6 +147,29 @@ final class SimplePaymentsSummaryViewModelTests: XCTestCase {
assertEqual("1.00", updatedAmount)
}

func test_when_updateOrder_then_amount_name_is_added_to_order_when_provided() {
// Given
let mockStores = MockStoresManager(sessionManager: .testingInstance)
let viewModel = SimplePaymentsSummaryViewModel(providedAmount: "1", amountName: "One dollar fee", totalWithTaxes: "1", taxLines: [], stores: mockStores)

// When
let updatedAmountName = waitFor { promise in
mockStores.whenReceivingAction(ofType: OrderAction.self) { action in
switch action {
case let .updateSimplePaymentsOrder(_, _, _, _, _, amountName, _, _, _, _):
promise(amountName)
default:
XCTFail("Unexpected action: \(action)")
}
}
viewModel.updateOrder()
}

// Then
assertEqual("One dollar fee", viewModel.amountName)
assertEqual("One dollar fee", updatedAmountName)
}

func test_provided_amount_with_taxes_gets_properly_formatted() {
// Given
let currencyFormatter = CurrencyFormatter(currencySettings: CurrencySettings()) // Default is US.
Expand Down Expand Up @@ -249,7 +272,7 @@ final class SimplePaymentsSummaryViewModelTests: XCTestCase {
stores: mockStores)
mockStores.whenReceivingAction(ofType: OrderAction.self) { action in
switch action {
case let .updateSimplePaymentsOrder(_, _, _, _, _, _, _, _, onCompletion):
case let .updateSimplePaymentsOrder(_, _, _, _, _, _, _, _, _, onCompletion):
onCompletion(.success(Order.fake()))
default:
XCTFail("Unexpected action: \(action)")
Expand Down Expand Up @@ -284,7 +307,7 @@ final class SimplePaymentsSummaryViewModelTests: XCTestCase {
stores: mockStores)
mockStores.whenReceivingAction(ofType: OrderAction.self) { action in
switch action {
case let .updateSimplePaymentsOrder(_, _, _, _, _, _, _, _, onCompletion):
case let .updateSimplePaymentsOrder(_, _, _, _, _, _, _, _, _, onCompletion):
onCompletion(.failure(NSError(domain: "Error", code: 0)))
default:
XCTFail("Received unsupported action: \(action)")
Expand Down Expand Up @@ -347,7 +370,7 @@ final class SimplePaymentsSummaryViewModelTests: XCTestCase {
let updateStatus: OrderStatusEnum = waitFor { promise in
mockStores.whenReceivingAction(ofType: OrderAction.self) { action in
switch action {
case let .updateSimplePaymentsOrder(_, _, _, status, _, _, _, _, _):
case let .updateSimplePaymentsOrder(_, _, _, status, _, _, _, _, _, _):
promise(status)
default:
XCTFail("Unexpected action: \(action)")
Expand All @@ -370,7 +393,7 @@ final class SimplePaymentsSummaryViewModelTests: XCTestCase {
stores: mockStores)
mockStores.whenReceivingAction(ofType: OrderAction.self) { action in
switch action {
case let .updateSimplePaymentsOrder(_, _, _, _, _, _, _, _, onCompletion):
case let .updateSimplePaymentsOrder(_, _, _, _, _, _, _, _, _, onCompletion):
onCompletion(.success(Order.fake()))
default:
XCTFail("Unexpected action: \(action)")
Expand Down Expand Up @@ -398,7 +421,7 @@ final class SimplePaymentsSummaryViewModelTests: XCTestCase {
let trimmedEmail: String? = waitFor { promise in
mockStores.whenReceivingAction(ofType: OrderAction.self) { action in
switch action {
case let .updateSimplePaymentsOrder(_, _, _, _, _, _, _, email, _):
case let .updateSimplePaymentsOrder(_, _, _, _, _, _, _, _, email, _):
promise(email)
default:
XCTFail("Unexpected action: \(action)")
Expand All @@ -425,7 +448,7 @@ final class SimplePaymentsSummaryViewModelTests: XCTestCase {
let emailSent: String? = waitFor { promise in
mockStores.whenReceivingAction(ofType: OrderAction.self) { action in
switch action {
case let .updateSimplePaymentsOrder(_, _, _, _, _, _, _, email, _):
case let .updateSimplePaymentsOrder(_, _, _, _, _, _, _, _, email, _):
promise(email)
default:
XCTFail("Unexpected action: \(action)")
Expand Down Expand Up @@ -513,7 +536,7 @@ final class SimplePaymentsSummaryViewModelTests: XCTestCase {
let mockStores = MockStoresManager(sessionManager: .testingInstance)
mockStores.whenReceivingAction(ofType: OrderAction.self) { action in
switch action {
case let .updateSimplePaymentsOrder(_, _, _, _, _, _, _, _, onCompletion):
case let .updateSimplePaymentsOrder(_, _, _, _, _, _, _, _, _, onCompletion):
onCompletion(.failure(NSError(domain: "", code: 0, userInfo: nil)))
default:
XCTFail("Unexpected action: \(action)")
Expand Down
1 change: 1 addition & 0 deletions Yosemite/Yosemite/Actions/OrderAction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ public enum OrderAction: Action {
feeID: Int64,
status: OrderStatusEnum,
amount: String,
amountName: String?,
taxable: Bool,
orderNote: String?,
email: String?,
Expand Down
4 changes: 2 additions & 2 deletions Yosemite/Yosemite/Stores/Order/OrderFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ public enum OrderFactory {

/// Creates a fee line suitable to be used within a simple payments order.
///
static func simplePaymentFee(feeID: Int64, amount: String, taxable: Bool) -> OrderFeeLine {
static func simplePaymentFee(feeID: Int64, amount: String, name: String? = nil, taxable: Bool) -> OrderFeeLine {
.init(feeID: feeID,
name: "Simple Payments",
name: name ?? "Simple Payments",
taxClass: "",
taxStatus: taxable ? .taxable : .none,
total: amount,
Expand Down
6 changes: 4 additions & 2 deletions Yosemite/Yosemite/Stores/OrderStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,13 @@ public class OrderStore: Store {
case let .createOrder(siteID, order, giftCard, onCompletion):
createOrder(siteID: siteID, order: order, giftCard: giftCard, onCompletion: onCompletion)

case let .updateSimplePaymentsOrder(siteID, orderID, feeID, status, amount, taxable, orderNote, email, onCompletion):
case let .updateSimplePaymentsOrder(siteID, orderID, feeID, status, amount, amountName, taxable, orderNote, email, onCompletion):
updateSimplePaymentsOrder(siteID: siteID,
orderID: orderID,
feeID: feeID,
status: status,
amount: amount,
amountName: amountName,
taxable: taxable,
orderNote: orderNote,
email: email,
Expand Down Expand Up @@ -400,6 +401,7 @@ private extension OrderStore {
feeID: Int64,
status: OrderStatusEnum,
amount: String,
amountName: String?,
taxable: Bool,
orderNote: String?,
email: String?,
Expand All @@ -409,7 +411,7 @@ private extension OrderStore {
let originalOrder = OrderFactory.simplePaymentsOrder(status: status, amount: amount, taxable: taxable)

// Create updated fields
let newFee = OrderFactory.simplePaymentFee(feeID: feeID, amount: amount, taxable: taxable)
let newFee = OrderFactory.simplePaymentFee(feeID: feeID, amount: amount, name: amountName, taxable: taxable)
let newBillingAddress = Address(firstName: "",
lastName: "",
company: nil,
Expand Down
40 changes: 39 additions & 1 deletion Yosemite/YosemiteTests/Stores/OrderStoreTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1165,6 +1165,7 @@ final class OrderStoreTests: XCTestCase {
// Given
let feeID: Int64 = 1234
let amount = "100.00"
let amountName = "A simple amount"
let taxable = true
let note = "This is a note"
let email = "[email protected]"
Expand All @@ -1178,6 +1179,7 @@ final class OrderStoreTests: XCTestCase {
feeID: feeID,
status: .pending,
amount: amount,
amountName: amountName,
taxable: taxable,
orderNote: note,
email: email) { _ in }
Expand All @@ -1188,7 +1190,7 @@ final class OrderStoreTests: XCTestCase {
let receivedFees = try XCTUnwrap(request.parameters["fee_lines"] as? [[String: AnyHashable]]).first
let expectedFees: [String: AnyHashable] = [
"id": 1234,
"name": "Simple Payments",
"name": "A simple amount",
"tax_status": "taxable",
"tax_class": "",
"total": "100.00"
Expand All @@ -1212,6 +1214,42 @@ final class OrderStoreTests: XCTestCase {
assertEqual(receivedNote, note)
}

func test_update_simple_payments_order_sends_default_name_when_none_provided() throws {
// Given
let feeID: Int64 = 1234
let amount = "100.00"
let taxable = true
let note = "This is a note"
let email = "[email protected]"

let store = OrderStore(dispatcher: dispatcher, storageManager: storageManager, network: network)
network.simulateResponse(requestUrlSuffix: "orders/963", filename: "order")

// When
let action = OrderAction.updateSimplePaymentsOrder(siteID: sampleSiteID,
orderID: sampleOrderID,
feeID: feeID,
status: .pending,
amount: amount,
amountName: nil,
taxable: taxable,
orderNote: note,
email: email) { _ in }
store.onAction(action)

// Then
let request = try XCTUnwrap(network.requestsForResponseData.last as? JetpackRequest)
let receivedFees = try XCTUnwrap(request.parameters["fee_lines"] as? [[String: AnyHashable]]).first
let expectedFees: [String: AnyHashable] = [
"id": 1234,
"name": "Simple Payments",
"tax_status": "taxable",
"tax_class": "",
"total": "100.00"
]
assertEqual(expectedFees, receivedFees)
}

func test_create_order_sends_expected_fields() throws {
// Given
let store = OrderStore(dispatcher: dispatcher, storageManager: storageManager, network: network)
Expand Down

0 comments on commit 74a25b0

Please sign in to comment.