diff --git a/WooCommerce/Classes/ViewRelated/Orders/OrderListViewController.swift b/WooCommerce/Classes/ViewRelated/Orders/OrderListViewController.swift index 0872f4ecf33..59740f96c0f 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/OrderListViewController.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/OrderListViewController.swift @@ -156,6 +156,10 @@ final class OrderListViewController: UIViewController, GhostableViewController { configureViewModel() configureSyncingCoordinator() + + if ServiceLocator.featureFlagService.isFeatureFlagEnabled(.IPPInAppFeedbackBanner) { + viewModel.displayIPPFeedbackBannerIfEligible() + } } override func viewWillAppear(_ animated: Bool) { diff --git a/WooCommerce/Classes/ViewRelated/Orders/OrderListViewModel.swift b/WooCommerce/Classes/ViewRelated/Orders/OrderListViewModel.swift index 089ce5fcf71..f53dd24cdb1 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/OrderListViewModel.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/OrderListViewModel.swift @@ -53,6 +53,47 @@ final class OrderListViewModel { /// private var isAppActive: Bool = true + private var isCODEnabled: Bool { + guard let codGateway = storageManager.viewStorage.loadPaymentGateway(siteID: siteID, gatewayID: "cod")?.toReadOnly() else { + return false + } + return codGateway.enabled + } + + private var isIPPSupportedCountry: Bool { + CardPresentConfigurationLoader().configuration.isSupportedCountry + } + + /// Results controller that fetches any IPP transactions via WooCommerce Payments + /// + private lazy var IPPOrdersResultsController: ResultsController = { + let paymentGateway = Constants.paymentMethodID + let predicate = NSPredicate( + format: "siteID == %lld AND paymentMethodID == %@", + argumentArray: [siteID, paymentGateway] + ) + return ResultsController(storageManager: storageManager, matching: predicate, sortedBy: []) + }() + + /// Results controller that fetches IPP transactions via WooCommerce Payments, within the last 30 days + /// + private lazy var recentIPPOrdersResultsController: ResultsController = { + let today = Date() + let paymentGateway = Constants.paymentMethodID + let thirtyDaysBeforeToday = Calendar.current.date( + byAdding: .day, + value: -30, + to: today + ) ?? Date() + + let predicate = NSPredicate( + format: "siteID == %lld AND paymentMethodID == %@ AND datePaid >= %@", + argumentArray: [siteID, paymentGateway, thirtyDaysBeforeToday] + ) + + return ResultsController(storageManager: storageManager, matching: predicate, sortedBy: []) + }() + /// Used for looking up the `OrderStatus` to show in the `OrderTableViewCell`. /// /// The `OrderStatus` data is fetched from the API by `OrdersTabbedViewModel`. @@ -125,6 +166,10 @@ final class OrderListViewModel { observeForegroundRemoteNotifications() bindTopBannerState() loadOrdersBannerVisibility() + + if ServiceLocator.featureFlagService.isFeatureFlagEnabled(.IPPInAppFeedbackBanner) { + fetchIPPTransactions() + } } func dismissOrdersBanner() { @@ -192,6 +237,46 @@ final class OrderListViewModel { completionHandler: completionHandler) } + private func fetchIPPTransactions() { + do { + try IPPOrdersResultsController.performFetch() + try recentIPPOrdersResultsController.performFetch() + } catch { + DDLogError("Error fetching IPP transactions: \(error)") + } + } + + func displayIPPFeedbackBannerIfEligible() { + if isCODEnabled && isIPPSupportedCountry { + let hasResults = IPPOrdersResultsController.fetchedObjects.isEmpty ? false : true + + /// In order to filter WCPay transactions processed through IPP within the last 30 days, + /// we check if these contain `receipt_url` in their metadata, unlike those processed through a website, + /// which doesn't + /// + let IPPTransactionsFound = recentIPPOrdersResultsController.fetchedObjects.filter({ + $0.customFields.contains(where: {$0.key == Constants.receiptURLKey }) && + $0.paymentMethodTitle == Constants.paymentMethodTitle}) + let IPPresultsCount = IPPTransactionsFound.count + + // TODO: Debug. Remove before merging + print("COD enabled? \(isCODEnabled) - Eligible Country? \(isIPPSupportedCountry)") + print("hasResults? \(hasResults)") + print("IPP transactions within 30 days: \(IPPresultsCount)") + print(recentIPPOrdersResultsController.fetchedObjects.map { + ("OrderID: \($0.orderID) - PaymentMethodID: \($0.paymentMethodID) (\($0.paymentMethodTitle) - DatePaid: \(String(describing: $0.datePaid))") + }) + + if !hasResults { + print("0 transactions. Banner 1 shown") + } else if IPPresultsCount < Constants.numberOfTransactions { + print("< 10 transactions within 30 days. Banner 2 shown") + } else if IPPresultsCount >= Constants.numberOfTransactions { + print(">= 10 transactions within 30 days. Banner 3 shown") + } + } + } + private func createQuery() -> FetchResultSnapshotsProvider.Query { let predicateStatus: NSPredicate = { let excludeSearchCache = NSPredicate(format: "exclusiveForSearch = false") @@ -337,3 +422,13 @@ extension OrderListViewModel { case none } } + +// MARK: IPP feedback constants +private extension OrderListViewModel { + enum Constants { + static let paymentMethodID = "woocommerce_payments" + static let paymentMethodTitle = "WooCommerce In-Person Payments" + static let receiptURLKey = "receipt_url" + static let numberOfTransactions = 10 + } +}