@jimrising/easymerchantsdk-react-native 1.4.3 → 1.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -4
- package/ios/Classes/EasyMerchantSdk.m +4 -2
- package/ios/Classes/EasyMerchantSdk.swift +2 -0
- package/ios/Models/Request.swift +45 -54
- package/ios/Models/Result.swift +1 -0
- package/ios/Pods/ViewControllers/AdditionalInfoVC.swift +262 -37
- package/ios/Pods/ViewControllers/BillingInfoVC/BillingInfoVC.swift +219 -18
- package/ios/Pods/ViewControllers/EmailVerificationVC.swift +41 -86
- package/ios/Pods/ViewControllers/OTPVerificationVC.swift +99 -96
- package/ios/Pods/ViewControllers/PaymentInformation/PaymentInfoVC.swift +782 -79
- package/ios/Pods/ViewControllers/ThreeDSecurePaymentDoneVC.swift +24 -10
- package/ios/easymerchantsdk.podspec +1 -1
- package/ios/easymerchantsdk.storyboard +92 -210
- package/package.json +1 -1
|
@@ -363,7 +363,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
|
|
|
363
363
|
var isFrom = String()
|
|
364
364
|
|
|
365
365
|
//Blink Card
|
|
366
|
-
|
|
366
|
+
// var blinkCardRecognizer: MBCBlinkCardRecognizer!
|
|
367
367
|
|
|
368
368
|
// Variables for Card Scanning Data Back
|
|
369
369
|
var cardNumber: String?
|
|
@@ -1931,8 +1931,62 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
|
|
|
1931
1931
|
}
|
|
1932
1932
|
|
|
1933
1933
|
// Redirect based on billing visibility
|
|
1934
|
-
if fieldSection.visibility.billing {
|
|
1935
|
-
// Instantiate BillingInfoVC and pass the selected card data and CVV text
|
|
1934
|
+
// if fieldSection.visibility.billing {
|
|
1935
|
+
// // Instantiate BillingInfoVC and pass the selected card data and CVV text
|
|
1936
|
+
// let billingInfoVC = UIStoryboard(name: "easymerchantsdk", bundle: .easyPayBundle).instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
|
|
1937
|
+
//
|
|
1938
|
+
// billingInfoVC.isFrom = "SavedCards"
|
|
1939
|
+
// billingInfoVC.selectedCard = self.selectedCard // Passing the selected card data
|
|
1940
|
+
// billingInfoVC.cvvText = cvvText // Passing the CVV text
|
|
1941
|
+
// billingInfoVC.amount = Int(self.request.amount ?? 0)
|
|
1942
|
+
// billingInfoVC.selectedPaymentMethod = self.selectedPaymentMethod
|
|
1943
|
+
//
|
|
1944
|
+
// if let billingInfoData = self.request.billingInfoData {
|
|
1945
|
+
// billingInfoVC.billingInfoData = billingInfoData
|
|
1946
|
+
// }
|
|
1947
|
+
//
|
|
1948
|
+
// billingInfoVC.request = self.request
|
|
1949
|
+
// billingInfoVC.chosenPlan = self.txtFieldSelectPlanSingleSavedCard.text
|
|
1950
|
+
// billingInfoVC.startDate = self.txtFieldSelectDateSingleSavedCard.text
|
|
1951
|
+
//
|
|
1952
|
+
// billingInfoVC.billingInfo = fieldSection.billing
|
|
1953
|
+
// billingInfoVC.additionalInfo = fieldSection.additional
|
|
1954
|
+
// billingInfoVC.visibility = fieldSection.visibility
|
|
1955
|
+
//
|
|
1956
|
+
// // Navigate to BillingInfoVC
|
|
1957
|
+
// self.navigationController?.pushViewController(billingInfoVC, animated: true)
|
|
1958
|
+
// }
|
|
1959
|
+
// else {
|
|
1960
|
+
// let additionalInfoVC = UIStoryboard(name: "easymerchantsdk", bundle: .easyPayBundle).instantiateViewController(withIdentifier: "AdditionalInfoVC") as! AdditionalInfoVC
|
|
1961
|
+
// additionalInfoVC.isFrom = "SavedCards"
|
|
1962
|
+
// additionalInfoVC.selectedCard = self.selectedCard // Passing the selected card data
|
|
1963
|
+
// additionalInfoVC.cvvText = cvvText // Passing the CVV text
|
|
1964
|
+
// additionalInfoVC.amount = Int(self.request.amount ?? 0)
|
|
1965
|
+
// additionalInfoVC.selectedPaymentMethod = self.selectedPaymentMethod
|
|
1966
|
+
//
|
|
1967
|
+
// if let billingInfoData = self.request.billingInfoData {
|
|
1968
|
+
// additionalInfoVC.billingInfoData = billingInfoData
|
|
1969
|
+
// }
|
|
1970
|
+
//
|
|
1971
|
+
// additionalInfoVC.request = self.request
|
|
1972
|
+
// additionalInfoVC.chosenPlan = self.txtFieldSelectPlanSingleSavedCard.text
|
|
1973
|
+
// additionalInfoVC.startDate = self.txtFieldSelectDateSingleSavedCard.text
|
|
1974
|
+
//
|
|
1975
|
+
// additionalInfoVC.billingInfo = fieldSection.billing
|
|
1976
|
+
// additionalInfoVC.additionalInfo = fieldSection.additional
|
|
1977
|
+
// additionalInfoVC.visibility = fieldSection.visibility
|
|
1978
|
+
//
|
|
1979
|
+
// self.navigationController?.pushViewController(additionalInfoVC, animated: true)
|
|
1980
|
+
// }
|
|
1981
|
+
|
|
1982
|
+
let showBilling = fieldSection.visibility.billing
|
|
1983
|
+
let showAdditional = fieldSection.visibility.additional
|
|
1984
|
+
|
|
1985
|
+
if !showBilling && !showAdditional {
|
|
1986
|
+
self.paymentIntentFromShowCardApi()
|
|
1987
|
+
}
|
|
1988
|
+
else if showBilling {
|
|
1989
|
+
// Push to BillingInfoVC
|
|
1936
1990
|
let billingInfoVC = UIStoryboard(name: "easymerchantsdk", bundle: .easyPayBundle).instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
|
|
1937
1991
|
|
|
1938
1992
|
billingInfoVC.isFrom = "SavedCards"
|
|
@@ -1957,6 +2011,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
|
|
|
1957
2011
|
self.navigationController?.pushViewController(billingInfoVC, animated: true)
|
|
1958
2012
|
}
|
|
1959
2013
|
else {
|
|
2014
|
+
// Push to AdditionalInfoVC
|
|
1960
2015
|
let additionalInfoVC = UIStoryboard(name: "easymerchantsdk", bundle: .easyPayBundle).instantiateViewController(withIdentifier: "AdditionalInfoVC") as! AdditionalInfoVC
|
|
1961
2016
|
additionalInfoVC.isFrom = "SavedCards"
|
|
1962
2017
|
additionalInfoVC.selectedCard = self.selectedCard // Passing the selected card data
|
|
@@ -1978,6 +2033,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
|
|
|
1978
2033
|
|
|
1979
2034
|
self.navigationController?.pushViewController(additionalInfoVC, animated: true)
|
|
1980
2035
|
}
|
|
2036
|
+
|
|
1981
2037
|
}
|
|
1982
2038
|
}
|
|
1983
2039
|
catch {
|
|
@@ -2193,9 +2249,13 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
|
|
|
2193
2249
|
|
|
2194
2250
|
let showBilling = fieldSection.visibility.billing
|
|
2195
2251
|
let showAdditional = fieldSection.visibility.additional
|
|
2196
|
-
|
|
2252
|
+
|
|
2197
2253
|
if !showBilling && !showAdditional {
|
|
2198
|
-
self.
|
|
2254
|
+
if self.request.secureAuthentication == true {
|
|
2255
|
+
self.threeDSecurePaymentNewCardApi(customerId: UserStoreSingleton.shared.customerId ?? "")
|
|
2256
|
+
} else {
|
|
2257
|
+
self.paymentIntentAddNewCardApi(customerId: UserStoreSingleton.shared.customerId)
|
|
2258
|
+
}
|
|
2199
2259
|
}
|
|
2200
2260
|
else if showBilling {
|
|
2201
2261
|
// Push to BillingInfoVC
|
|
@@ -2751,7 +2811,8 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
|
|
|
2751
2811
|
|
|
2752
2812
|
if !showBilling && !showAdditional {
|
|
2753
2813
|
// Navigate directly to EmailVerificationVC
|
|
2754
|
-
let vc = easymerchantsdk.instantiateViewController(withIdentifier: "EmailVerificationVC") as! EmailVerificationVC
|
|
2814
|
+
// let vc = easymerchantsdk.instantiateViewController(withIdentifier: "EmailVerificationVC") as! EmailVerificationVC
|
|
2815
|
+
let vc = easymerchantsdk.instantiateViewController(withIdentifier: "OTPVerificationVC") as! OTPVerificationVC
|
|
2755
2816
|
vc.easyPayDelegate = self.easyPayDelegate
|
|
2756
2817
|
vc.grailPayAccountID = self.grailPayAccountID
|
|
2757
2818
|
vc.selectedGrailPayAccountType = self.selectedGrailPayAccountType
|
|
@@ -2766,6 +2827,8 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
|
|
|
2766
2827
|
vc.billingInfo = fieldSection.billing
|
|
2767
2828
|
vc.additionalInfo = fieldSection.additional
|
|
2768
2829
|
vc.visibility = fieldSection.visibility
|
|
2830
|
+
vc.amount = self.amount
|
|
2831
|
+
vc.email = self.txtFieldEmailGrailPayView.text
|
|
2769
2832
|
self.navigationController?.pushViewController(vc, animated: true)
|
|
2770
2833
|
}
|
|
2771
2834
|
else if showBilling {
|
|
@@ -2819,7 +2882,8 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
|
|
|
2819
2882
|
else {
|
|
2820
2883
|
//If billing info is nil
|
|
2821
2884
|
// Navigate to EmailVerificationVC directly
|
|
2822
|
-
let vc = easymerchantsdk.instantiateViewController(withIdentifier: "EmailVerificationVC") as! EmailVerificationVC
|
|
2885
|
+
// let vc = easymerchantsdk.instantiateViewController(withIdentifier: "EmailVerificationVC") as! EmailVerificationVC
|
|
2886
|
+
let vc = easymerchantsdk.instantiateViewController(withIdentifier: "OTPVerificationVC") as! OTPVerificationVC
|
|
2823
2887
|
vc.easyPayDelegate = self.easyPayDelegate
|
|
2824
2888
|
vc.grailPayAccountID = self.grailPayAccountID
|
|
2825
2889
|
vc.selectedGrailPayAccountType = self.selectedGrailPayAccountType
|
|
@@ -2829,7 +2893,8 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
|
|
|
2829
2893
|
vc.request = self.request
|
|
2830
2894
|
vc.isSavedForFuture = self.isSavedForFuture
|
|
2831
2895
|
vc.selectedPaymentMethod = "GrailPay"
|
|
2832
|
-
vc.
|
|
2896
|
+
vc.email = self.txtFieldEmailGrailPayView.text
|
|
2897
|
+
vc.amount = self.amount
|
|
2833
2898
|
self.navigationController?.pushViewController(vc, animated: true)
|
|
2834
2899
|
}
|
|
2835
2900
|
} else {
|
|
@@ -4113,7 +4178,15 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
|
|
|
4113
4178
|
let showAdditional = fieldSection.visibility.additional
|
|
4114
4179
|
|
|
4115
4180
|
if !showBilling && !showAdditional {
|
|
4116
|
-
self.
|
|
4181
|
+
if self.isSavedForFuture {
|
|
4182
|
+
self.navigateCardDataToEmailVerificationVC()
|
|
4183
|
+
} else {
|
|
4184
|
+
if self.request.secureAuthentication == true {
|
|
4185
|
+
self.threeDSecurePaymentApi()
|
|
4186
|
+
} else {
|
|
4187
|
+
self.paymentIntentCardApi()
|
|
4188
|
+
}
|
|
4189
|
+
}
|
|
4117
4190
|
}
|
|
4118
4191
|
else if showBilling {
|
|
4119
4192
|
// Push to BillingInfoVC
|
|
@@ -4444,7 +4517,8 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
|
|
|
4444
4517
|
|
|
4445
4518
|
// Function to navigate to EmailVerificationVC
|
|
4446
4519
|
func navigateCardDataToEmailVerificationVC() {
|
|
4447
|
-
if let emailVerificationVC = storyboard?.instantiateViewController(withIdentifier: "EmailVerificationVC") as? EmailVerificationVC {
|
|
4520
|
+
// if let emailVerificationVC = storyboard?.instantiateViewController(withIdentifier: "EmailVerificationVC") as? EmailVerificationVC {
|
|
4521
|
+
if let emailVerificationVC = storyboard?.instantiateViewController(withIdentifier: "OTPVerificationVC") as? OTPVerificationVC {
|
|
4448
4522
|
if let billingInfoData = request.billingInfoData {
|
|
4449
4523
|
do {
|
|
4450
4524
|
let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
|
|
@@ -4463,6 +4537,9 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
|
|
|
4463
4537
|
emailVerificationVC.request = self.request
|
|
4464
4538
|
emailVerificationVC.chosenPlan = self.txtFieldChosePlanCard.text
|
|
4465
4539
|
emailVerificationVC.startDate = self.txtFieldStartDateCard.text
|
|
4540
|
+
emailVerificationVC.userEmail = self.txtFieldEmailCardView.text
|
|
4541
|
+
emailVerificationVC.email = self.txtFieldEmailCardView.text
|
|
4542
|
+
emailVerificationVC.amount = self.amount
|
|
4466
4543
|
}
|
|
4467
4544
|
catch {
|
|
4468
4545
|
print("Failed to decode billingInfoData: \(error.localizedDescription)")
|
|
@@ -4472,7 +4549,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
|
|
|
4472
4549
|
self.navigationController?.pushViewController(emailVerificationVC, animated: true)
|
|
4473
4550
|
}
|
|
4474
4551
|
}
|
|
4475
|
-
|
|
4552
|
+
|
|
4476
4553
|
func navigateBankDataToEmailVerificationVC() {
|
|
4477
4554
|
if let emailVerificationVC = storyboard?.instantiateViewController(withIdentifier: "EmailVerificationVC") as? EmailVerificationVC {
|
|
4478
4555
|
if let billingInfoData = request.billingInfoData {
|
|
@@ -4493,6 +4570,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
|
|
|
4493
4570
|
emailVerificationVC.chosenPlan = self.txtFieldSelectPlanViewBankFields.text
|
|
4494
4571
|
emailVerificationVC.startDate = self.txtFieldSelectDateViewBankFields.text
|
|
4495
4572
|
emailVerificationVC.request = self.request
|
|
4573
|
+
emailVerificationVC.userEmail = self.txtFieldEmailAccountView.text
|
|
4496
4574
|
}
|
|
4497
4575
|
catch {
|
|
4498
4576
|
print("Failed to decode billingInfoData: \(error.localizedDescription)")
|
|
@@ -5755,6 +5833,214 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
|
|
|
5755
5833
|
task.resume()
|
|
5756
5834
|
}
|
|
5757
5835
|
|
|
5836
|
+
// MARK: - Credit Card Charge Api if billing info is available but visibility of billing and additinal is false
|
|
5837
|
+
func paymentIntentCardApi() {
|
|
5838
|
+
showLoadingIndicator()
|
|
5839
|
+
|
|
5840
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.charges.path()
|
|
5841
|
+
|
|
5842
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
5843
|
+
print("Invalid URL")
|
|
5844
|
+
hideLoadingIndicator()
|
|
5845
|
+
return
|
|
5846
|
+
}
|
|
5847
|
+
|
|
5848
|
+
var urlRequest = URLRequest(url: serviceURL)
|
|
5849
|
+
urlRequest.httpMethod = "POST"
|
|
5850
|
+
urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
5851
|
+
|
|
5852
|
+
let token = UserStoreSingleton.shared.clientToken
|
|
5853
|
+
print("Setting clientToken header: \(token ?? "None")")
|
|
5854
|
+
urlRequest.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
5855
|
+
|
|
5856
|
+
var params: [String: Any] = [
|
|
5857
|
+
"name": cardNameTextField.text,
|
|
5858
|
+
"email": UserStoreSingleton.shared.merchantEmail ?? "",
|
|
5859
|
+
"card_number": cardNumberTextField.text.replacingOccurrences(of: " ", with: ""),
|
|
5860
|
+
"cardholder_name": cardNameTextField.text,
|
|
5861
|
+
"exp_month": cardExpiryTextField.text.components(separatedBy: "/").first ?? "",
|
|
5862
|
+
"exp_year": cardExpiryTextField.text.components(separatedBy: "/").last ?? "",
|
|
5863
|
+
"cvc": cardCvvTextField.text,
|
|
5864
|
+
"currency": "usd"
|
|
5865
|
+
]
|
|
5866
|
+
|
|
5867
|
+
if let billingInfoData = request.billingInfoData {
|
|
5868
|
+
do {
|
|
5869
|
+
let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
|
|
5870
|
+
|
|
5871
|
+
// Billing Info
|
|
5872
|
+
let billing = fieldSection.billing
|
|
5873
|
+
if !billing.isEmpty {
|
|
5874
|
+
var billingDict: [String: Any] = [:]
|
|
5875
|
+
billing.forEach { billingDict[$0.name] = $0.value }
|
|
5876
|
+
|
|
5877
|
+
if let address = billingDict["address"] as? String, !address.isEmpty {
|
|
5878
|
+
params["address"] = address
|
|
5879
|
+
}
|
|
5880
|
+
if let country = billingDict["country"] as? String, !country.isEmpty {
|
|
5881
|
+
params["country"] = country
|
|
5882
|
+
}
|
|
5883
|
+
if let state = billingDict["state"] as? String, !state.isEmpty {
|
|
5884
|
+
params["state"] = state
|
|
5885
|
+
}
|
|
5886
|
+
if let city = billingDict["city"] as? String, !city.isEmpty {
|
|
5887
|
+
params["city"] = city
|
|
5888
|
+
}
|
|
5889
|
+
if let postalCode = billingDict["postal_code"] as? String, !postalCode.isEmpty {
|
|
5890
|
+
params["zip"] = postalCode
|
|
5891
|
+
}
|
|
5892
|
+
}
|
|
5893
|
+
|
|
5894
|
+
// Additional Info
|
|
5895
|
+
let additional = fieldSection.additional
|
|
5896
|
+
if !additional.isEmpty {
|
|
5897
|
+
var additionalDict: [String: Any] = [:]
|
|
5898
|
+
additional.forEach { additionalDict[$0.name] = $0.value }
|
|
5899
|
+
|
|
5900
|
+
if let desc = additionalDict["description"] as? String, !desc.isEmpty {
|
|
5901
|
+
params["description"] = desc
|
|
5902
|
+
} else {
|
|
5903
|
+
params["description"] = "Hosted payment checkout"
|
|
5904
|
+
}
|
|
5905
|
+
|
|
5906
|
+
if let phone = additionalDict["phone_number"] as? String, !phone.isEmpty {
|
|
5907
|
+
params["phone_number"] = phone
|
|
5908
|
+
}
|
|
5909
|
+
if let email = additionalDict["email"] as? String, !email.isEmpty {
|
|
5910
|
+
params["email"] = email
|
|
5911
|
+
}
|
|
5912
|
+
if let name = additionalDict["name"] as? String, !name.isEmpty {
|
|
5913
|
+
params["name"] = name
|
|
5914
|
+
}
|
|
5915
|
+
} else {
|
|
5916
|
+
// If no description in additional info, set default
|
|
5917
|
+
params["description"] = "Hosted payment checkout"
|
|
5918
|
+
}
|
|
5919
|
+
|
|
5920
|
+
} catch {
|
|
5921
|
+
print("Failed to decode FieldSection: \(error)")
|
|
5922
|
+
params["description"] = "Hosted payment checkout"
|
|
5923
|
+
}
|
|
5924
|
+
} else {
|
|
5925
|
+
// Fallback if billingInfoData is missing
|
|
5926
|
+
params["description"] = "Hosted payment checkout"
|
|
5927
|
+
}
|
|
5928
|
+
|
|
5929
|
+
// Add these if recurring is enabled
|
|
5930
|
+
if let req = request, req.is_recurring == true {
|
|
5931
|
+
if let recurringType = req.recurringStartDateType, recurringType == .custom {
|
|
5932
|
+
// Only send start_date if type is .custom and field is not empty
|
|
5933
|
+
if let startDateText = txtFieldStartDateCard?.text, !startDateText.isEmpty {
|
|
5934
|
+
let inputFormatter = DateFormatter()
|
|
5935
|
+
inputFormatter.dateFormat = "dd/MM/yyyy"
|
|
5936
|
+
|
|
5937
|
+
let outputFormatter = DateFormatter()
|
|
5938
|
+
outputFormatter.dateFormat = "MM/dd/yyyy"
|
|
5939
|
+
|
|
5940
|
+
if let date = inputFormatter.date(from: startDateText) {
|
|
5941
|
+
let apiFormattedDate = outputFormatter.string(from: date)
|
|
5942
|
+
params["start_date"] = apiFormattedDate
|
|
5943
|
+
} else {
|
|
5944
|
+
print("Invalid date format in startDateText")
|
|
5945
|
+
}
|
|
5946
|
+
}
|
|
5947
|
+
}
|
|
5948
|
+
|
|
5949
|
+
params["interval"] = txtFieldChosePlanCard.text.lowercased()
|
|
5950
|
+
}
|
|
5951
|
+
|
|
5952
|
+
print(params)
|
|
5953
|
+
|
|
5954
|
+
do {
|
|
5955
|
+
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
5956
|
+
urlRequest.httpBody = jsonData
|
|
5957
|
+
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
5958
|
+
print("JSON Payload: \(jsonString)")
|
|
5959
|
+
}
|
|
5960
|
+
} catch let error {
|
|
5961
|
+
print("Error creating JSON data: \(error)")
|
|
5962
|
+
hideLoadingIndicator()
|
|
5963
|
+
return
|
|
5964
|
+
}
|
|
5965
|
+
|
|
5966
|
+
let session = URLSession.shared
|
|
5967
|
+
let task = session.dataTask(with: urlRequest) { (serviceData, serviceResponse, error) in
|
|
5968
|
+
|
|
5969
|
+
DispatchQueue.main.async {
|
|
5970
|
+
self.hideLoadingIndicator()
|
|
5971
|
+
}
|
|
5972
|
+
|
|
5973
|
+
if let error = error {
|
|
5974
|
+
print("Error: \(error.localizedDescription)")
|
|
5975
|
+
self.presentPaymentErrorVC(errorMessage: error.localizedDescription)
|
|
5976
|
+
return
|
|
5977
|
+
}
|
|
5978
|
+
|
|
5979
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse else {
|
|
5980
|
+
print("Invalid response")
|
|
5981
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid response from server.")
|
|
5982
|
+
return
|
|
5983
|
+
}
|
|
5984
|
+
|
|
5985
|
+
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
5986
|
+
if let data = serviceData {
|
|
5987
|
+
do {
|
|
5988
|
+
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
|
5989
|
+
print("Response Data: \(responseObject)")
|
|
5990
|
+
|
|
5991
|
+
if let status = responseObject["status"] as? Int, status == 0 {
|
|
5992
|
+
let errorMessage = responseObject["message"] as? String ?? "Unknown error occurred."
|
|
5993
|
+
self.presentPaymentErrorVC(errorMessage: errorMessage)
|
|
5994
|
+
} else {
|
|
5995
|
+
DispatchQueue.main.async {
|
|
5996
|
+
if let paymentDoneVC = self.storyboard?.instantiateViewController(withIdentifier: "PaymentDoneVC") as? PaymentDoneVC {
|
|
5997
|
+
paymentDoneVC.chargeData = responseObject
|
|
5998
|
+
paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
|
|
5999
|
+
paymentDoneVC.easyPayDelegate = self.easyPayDelegate
|
|
6000
|
+
// Pass billing info and additional info if available
|
|
6001
|
+
if let billingInfoData = self.request.billingInfoData,
|
|
6002
|
+
let fieldSection = try? JSONDecoder().decode(FieldSection.self, from: billingInfoData) {
|
|
6003
|
+
|
|
6004
|
+
// Filter billing info: only include non-empty values
|
|
6005
|
+
let filteredBilling = fieldSection.billing.filter { !($0.value.trimmingCharacters(in: .whitespaces).isEmpty) }
|
|
6006
|
+
paymentDoneVC.billingInfoData = filteredBilling
|
|
6007
|
+
var billingDict: [String: Any] = [:]
|
|
6008
|
+
filteredBilling.forEach { billingDict[$0.name] = $0.value }
|
|
6009
|
+
paymentDoneVC.billingInfo = billingDict
|
|
6010
|
+
|
|
6011
|
+
// Filter additional info: only include non-empty values
|
|
6012
|
+
let filteredAdditional = fieldSection.additional.filter { !($0.value.trimmingCharacters(in: .whitespaces).isEmpty) }
|
|
6013
|
+
paymentDoneVC.additionalInfoData = filteredAdditional
|
|
6014
|
+
var additionalDict: [String: Any] = [:]
|
|
6015
|
+
filteredAdditional.forEach { additionalDict[$0.name] = $0.value }
|
|
6016
|
+
paymentDoneVC.additionalInfo = additionalDict
|
|
6017
|
+
}
|
|
6018
|
+
self.navigationController?.pushViewController(paymentDoneVC, animated: true)
|
|
6019
|
+
}
|
|
6020
|
+
}
|
|
6021
|
+
}
|
|
6022
|
+
} else {
|
|
6023
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid JSON format")
|
|
6024
|
+
}
|
|
6025
|
+
} catch let jsonError {
|
|
6026
|
+
self.presentPaymentErrorVC(errorMessage: "Error parsing response: \(jsonError.localizedDescription)")
|
|
6027
|
+
}
|
|
6028
|
+
} else {
|
|
6029
|
+
self.presentPaymentErrorVC(errorMessage: "No data received from server.")
|
|
6030
|
+
}
|
|
6031
|
+
} else {
|
|
6032
|
+
if let data = serviceData,
|
|
6033
|
+
let responseObj = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
|
|
6034
|
+
let message = responseObj["message"] as? String {
|
|
6035
|
+
self.presentPaymentErrorVC(errorMessage: message)
|
|
6036
|
+
} else {
|
|
6037
|
+
self.presentPaymentErrorVC(errorMessage: "HTTP Status Code: \(httpResponse.statusCode)")
|
|
6038
|
+
}
|
|
6039
|
+
}
|
|
6040
|
+
}
|
|
6041
|
+
task.resume()
|
|
6042
|
+
}
|
|
6043
|
+
|
|
5758
6044
|
// MARK: - Credit Card Charge API (Saved Cards, No Billing Info, Logged In)
|
|
5759
6045
|
func paymentIntentFromShowSavedCardApi() {
|
|
5760
6046
|
showLoadingIndicator()
|
|
@@ -5915,45 +6201,249 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
|
|
|
5915
6201
|
task.resume()
|
|
5916
6202
|
}
|
|
5917
6203
|
|
|
5918
|
-
//MARK: - Credit Card Charge Api from
|
|
5919
|
-
func
|
|
5920
|
-
|
|
5921
|
-
let nameText = txtFieldNameOnCardNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
5922
|
-
let cvvText = txtFieldCVVNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
5923
|
-
let cardNumberText = (txtFieldCardNumberNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "").replacingOccurrences(of: " ", with: "")
|
|
5924
|
-
let expiryText = txtFieldExpiryDateNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
6204
|
+
//MARK: - Credit Card Charge Api from Saved cards if Billing info exist but not go to billing and additonal page
|
|
6205
|
+
func paymentIntentFromShowCardApi() {
|
|
6206
|
+
showLoadingIndicator()
|
|
5925
6207
|
|
|
6208
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.charges.path()
|
|
5926
6209
|
|
|
5927
|
-
|
|
5928
|
-
|
|
5929
|
-
|
|
5930
|
-
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
|
|
5931
|
-
self.present(alert, animated: true, completion: nil)
|
|
6210
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
6211
|
+
print("Invalid URL")
|
|
6212
|
+
hideLoadingIndicator()
|
|
5932
6213
|
return
|
|
5933
6214
|
}
|
|
5934
6215
|
|
|
5935
|
-
|
|
5936
|
-
|
|
5937
|
-
|
|
5938
|
-
dateFormatter.dateFormat = expiryDateFormat
|
|
5939
|
-
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
|
|
6216
|
+
var uRLRequest = URLRequest(url: serviceURL)
|
|
6217
|
+
uRLRequest.httpMethod = "POST"
|
|
6218
|
+
uRLRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
5940
6219
|
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
let alert = UIAlertController(title: "Invalid Expiry Date", message: "Please enter the expiry date in the format MM/yyyy.", preferredStyle: .alert)
|
|
5945
|
-
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
|
|
5946
|
-
self.present(alert, animated: true, completion: nil)
|
|
5947
|
-
return
|
|
5948
|
-
}
|
|
6220
|
+
let token = UserStoreSingleton.shared.clientToken
|
|
6221
|
+
print("Setting clientToken header: \(token ?? "None")")
|
|
6222
|
+
uRLRequest.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
5949
6223
|
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
|
|
6224
|
+
var params: [String: Any] = [
|
|
6225
|
+
"currency": "usd",
|
|
6226
|
+
"payment_method": "card",
|
|
6227
|
+
"save_card": 0,
|
|
6228
|
+
"customer" : selectedCard?.customerId ?? "",
|
|
6229
|
+
"customer_id" : selectedCard?.customerId ?? "",
|
|
6230
|
+
"card_id" : selectedCard?.cardId ?? "",
|
|
6231
|
+
"cvc" : txtFieldCVVSingleSavedCard.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "",
|
|
6232
|
+
]
|
|
6233
|
+
|
|
6234
|
+
if let billingInfoData = request.billingInfoData {
|
|
6235
|
+
do {
|
|
6236
|
+
let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
|
|
6237
|
+
|
|
6238
|
+
// Billing Info
|
|
6239
|
+
let billing = fieldSection.billing
|
|
6240
|
+
if !billing.isEmpty {
|
|
6241
|
+
var billingDict: [String: Any] = [:]
|
|
6242
|
+
billing.forEach { billingDict[$0.name] = $0.value }
|
|
6243
|
+
|
|
6244
|
+
if let address = billingDict["address"] as? String, !address.isEmpty {
|
|
6245
|
+
params["address"] = address
|
|
6246
|
+
}
|
|
6247
|
+
if let country = billingDict["country"] as? String, !country.isEmpty {
|
|
6248
|
+
params["country"] = country
|
|
6249
|
+
}
|
|
6250
|
+
if let state = billingDict["state"] as? String, !state.isEmpty {
|
|
6251
|
+
params["state"] = state
|
|
6252
|
+
}
|
|
6253
|
+
if let city = billingDict["city"] as? String, !city.isEmpty {
|
|
6254
|
+
params["city"] = city
|
|
6255
|
+
}
|
|
6256
|
+
if let postalCode = billingDict["postal_code"] as? String, !postalCode.isEmpty {
|
|
6257
|
+
params["zip"] = postalCode
|
|
6258
|
+
}
|
|
6259
|
+
}
|
|
6260
|
+
|
|
6261
|
+
// Additional Info
|
|
6262
|
+
let additional = fieldSection.additional
|
|
6263
|
+
if !additional.isEmpty {
|
|
6264
|
+
var additionalDict: [String: Any] = [:]
|
|
6265
|
+
additional.forEach { additionalDict[$0.name] = $0.value }
|
|
6266
|
+
|
|
6267
|
+
if let desc = additionalDict["description"] as? String, !desc.isEmpty {
|
|
6268
|
+
params["description"] = desc
|
|
6269
|
+
} else {
|
|
6270
|
+
params["description"] = "Hosted payment checkout"
|
|
6271
|
+
}
|
|
6272
|
+
|
|
6273
|
+
if let phone = additionalDict["phone_number"] as? String, !phone.isEmpty {
|
|
6274
|
+
params["phone_number"] = phone
|
|
6275
|
+
}
|
|
6276
|
+
if let email = additionalDict["email"] as? String, !email.isEmpty {
|
|
6277
|
+
params["email"] = email
|
|
6278
|
+
}
|
|
6279
|
+
if let name = additionalDict["name"] as? String, !name.isEmpty {
|
|
6280
|
+
params["name"] = name
|
|
6281
|
+
}
|
|
6282
|
+
} else {
|
|
6283
|
+
// If no description in additional info, set default
|
|
6284
|
+
params["description"] = "Hosted payment checkout"
|
|
6285
|
+
}
|
|
6286
|
+
|
|
6287
|
+
} catch {
|
|
6288
|
+
print("Failed to decode FieldSection: \(error)")
|
|
6289
|
+
params["description"] = "Hosted payment checkout"
|
|
6290
|
+
}
|
|
6291
|
+
} else {
|
|
6292
|
+
// Fallback if billingInfoData is missing
|
|
6293
|
+
params["description"] = "Hosted payment checkout"
|
|
6294
|
+
}
|
|
6295
|
+
|
|
6296
|
+
// Add these if recurring is enabled
|
|
6297
|
+
if let req = request, req.is_recurring == true {
|
|
6298
|
+
if let recurringType = req.recurringStartDateType, recurringType == .custom {
|
|
6299
|
+
// Only send start_date if type is .custom and field is not empty
|
|
6300
|
+
if let startDateText = txtFieldSelectDateSingleSavedCard?.text, !startDateText.isEmpty {
|
|
6301
|
+
let inputFormatter = DateFormatter()
|
|
6302
|
+
inputFormatter.dateFormat = "dd/MM/yyyy"
|
|
6303
|
+
|
|
6304
|
+
let outputFormatter = DateFormatter()
|
|
6305
|
+
outputFormatter.dateFormat = "MM/dd/yyyy"
|
|
6306
|
+
|
|
6307
|
+
if let date = inputFormatter.date(from: startDateText) {
|
|
6308
|
+
let apiFormattedDate = outputFormatter.string(from: date)
|
|
6309
|
+
params["start_date"] = apiFormattedDate
|
|
6310
|
+
} else {
|
|
6311
|
+
print("Invalid date format in startDateText")
|
|
6312
|
+
}
|
|
6313
|
+
}
|
|
6314
|
+
}
|
|
6315
|
+
|
|
6316
|
+
params["interval"] = txtFieldSelectPlanSingleSavedCard.text.lowercased()
|
|
6317
|
+
}
|
|
6318
|
+
|
|
6319
|
+
do {
|
|
6320
|
+
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
6321
|
+
uRLRequest.httpBody = jsonData
|
|
6322
|
+
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
6323
|
+
print("JSON Payload: \(jsonString)")
|
|
6324
|
+
}
|
|
6325
|
+
} catch let error {
|
|
6326
|
+
print("Error creating JSON data: \(error)")
|
|
6327
|
+
hideLoadingIndicator()
|
|
6328
|
+
return
|
|
6329
|
+
}
|
|
6330
|
+
|
|
6331
|
+
let session = URLSession.shared
|
|
6332
|
+
let task = session.dataTask(with: uRLRequest) { (serviceData, serviceResponse, error) in
|
|
6333
|
+
|
|
6334
|
+
DispatchQueue.main.async {
|
|
6335
|
+
self.hideLoadingIndicator() // Stop loader when response is received
|
|
6336
|
+
}
|
|
6337
|
+
|
|
6338
|
+
if let error = error {
|
|
6339
|
+
print("Error: \(error.localizedDescription)")
|
|
6340
|
+
return
|
|
6341
|
+
}
|
|
6342
|
+
|
|
6343
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse else {
|
|
6344
|
+
print("Invalid response")
|
|
6345
|
+
return
|
|
6346
|
+
}
|
|
6347
|
+
|
|
6348
|
+
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
6349
|
+
if let data = serviceData {
|
|
6350
|
+
do {
|
|
6351
|
+
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
|
6352
|
+
print("Response Data: \(responseObject)")
|
|
6353
|
+
|
|
6354
|
+
// Check if status is 0 and handle the error
|
|
6355
|
+
if let status = responseObject["status"] as? Int, status == 0 {
|
|
6356
|
+
let errorMessage = responseObject["message"] as? String ?? "Unknown error"
|
|
6357
|
+
self.presentPaymentErrorVC(errorMessage: errorMessage)
|
|
6358
|
+
} else {
|
|
6359
|
+
DispatchQueue.main.async {
|
|
6360
|
+
if let paymentDoneVC = self.storyboard?.instantiateViewController(withIdentifier: "PaymentDoneVC") as? PaymentDoneVC {
|
|
6361
|
+
paymentDoneVC.chargeData = responseObject
|
|
6362
|
+
paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
|
|
6363
|
+
paymentDoneVC.easyPayDelegate = self.easyPayDelegate
|
|
6364
|
+
// Pass billing info and additional info if available
|
|
6365
|
+
if let billingInfoData = self.request.billingInfoData,
|
|
6366
|
+
let fieldSection = try? JSONDecoder().decode(FieldSection.self, from: billingInfoData) {
|
|
6367
|
+
|
|
6368
|
+
// Filter billing info: only include non-empty values
|
|
6369
|
+
let filteredBilling = fieldSection.billing.filter { !($0.value.trimmingCharacters(in: .whitespaces).isEmpty) }
|
|
6370
|
+
paymentDoneVC.billingInfoData = filteredBilling
|
|
6371
|
+
var billingDict: [String: Any] = [:]
|
|
6372
|
+
filteredBilling.forEach { billingDict[$0.name] = $0.value }
|
|
6373
|
+
paymentDoneVC.billingInfo = billingDict
|
|
6374
|
+
|
|
6375
|
+
// Filter additional info: only include non-empty values
|
|
6376
|
+
let filteredAdditional = fieldSection.additional.filter { !($0.value.trimmingCharacters(in: .whitespaces).isEmpty) }
|
|
6377
|
+
paymentDoneVC.additionalInfoData = filteredAdditional
|
|
6378
|
+
var additionalDict: [String: Any] = [:]
|
|
6379
|
+
filteredAdditional.forEach { additionalDict[$0.name] = $0.value }
|
|
6380
|
+
paymentDoneVC.additionalInfo = additionalDict
|
|
6381
|
+
}
|
|
6382
|
+
self.navigationController?.pushViewController(paymentDoneVC, animated: true)
|
|
6383
|
+
}
|
|
6384
|
+
}
|
|
6385
|
+
}
|
|
6386
|
+
} else {
|
|
6387
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid JSON format")
|
|
6388
|
+
}
|
|
6389
|
+
} catch let jsonError {
|
|
6390
|
+
self.presentPaymentErrorVC(errorMessage: "Error parsing JSON: \(jsonError)")
|
|
6391
|
+
}
|
|
6392
|
+
} else {
|
|
6393
|
+
self.presentPaymentErrorVC(errorMessage: "No data received")
|
|
6394
|
+
}
|
|
6395
|
+
} else {
|
|
6396
|
+
if let data = serviceData,
|
|
6397
|
+
let responseObj = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
|
|
6398
|
+
let message = responseObj["message"] as? String {
|
|
6399
|
+
self.presentPaymentErrorVC(errorMessage: message)
|
|
6400
|
+
} else {
|
|
6401
|
+
self.presentPaymentErrorVC(errorMessage: "HTTP Status Code: \(httpResponse.statusCode)")
|
|
6402
|
+
}
|
|
6403
|
+
}
|
|
6404
|
+
}
|
|
6405
|
+
task.resume()
|
|
6406
|
+
}
|
|
6407
|
+
|
|
6408
|
+
//MARK: - Credit Card Charge Api from Add new cards If Billing info is nil and Logged in.
|
|
6409
|
+
func paymentIntentFromAddNewCardApi(customerId: String?) {
|
|
6410
|
+
// Get the text fields from the selected cell and trim whitespace
|
|
6411
|
+
let nameText = txtFieldNameOnCardNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
6412
|
+
let cvvText = txtFieldCVVNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
6413
|
+
let cardNumberText = (txtFieldCardNumberNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "").replacingOccurrences(of: " ", with: "")
|
|
6414
|
+
let expiryText = txtFieldExpiryDateNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
6415
|
+
|
|
6416
|
+
|
|
6417
|
+
// Check if any field is empty
|
|
6418
|
+
if cardNumberText.isEmpty || expiryText.isEmpty || cvvText.isEmpty || nameText.isEmpty {
|
|
6419
|
+
let alert = UIAlertController(title: "Missing Information", message: "Please fill in all card details.", preferredStyle: .alert)
|
|
6420
|
+
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
|
|
6421
|
+
self.present(alert, animated: true, completion: nil)
|
|
6422
|
+
return
|
|
6423
|
+
}
|
|
6424
|
+
|
|
6425
|
+
// Validate expiry date format
|
|
6426
|
+
let expiryDateFormat = "MM/yyyy"
|
|
6427
|
+
let dateFormatter = DateFormatter()
|
|
6428
|
+
dateFormatter.dateFormat = expiryDateFormat
|
|
6429
|
+
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
|
|
6430
|
+
|
|
6431
|
+
// Split the expiry date and validate its format
|
|
6432
|
+
let exp = expiryText.split(separator: "/")
|
|
6433
|
+
if exp.count != 2 || exp[0].count != 2 || exp[1].count != 4 {
|
|
6434
|
+
let alert = UIAlertController(title: "Invalid Expiry Date", message: "Please enter the expiry date in the format MM/yyyy.", preferredStyle: .alert)
|
|
6435
|
+
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
|
|
6436
|
+
self.present(alert, animated: true, completion: nil)
|
|
6437
|
+
return
|
|
6438
|
+
}
|
|
6439
|
+
|
|
6440
|
+
// Check if the expiry date is valid
|
|
6441
|
+
if let expiryDateObj = dateFormatter.date(from: expiryText) {
|
|
6442
|
+
// Check if the expiry date is in the past
|
|
6443
|
+
let currentDate = Date()
|
|
6444
|
+
let calendar = Calendar.current
|
|
6445
|
+
let currentMonthYear = calendar.date(from: calendar.dateComponents([.year, .month], from: currentDate))
|
|
6446
|
+
if expiryDateObj < currentMonthYear! {
|
|
5957
6447
|
let alert = UIAlertController(title: "Expired Card", message: "The expiry date cannot be in the past. Please enter a valid expiry date.", preferredStyle: .alert)
|
|
5958
6448
|
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
|
|
5959
6449
|
self.present(alert, animated: true, completion: nil)
|
|
@@ -6158,6 +6648,237 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
|
|
|
6158
6648
|
task.resume()
|
|
6159
6649
|
}
|
|
6160
6650
|
|
|
6651
|
+
//MARK: - Credit Card Charge Api from Add new card from saved cards if billing info is available but their visibility is off
|
|
6652
|
+
func paymentIntentAddNewCardApi(customerId: String?) {
|
|
6653
|
+
showLoadingIndicator()
|
|
6654
|
+
|
|
6655
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.charges.path()
|
|
6656
|
+
|
|
6657
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
6658
|
+
print("Invalid URL")
|
|
6659
|
+
hideLoadingIndicator()
|
|
6660
|
+
return
|
|
6661
|
+
}
|
|
6662
|
+
|
|
6663
|
+
var uRLRequest = URLRequest(url: serviceURL)
|
|
6664
|
+
uRLRequest.httpMethod = "POST"
|
|
6665
|
+
uRLRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
6666
|
+
|
|
6667
|
+
let token = UserStoreSingleton.shared.clientToken
|
|
6668
|
+
print("Setting clientToken header: \(token ?? "None")")
|
|
6669
|
+
uRLRequest.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
6670
|
+
|
|
6671
|
+
let emailPrefix = UserStoreSingleton.shared.verificationEmail?.components(separatedBy: "@").first ?? ""
|
|
6672
|
+
|
|
6673
|
+
// Get the text fields from the selected cell and trim whitespace
|
|
6674
|
+
let nameText = txtFieldNameOnCardNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
6675
|
+
let cvvText = txtFieldCVVNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
6676
|
+
let cardNumberText = (txtFieldCardNumberNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "").replacingOccurrences(of: " ", with: "")
|
|
6677
|
+
let expiryText = txtFieldExpiryDateNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
6678
|
+
|
|
6679
|
+
var params: [String: Any] = [
|
|
6680
|
+
"name": nameText,
|
|
6681
|
+
"card_number": cardNumberText,
|
|
6682
|
+
"cardholder_name": nameText,
|
|
6683
|
+
"exp_month": expiryText.components(separatedBy: "/").first ?? "",
|
|
6684
|
+
"exp_year": expiryText.components(separatedBy: "/").last ?? "",
|
|
6685
|
+
"cvc": cvvText,
|
|
6686
|
+
"description": "TestDescription",
|
|
6687
|
+
"currency": "usd",
|
|
6688
|
+
"payment_method": "card",
|
|
6689
|
+
"save_card": isSavedNewCardForFuture ? 1 : 0,
|
|
6690
|
+
"email" : UserStoreSingleton.shared.verificationEmail ?? ""
|
|
6691
|
+
]
|
|
6692
|
+
|
|
6693
|
+
// Add is_default parameter if save_card is 1
|
|
6694
|
+
if isSavedNewCard {
|
|
6695
|
+
params["is_default"] = "1"
|
|
6696
|
+
}
|
|
6697
|
+
|
|
6698
|
+
if let billingInfoData = request.billingInfoData {
|
|
6699
|
+
do {
|
|
6700
|
+
let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
|
|
6701
|
+
|
|
6702
|
+
// Billing Info
|
|
6703
|
+
let billing = fieldSection.billing
|
|
6704
|
+
if !billing.isEmpty {
|
|
6705
|
+
var billingDict: [String: Any] = [:]
|
|
6706
|
+
billing.forEach { billingDict[$0.name] = $0.value }
|
|
6707
|
+
|
|
6708
|
+
if let address = billingDict["address"] as? String, !address.isEmpty {
|
|
6709
|
+
params["address"] = address
|
|
6710
|
+
}
|
|
6711
|
+
if let country = billingDict["country"] as? String, !country.isEmpty {
|
|
6712
|
+
params["country"] = country
|
|
6713
|
+
}
|
|
6714
|
+
if let state = billingDict["state"] as? String, !state.isEmpty {
|
|
6715
|
+
params["state"] = state
|
|
6716
|
+
}
|
|
6717
|
+
if let city = billingDict["city"] as? String, !city.isEmpty {
|
|
6718
|
+
params["city"] = city
|
|
6719
|
+
}
|
|
6720
|
+
if let postalCode = billingDict["postal_code"] as? String, !postalCode.isEmpty {
|
|
6721
|
+
params["zip"] = postalCode
|
|
6722
|
+
}
|
|
6723
|
+
}
|
|
6724
|
+
|
|
6725
|
+
// Additional Info
|
|
6726
|
+
let additional = fieldSection.additional
|
|
6727
|
+
if !additional.isEmpty {
|
|
6728
|
+
var additionalDict: [String: Any] = [:]
|
|
6729
|
+
additional.forEach { additionalDict[$0.name] = $0.value }
|
|
6730
|
+
|
|
6731
|
+
if let desc = additionalDict["description"] as? String, !desc.isEmpty {
|
|
6732
|
+
params["description"] = desc
|
|
6733
|
+
} else {
|
|
6734
|
+
params["description"] = "Hosted payment checkout"
|
|
6735
|
+
}
|
|
6736
|
+
|
|
6737
|
+
if let phone = additionalDict["phone_number"] as? String, !phone.isEmpty {
|
|
6738
|
+
params["phone_number"] = phone
|
|
6739
|
+
}
|
|
6740
|
+
if let email = additionalDict["email"] as? String, !email.isEmpty {
|
|
6741
|
+
params["email"] = email
|
|
6742
|
+
}
|
|
6743
|
+
if let name = additionalDict["name"] as? String, !name.isEmpty {
|
|
6744
|
+
params["name"] = name
|
|
6745
|
+
}
|
|
6746
|
+
} else {
|
|
6747
|
+
// If no description in additional info, set default
|
|
6748
|
+
params["description"] = "Hosted payment checkout"
|
|
6749
|
+
}
|
|
6750
|
+
|
|
6751
|
+
} catch {
|
|
6752
|
+
print("Failed to decode FieldSection: \(error)")
|
|
6753
|
+
params["description"] = "Hosted payment checkout"
|
|
6754
|
+
}
|
|
6755
|
+
} else {
|
|
6756
|
+
// Fallback if billingInfoData is missing
|
|
6757
|
+
params["description"] = "Hosted payment checkout"
|
|
6758
|
+
}
|
|
6759
|
+
|
|
6760
|
+
// Add these if recurring is enabled
|
|
6761
|
+
if let req = request, req.is_recurring == true {
|
|
6762
|
+
if let recurringType = req.recurringStartDateType, recurringType == .custom {
|
|
6763
|
+
// Only send start_date if type is .custom and field is not empty
|
|
6764
|
+
if let startDateText = txtFieldSelectDateNewCardView?.text, !startDateText.isEmpty {
|
|
6765
|
+
let inputFormatter = DateFormatter()
|
|
6766
|
+
inputFormatter.dateFormat = "dd/MM/yyyy"
|
|
6767
|
+
|
|
6768
|
+
let outputFormatter = DateFormatter()
|
|
6769
|
+
outputFormatter.dateFormat = "MM/dd/yyyy"
|
|
6770
|
+
|
|
6771
|
+
if let date = inputFormatter.date(from: startDateText) {
|
|
6772
|
+
let apiFormattedDate = outputFormatter.string(from: date)
|
|
6773
|
+
params["start_date"] = apiFormattedDate
|
|
6774
|
+
} else {
|
|
6775
|
+
print("Invalid date format in startDateText")
|
|
6776
|
+
}
|
|
6777
|
+
}
|
|
6778
|
+
}
|
|
6779
|
+
|
|
6780
|
+
params["interval"] = txtFieldSelectPlanNewCardView.text.lowercased()
|
|
6781
|
+
}
|
|
6782
|
+
|
|
6783
|
+
if let customerId = customerId {
|
|
6784
|
+
params["customer"] = customerId
|
|
6785
|
+
params["customer_id"] = customerId
|
|
6786
|
+
} else {
|
|
6787
|
+
params["username"] = emailPrefix
|
|
6788
|
+
params["email"] = UserStoreSingleton.shared.verificationEmail
|
|
6789
|
+
}
|
|
6790
|
+
|
|
6791
|
+
print(params)
|
|
6792
|
+
|
|
6793
|
+
do {
|
|
6794
|
+
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
6795
|
+
uRLRequest.httpBody = jsonData
|
|
6796
|
+
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
6797
|
+
print("JSON Payload: \(jsonString)")
|
|
6798
|
+
}
|
|
6799
|
+
} catch let error {
|
|
6800
|
+
print("Error creating JSON data: \(error)")
|
|
6801
|
+
hideLoadingIndicator()
|
|
6802
|
+
return
|
|
6803
|
+
}
|
|
6804
|
+
|
|
6805
|
+
let session = URLSession.shared
|
|
6806
|
+
let task = session.dataTask(with: uRLRequest) { (serviceData, serviceResponse, error) in
|
|
6807
|
+
|
|
6808
|
+
DispatchQueue.main.async {
|
|
6809
|
+
self.hideLoadingIndicator() // Stop loader when response is received
|
|
6810
|
+
}
|
|
6811
|
+
|
|
6812
|
+
if let error = error {
|
|
6813
|
+
self.presentPaymentErrorVC(errorMessage: error.localizedDescription)
|
|
6814
|
+
return
|
|
6815
|
+
}
|
|
6816
|
+
|
|
6817
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse else {
|
|
6818
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid response")
|
|
6819
|
+
return
|
|
6820
|
+
}
|
|
6821
|
+
|
|
6822
|
+
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
6823
|
+
if let data = serviceData {
|
|
6824
|
+
do {
|
|
6825
|
+
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
|
6826
|
+
print("Response Data: \(responseObject)")
|
|
6827
|
+
|
|
6828
|
+
// Check if status is 0 and handle the error
|
|
6829
|
+
if let status = responseObject["status"] as? Int, status == 0 {
|
|
6830
|
+
let errorMessage = responseObject["message"] as? String ?? "Unknown error"
|
|
6831
|
+
self.presentPaymentErrorVC(errorMessage: errorMessage)
|
|
6832
|
+
} else {
|
|
6833
|
+
DispatchQueue.main.async {
|
|
6834
|
+
if let paymentDoneVC = self.storyboard?.instantiateViewController(withIdentifier: "PaymentDoneVC") as? PaymentDoneVC {
|
|
6835
|
+
paymentDoneVC.chargeData = responseObject
|
|
6836
|
+
paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
|
|
6837
|
+
paymentDoneVC.easyPayDelegate = self.easyPayDelegate
|
|
6838
|
+
// Pass billing info and additional info if available
|
|
6839
|
+
if let billingInfoData = self.request.billingInfoData,
|
|
6840
|
+
let fieldSection = try? JSONDecoder().decode(FieldSection.self, from: billingInfoData) {
|
|
6841
|
+
|
|
6842
|
+
// Filter billing info: only include non-empty values
|
|
6843
|
+
let filteredBilling = fieldSection.billing.filter { !($0.value.trimmingCharacters(in: .whitespaces).isEmpty) }
|
|
6844
|
+
paymentDoneVC.billingInfoData = filteredBilling
|
|
6845
|
+
var billingDict: [String: Any] = [:]
|
|
6846
|
+
filteredBilling.forEach { billingDict[$0.name] = $0.value }
|
|
6847
|
+
paymentDoneVC.billingInfo = billingDict
|
|
6848
|
+
|
|
6849
|
+
// Filter additional info: only include non-empty values
|
|
6850
|
+
let filteredAdditional = fieldSection.additional.filter { !($0.value.trimmingCharacters(in: .whitespaces).isEmpty) }
|
|
6851
|
+
paymentDoneVC.additionalInfoData = filteredAdditional
|
|
6852
|
+
var additionalDict: [String: Any] = [:]
|
|
6853
|
+
filteredAdditional.forEach { additionalDict[$0.name] = $0.value }
|
|
6854
|
+
paymentDoneVC.additionalInfo = additionalDict
|
|
6855
|
+
}
|
|
6856
|
+
self.navigationController?.pushViewController(paymentDoneVC, animated: true)
|
|
6857
|
+
}
|
|
6858
|
+
}
|
|
6859
|
+
}
|
|
6860
|
+
} else {
|
|
6861
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid JSON format")
|
|
6862
|
+
}
|
|
6863
|
+
} catch let jsonError {
|
|
6864
|
+
self.presentPaymentErrorVC(errorMessage: "Error parsing JSON: \(jsonError)")
|
|
6865
|
+
}
|
|
6866
|
+
} else {
|
|
6867
|
+
self.presentPaymentErrorVC(errorMessage: "No data received")
|
|
6868
|
+
}
|
|
6869
|
+
} else {
|
|
6870
|
+
if let data = serviceData,
|
|
6871
|
+
let responseObj = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
|
|
6872
|
+
let message = responseObj["message"] as? String {
|
|
6873
|
+
self.presentPaymentErrorVC(errorMessage: message)
|
|
6874
|
+
} else {
|
|
6875
|
+
self.presentPaymentErrorVC(errorMessage: "HTTP Status Code: \(httpResponse.statusCode)")
|
|
6876
|
+
}
|
|
6877
|
+
}
|
|
6878
|
+
}
|
|
6879
|
+
task.resume()
|
|
6880
|
+
}
|
|
6881
|
+
|
|
6161
6882
|
//MARK: - Update Cards Api.
|
|
6162
6883
|
func updateCardApi(cardID: String) {
|
|
6163
6884
|
showLoadingIndicator()
|
|
@@ -7691,44 +8412,22 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
|
|
|
7691
8412
|
paymentDoneVC.chargeData = responseObject
|
|
7692
8413
|
paymentDoneVC.easyPayDelegate = self.easyPayDelegate
|
|
7693
8414
|
paymentDoneVC.amount = self.amount
|
|
7694
|
-
// // Pass billingInfo and additionalInfo
|
|
7695
|
-
// if let billingData = self.request.billingInfoData,
|
|
7696
|
-
// let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
|
|
7697
|
-
//
|
|
7698
|
-
// // Extract main billing fields
|
|
7699
|
-
// let cleanBillingInfo: [String: Any] = [
|
|
7700
|
-
// "postal_code": billingInfoDict["postal_code"] ?? "",
|
|
7701
|
-
// "country": billingInfoDict["country"] ?? "",
|
|
7702
|
-
// "city": billingInfoDict["city"] ?? "",
|
|
7703
|
-
// "address": billingInfoDict["address"] ?? "",
|
|
7704
|
-
// "state": billingInfoDict["state"] ?? ""
|
|
7705
|
-
// ]
|
|
7706
|
-
// paymentDoneVC.billingInfo = cleanBillingInfo
|
|
7707
|
-
//
|
|
7708
|
-
// // Extract additional_info
|
|
7709
|
-
// if let additional = billingInfoDict["additional_info"] as? [String: Any] {
|
|
7710
|
-
// let cleanAdditionalInfo: [String: Any] = [
|
|
7711
|
-
// "email": additional["email"] ?? "",
|
|
7712
|
-
// "phone_number": additional["phone_number"] ?? "",
|
|
7713
|
-
// "name": additional["name"] ?? "",
|
|
7714
|
-
// "country_code": additional["country_code"] ?? ""
|
|
7715
|
-
// ]
|
|
7716
|
-
// paymentDoneVC.additionalInfo = cleanAdditionalInfo
|
|
7717
|
-
// }
|
|
7718
|
-
// }
|
|
7719
|
-
|
|
7720
8415
|
// Pass billing info and additional info if available
|
|
7721
8416
|
if let billingInfoData = self.request.billingInfoData,
|
|
7722
8417
|
let fieldSection = try? JSONDecoder().decode(FieldSection.self, from: billingInfoData) {
|
|
7723
8418
|
|
|
7724
|
-
|
|
8419
|
+
// Filter billing info: only include non-empty values
|
|
8420
|
+
let filteredBilling = fieldSection.billing.filter { !($0.value.trimmingCharacters(in: .whitespaces).isEmpty) }
|
|
8421
|
+
paymentDoneVC.billingInfoData = filteredBilling
|
|
7725
8422
|
var billingDict: [String: Any] = [:]
|
|
7726
|
-
|
|
8423
|
+
filteredBilling.forEach { billingDict[$0.name] = $0.value }
|
|
7727
8424
|
paymentDoneVC.billingInfo = billingDict
|
|
7728
|
-
|
|
7729
|
-
|
|
8425
|
+
|
|
8426
|
+
// Filter additional info: only include non-empty values
|
|
8427
|
+
let filteredAdditional = fieldSection.additional.filter { !($0.value.trimmingCharacters(in: .whitespaces).isEmpty) }
|
|
8428
|
+
paymentDoneVC.additionalInfoData = filteredAdditional
|
|
7730
8429
|
var additionalDict: [String: Any] = [:]
|
|
7731
|
-
|
|
8430
|
+
filteredAdditional.forEach { additionalDict[$0.name] = $0.value }
|
|
7732
8431
|
paymentDoneVC.additionalInfo = additionalDict
|
|
7733
8432
|
}
|
|
7734
8433
|
self.navigationController?.pushViewController(paymentDoneVC, animated: true)
|
|
@@ -8007,14 +8706,18 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
|
|
|
8007
8706
|
if let billingInfoData = self.request.billingInfoData,
|
|
8008
8707
|
let fieldSection = try? JSONDecoder().decode(FieldSection.self, from: billingInfoData) {
|
|
8009
8708
|
|
|
8010
|
-
|
|
8709
|
+
// Filter billing info: only include non-empty values
|
|
8710
|
+
let filteredBilling = fieldSection.billing.filter { !($0.value.trimmingCharacters(in: .whitespaces).isEmpty) }
|
|
8711
|
+
paymentDoneVC.billingInfoData = filteredBilling
|
|
8011
8712
|
var billingDict: [String: Any] = [:]
|
|
8012
|
-
|
|
8713
|
+
filteredBilling.forEach { billingDict[$0.name] = $0.value }
|
|
8013
8714
|
paymentDoneVC.billingInfo = billingDict
|
|
8014
|
-
|
|
8015
|
-
|
|
8715
|
+
|
|
8716
|
+
// Filter additional info: only include non-empty values
|
|
8717
|
+
let filteredAdditional = fieldSection.additional.filter { !($0.value.trimmingCharacters(in: .whitespaces).isEmpty) }
|
|
8718
|
+
paymentDoneVC.additionalInfoData = filteredAdditional
|
|
8016
8719
|
var additionalDict: [String: Any] = [:]
|
|
8017
|
-
|
|
8720
|
+
filteredAdditional.forEach { additionalDict[$0.name] = $0.value }
|
|
8018
8721
|
paymentDoneVC.additionalInfo = additionalDict
|
|
8019
8722
|
}
|
|
8020
8723
|
self.navigationController?.pushViewController(paymentDoneVC, animated: true)
|