// // CanPgPaymentViewModel.swift // SodaLive // // Created by klaus on 2023/08/11. // import Foundation import Combine import Bootpay enum PaymentMethod: String { case unified = "통합 결제" case phone = "휴대폰" case kakaopay = "카카오페이" } final class CanPgPaymentViewModel: ObservableObject { private let repository = CanRepository() private var subscription = Set() @Published var isTermsAgree = false @Published var errorMessage = "" @Published var isShowPopup = false @Published var isLoading = false @Published var isShowPaymentView = false @Published var isShowPayversePaymentView = false @Published var paymentMethod: PaymentMethod? = nil let payload = Payload() var payversePayloadJson: String = "" var canResponse: GetCanResponse? = nil var refresh: (() -> Void)? = nil var afterCompletionToGoBack: Bool? = nil func chargeCan(canId: Int, onSuccess: @escaping () -> Void) { isLoading = true repository.pgChargeCan(canId: canId) .sink { result in switch result { case .finished: DEBUG_LOG("finish") case .failure(let error): ERROR_LOG(error.localizedDescription) } } receiveValue: { [unowned self] response in self.isLoading = false let responseData = response.data do { let jsonDecoder = JSONDecoder() let decoded = try jsonDecoder.decode(ApiResponse.self, from: responseData) if let data = decoded.data, decoded.success { payload.applicationId = BOOTPAY_APP_HECTO_ID payload.pg = paymentMethod == .kakaopay ? "카카오" : "세틀뱅크" payload.orderId = "\(data.chargeId)" payload.method = paymentMethod!.rawValue var username = UserDefaults.string(forKey: .nickname) if username.count > 10 { username = "\(username.prefix(6))..." } let bootUser = BootUser() bootUser.userId = "\(UserDefaults.int(forKey: .userId))" bootUser.username = UserDefaults.string(forKey: .nickname) payload.user = bootUser onSuccess() } else { if let message = decoded.message { self.errorMessage = message } else { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." } self.isShowPopup = true } } catch { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." self.isShowPopup = true } } .store(in: &subscription) } func verifyPayment(_ data: [String: Any], onSuccess: @escaping () -> Void) { isLoading = true let _data = data["data"] as? [String: Any] if let data = _data { let receiptId = data["receipt_id"] as! String let orderId = data["order_id"] as! String repository.pgVerifyHecto(receiptId: receiptId, orderId: orderId) .sink { result in switch result { case .finished: DEBUG_LOG("finish") case .failure(let error): ERROR_LOG(error.localizedDescription) } } receiveValue: { [unowned self] response in self.isLoading = false let responseData = response.data do { let jsonDecoder = JSONDecoder() let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData) if decoded.success { self.errorMessage = "캔이 충전되었습니다" self.isShowPopup = true onSuccess() } else { if let message = decoded.message { self.errorMessage = message } else { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." } self.isShowPopup = true } } catch { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." self.isShowPopup = true } } .store(in: &subscription) } else { isLoading = false self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." isShowPopup = true } } func payverseChargeCan(canId: Int) { isLoading = true repository.payverseChargeCan(canId: canId) .sink { result in switch result { case .finished: DEBUG_LOG("finish") case .failure(let error): ERROR_LOG(error.localizedDescription) } } receiveValue: { [unowned self] response in self.isLoading = false let responseData = response.data do { let jsonDecoder = JSONDecoder() let decoded = try jsonDecoder.decode(ApiResponse.self, from: responseData) if let data = decoded.data, decoded.success { if let payloadJson = data.payloadJson.data(using: .utf8) { var obj = try JSONSerialization.jsonObject(with: payloadJson, options: []) as? [String: Any] ?? [:] obj["returnUrl"] = "\(APPSCHEME)://payverse/result" obj["webhookUrl"] = "\(BASE_URL)/charge/payverse/webhook" obj["appScheme"] = APPSCHEME let merged = try JSONSerialization.data(withJSONObject: obj, options: []) self.payversePayloadJson = String(data: merged, encoding: .utf8)! self.isShowPayversePaymentView = true } else { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." self.isShowPopup = true return } } else { if let message = decoded.message { self.errorMessage = message } else { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." } self.isShowPopup = true } } catch { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." self.isShowPopup = true } } .store(in: &subscription) } func handleVerifyOpenURL(_ url: URL) { guard let comps = URLComponents(url: url, resolvingAgainstBaseURL: false) else { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." self.isShowPopup = true return } let q = comps.queryItems?.reduce(into: [String:String]()) { $0[$1.name] = $1.value } ?? [:] let tid = q["tid"] ?? q["tx_id"] let orderId = q["orderId"] let resultStatus = q["resultStatus"] if resultStatus == "FAILED" || resultStatus == "DECLINE" || orderId == nil || orderId?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true || tid == nil || tid?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." self.isShowPopup = true DispatchQueue.main.asyncAfter(deadline: .now() + 1) { AppState.shared.back() } return } else { payverseVerify(transactionId: tid!, orderId: orderId!) } } func payverseVerify(transactionId: String, orderId: String) { isLoading = true repository.payverseVerify(transactionId: transactionId, orderId: orderId) .sink { result in switch result { case .finished: DEBUG_LOG("finish") case .failure(let error): ERROR_LOG(error.localizedDescription) } } receiveValue: { [unowned self] response in self.isLoading = false let responseData = response.data do { let jsonDecoder = JSONDecoder() let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData) if decoded.success { if let canResponse = self.canResponse { let can = UserDefaults.int(forKey: .can) UserDefaults.set(can + canResponse.can + canResponse.rewardCan, forKey: .can) if let refresh = refresh { refresh() } DispatchQueue.main.asyncAfter(deadline: .now() + 1) { if let afterCompletionToGoBack = self.afterCompletionToGoBack, afterCompletionToGoBack { AppState.shared.back() AppState.shared.back() } else { if let refresh = self.refresh { AppState.shared.setAppStep(step: .canStatus(refresh: refresh)) } else { AppState.shared.setAppStep(step: .canStatus(refresh: {})) } } } } else { AppState.shared.setAppStep(step: .canStatus(refresh: {})) } } else { if let message = decoded.message { self.errorMessage = message } else { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." } self.isShowPopup = true } } catch { self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." self.isShowPopup = true } } .store(in: &subscription) } }