commit 23cab0bb8454e7aaf64e24de4f535a0591edef16 Author: Facundo Médica Date: Wed Feb 21 16:27:34 2018 +0000 test diff --git a/MercadoPagoSDK/MercadoPagoSDK/MercadoPagoCheckoutServices.swift b/MercadoPagoSDK/MercadoPagoSDK/MercadoPagoCheckoutServices.swift index bad101b7..51ca8888 100644 --- a/MercadoPagoSDK/MercadoPagoSDK/MercadoPagoCheckoutServices.swift +++ b/MercadoPagoSDK/MercadoPagoSDK/MercadoPagoCheckoutServices.swift @@ -9,123 +9,129 @@ import Foundation extension MercadoPagoCheckout { - + func getCheckoutPreference() { self.presentLoading() self.viewModel.mercadoPagoServicesAdapter.getCheckoutPreference(checkoutPreferenceId: self.viewModel.checkoutPreference._id, callback: { [weak self] (checkoutPreference) in - + guard let strongSelf = self else { return } - + strongSelf.viewModel.checkoutPreference = checkoutPreference strongSelf.viewModel.paymentData.payer = checkoutPreference.getPayer() strongSelf.dismissLoading() strongSelf.executeNextStep() - + }) { [weak self] (error) in - + guard let strongSelf = self else { return } - + strongSelf.dismissLoading() strongSelf.viewModel.errorInputs(error: MPSDKError.convertFrom(error, requestOrigin: ApiUtil.RequestOrigin.GET_PREFERENCE.rawValue), errorCallback: { [weak self] (_) -> Void in self?.getCheckoutPreference() }) strongSelf.executeNextStep() - + } } - + func getDirectDiscount() { self.presentLoading() self.viewModel.mercadoPagoServicesAdapter.getDirectDiscount(amount: self.viewModel.getFinalAmount(), payerEmail: self.viewModel.checkoutPreference.payer.email, callback: { [weak self] (discount) in - + guard let strongSelf = self else { return } - + strongSelf.viewModel.paymentData.discount = discount strongSelf.executeNextStep() strongSelf.dismissLoading() - + }) { [weak self] (error) in - + guard let strongSelf = self else { return } - + strongSelf.dismissLoading() strongSelf.executeNextStep() - + } } - + func getPaymentMethodSearch() { self.presentLoading() - + self.viewModel.mercadoPagoServicesAdapter.getPaymentMethodSearch(amount: self.viewModel.getFinalAmount(), excludedPaymentTypesIds: self.viewModel.getExcludedPaymentTypesIds(), excludedPaymentMethodsIds: self.viewModel.getExcludedPaymentMethodsIds(), defaultPaymentMethod: self.viewModel.getDefaultPaymentMethodId(), payer: Payer(), site: MercadoPagoContext.getSite(), callback: { [weak self] (paymentMethodSearch) in - + guard let strongSelf = self else { return } - + strongSelf.viewModel.updateCheckoutModel(paymentMethodSearch: paymentMethodSearch) strongSelf.dismissLoading() strongSelf.executeNextStep() - + }) { [weak self] (error) in - + guard let strongSelf = self else { return } - + strongSelf.dismissLoading() strongSelf.viewModel.errorInputs(error: MPSDKError.convertFrom(error, requestOrigin: ApiUtil.RequestOrigin.PAYMENT_METHOD_SEARCH.rawValue), errorCallback: { [weak self] (_) -> Void in - + self?.getPaymentMethodSearch() }) strongSelf.executeNextStep() - + } } - - func getIssuers() { + + func getIssuers(updateCallback: (() -> Void)? = nil){ // Le agregué un callback para poder ordenar los requests (primero este, despues getpayercost, etc) self.presentLoading() guard let paymentMethod = self.viewModel.paymentData.getPaymentMethod() else { return } let bin = self.viewModel.cardToken?.getBin() self.viewModel.mercadoPagoServicesAdapter.getIssuers(paymentMethodId: paymentMethod._id, bin: bin, callback: { [weak self] (issuers) in - + guard let strongSelf = self else { return } - + strongSelf.viewModel.issuers = issuers - + if issuers.count == 1 { strongSelf.viewModel.updateCheckoutModel(issuer: issuers[0]) } - strongSelf.dismissLoading() - strongSelf.executeNextStep() - + + if let updateCallback = updateCallback { + updateCallback() + strongSelf.dismissLoading() + } else { + strongSelf.dismissLoading() + strongSelf.executeNextStep() + } + }) { [weak self] (error) in - + guard let strongSelf = self else { return } - + strongSelf.dismissLoading() strongSelf.viewModel.errorInputs(error: MPSDKError.convertFrom(error, requestOrigin: ApiUtil.RequestOrigin.GET_ISSUERS.rawValue), errorCallback: { [weak self] (_) in self?.getIssuers() }) strongSelf.executeNextStep() - + } } - + func createCardToken(cardInformation: CardInformation? = nil, securityCode: String? = nil) { guard let cardInfo = self.viewModel.paymentOptionSelected as? CardInformation else { createNewCardToken() @@ -136,44 +142,44 @@ extension MercadoPagoCheckout { return // TODO Refactor : Tenemos unos lios barbaros con CardInformation y CardInformationForm, no entiendo porque hay uno y otr } cloneCardToken(token: token, securityCode: securityCode!) - + } else if self.viewModel.mpESCManager.hasESCEnable() { var savedESCCardToken: SavedESCCardToken - + let esc = self.viewModel.mpESCManager.getESC(cardId: cardInfo.getCardId()) - + if !String.isNullOrEmpty(esc) { savedESCCardToken = SavedESCCardToken(cardId: cardInfo.getCardId(), esc: esc) } else { savedESCCardToken = SavedESCCardToken(cardId: cardInfo.getCardId(), securityCode: securityCode) } createSavedESCCardToken(savedESCCardToken: savedESCCardToken) - + } else { createSavedCardToken(cardInformation: cardInfo, securityCode: securityCode!) } } - + func createNewCardToken() { self.presentLoading() - + self.viewModel.mercadoPagoServicesAdapter.createToken(cardToken: self.viewModel.cardToken!, callback: { [weak self] (token) in - + guard let strongSelf = self else { return } - + strongSelf.viewModel.updateCheckoutModel(token: token) strongSelf.dismissLoading() strongSelf.executeNextStep() - + }) { [weak self] (error) in - + guard let strongSelf = self else { return } let error = MPSDKError.convertFrom(error, requestOrigin: ApiUtil.RequestOrigin.CREATE_TOKEN.rawValue) - + if error.apiException?.containsCause(code: ApiUtil.ErrorCauseCodes.INVALID_IDENTIFICATION_NUMBER.rawValue) == true { if let identificationViewController = strongSelf.navigationController.viewControllers.last as? IdentificationViewController { identificationViewController.showErrorMessage("Revisa este dato".localized) @@ -186,52 +192,52 @@ extension MercadoPagoCheckout { strongSelf.dismissLoading() strongSelf.executeNextStep() } - + } } - + func createSavedCardToken(cardInformation: CardInformation, securityCode: String) { self.presentLoading() - + let cardInformation = self.viewModel.paymentOptionSelected as! CardInformation let saveCardToken = SavedCardToken(card: cardInformation, securityCode: securityCode, securityCodeRequired: true) - + self.viewModel.mercadoPagoServicesAdapter.createToken(savedCardToken: saveCardToken, callback: { [weak self] (token) in - + guard let strongSelf = self else { return } - + if token.lastFourDigits.isEmpty { token.lastFourDigits = cardInformation.getCardLastForDigits() } strongSelf.viewModel.updateCheckoutModel(token: token) strongSelf.dismissLoading() strongSelf.executeNextStep() - + }) { [weak self] (error) in - + guard let strongSelf = self else { return } - + strongSelf.dismissLoading() strongSelf.viewModel.errorInputs(error: MPSDKError.convertFrom(error, requestOrigin: ApiUtil.RequestOrigin.CREATE_TOKEN.rawValue), errorCallback: { [weak self] (_) in self?.createSavedCardToken(cardInformation: cardInformation, securityCode: securityCode) }) strongSelf.executeNextStep() - + } } - + func createSavedESCCardToken(savedESCCardToken: SavedESCCardToken) { self.presentLoading() self.viewModel.mercadoPagoServicesAdapter.createToken(savedESCCardToken: savedESCCardToken, callback: { [weak self] (token) in - + guard let strongSelf = self else { return } - + if token.lastFourDigits.isEmpty { let cardInformation = strongSelf.viewModel.paymentOptionSelected as? CardInformation token.lastFourDigits = cardInformation?.getCardLastForDigits() ?? "" @@ -239,79 +245,79 @@ extension MercadoPagoCheckout { strongSelf.viewModel.updateCheckoutModel(token: token) strongSelf.dismissLoading() strongSelf.executeNextStep() - + }) { [weak self] (error) in - + guard let strongSelf = self else { return } let mpError = MPSDKError.convertFrom(error, requestOrigin: ApiUtil.RequestOrigin.CREATE_TOKEN.rawValue) - + if let apiException = mpError.apiException, apiException.containsCause(code: ApiUtil.ErrorCauseCodes.INVALID_ESC.rawValue) || apiException.containsCause(code: ApiUtil.ErrorCauseCodes.INVALID_FINGERPRINT.rawValue) { - + strongSelf.viewModel.mpESCManager.deleteESC(cardId: savedESCCardToken.cardId) - + } else { strongSelf.viewModel.errorInputs(error: mpError, errorCallback: { [weak self] (_) in self?.createSavedESCCardToken(savedESCCardToken: savedESCCardToken) }) - + } strongSelf.dismissLoading() strongSelf.executeNextStep() - + } } - + func cloneCardToken(token: Token, securityCode: String) { self.presentLoading() self.viewModel.mercadoPagoServicesAdapter.cloneToken(tokenId: token._id, securityCode: securityCode, callback: { [weak self] (token) in - + guard let strongSelf = self else { return } - + strongSelf.viewModel.updateCheckoutModel(token: token) strongSelf.dismissLoading() strongSelf.executeNextStep() - + }) { [weak self] (error) in - + guard let strongSelf = self else { return } - + strongSelf.dismissLoading() strongSelf.viewModel.errorInputs(error: MPSDKError.convertFrom(error, requestOrigin: ApiUtil.RequestOrigin.CREATE_TOKEN.rawValue), errorCallback: { [weak self] (_) in self?.cloneCardToken(token: token, securityCode: securityCode) }) strongSelf.executeNextStep() - + } } - + func getPayerCosts(updateCallback: (() -> Void)? = nil) { self.presentLoading() - + guard let paymentMethod = self.viewModel.paymentData.getPaymentMethod() else { return } - + let bin = self.viewModel.cardToken?.getBin() - + self.viewModel.mercadoPagoServicesAdapter.getInstallments(bin: bin, amount: self.viewModel.getFinalAmount(), issuer: self.viewModel.paymentData.getIssuer(), paymentMethodId: paymentMethod._id, callback: { [weak self] (installments) in - + guard let strongSelf = self else { return } - + strongSelf.viewModel.payerCosts = installments[0].payerCosts - + let defaultPayerCost = strongSelf.viewModel.checkoutPreference.paymentPreference?.autoSelectPayerCost(installments[0].payerCosts) if let defaultPC = defaultPayerCost { strongSelf.viewModel.updateCheckoutModel(payerCost: defaultPC) } - + if let updateCallback = updateCallback { updateCallback() strongSelf.dismissLoading() @@ -319,105 +325,109 @@ extension MercadoPagoCheckout { strongSelf.dismissLoading() strongSelf.executeNextStep() } - + }) { [weak self] (error) in - + guard let strongSelf = self else { return } - + strongSelf.dismissLoading() strongSelf.viewModel.errorInputs(error: MPSDKError.convertFrom(error, requestOrigin: ApiUtil.RequestOrigin.GET_INSTALLMENTS.rawValue), errorCallback: { [weak self] (_) in self?.getPayerCosts() }) strongSelf.executeNextStep() - + } } - + func createPayment() { self.presentLoading() - - var paymentBody: [String:Any] - if MercadoPagoCheckoutViewModel.servicePreference.isUsingDeafaultPaymentSettings() { - let mpPayment = MercadoPagoCheckoutViewModel.createMPPayment(preferenceId: self.viewModel.checkoutPreference._id, paymentData: self.viewModel.paymentData, binaryMode: self.viewModel.binaryMode) - paymentBody = mpPayment.toJSON() - } else { - paymentBody = self.viewModel.paymentData.toJSON() - } - - var createPaymentQuery: [String:String]? = [:] - if let paymentAdditionalInfo = MercadoPagoCheckoutViewModel.servicePreference.getPaymentAddionalInfo() as? [String:String] { - createPaymentQuery = paymentAdditionalInfo - } else { - createPaymentQuery = nil - } - - self.viewModel.mercadoPagoServicesAdapter.createPayment(url: MercadoPagoCheckoutViewModel.servicePreference.getPaymentURL(), uri: MercadoPagoCheckoutViewModel.servicePreference.getPaymentURI(), paymentData: paymentBody as NSDictionary, query: createPaymentQuery, callback: { [weak self] (payment) in - - guard let strongSelf = self else { - return - } - - strongSelf.viewModel.updateCheckoutModel(payment: payment) - strongSelf.dismissLoading() - strongSelf.executeNextStep() - - }) { [weak self] (error) in - - guard let strongSelf = self else { - return - } - - strongSelf.dismissLoading() - let mpError = MPSDKError.convertFrom(error, requestOrigin: ApiUtil.RequestOrigin.CREATE_PAYMENT.rawValue) - - if let apiException = mpError.apiException, apiException.containsCause(code: ApiUtil.ErrorCauseCodes.INVALID_PAYMENT_WITH_ESC.rawValue) { - strongSelf.viewModel.prepareForInvalidPaymentWithESC() - } else if let apiException = mpError.apiException, apiException.containsCause(code: ApiUtil.ErrorCauseCodes.INVALID_PAYMENT_IDENTIFICATION_NUMBER.rawValue) { - self?.viewModel.paymentData.clearCollectedData() - let mpInvalidIdentificationError = MPSDKError.init(message: "Algo salió mal… ".localized, errorDetail: "El número de identificación es inválido".localized, retry: true) - strongSelf.viewModel.errorInputs(error: mpInvalidIdentificationError, errorCallback: { [weak self] (_) in - self?.viewModel.resetInformation() - self?.viewModel.resetGroupSelection() - self?.executeNextStep() - }) - } else { - strongSelf.viewModel.errorInputs(error: mpError, errorCallback: { [weak self] (_) in - self?.createPayment() - }) - } - strongSelf.executeNextStep() - - } + self.getIssuers(updateCallback: { // Esto lo agregué porque en la llamada getPayerCosts daba error por no tener issuer + self.getPayerCosts(updateCallback: { // Sin esto no había forma de obtener el transactionAmount y otros datos necesarios + var paymentBody: [String:Any] + if MercadoPagoCheckoutViewModel.servicePreference.isUsingDeafaultPaymentSettings() { + let mpPayment = MercadoPagoCheckoutViewModel.createMPPayment(preferenceId: self.viewModel.checkoutPreference._id, paymentData: self.viewModel.paymentData, binaryMode: self.viewModel.binaryMode) + paymentBody = mpPayment.toJSON() + } else { + paymentBody = self.viewModel.paymentData.toCustomJSON() + } + + // Ahora el additionalInfo se agrega en el body, tal como lo hace el SDK de Android + if let paymentAdditionalInfo = MercadoPagoCheckoutViewModel.servicePreference.getPaymentAddionalInfo() as? [String:String] { + for (k, v) in paymentAdditionalInfo { + paymentBody[k] = v + } + } + + // query ahora es nil, ya que no paso ningún dato utilizando ese método + self.viewModel.mercadoPagoServicesAdapter.createPayment(url: MercadoPagoCheckoutViewModel.servicePreference.getPaymentURL(), uri: MercadoPagoCheckoutViewModel.servicePreference.getPaymentURI(), paymentData: paymentBody as NSDictionary, query: nil, callback: { [weak self] (payment) in + + guard let strongSelf = self else { + return + } + + strongSelf.viewModel.updateCheckoutModel(payment: payment) + strongSelf.dismissLoading() + strongSelf.executeNextStep() + + }) { [weak self] (error) in + + guard let strongSelf = self else { + return + } + + strongSelf.dismissLoading() + let mpError = MPSDKError.convertFrom(error, requestOrigin: ApiUtil.RequestOrigin.CREATE_PAYMENT.rawValue) + + if let apiException = mpError.apiException, apiException.containsCause(code: ApiUtil.ErrorCauseCodes.INVALID_PAYMENT_WITH_ESC.rawValue) { + strongSelf.viewModel.prepareForInvalidPaymentWithESC() + } else if let apiException = mpError.apiException, apiException.containsCause(code: ApiUtil.ErrorCauseCodes.INVALID_PAYMENT_IDENTIFICATION_NUMBER.rawValue) { + self?.viewModel.paymentData.clearCollectedData() + let mpInvalidIdentificationError = MPSDKError.init(message: "Algo salió mal… ".localized, errorDetail: "El número de identificación es inválido".localized, retry: true) + strongSelf.viewModel.errorInputs(error: mpInvalidIdentificationError, errorCallback: { [weak self] (_) in + self?.viewModel.resetInformation() + self?.viewModel.resetGroupSelection() + self?.executeNextStep() + }) + } else { + strongSelf.viewModel.errorInputs(error: mpError, errorCallback: { [weak self] (_) in + self?.createPayment() + }) + } + strongSelf.executeNextStep() + + } + }) + }) } - + func getInstructions() { self.presentLoading() - + guard let paymentResult = self.viewModel.paymentResult else { fatalError("Get Instructions - Payment Result does no exist") } - + guard let paymentId = paymentResult._id else { - fatalError("Get Instructions - Payment Id does no exist") + fatalError("Get Instructions - Payment Id does no exist") } - + guard let paymentTypeId = paymentResult.paymentData?.getPaymentMethod()?.paymentTypeId else { fatalError("Get Instructions - Payment Method Type Id does no exist") } - + self.viewModel.mercadoPagoServicesAdapter.getInstructions(paymentId: paymentId, paymentTypeId: paymentTypeId, callback: { [weak self] (instructionsInfo) in - + guard let strongSelf = self else { return } strongSelf.viewModel.instructionsInfo = instructionsInfo strongSelf.dismissLoading() strongSelf.executeNextStep() - + }) { [weak self] (error) in - + guard let strongSelf = self else { return } @@ -426,34 +436,34 @@ extension MercadoPagoCheckout { self?.getInstructions() }) strongSelf.executeNextStep() - + } } - + func getIdentificationTypes() { self.presentLoading() self.viewModel.mercadoPagoServicesAdapter.getIdentificationTypes(callback: { [weak self] (identificationTypes) in - + guard let strongSelf = self else { return } - + strongSelf.viewModel.updateCheckoutModel(identificationTypes: identificationTypes) strongSelf.dismissLoading() strongSelf.executeNextStep() - + }) { [weak self] (error) in - + guard let strongSelf = self else { return } - + strongSelf.dismissLoading() strongSelf.viewModel.errorInputs(error: MPSDKError.convertFrom(error, requestOrigin: ApiUtil.RequestOrigin.GET_IDENTIFICATION_TYPES.rawValue), errorCallback: { [weak self] (_) in self?.getIdentificationTypes() }) strongSelf.executeNextStep() - + } } } diff --git a/MercadoPagoSDK/MercadoPagoSDK/PaymentData.swift b/MercadoPagoSDK/MercadoPagoSDK/PaymentData.swift index 3974c90a..2d636ad7 100644 --- a/MercadoPagoSDK/MercadoPagoSDK/PaymentData.swift +++ b/MercadoPagoSDK/MercadoPagoSDK/PaymentData.swift @@ -9,7 +9,7 @@ import UIKit public class PaymentData: NSObject { - + public var paymentMethod: PaymentMethod? public var issuer: Issuer? public var payerCost: PayerCost? @@ -17,7 +17,7 @@ public class PaymentData: NSObject { public var payer = Payer() public var transactionDetails: TransactionDetails? public var discount: DiscountCoupon? - + func clearCollectedData() { self.paymentMethod = nil self.issuer = nil @@ -27,60 +27,60 @@ public class PaymentData: NSObject { self.transactionDetails = nil // No borrar el descuento } - + func isComplete() -> Bool { - + guard let paymentMethod = self.paymentMethod else { return false } - + if paymentMethod.isEntityTypeRequired && payer.entityType == nil { return false } - + if paymentMethod.isPayerInfoRequired && payer.identification == nil { return false } - + if !Array.isNullOrEmpty(paymentMethod.financialInstitutions) && transactionDetails?.financialInstitution == nil { return false } - + if paymentMethod._id == PaymentTypeId.ACCOUNT_MONEY.rawValue || !paymentMethod.isOnlinePaymentMethod { return true } - + if paymentMethod.isCard && (token == nil || payerCost == nil) { - + if (paymentMethod.paymentTypeId == PaymentTypeId.DEBIT_CARD.rawValue || paymentMethod.paymentTypeId == PaymentTypeId.PREPAID_CARD.rawValue ) && token != nil { return true } return false } - + return true } - + func hasToken() -> Bool { return token != nil } - + func hasIssuer() -> Bool { return issuer != nil } - + func hasPayerCost() -> Bool { return payerCost != nil } - + func hasPaymentMethod() -> Bool { return paymentMethod != nil } - + func hasCustomerPaymentOption() -> Bool { return hasPaymentMethod() && (self.paymentMethod!.isAccountMoney || (hasToken() && !String.isNullOrEmpty(self.token!.cardId))) } - + public func updatePaymentDataWith(paymentMethod: PaymentMethod?) { guard let paymentMethod = paymentMethod else { return @@ -90,21 +90,21 @@ public class PaymentData: NSObject { cleanPayerCost() self.paymentMethod = paymentMethod } - + public func updatePaymentDataWith(token: Token?) { guard let token = token else { return } self.token = token } - + public func updatePaymentDataWith(payerCost: PayerCost?) { guard let payerCost = payerCost else { return } self.payerCost = payerCost } - + public func updatePaymentDataWith(issuer: Issuer?) { guard let issuer = issuer else { return @@ -112,75 +112,108 @@ public class PaymentData: NSObject { cleanPayerCost() self.issuer = issuer } - + public func updatePaymentDataWith(payer: Payer?) { guard let payer = payer else { return } self.payer = payer } - + public func cleanToken() { self.token = nil } - + public func cleanPayerCost() { self.payerCost = nil } - + func cleanIssuer() { self.issuer = nil } - + func cleanPaymentMethod() { self.paymentMethod = nil } - - public func getToken() -> Token? { + + public func getToken() -> Token? { return token } - + public func getPayerCost() -> PayerCost? { return payerCost } - + public func getIssuer() -> Issuer? { return issuer } - + public func getPaymentMethod() -> PaymentMethod? { return paymentMethod } - + func toJSONString() -> String { return JSONHandler.jsonCoding(toJSON()) } - + func toJSON() -> [String:Any] { - var obj: [String:Any] = [ + var obj: [String:Any] = [ "payer": payer.toJSON() - ] + ] if let paymentMethod = self.paymentMethod { obj["payment_method"] = paymentMethod.toJSON() } - + if let payerCost = self.payerCost { obj["payer_cost"] = payerCost.toJSON() } - + if let token = self.token { obj["card_token"] = token.toJSON() } - + if let issuer = self.issuer { obj["issuer"] = issuer.toJSON() } - + if let discount = self.discount { obj["discount"] = discount.toJSON() } - + return obj } - + + // Agrego este método para no modificar el otro + // Le agrego algunos tags y modifico otros para que sea "compliant" con el request que hace Android + func toCustomJSON() -> [String:Any] { + var obj: [String:Any] = [ + "payer": payer.toJSON() + ] + if let paymentMethod = self.paymentMethod { + obj["payment_method"] = paymentMethod.toJSON() + obj["payment_method_id"] = paymentMethod._id + } + + if let payerCost = self.payerCost { + obj["transaction_amount"] = payerCost.totalAmount + obj["installments"] = payerCost.installments + } + + if let token = self.token { + obj["card_token"] = token._id + } + + if let issuer = self.issuer { + obj["issuer"] = issuer.toJSON() + obj["card_issuer_id"] = issuer._id + } + + if let discount = self.discount { + obj["discount"] = discount.toJSON() + obj["campaign_id"] = discount._id + } + + return obj + } + } commit 23cab0bb8454e7aaf64e24de4f535a0591edef16 Author: Facundo Médica Date: Wed Feb 21 16:27:34 2018 +0000 test diff --git a/MercadoPagoSDK/MercadoPagoSDK/MercadoPagoCheckoutServices.swift b/MercadoPagoSDK/MercadoPagoSDK/MercadoPagoCheckoutServices.swift index bad101b7..51ca8888 100644 --- a/MercadoPagoSDK/MercadoPagoSDK/MercadoPagoCheckoutServices.swift +++ b/MercadoPagoSDK/MercadoPagoSDK/MercadoPagoCheckoutServices.swift @@ -9,123 +9,129 @@ import Foundation extension MercadoPagoCheckout { - + func getCheckoutPreference() { self.presentLoading() self.viewModel.mercadoPagoServicesAdapter.getCheckoutPreference(checkoutPreferenceId: self.viewModel.checkoutPreference._id, callback: { [weak self] (checkoutPreference) in - + guard let strongSelf = self else { return } - + strongSelf.viewModel.checkoutPreference = checkoutPreference strongSelf.viewModel.paymentData.payer = checkoutPreference.getPayer() strongSelf.dismissLoading() strongSelf.executeNextStep() - + }) { [weak self] (error) in - + guard let strongSelf = self else { return } - + strongSelf.dismissLoading() strongSelf.viewModel.errorInputs(error: MPSDKError.convertFrom(error, requestOrigin: ApiUtil.RequestOrigin.GET_PREFERENCE.rawValue), errorCallback: { [weak self] (_) -> Void in self?.getCheckoutPreference() }) strongSelf.executeNextStep() - + } } - + func getDirectDiscount() { self.presentLoading() self.viewModel.mercadoPagoServicesAdapter.getDirectDiscount(amount: self.viewModel.getFinalAmount(), payerEmail: self.viewModel.checkoutPreference.payer.email, callback: { [weak self] (discount) in - + guard let strongSelf = self else { return } - + strongSelf.viewModel.paymentData.discount = discount strongSelf.executeNextStep() strongSelf.dismissLoading() - + }) { [weak self] (error) in - + guard let strongSelf = self else { return } - + strongSelf.dismissLoading() strongSelf.executeNextStep() - + } } - + func getPaymentMethodSearch() { self.presentLoading() - + self.viewModel.mercadoPagoServicesAdapter.getPaymentMethodSearch(amount: self.viewModel.getFinalAmount(), excludedPaymentTypesIds: self.viewModel.getExcludedPaymentTypesIds(), excludedPaymentMethodsIds: self.viewModel.getExcludedPaymentMethodsIds(), defaultPaymentMethod: self.viewModel.getDefaultPaymentMethodId(), payer: Payer(), site: MercadoPagoContext.getSite(), callback: { [weak self] (paymentMethodSearch) in - + guard let strongSelf = self else { return } - + strongSelf.viewModel.updateCheckoutModel(paymentMethodSearch: paymentMethodSearch) strongSelf.dismissLoading() strongSelf.executeNextStep() - + }) { [weak self] (error) in - + guard let strongSelf = self else { return } - + strongSelf.dismissLoading() strongSelf.viewModel.errorInputs(error: MPSDKError.convertFrom(error, requestOrigin: ApiUtil.RequestOrigin.PAYMENT_METHOD_SEARCH.rawValue), errorCallback: { [weak self] (_) -> Void in - + self?.getPaymentMethodSearch() }) strongSelf.executeNextStep() - + } } - - func getIssuers() { + + func getIssuers(updateCallback: (() -> Void)? = nil){ // Le agregué un callback para poder ordenar los requests (primero este, despues getpayercost, etc) self.presentLoading() guard let paymentMethod = self.viewModel.paymentData.getPaymentMethod() else { return } let bin = self.viewModel.cardToken?.getBin() self.viewModel.mercadoPagoServicesAdapter.getIssuers(paymentMethodId: paymentMethod._id, bin: bin, callback: { [weak self] (issuers) in - + guard let strongSelf = self else { return } - + strongSelf.viewModel.issuers = issuers - + if issuers.count == 1 { strongSelf.viewModel.updateCheckoutModel(issuer: issuers[0]) } - strongSelf.dismissLoading() - strongSelf.executeNextStep() - + + if let updateCallback = updateCallback { + updateCallback() + strongSelf.dismissLoading() + } else { + strongSelf.dismissLoading() + strongSelf.executeNextStep() + } + }) { [weak self] (error) in - + guard let strongSelf = self else { return } - + strongSelf.dismissLoading() strongSelf.viewModel.errorInputs(error: MPSDKError.convertFrom(error, requestOrigin: ApiUtil.RequestOrigin.GET_ISSUERS.rawValue), errorCallback: { [weak self] (_) in self?.getIssuers() }) strongSelf.executeNextStep() - + } } - + func createCardToken(cardInformation: CardInformation? = nil, securityCode: String? = nil) { guard let cardInfo = self.viewModel.paymentOptionSelected as? CardInformation else { createNewCardToken() @@ -136,44 +142,44 @@ extension MercadoPagoCheckout { return // TODO Refactor : Tenemos unos lios barbaros con CardInformation y CardInformationForm, no entiendo porque hay uno y otr } cloneCardToken(token: token, securityCode: securityCode!) - + } else if self.viewModel.mpESCManager.hasESCEnable() { var savedESCCardToken: SavedESCCardToken - + let esc = self.viewModel.mpESCManager.getESC(cardId: cardInfo.getCardId()) - + if !String.isNullOrEmpty(esc) { savedESCCardToken = SavedESCCardToken(cardId: cardInfo.getCardId(), esc: esc) } else { savedESCCardToken = SavedESCCardToken(cardId: cardInfo.getCardId(), securityCode: securityCode) } createSavedESCCardToken(savedESCCardToken: savedESCCardToken) - + } else { createSavedCardToken(cardInformation: cardInfo, securityCode: securityCode!) } } - + func createNewCardToken() { self.presentLoading() - + self.viewModel.mercadoPagoServicesAdapter.createToken(cardToken: self.viewModel.cardToken!, callback: { [weak self] (token) in - + guard let strongSelf = self else { return } - + strongSelf.viewModel.updateCheckoutModel(token: token) strongSelf.dismissLoading() strongSelf.executeNextStep() - + }) { [weak self] (error) in - + guard let strongSelf = self else { return } let error = MPSDKError.convertFrom(error, requestOrigin: ApiUtil.RequestOrigin.CREATE_TOKEN.rawValue) - + if error.apiException?.containsCause(code: ApiUtil.ErrorCauseCodes.INVALID_IDENTIFICATION_NUMBER.rawValue) == true { if let identificationViewController = strongSelf.navigationController.viewControllers.last as? IdentificationViewController { identificationViewController.showErrorMessage("Revisa este dato".localized) @@ -186,52 +192,52 @@ extension MercadoPagoCheckout { strongSelf.dismissLoading() strongSelf.executeNextStep() } - + } } - + func createSavedCardToken(cardInformation: CardInformation, securityCode: String) { self.presentLoading() - + let cardInformation = self.viewModel.paymentOptionSelected as! CardInformation let saveCardToken = SavedCardToken(card: cardInformation, securityCode: securityCode, securityCodeRequired: true) - + self.viewModel.mercadoPagoServicesAdapter.createToken(savedCardToken: saveCardToken, callback: { [weak self] (token) in - + guard let strongSelf = self else { return } - + if token.lastFourDigits.isEmpty { token.lastFourDigits = cardInformation.getCardLastForDigits() } strongSelf.viewModel.updateCheckoutModel(token: token) strongSelf.dismissLoading() strongSelf.executeNextStep() - + }) { [weak self] (error) in - + guard let strongSelf = self else { return } - + strongSelf.dismissLoading() strongSelf.viewModel.errorInputs(error: MPSDKError.convertFrom(error, requestOrigin: ApiUtil.RequestOrigin.CREATE_TOKEN.rawValue), errorCallback: { [weak self] (_) in self?.createSavedCardToken(cardInformation: cardInformation, securityCode: securityCode) }) strongSelf.executeNextStep() - + } } - + func createSavedESCCardToken(savedESCCardToken: SavedESCCardToken) { self.presentLoading() self.viewModel.mercadoPagoServicesAdapter.createToken(savedESCCardToken: savedESCCardToken, callback: { [weak self] (token) in - + guard let strongSelf = self else { return } - + if token.lastFourDigits.isEmpty { let cardInformation = strongSelf.viewModel.paymentOptionSelected as? CardInformation token.lastFourDigits = cardInformation?.getCardLastForDigits() ?? "" @@ -239,79 +245,79 @@ extension MercadoPagoCheckout { strongSelf.viewModel.updateCheckoutModel(token: token) strongSelf.dismissLoading() strongSelf.executeNextStep() - + }) { [weak self] (error) in - + guard let strongSelf = self else { return } let mpError = MPSDKError.convertFrom(error, requestOrigin: ApiUtil.RequestOrigin.CREATE_TOKEN.rawValue) - + if let apiException = mpError.apiException, apiException.containsCause(code: ApiUtil.ErrorCauseCodes.INVALID_ESC.rawValue) || apiException.containsCause(code: ApiUtil.ErrorCauseCodes.INVALID_FINGERPRINT.rawValue) { - + strongSelf.viewModel.mpESCManager.deleteESC(cardId: savedESCCardToken.cardId) - + } else { strongSelf.viewModel.errorInputs(error: mpError, errorCallback: { [weak self] (_) in self?.createSavedESCCardToken(savedESCCardToken: savedESCCardToken) }) - + } strongSelf.dismissLoading() strongSelf.executeNextStep() - + } } - + func cloneCardToken(token: Token, securityCode: String) { self.presentLoading() self.viewModel.mercadoPagoServicesAdapter.cloneToken(tokenId: token._id, securityCode: securityCode, callback: { [weak self] (token) in - + guard let strongSelf = self else { return } - + strongSelf.viewModel.updateCheckoutModel(token: token) strongSelf.dismissLoading() strongSelf.executeNextStep() - + }) { [weak self] (error) in - + guard let strongSelf = self else { return } - + strongSelf.dismissLoading() strongSelf.viewModel.errorInputs(error: MPSDKError.convertFrom(error, requestOrigin: ApiUtil.RequestOrigin.CREATE_TOKEN.rawValue), errorCallback: { [weak self] (_) in self?.cloneCardToken(token: token, securityCode: securityCode) }) strongSelf.executeNextStep() - + } } - + func getPayerCosts(updateCallback: (() -> Void)? = nil) { self.presentLoading() - + guard let paymentMethod = self.viewModel.paymentData.getPaymentMethod() else { return } - + let bin = self.viewModel.cardToken?.getBin() - + self.viewModel.mercadoPagoServicesAdapter.getInstallments(bin: bin, amount: self.viewModel.getFinalAmount(), issuer: self.viewModel.paymentData.getIssuer(), paymentMethodId: paymentMethod._id, callback: { [weak self] (installments) in - + guard let strongSelf = self else { return } - + strongSelf.viewModel.payerCosts = installments[0].payerCosts - + let defaultPayerCost = strongSelf.viewModel.checkoutPreference.paymentPreference?.autoSelectPayerCost(installments[0].payerCosts) if let defaultPC = defaultPayerCost { strongSelf.viewModel.updateCheckoutModel(payerCost: defaultPC) } - + if let updateCallback = updateCallback { updateCallback() strongSelf.dismissLoading() @@ -319,105 +325,109 @@ extension MercadoPagoCheckout { strongSelf.dismissLoading() strongSelf.executeNextStep() } - + }) { [weak self] (error) in - + guard let strongSelf = self else { return } - + strongSelf.dismissLoading() strongSelf.viewModel.errorInputs(error: MPSDKError.convertFrom(error, requestOrigin: ApiUtil.RequestOrigin.GET_INSTALLMENTS.rawValue), errorCallback: { [weak self] (_) in self?.getPayerCosts() }) strongSelf.executeNextStep() - + } } - + func createPayment() { self.presentLoading() - - var paymentBody: [String:Any] - if MercadoPagoCheckoutViewModel.servicePreference.isUsingDeafaultPaymentSettings() { - let mpPayment = MercadoPagoCheckoutViewModel.createMPPayment(preferenceId: self.viewModel.checkoutPreference._id, paymentData: self.viewModel.paymentData, binaryMode: self.viewModel.binaryMode) - paymentBody = mpPayment.toJSON() - } else { - paymentBody = self.viewModel.paymentData.toJSON() - } - - var createPaymentQuery: [String:String]? = [:] - if let paymentAdditionalInfo = MercadoPagoCheckoutViewModel.servicePreference.getPaymentAddionalInfo() as? [String:String] { - createPaymentQuery = paymentAdditionalInfo - } else { - createPaymentQuery = nil - } - - self.viewModel.mercadoPagoServicesAdapter.createPayment(url: MercadoPagoCheckoutViewModel.servicePreference.getPaymentURL(), uri: MercadoPagoCheckoutViewModel.servicePreference.getPaymentURI(), paymentData: paymentBody as NSDictionary, query: createPaymentQuery, callback: { [weak self] (payment) in - - guard let strongSelf = self else { - return - } - - strongSelf.viewModel.updateCheckoutModel(payment: payment) - strongSelf.dismissLoading() - strongSelf.executeNextStep() - - }) { [weak self] (error) in - - guard let strongSelf = self else { - return - } - - strongSelf.dismissLoading() - let mpError = MPSDKError.convertFrom(error, requestOrigin: ApiUtil.RequestOrigin.CREATE_PAYMENT.rawValue) - - if let apiException = mpError.apiException, apiException.containsCause(code: ApiUtil.ErrorCauseCodes.INVALID_PAYMENT_WITH_ESC.rawValue) { - strongSelf.viewModel.prepareForInvalidPaymentWithESC() - } else if let apiException = mpError.apiException, apiException.containsCause(code: ApiUtil.ErrorCauseCodes.INVALID_PAYMENT_IDENTIFICATION_NUMBER.rawValue) { - self?.viewModel.paymentData.clearCollectedData() - let mpInvalidIdentificationError = MPSDKError.init(message: "Algo salió mal… ".localized, errorDetail: "El número de identificación es inválido".localized, retry: true) - strongSelf.viewModel.errorInputs(error: mpInvalidIdentificationError, errorCallback: { [weak self] (_) in - self?.viewModel.resetInformation() - self?.viewModel.resetGroupSelection() - self?.executeNextStep() - }) - } else { - strongSelf.viewModel.errorInputs(error: mpError, errorCallback: { [weak self] (_) in - self?.createPayment() - }) - } - strongSelf.executeNextStep() - - } + self.getIssuers(updateCallback: { // Esto lo agregué porque en la llamada getPayerCosts daba error por no tener issuer + self.getPayerCosts(updateCallback: { // Sin esto no había forma de obtener el transactionAmount y otros datos necesarios + var paymentBody: [String:Any] + if MercadoPagoCheckoutViewModel.servicePreference.isUsingDeafaultPaymentSettings() { + let mpPayment = MercadoPagoCheckoutViewModel.createMPPayment(preferenceId: self.viewModel.checkoutPreference._id, paymentData: self.viewModel.paymentData, binaryMode: self.viewModel.binaryMode) + paymentBody = mpPayment.toJSON() + } else { + paymentBody = self.viewModel.paymentData.toCustomJSON() + } + + // Ahora el additionalInfo se agrega en el body, tal como lo hace el SDK de Android + if let paymentAdditionalInfo = MercadoPagoCheckoutViewModel.servicePreference.getPaymentAddionalInfo() as? [String:String] { + for (k, v) in paymentAdditionalInfo { + paymentBody[k] = v + } + } + + // query ahora es nil, ya que no paso ningún dato utilizando ese método + self.viewModel.mercadoPagoServicesAdapter.createPayment(url: MercadoPagoCheckoutViewModel.servicePreference.getPaymentURL(), uri: MercadoPagoCheckoutViewModel.servicePreference.getPaymentURI(), paymentData: paymentBody as NSDictionary, query: nil, callback: { [weak self] (payment) in + + guard let strongSelf = self else { + return + } + + strongSelf.viewModel.updateCheckoutModel(payment: payment) + strongSelf.dismissLoading() + strongSelf.executeNextStep() + + }) { [weak self] (error) in + + guard let strongSelf = self else { + return + } + + strongSelf.dismissLoading() + let mpError = MPSDKError.convertFrom(error, requestOrigin: ApiUtil.RequestOrigin.CREATE_PAYMENT.rawValue) + + if let apiException = mpError.apiException, apiException.containsCause(code: ApiUtil.ErrorCauseCodes.INVALID_PAYMENT_WITH_ESC.rawValue) { + strongSelf.viewModel.prepareForInvalidPaymentWithESC() + } else if let apiException = mpError.apiException, apiException.containsCause(code: ApiUtil.ErrorCauseCodes.INVALID_PAYMENT_IDENTIFICATION_NUMBER.rawValue) { + self?.viewModel.paymentData.clearCollectedData() + let mpInvalidIdentificationError = MPSDKError.init(message: "Algo salió mal… ".localized, errorDetail: "El número de identificación es inválido".localized, retry: true) + strongSelf.viewModel.errorInputs(error: mpInvalidIdentificationError, errorCallback: { [weak self] (_) in + self?.viewModel.resetInformation() + self?.viewModel.resetGroupSelection() + self?.executeNextStep() + }) + } else { + strongSelf.viewModel.errorInputs(error: mpError, errorCallback: { [weak self] (_) in + self?.createPayment() + }) + } + strongSelf.executeNextStep() + + } + }) + }) } - + func getInstructions() { self.presentLoading() - + guard let paymentResult = self.viewModel.paymentResult else { fatalError("Get Instructions - Payment Result does no exist") } - + guard let paymentId = paymentResult._id else { - fatalError("Get Instructions - Payment Id does no exist") + fatalError("Get Instructions - Payment Id does no exist") } - + guard let paymentTypeId = paymentResult.paymentData?.getPaymentMethod()?.paymentTypeId else { fatalError("Get Instructions - Payment Method Type Id does no exist") } - + self.viewModel.mercadoPagoServicesAdapter.getInstructions(paymentId: paymentId, paymentTypeId: paymentTypeId, callback: { [weak self] (instructionsInfo) in - + guard let strongSelf = self else { return } strongSelf.viewModel.instructionsInfo = instructionsInfo strongSelf.dismissLoading() strongSelf.executeNextStep() - + }) { [weak self] (error) in - + guard let strongSelf = self else { return } @@ -426,34 +436,34 @@ extension MercadoPagoCheckout { self?.getInstructions() }) strongSelf.executeNextStep() - + } } - + func getIdentificationTypes() { self.presentLoading() self.viewModel.mercadoPagoServicesAdapter.getIdentificationTypes(callback: { [weak self] (identificationTypes) in - + guard let strongSelf = self else { return } - + strongSelf.viewModel.updateCheckoutModel(identificationTypes: identificationTypes) strongSelf.dismissLoading() strongSelf.executeNextStep() - + }) { [weak self] (error) in - + guard let strongSelf = self else { return } - + strongSelf.dismissLoading() strongSelf.viewModel.errorInputs(error: MPSDKError.convertFrom(error, requestOrigin: ApiUtil.RequestOrigin.GET_IDENTIFICATION_TYPES.rawValue), errorCallback: { [weak self] (_) in self?.getIdentificationTypes() }) strongSelf.executeNextStep() - + } } } diff --git a/MercadoPagoSDK/MercadoPagoSDK/PaymentData.swift b/MercadoPagoSDK/MercadoPagoSDK/PaymentData.swift index 3974c90a..2d636ad7 100644 --- a/MercadoPagoSDK/MercadoPagoSDK/PaymentData.swift +++ b/MercadoPagoSDK/MercadoPagoSDK/PaymentData.swift @@ -9,7 +9,7 @@ import UIKit public class PaymentData: NSObject { - + public var paymentMethod: PaymentMethod? public var issuer: Issuer? public var payerCost: PayerCost? @@ -17,7 +17,7 @@ public class PaymentData: NSObject { public var payer = Payer() public var transactionDetails: TransactionDetails? public var discount: DiscountCoupon? - + func clearCollectedData() { self.paymentMethod = nil self.issuer = nil @@ -27,60 +27,60 @@ public class PaymentData: NSObject { self.transactionDetails = nil // No borrar el descuento } - + func isComplete() -> Bool { - + guard let paymentMethod = self.paymentMethod else { return false } - + if paymentMethod.isEntityTypeRequired && payer.entityType == nil { return false } - + if paymentMethod.isPayerInfoRequired && payer.identification == nil { return false } - + if !Array.isNullOrEmpty(paymentMethod.financialInstitutions) && transactionDetails?.financialInstitution == nil { return false } - + if paymentMethod._id == PaymentTypeId.ACCOUNT_MONEY.rawValue || !paymentMethod.isOnlinePaymentMethod { return true } - + if paymentMethod.isCard && (token == nil || payerCost == nil) { - + if (paymentMethod.paymentTypeId == PaymentTypeId.DEBIT_CARD.rawValue || paymentMethod.paymentTypeId == PaymentTypeId.PREPAID_CARD.rawValue ) && token != nil { return true } return false } - + return true } - + func hasToken() -> Bool { return token != nil } - + func hasIssuer() -> Bool { return issuer != nil } - + func hasPayerCost() -> Bool { return payerCost != nil } - + func hasPaymentMethod() -> Bool { return paymentMethod != nil } - + func hasCustomerPaymentOption() -> Bool { return hasPaymentMethod() && (self.paymentMethod!.isAccountMoney || (hasToken() && !String.isNullOrEmpty(self.token!.cardId))) } - + public func updatePaymentDataWith(paymentMethod: PaymentMethod?) { guard let paymentMethod = paymentMethod else { return @@ -90,21 +90,21 @@ public class PaymentData: NSObject { cleanPayerCost() self.paymentMethod = paymentMethod } - + public func updatePaymentDataWith(token: Token?) { guard let token = token else { return } self.token = token } - + public func updatePaymentDataWith(payerCost: PayerCost?) { guard let payerCost = payerCost else { return } self.payerCost = payerCost } - + public func updatePaymentDataWith(issuer: Issuer?) { guard let issuer = issuer else { return @@ -112,75 +112,108 @@ public class PaymentData: NSObject { cleanPayerCost() self.issuer = issuer } - + public func updatePaymentDataWith(payer: Payer?) { guard let payer = payer else { return } self.payer = payer } - + public func cleanToken() { self.token = nil } - + public func cleanPayerCost() { self.payerCost = nil } - + func cleanIssuer() { self.issuer = nil } - + func cleanPaymentMethod() { self.paymentMethod = nil } - - public func getToken() -> Token? { + + public func getToken() -> Token? { return token } - + public func getPayerCost() -> PayerCost? { return payerCost } - + public func getIssuer() -> Issuer? { return issuer } - + public func getPaymentMethod() -> PaymentMethod? { return paymentMethod } - + func toJSONString() -> String { return JSONHandler.jsonCoding(toJSON()) } - + func toJSON() -> [String:Any] { - var obj: [String:Any] = [ + var obj: [String:Any] = [ "payer": payer.toJSON() - ] + ] if let paymentMethod = self.paymentMethod { obj["payment_method"] = paymentMethod.toJSON() } - + if let payerCost = self.payerCost { obj["payer_cost"] = payerCost.toJSON() } - + if let token = self.token { obj["card_token"] = token.toJSON() } - + if let issuer = self.issuer { obj["issuer"] = issuer.toJSON() } - + if let discount = self.discount { obj["discount"] = discount.toJSON() } - + return obj } - + + // Agrego este método para no modificar el otro + // Le agrego algunos tags y modifico otros para que sea "compliant" con el request que hace Android + func toCustomJSON() -> [String:Any] { + var obj: [String:Any] = [ + "payer": payer.toJSON() + ] + if let paymentMethod = self.paymentMethod { + obj["payment_method"] = paymentMethod.toJSON() + obj["payment_method_id"] = paymentMethod._id + } + + if let payerCost = self.payerCost { + obj["transaction_amount"] = payerCost.totalAmount + obj["installments"] = payerCost.installments + } + + if let token = self.token { + obj["card_token"] = token._id + } + + if let issuer = self.issuer { + obj["issuer"] = issuer.toJSON() + obj["card_issuer_id"] = issuer._id + } + + if let discount = self.discount { + obj["discount"] = discount.toJSON() + obj["campaign_id"] = discount._id + } + + return obj + } + }