Skip to content

Commit 9d80e53

Browse files
committed
5342 Include customerNote in receipts
Quick Orders do not include any information about what was sold, so adding the order notes to the receipt will enable the merchant to provide some context for what was sold.
1 parent d39c379 commit 9d80e53

File tree

4 files changed

+86
-6
lines changed

4 files changed

+86
-6
lines changed

Hardware/Hardware/Printer/AirPrintReceipt/ReceiptRenderer.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ public extension ReceiptRenderer {
8686
</header>
8787
<h3>\(summarySectionTitle.uppercased())</h3>
8888
\(summaryTable())
89+
\(orderNoteSection())
8990
<footer>
9091
<p>
9192
\(requiredItems())
@@ -138,6 +139,16 @@ private extension ReceiptRenderer {
138139
"""
139140
}
140141

142+
private func orderNoteSection() -> String {
143+
guard let orderNote = content.orderNote else {
144+
return ""
145+
}
146+
return """
147+
<h3>\(Localization.orderNoteSectionTitle.uppercased())</h3>
148+
<p>\(orderNote)
149+
"""
150+
}
151+
141152
private func requiredItems() -> String {
142153
guard let emv = content.parameters.cardDetails.receipt else {
143154
return "<br/>"
@@ -214,6 +225,10 @@ private extension ReceiptRenderer {
214225
comment: "Title of 'Summary' section in the receipt when the order number is unknown"
215226
)
216227

228+
static let orderNoteSectionTitle = NSLocalizedString(
229+
"Notes",
230+
comment: "Title of order note section in the receipt, commonly used for Quick Orders.")
231+
217232
static let summarySectionTitleWithOrderFormat = NSLocalizedString(
218233
"Summary: Order #%1$@",
219234
comment: "Title of 'Summary' section in the receipt. %1$@ is the order number, e.g. 4920"

Hardware/Hardware/Printer/ReceiptContent.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,16 @@ public struct ReceiptContent: Codable {
44
public let lineItems: [ReceiptLineItem]
55
public let parameters: CardPresentReceiptParameters
66
public let cartTotals: [ReceiptTotalLine]
7+
public let orderNote: String?
78

8-
public init(parameters: CardPresentReceiptParameters, lineItems: [ReceiptLineItem], cartTotals: [ReceiptTotalLine]) {
9+
public init(parameters: CardPresentReceiptParameters,
10+
lineItems: [ReceiptLineItem],
11+
cartTotals: [ReceiptTotalLine],
12+
orderNote: String?) {
913
self.lineItems = lineItems
1014
self.parameters = parameters
1115
self.cartTotals = cartTotals
16+
self.orderNote = orderNote
1217
}
1318
}
1419

@@ -17,6 +22,7 @@ extension ReceiptContent {
1722
case lineItems = "line_items"
1823
case parameters = "parameters"
1924
case cartTotals = "cart_totals"
25+
case orderNote = "order_note"
2026
}
2127
}
2228

Yosemite/Yosemite/Stores/ReceiptStore.swift

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public class ReceiptStore: Store {
5959

6060
private extension ReceiptStore {
6161
func print(order: Order, parameters: CardPresentReceiptParameters, completion: @escaping (PrintingResult) -> Void) {
62-
let content = generateReceiptContent(order: order, parameters: parameters)
62+
let content = generateReceiptContent(order: order, parameters: parameters, removingHtml: true)
6363
receiptPrinterService.printReceipt(content: content, completion: completion)
6464
}
6565

@@ -69,11 +69,27 @@ private extension ReceiptStore {
6969
onContent(renderer.htmlContent())
7070
}
7171

72-
func generateReceiptContent(order: Order, parameters: CardPresentReceiptParameters) -> ReceiptContent {
72+
func generateReceiptContent(order: Order, parameters: CardPresentReceiptParameters, removingHtml: Bool = false) -> ReceiptContent {
7373
let lineItems = generateLineItems(order: order)
7474
let cartTotals = generateCartTotals(order: order, parameters: parameters)
75+
let note = receiptOrderNote(order: order, removingHtml: removingHtml)
76+
77+
return ReceiptContent(parameters: parameters,
78+
lineItems: lineItems,
79+
cartTotals: cartTotals,
80+
orderNote: note)
81+
}
7582

76-
return ReceiptContent(parameters: parameters, lineItems: lineItems, cartTotals: cartTotals)
83+
private func receiptOrderNote(order: Order, removingHtml: Bool) -> String? {
84+
guard let orderNote = order.customerNote else {
85+
return nil
86+
}
87+
if removingHtml {
88+
// TODO: move this logic to the WooCommerce target, and then use String.removedHTMLTags extension function
89+
return orderNote.replacingOccurrences(of: "<[^>]+>", with: "", options: .regularExpression, range: nil)
90+
} else {
91+
return orderNote
92+
}
7793
}
7894

7995
func generateLineItems(order: Order) -> [ReceiptLineItem] {

Yosemite/YosemiteTests/Stores/ReceiptStoreTests.swift

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,11 +352,54 @@ final class ReceiptStoreTests: XCTestCase {
352352
}
353353
XCTAssertEqual("30.00", lineItemsTotalLine?.amount)
354354
}
355+
356+
func test_generateContent_callsGenerate_passingUnmodified_customerNote() throws {
357+
let mockParameters = try XCTUnwrap(MockPaymentIntent.mock().receiptParameters())
358+
let expectedNote = "<a href=\"https://example.com\">This note has a link</a>"
359+
let mockOrder = makeOrder(customerNote: expectedNote)
360+
let expectation = expectation(description: #function)
361+
362+
let receiptStore = ReceiptStore(dispatcher: dispatcher,
363+
storageManager: storageManager,
364+
network: network,
365+
receiptPrinterService: receiptPrinterService,
366+
fileStorage: MockInMemoryStorage())
367+
368+
let action = ReceiptAction.generateContent(
369+
order: mockOrder,
370+
parameters: mockParameters,
371+
onContent: { content in
372+
XCTAssert(content.contains(expectedNote))
373+
expectation.fulfill()
374+
})
375+
376+
receiptStore.onAction(action)
377+
378+
wait(for: [expectation], timeout: Constants.expectationTimeout)
379+
}
380+
381+
func test_print_callsPrint_passingHTMLStripped_customerNote() throws {
382+
let mockParameters = try XCTUnwrap(MockPaymentIntent.mock().receiptParameters())
383+
let mockOrder = makeOrder(customerNote: "<a href=\"https://example.com\">This note has a link</a>")
384+
385+
let receiptStore = ReceiptStore(dispatcher: dispatcher,
386+
storageManager: storageManager,
387+
network: network,
388+
receiptPrinterService: receiptPrinterService,
389+
fileStorage: MockInMemoryStorage())
390+
391+
let action = ReceiptAction.print(order: mockOrder, parameters: mockParameters, completion: { _ in })
392+
393+
receiptStore.onAction(action)
394+
395+
XCTAssertEqual(receiptPrinterService.contentProvided?.orderNote, "This note has a link")
396+
}
355397
}
356398

357399

358400
private extension ReceiptStoreTests {
359-
func makeOrder(discountTotal: String = "",
401+
func makeOrder(customerNote: String? = nil,
402+
discountTotal: String = "",
360403
discountTax: String = "",
361404
shippingTotal: String = "",
362405
shippingTax: String = "",
@@ -371,7 +414,7 @@ private extension ReceiptStoreTests {
371414
number: "",
372415
status: .custom(""),
373416
currency: "usd",
374-
customerNote: nil,
417+
customerNote: customerNote,
375418
dateCreated: Date(),
376419
dateModified: Date(),
377420
datePaid: nil,

0 commit comments

Comments
 (0)