Skip to content

Commit

Permalink
Send Receipt After Payment: Add eligibility checker (#14446)
Browse files Browse the repository at this point in the history
  • Loading branch information
staskus authored Nov 19, 2024
2 parents 9b91dc3 + 01c94d9 commit 09e8f0e
Show file tree
Hide file tree
Showing 3 changed files with 211 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,28 +32,76 @@ final class ReceiptEligibilityUseCase: ReceiptEligibilityUseCaseProtocol {
return onCompletion(false)
}
// 2. If WooCommerce version is any of the specific API development branches, mark as eligible
if Constants.wcPluginDevVersion.contains(wcPlugin.version) {
if Constants.BackendReceipt.wcPluginDevVersion.contains(wcPlugin.version) {
onCompletion(true)
} else {
// 3. Else, if WooCommerce version is higher than minimum required version, mark as eligible
let isSupported = VersionHelpers.isVersionSupported(version: wcPlugin.version,
minimumRequired: Constants.wcPluginMinimumVersion)
minimumRequired: Constants.BackendReceipt.wcPluginMinimumVersion)
onCompletion(isSupported)
}
}
stores.dispatch(action)
}

func isEligibleSendingReceiptAfterPayment(onCompletion: @escaping (Bool) -> Void) {
// TODO: WooCommerce 9.5.0
onCompletion(featureFlagService.isFeatureFlagEnabled(.sendReceiptAfterPayment))
guard featureFlagService.isFeatureFlagEnabled(.sendReceiptAfterPayment) else {
return onCompletion(false)
}

Task { @MainActor in
async let isWooCommerceSupported = isPluginSupported(Constants.wcPluginName,
minimumVersion: Constants.ReceiptAfterPayment.wcPluginMinimumVersion)
async let isWooPaymentsSupported = isPluginSupported(Constants.wcPayPluginName,
minimumVersion: Constants.ReceiptAfterPayment.wcPayPluginMinimumVersion)
let wooCommerceResult = await isWooCommerceSupported
let wooPaymentsResult = await isWooPaymentsSupported
let isSupported = wooCommerceResult && wooPaymentsResult

onCompletion(isSupported)
}
}
}

private extension ReceiptEligibilityUseCase {
@MainActor
func isPluginSupported(_ pluginName: String, minimumVersion: String) async -> Bool {
await withCheckedContinuation { continuation in
let action = SystemStatusAction.fetchSystemPlugin(siteID: siteID, systemPluginName: pluginName) { plugin in
// Plugin must be installed and active
guard let plugin, plugin.active else {
return continuation.resume(returning: false)
}

// Checking for concrete versions to cover dev and beta versions
if plugin.version.contains(minimumVersion) {
return continuation.resume(returning: true)
}

// If plugin version is higher than minimum required version, mark as eligible
let isSupported = VersionHelpers.isVersionSupported(version: plugin.version,
minimumRequired: minimumVersion)
continuation.resume(returning: isSupported)
}
stores.dispatch(action)
}
}
}

private extension ReceiptEligibilityUseCase {
enum Constants {
static let wcPluginName = "WooCommerce"
static let wcPluginMinimumVersion = "8.7.0"
static let wcPluginDevVersion: [String] = ["8.7.0-dev", "8.6.0-dev"]
static let wcPayPluginName = "WooPayments"

enum BackendReceipt {
static let wcPluginMinimumVersion = "8.7.0"
static let wcPluginDevVersion: [String] = ["8.7.0-dev", "8.6.0-dev"]
}

enum ReceiptAfterPayment {
static let wcPluginMinimumVersion = "9.5.0"
static let wcPayPluginMinimumVersion = "8.6.0"
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ struct MockFeatureFlagService: FeatureFlagService {
private let favoriteProducts: Bool
private let paymentsOnboardingInPointOfSale: Bool
private let isProductGlobalUniqueIdentifierSupported: Bool
private let isSendReceiptAfterPaymentEnabled: Bool

init(isInboxOn: Bool = false,
isShowInboxCTAEnabled: Bool = false,
Expand All @@ -46,7 +47,8 @@ struct MockFeatureFlagService: FeatureFlagService {
viewEditCustomFieldsInProductsAndOrders: Bool = false,
favoriteProducts: Bool = false,
paymentsOnboardingInPointOfSale: Bool = false,
isProductGlobalUniqueIdentifierSupported: Bool = false) {
isProductGlobalUniqueIdentifierSupported: Bool = false,
isSendReceiptAfterPaymentEnabled: Bool = false) {
self.isInboxOn = isInboxOn
self.isShowInboxCTAEnabled = isShowInboxCTAEnabled
self.isUpdateOrderOptimisticallyOn = isUpdateOrderOptimisticallyOn
Expand All @@ -69,6 +71,7 @@ struct MockFeatureFlagService: FeatureFlagService {
self.favoriteProducts = favoriteProducts
self.paymentsOnboardingInPointOfSale = paymentsOnboardingInPointOfSale
self.isProductGlobalUniqueIdentifierSupported = isProductGlobalUniqueIdentifierSupported
self.isSendReceiptAfterPaymentEnabled = isSendReceiptAfterPaymentEnabled
}

func isFeatureFlagEnabled(_ featureFlag: FeatureFlag) -> Bool {
Expand Down Expand Up @@ -117,6 +120,8 @@ struct MockFeatureFlagService: FeatureFlagService {
return paymentsOnboardingInPointOfSale
case .productGlobalUniqueIdentifierSupport:
return isProductGlobalUniqueIdentifierSupported
case .sendReceiptAfterPayment:
return isSendReceiptAfterPaymentEnabled
default:
return false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,155 @@ final class ReceiptEligibilityUseCaseTests: XCTestCase {
// Then
XCTAssertTrue(isEligible)
}

// MARK: - Send Receipt After Payment

func test_isEligibleSendingReceiptAfterPayment_when_feature_flag_is_disabled_then_returns_false() {
// Given
let featureFlag = MockFeatureFlagService(isSendReceiptAfterPaymentEnabled: false)
let stores = MockStoresManager(sessionManager: .makeForTesting())
let sut = ReceiptEligibilityUseCase(stores: stores, featureFlagService: featureFlag)

// When
let isEligible: Bool = waitFor { promise in
sut.isEligibleSendingReceiptAfterPayment(onCompletion: { result in
promise(result)
})
}

// Then
XCTAssertFalse(isEligible)
}

func test_isEligibleSendingReceiptAfterPayment_when_plugins_are_inactive_then_returns_false() {
// Given
let featureFlag = MockFeatureFlagService(isSendReceiptAfterPaymentEnabled: true)
let stores = MockStoresManager(sessionManager: .makeForTesting())
let wooCommercePlugin = SystemPlugin.fake().copy(name: "WooCommerce", version: "9.6.0", active: false)
let wooPaymentsPlugin = SystemPlugin.fake().copy(name: "WooPayments", version: "8.9.0", active: false)

stores.whenReceivingAction(ofType: SystemStatusAction.self) { action in
switch action {
case let .fetchSystemPlugin(_, systemPluginName, onCompletion):
if systemPluginName == "WooCommerce" {
onCompletion(wooCommercePlugin)
} else if systemPluginName == "WooPayments" {
onCompletion(wooPaymentsPlugin)
}
default:
XCTFail("Unexpected action")
}
}

let sut = ReceiptEligibilityUseCase(stores: stores, featureFlagService: featureFlag)

// When
let isEligible: Bool = waitFor { promise in
sut.isEligibleSendingReceiptAfterPayment(onCompletion: { result in
promise(result)
})
}

// Then
XCTAssertFalse(isEligible)
}

func test_isEligibleSendingReceiptAfterPayment_when_plugins_are_supported_then_returns_true() {
// Given
let featureFlag = MockFeatureFlagService(isSendReceiptAfterPaymentEnabled: true)
let stores = MockStoresManager(sessionManager: .makeForTesting())
let wooCommercePlugin = SystemPlugin.fake().copy(name: "WooCommerce", version: "9.5.0", active: true)
let wooPaymentsPlugin = SystemPlugin.fake().copy(name: "WooPayments", version: "8.6.0", active: true)

stores.whenReceivingAction(ofType: SystemStatusAction.self) { action in
switch action {
case let .fetchSystemPlugin(_, systemPluginName, onCompletion):
if systemPluginName == "WooCommerce" {
onCompletion(wooCommercePlugin)
} else if systemPluginName == "WooPayments" {
onCompletion(wooPaymentsPlugin)
}
default:
XCTFail("Unexpected action")
}
}

let sut = ReceiptEligibilityUseCase(stores: stores, featureFlagService: featureFlag)

// When
let isEligible: Bool = waitFor { promise in
sut.isEligibleSendingReceiptAfterPayment(onCompletion: { result in
promise(result)
})
}

// Then
XCTAssertTrue(isEligible)
}

func test_isEligibleSendingReceiptAfterPayment_when_plugins_are_supported_dev_then_returns_true() {
// Given
let featureFlag = MockFeatureFlagService(isSendReceiptAfterPaymentEnabled: true)
let stores = MockStoresManager(sessionManager: .makeForTesting())
let wooCommercePlugin = SystemPlugin.fake().copy(name: "WooCommerce", version: "9.6.0-dev-1181231238", active: true)
let wooPaymentsPlugin = SystemPlugin.fake().copy(name: "WooPayments", version: "8.6.0-test-1", active: true)

stores.whenReceivingAction(ofType: SystemStatusAction.self) { action in
switch action {
case let .fetchSystemPlugin(_, systemPluginName, onCompletion):
if systemPluginName == "WooCommerce" {
onCompletion(wooCommercePlugin)
} else if systemPluginName == "WooPayments" {
onCompletion(wooPaymentsPlugin)
}
default:
XCTFail("Unexpected action")
}
}

let sut = ReceiptEligibilityUseCase(stores: stores, featureFlagService: featureFlag)

// When
let isEligible: Bool = waitFor { promise in
sut.isEligibleSendingReceiptAfterPayment(onCompletion: { result in
promise(result)
})
}

// Then
XCTAssertTrue(isEligible)
}

func test_isEligibleSendingReceiptAfterPayment_when_woopayments_version_is_incorrect_then_returns_false() {
// Given
let featureFlag = MockFeatureFlagService(isSendReceiptAfterPaymentEnabled: true)
let stores = MockStoresManager(sessionManager: .makeForTesting())
let wooCommercePlugin = SystemPlugin.fake().copy(name: "WooCommerce", version: "9.5.0", active: true)
let wooPaymentsPlugin = SystemPlugin.fake().copy(name: "WooPayments", version: "5.0.0-dev", active: true)

stores.whenReceivingAction(ofType: SystemStatusAction.self) { action in
switch action {
case let .fetchSystemPlugin(_, systemPluginName, onCompletion):
if systemPluginName == "WooCommerce" {
onCompletion(wooCommercePlugin)
} else if systemPluginName == "WooPayments" {
onCompletion(wooPaymentsPlugin)
}
default:
XCTFail("Unexpected action")
}
}

let sut = ReceiptEligibilityUseCase(stores: stores, featureFlagService: featureFlag)

// When
let isEligible: Bool = waitFor { promise in
sut.isEligibleSendingReceiptAfterPayment(onCompletion: { result in
promise(result)
})
}

// Then
XCTAssertFalse(isEligible)
}
}

0 comments on commit 09e8f0e

Please sign in to comment.