@@ -20,6 +20,13 @@ final class PaymentCaptureOrchestrator {
2020 onClearMessage: @escaping ( ) -> Void ,
2121 onProcessingMessage: @escaping ( ) -> Void ,
2222 onCompletion: @escaping ( Result < CardPresentReceiptParameters , Error > ) -> Void ) {
23+ /// Bail out if the order amount is below the minimum allowed:
24+ /// https://stripe.com/docs/currencies#minimum-and-maximum-charge-amounts
25+ guard isTotalAmountValid ( order: order) else {
26+ DDLogError ( " 💳 Error: failed to capture payment for order. Order amount is below minimum " )
27+ onCompletion ( . failure( minimumAmountError ( order: order, minimumAmount: Constants . minimumAmount) ) )
28+ return
29+ }
2330 /// First ask the backend to create/assign a Stripe customer for the order
2431 ///
2532 var customerID : String ?
@@ -258,6 +265,30 @@ private extension PaymentCaptureOrchestrator {
258265 }
259266}
260267
268+ private extension PaymentCaptureOrchestrator {
269+ enum Constants {
270+ /// Minimum order amount in USD:
271+ /// https://stripe.com/docs/currencies#minimum-and-maximum-charge-amounts
272+ static let minimumAmount = NSDecimalNumber ( string: " 0.5 " )
273+ }
274+
275+ func isTotalAmountValid( order: Order ) -> Bool {
276+ guard let orderTotal = currencyFormatter. convertToDecimal ( from: order. total) else {
277+ return false
278+ }
279+
280+ return orderTotal as Decimal >= Constants . minimumAmount as Decimal
281+ }
282+
283+ func minimumAmountError( order: Order , minimumAmount: NSDecimalNumber ) -> Error {
284+ guard let minimum = currencyFormatter. formatAmount ( minimumAmount, with: order. currency) else {
285+ return NotValidAmountError . other
286+ }
287+
288+ return NotValidAmountError . belowMinimumAmount ( amount: minimum)
289+ }
290+ }
291+
261292private extension PaymentCaptureOrchestrator {
262293 enum Localization {
263294 static let receiptDescription = NSLocalizedString ( " In-Person Payment for Order #%1$@ for %2$@ " ,
@@ -268,3 +299,31 @@ private extension PaymentCaptureOrchestrator {
268299 + " %2$@ - store name " )
269300 }
270301}
302+
303+ private extension PaymentCaptureOrchestrator {
304+ private enum NotValidAmountError : Error , LocalizedError {
305+ case belowMinimumAmount( amount: String )
306+ case other
307+
308+ public var errorDescription : String ? {
309+ switch self {
310+ case . belowMinimumAmount( let amount) :
311+ return String . localizedStringWithFormat ( Localizations . belowMinimumAmount, amount)
312+ case . other:
313+ return Localizations . defaultMessage
314+ }
315+ }
316+
317+ enum Localizations {
318+ static let defaultMessage = NSLocalizedString (
319+ " Unable to process payment. Order total amount is not valid. " ,
320+ comment: " Error message when the order amount is not valid. "
321+ )
322+
323+ static let belowMinimumAmount = NSLocalizedString (
324+ " Unable to process payment. Order total amount is below the minimum amount you can charge, which is %1$@ " ,
325+ comment: " Error message when the order amount is below the minimum amount allowed. "
326+ )
327+ }
328+ }
329+ }
0 commit comments