Skip to content

[Woo POS] Coupons: Disallow adding duplicate coupons to cart #15551

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
May 6, 2025
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion WooCommerce/Classes/POS/Models/Cart.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ extension Cart {
case .variableParentProduct:
return
case .coupon(let coupon):
let couponItem = Cart.CouponItem(id: UUID(), code: coupon.code, summary: coupon.summary)
let couponItem = Cart.CouponItem(id: coupon.id, code: coupon.code, summary: coupon.summary)
coupons.insert(couponItem, at: coupons.startIndex)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ extension POSItemActionHandler {
break
}
}

func shouldSkipDuplicate(_ item: POSItem, itemListType: ItemListType, posModel: PointOfSaleAggregateModelProtocol) -> Bool {
switch itemListType {
case .coupons:
return posModel.cart.coupons.contains(where: { $0.id == item.id })
default:
return false
}
}
}

/// Standard handler for handling item taps without any special context
Expand All @@ -45,8 +54,10 @@ final class StandardPOSItemActionHandler: POSItemActionHandler {
}

func handleTap(_ item: POSItem) {
if shouldSkipDuplicate(item, itemListType: itemListType, posModel: posModel) {
return
}
posModel.addToCart(item)

trackTapAnalytics(for: item, itemListType: itemListType, using: analytics)
}
}
Expand All @@ -70,6 +81,9 @@ final class SearchResultItemActionHandler: POSItemActionHandler {
}

func handleTap(_ item: POSItem) {
if shouldSkipDuplicate(item, itemListType: itemListType, posModel: posModel) {
return
}
posModel.saveSearchTerm(searchTerm, for: itemListType.itemType)

posModel.addToCart(item)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,14 +243,7 @@ struct PointOfSaleAggregateModelTests {
}

@available(iOS 17.0, *)
@Test(.disabled(
"""
This test doesn't currently work; analytics extensions are not thread-safe,
and using the MainActor means the assert happens too early. I don't think
we want the addToCart to be async, but that would be one way to fix it.
"""))
func addToCart_tracks_analytics_event() async throws {
// Given
@Test func addToCart_when_attempt_to_add_duplicated_coupon_then_does_not_add_it_to_cart() {
let sut = PointOfSaleAggregateModel(itemsController: MockPointOfSaleItemsController(),
purchasableItemsSearchController: MockPointOfSalePurchasableItemsSearchController(),
couponsController: MockPointOfSaleCouponsController(),
Expand All @@ -261,14 +254,14 @@ struct PointOfSaleAggregateModelTests {
collectOrderPaymentAnalyticsTracker: MockPOSCollectOrderPaymentAnalyticsTracker(),
searchHistoryService: MockPOSSearchHistoryService(),
popularItemsController: MockPointOfSalePopularItemsController())
let item = makePurchasableItem()
let coupon = makeCouponItem(code: "DISCOUNT!")

// When
sut.addToCart(item)
sut.addToCart(coupon)
sut.addToCart(coupon)

// Then
let event = try #require(analyticsProvider.receivedEvents.first)
#expect(event == "item_added_to_cart")
#expect(sut.cart.coupons.count == 1)
}
}

Expand Down