Untitled
unknown
plain_text
a month ago
34 kB
5
Indexable
// // QrisPayAmountViewModel.swift // IDBank // // Created by Myoungkyu.Shin on 11/06/2019. // Copyright (c) 2019 LINE Bank Indonesia Corporation. All rights reserved. // import RxSwift import RxCocoa import RxSwiftExt import BuffettRemote enum QrisPayAmountValidState { case inputAmount case sendMoney case validate var title: String { switch self { case .inputAmount: return LocalizableString.commonOkButton case .sendMoney, .validate: return LocalizableString.qrpaymentPayButton } } var isConfirmState: Bool { [.sendMoney, .validate].contains(self) } } enum QrisPayAmountResult { enum ErrorType: Error { case notEnough case dataIsNil case serverError(error: ResultError) case serverErrorWithPay(error: ResultError) } enum Validation { case ok case ready case overAccountBalance(message: String) case overOnetimeLimit(message: String) case underMinimumLimit(message: String) case invalid(message: String) } } enum QrisPayPendingStatus: Int { case unknown case first = 1 case second = 2 case last = 3 func next() -> QrisPayPendingStatus { switch self { case .unknown: return .first case .first: return .second case .second: return .last case .last: return .unknown } } } extension QrisPayAmountResult.Validation: Equatable { static func == (lhs: QrisPayAmountResult.Validation, rhs: QrisPayAmountResult.Validation) -> Bool { switch (lhs, rhs) { case (.ok, .ok): return true case (.ready, .ready): return true case (.overAccountBalance, .overAccountBalance): return true case (.overOnetimeLimit, .overOnetimeLimit): return true case (.underMinimumLimit, .underMinimumLimit): return true case (.invalid, .invalid): return true default: return false } } } extension QrisPayAmountResult.Validation { var valid: Bool { self == .ok } var isError: Bool { errorMessage?.isEmpty != nil } var errorMessage: String? { switch self { case let .overAccountBalance(message): return message case let .overOnetimeLimit(message): return message case let .underMinimumLimit(message): return message case let .invalid(message): return message default: return nil } } } protocol QrisPayAmountViewModelType { var inputs: QrisPayAmountViewModelInputs { get } var outputs: QrisPayAmountViewModelOutputs { get } } protocol QrisPayAmountViewModelInputs { func setup(params: QrisPayParams) func fetch() func refreshAccountData() func fetchDisbursalLimit(payload: QrisPayAPIModel.QRISPaymentDisbursalLimitRequest) func validation() func amountChanged(to amount: Decimal) // User input amount func inputAmountChanged(to amount: Decimal) func addAmount(to amount: Decimal) func changeAccount(with account: AccountAPIModel.AccountSimpleInfo) func createParams(payInfo: QrisPayAmountViewModel.PayInfo) func pay(payload: QrisPayAmountViewModel.PayloadRequest) func tipAmount(to amount: Decimal) func changeInputState() func changeSendMoneyState() func updateState() func qrisPendingResponse(_ pendingResponse: QrisPayAPIModel.PayResult, _ isDisbursal: Bool) func allUsedQuickCreditPayment(_ isAll: Bool) func showResult() } protocol QrisPayAmountViewModelOutputs { var payParam: Observable<QrisPayParams?> { get } var cellModelObservable: Observable<QrisPayAmountCellModel?> { get } var accountList: Observable<AccountAPIModel.Accounts> { get } var disbursalLimit: Observable<QrisPayAPIModel.QRISPaymentDisbursalLimitResponse> { get } var validationResult: Driver<QrisPayAmountResult.Validation> { get } var inputValidationResult: Driver<QrisPayAmountResult.Validation> { get } var amountResult: Driver<String?> { get } var tips: Observable<QrisPayParams.Tips> { get } var fixedAmount: Observable<Bool> { get } var tipAmount: Observable<Decimal> { get } var createdParam: Observable<QrisPayAmountViewModel.PayloadRequest> { get } var completeTransfer: Observable<QrisPayment.Transaction> { get } var state: Driver<QrisPayAmountValidState> { get } var isConfirmState: Bool { get } var qrisPending: Observable<(QrisPayAPIModel.PayResult, Bool)> { get } var qrisPendingStatus: Driver<QrisPayPendingStatus> { get } var isAllUsedQuickCredit: Driver<Bool> { get } var invalidRecentlyFavorite: Driver<()> { get } var isLoading: Driver<Bool> { get } var error: Driver<QrisPayAmountResult.ErrorType> { get } } private extension QrisPayAmountViewModel { struct QrisPay: Codable { // account Identification1 let acctIdentification1: String? // acquiring institution Id let acquInstId: String // additional data let addtnlData: String // additional Data National let addtnlDataNatnl: String // approval code let apprCode: String? // card acceptorId let cardAcceptId: String // card acceptor name & location let cardAcceptNmLoc: String // card acceptor terminal identification let cardAcceptTermId: String? // currency let ccy: String // length: 3 // amount convenience fee let convFee: String? // receiver account holder let crAcctNm1: String? // length: 30 // receiver account holder2 let crAcctNm2: String? // length: 30 // receiver account no let crAcctNo: String // length: 30 // receiver account type let crAcctType: String? // length: 3 // receiver bank code let crBankCd: String? // length: 6 // receiver card no let crCardNo: String? // length: 50 // withdrawal account holder let dbAcctNm: String // withdrawal account no let dbAcctNo: String // length: 30 // forwarding institution Id let fwdInstId: String // issuer Id let issuerId: String // merchantCity let merchantCity: String? // merchants name let merchantName: String // merchants type let merchantType: String // length: 4 // reserved2 let reserved2: String? // reserved3 let reserved3: String? // point of service entry mode let svcEntryMode: String // tips let tipsAmount: String? // transaction amount let trxAmt: String // quick credit disbursal Y/N let quickCreditDisbursalYn: String // loan Account number let loanAcctNo: String? // using loan amount let loanAmt: String? } } final class QrisPayAmountViewModel: QrisPayAmountViewModelType { typealias PayloadRequest = [String: Any] typealias RecentlyFavoriteModel = TransferAPIModel.RecentBookMark.TransferTransaction typealias LoanInfo = (quickCreditDisbursalYn: String, loanAcctNo: String?, loanAmt: String?) // swiftlint:disable superfluous_disable_command large_tuple typealias PayInfo = (withdrawMerchantPan: String, withdrawMerchantName: String, amount: Decimal, tip: Decimal, loanInfo: LoanInfo) private enum Constant { static let hotKeyAllAmountTag: Decimal = 4444_987_654_321 } private let disposeBag = DisposeBag() // output private let cellModelRelay: BehaviorRelay<QrisPayAmountCellModel?> = .init(value: nil) private let accountListSubject: PublishSubject<AccountAPIModel.Accounts?> = .init() private let disbursalLimitRelay: BehaviorRelay<QrisPayAPIModel.QRISPaymentDisbursalLimitResponse?> = .init(value: nil) private let validationResultSubject: BehaviorSubject<QrisPayAmountResult.Validation> = .init(value: .ready) private let amountSubject: BehaviorSubject<String?> = .init(value: nil) private let inputValidationResultSubject: BehaviorSubject<QrisPayAmountResult.Validation> = .init(value: .ready) private let isLoadingRelay: BehaviorRelay<Bool> = .init(value: false) private let tipsSubject: BehaviorSubject<QrisPayParams.Tips> = .init(value: (.none, nil)) private let enableAmountSubject: BehaviorSubject<Bool> = .init(value: true) private let createdParamSubject: PublishSubject<PayloadRequest> = .init() private let completeTransferSubject: PublishSubject<QrisPayment.Transaction> = .init() private let stateSubject: BehaviorRelay<QrisPayAmountValidState> = .init(value: .inputAmount) private let pendingResponseSubject: BehaviorSubject<(QrisPayAPIModel.PayResult, Bool)?> = .init(value: nil) private let pendingStatusRelay: BehaviorRelay<QrisPayPendingStatus> = .init(value: .unknown) private let errorSubject: PublishSubject<QrisPayAmountResult.ErrorType?> = .init() init() { setupRemote() } /// inputs private let recentlyFavoriteModelProperty: BehaviorRelay<RecentlyFavoriteModel?> = .init(value: nil) private let payParamProperty: BehaviorRelay<QrisPayParams?> = .init(value: nil) private var transferOptionViewModel: TransferOptionViewModelType? private let fetchProperty: PublishSubject<()> = .init() private let refreshAccountDataProperty: PublishSubject<()> = .init() private let fetchDisbursalLimitProperty: PublishSubject<QrisPayAPIModel.QRISPaymentDisbursalLimitRequest> = .init() private let validationProperty: PublishSubject<()> = .init() private let amountChangedProperty: PublishSubject<Decimal> = .init() private let inputAmountChangedProperty: PublishSubject<Decimal> = .init() private let addAmountProperty: PublishSubject<Decimal> = .init() private let tipAmountProperty: BehaviorSubject<Decimal> = .init(value: 0) private let currentAccountProperty: PublishSubject<AccountAPIModel.AccountSimpleInfo> = .init() private let createParamProperty: PublishSubject<PayInfo> = .init() private let payProperty: PublishSubject<PayloadRequest> = .init() private let showResultProperty: PublishSubject<Void> = .init() private let allUsedQuickCreditRelay: BehaviorRelay<Bool> = .init(value: false) var inputs: QrisPayAmountViewModelInputs { self } var outputs: QrisPayAmountViewModelOutputs { self } } extension QrisPayAmountViewModel: QrisPayAmountViewModelOutputs { var payParam: Observable<QrisPayParams?> { payParamProperty.asObservable() } var cellModelObservable: Observable<QrisPayAmountCellModel?> { cellModelRelay.asObservable() } var accountList: Observable<AccountAPIModel.Accounts> { accountListSubject.asObservable().filterNil() } var disbursalLimit: Observable<QrisPayAPIModel.QRISPaymentDisbursalLimitResponse> { disbursalLimitRelay.asObservable().filterNil() } var validationResult: Driver<QrisPayAmountResult.Validation> { validationResultSubject.asDriver(onErrorJustReturn: .ready) } var inputValidationResult: Driver<QrisPayAmountResult.Validation> { inputValidationResultSubject.asDriver(onErrorJustReturn: .ready) } var amountResult: Driver<String?> { amountSubject.asDriver(onErrorJustReturn: nil) } var tips: Observable<QrisPayParams.Tips> { tipsSubject.asObservable() } var fixedAmount: Observable<Bool> { enableAmountSubject.asObservable() } var tipAmount: Observable<Decimal> { tipAmountProperty.asObservable() } var createdParam: Observable<QrisPayAmountViewModel.PayloadRequest> { createdParamSubject.asObservable() } var completeTransfer: Observable<QrisPayment.Transaction> { completeTransferSubject.asObservable() } var state: Driver<QrisPayAmountValidState> { stateSubject.asDriver(onErrorJustReturn: .inputAmount) } var isConfirmState: Bool { stateSubject.value.isConfirmState } var qrisPending: Observable<(QrisPayAPIModel.PayResult, Bool)> { pendingResponseSubject.asObservable().filterNil() } var qrisPendingStatus: Driver<QrisPayPendingStatus> { pendingStatusRelay.asDriver(onErrorJustReturn: .unknown) } var isAllUsedQuickCredit: Driver<Bool> { allUsedQuickCreditRelay.asDriver(onErrorJustReturn: false) } var invalidRecentlyFavorite: Driver<()> { error.filter { $0.serverError == .invalidRecentBookmarkAccountNo }.mapTo(()) } var isLoading: Driver<Bool> { isLoadingRelay.asDriver() } var error: Driver<QrisPayAmountResult.ErrorType> { errorSubject.asDriver(onErrorJustReturn: nil).filterNil() } } extension QrisPayAmountViewModel: QrisPayAmountViewModelInputs { func setup(params: QrisPayParams) { // recentlyFavoriteModelProperty.accept(recentlyFavorite) tipsSubject.onNext(params.tips) payParamProperty.accept(params) } func fetch() { fetchProperty.onNext(()) } func refreshAccountData() { refreshAccountDataProperty.onNext(()) } func fetchDisbursalLimit(payload: QrisPayAPIModel.QRISPaymentDisbursalLimitRequest) { fetchDisbursalLimitProperty.onNext(payload) } func validation() { validationResultSubject.onNext(.ready) validationProperty.onNext(()) } func amountChanged(to amount: Decimal) { amountChangedProperty.onNext(amount) } func inputAmountChanged(to amount: Decimal) { inputAmountChangedProperty.onNext(amount) } func addAmount(to amount: Decimal) { addAmountProperty.onNext(amount) } func changeAccount(with account: AccountAPIModel.AccountSimpleInfo) { currentAccountProperty.onNext(account) } func createParams(payInfo: PayInfo) { createParamProperty.onNext(payInfo) } func pay(payload: QrisPayAmountViewModel.PayloadRequest) { payProperty.onNext(payload) } func tipAmount(to amount: Decimal) { tipAmountProperty.onNext(amount) } func changeInputState() { stateSubject.accept(.inputAmount) } func changeSendMoneyState() { stateSubject.accept(.sendMoney) } func updateState() { stateSubject.accept(isConfirmState ? .validate : .sendMoney) } func qrisPendingResponse(_ pendingResponse: QrisPayAPIModel.PayResult, _ isDisbursal: Bool) { pendingResponseSubject.onNext((pendingResponse, isDisbursal)) pendingStatusRelay.accept(pendingStatusRelay.value.next()) changeSendMoneyState() } func allUsedQuickCreditPayment(_ isAll: Bool) { allUsedQuickCreditRelay.accept(isAll) } func showResult() { showResultProperty.onNext(()) } // func fetchDisbursalLimitQuickCredit(){ // isLoadingRelay.accept(true) // // disposable += allUsedQuickCreditRelay // .flatMapLatest { // Remote<QuickCreditAPIModel.Main>.QuickCredit // .main(loanAccountNo: $0) // .useErrorLog() // .asObservable() // } // .subscribe(onNext: { [weak self] in // guard let self = self else { return } // // self.isLoadingRelay.accept(false) // // switch $0 { // case let .success(value): // self.infoSubject.onNext(QuickCreditHeaderPresentModel(value)) // self.hasAnyPrevBillsSubject.onNext(value.monthlyBill != nil) // // case let .failure(error): // self.errorSubject.onNext(error) // } // }) // // } } // MARK: Factory extension QrisPayAmountViewModel { // func createOptionViewModel(transferType: QrisPaymentAPIModel.PayType) -> QrisPayOptionViewModelType? { // switch transferType { // case .lineToLine: // return TransferLineBankViewModel() // case .lineToNonBank: // return TransferLineNonBankViewModel() // case .phoneToLineBank: // return TransferPhoneBankViewModel() // case .phoneToNonBank: // return TransferPhoneNonBankViewModel() // case .lineBankAccount, .otherBankAccount: // return TransferBankAccountViewModel() // case .myAccount: // return TransferMyAccountViewModel() // case .unknown: // return nil // } // } } // MARK: - Remote private extension QrisPayAmountViewModel { func setupRemote() { fetchProperty .do(onNext: { [weak self] _ in self?.isLoadingRelay.accept(true) }) .withLatestFrom(payParamProperty) .filterNil() .flatMapLatest { [weak self] param -> Observable<(QrisPayParams, QrisPayAPIModel.QRISPaymentDisbursalLimitResponse)> in guard let self = self else { return .empty() } let initData = QrisPayAPIModel.QRISPaymentDisbursalLimitRequest(loanAcctNo: 0, quickCreditDisbursalYn: "",amount: 0) self.fetchDisbursalLimit(payload: initData) return .create { self.disbursalLimitRelay .filterNil() .map { (param, $0) } .bind(to: $0) } } .flatMapLatest { [weak self] param, limit -> Observable<(QrisPayParams, QrisPayAPIModel.QRISPaymentDisbursalLimitResponse, AccountAPIModel.Accounts)> in guard let self = self else { return .empty() } return .create { observer -> Disposable in Remote<AccountAPIModel.Accounts>.Account .list() .useErrorLog() .asObservable() .subscribe(onNext: { [weak self] in guard let self = self else { return } switch $0 { case let .success(value): self.accountListSubject.onNext(value) observer.onNext((param, limit, value)) case let .failure(error): self.errorSubject.onNext(.serverError(error: error)) observer.onCompleted() } }) } } .bind(onNext: { [weak self] _, _, accountList in guard let self = self else { return } guard let currentAccount = accountList.list.filter({ $0.dpAcctYn }).first else { self.errorSubject.onNext(.dataIsNil) return } self.currentAccountProperty.onNext(currentAccount) }).disposed(by: disposeBag) refreshAccountDataProperty .do(onNext: { [weak self] _ in self?.isLoadingRelay.accept(true) }) .flatMapLatest { _ -> Observable<Result<AccountAPIModel.Accounts>> in Remote<AccountAPIModel.Accounts>.Account .list() .useErrorLog() .asObservable() } .compactMap { [weak self] result -> AccountAPIModel.Accounts? in guard let self = self else { return nil } switch result { case let .success(value): return value case let .failure(error): self.errorSubject.onNext(.serverError(error: error)) return nil } } .withLatestFrom(currentAccountProperty) { ($0, $1) } .do(onNext: { [weak self] _ in self?.isLoadingRelay.accept(false) }) .bind(onNext: { [weak self] accountList, currentAccount in guard let self = self else { return } defer { self.accountListSubject.onNext(accountList) } guard let currentAccount = accountList.list.first(where: { $0.acctNo == currentAccount.acctNo }) else { self.errorSubject.onNext(.dataIsNil) return } self.currentAccountProperty.onNext(currentAccount) }).disposed(by: disposeBag) fetchDisbursalLimitProperty .flatMapLatest { data -> Observable<Result<QrisPayAPIModel.QRISPaymentDisbursalLimitResponse>> in let payloadDisbursalLimit = QrisPayAPIModel.QRISPaymentDisbursalLimitRequest(loanAcctNo: data.loanAcctNo, quickCreditDisbursalYn: data.quickCreditDisbursalYn, amount: data.amount) return Remote<QrisPayAPIModel.QRISPaymentDisbursalLimitResponse>.QrisPayment .disbursalLimit(payloadDisbursalLimit) .useErrorLog() .asObservable() } .bind(onNext: { [weak self] in guard let self = self else { return } switch $0 { case let .success(value): self.disbursalLimitRelay.accept(value) case let .failure(error): self.errorSubject.onNext(.serverError(error: error)) } }).disposed(by: disposeBag) validationProperty .withLatestFrom(cellModelRelay) { $1 } .filterNil() .map { self.validation(to: $0.amount) } .bind(onNext: { self.validationResultSubject.onNext($0) }).disposed(by: disposeBag) amountChangedProperty .withLatestFrom(cellModelRelay) { ($0, $1) } .map { amount, cellModel -> (QrisPayAmountResult.Validation, Decimal) in let resultAmount = amount.compareLength(13) == .greaterThan ? (cellModel?.amount ?? 0) : amount let validationResult = self.validation(to: resultAmount) cellModel?.amount = resultAmount return (validationResult, resultAmount) }.bind(onNext: { self.validationResultSubject.onNext($0.0) self.amountSubject.onNext($0.1 == 0 ? nil : $0.1.currencyFormatted(showSymbol: false)) }).disposed(by: disposeBag) inputAmountChangedProperty .withLatestFrom(cellModelRelay) { ($0, $1) } .compactMap { [weak self] amount, cellModel -> (QrisPayAmountResult.Validation, Decimal)? in guard let self = self else { return nil } let resultAmount = amount.compareLength(13) == .greaterThan ? (cellModel?.amount ?? 0) : amount let validationResult = self.validation(to: resultAmount) cellModel?.amount = resultAmount return (validationResult, resultAmount) }.bind(onNext: { [weak self] in guard let self = self else { return } self.inputValidationResultSubject.onNext($0.0) switch $0.0 { case .underMinimumLimit: break default: self.validationResultSubject.onNext($0.0) } }).disposed(by: disposeBag) tipAmountProperty .withLatestFrom(tipsSubject) .filter { $0.0 == .input } .withLatestFrom(cellModelRelay) .compactMap { [weak self] cellModel -> QrisPayAmountResult.Validation? in guard let self = self else { return nil } let validationResult = self.validation(to: cellModel?.amount ?? 0) return validationResult }.bind(onNext: { [weak self] in guard let self = self else { return } switch $0 { case .underMinimumLimit: break default: self.validationResultSubject.onNext($0) } }).disposed(by: disposeBag) addAmountProperty .withLatestFrom(cellModelRelay.filterNil()) { ($0, $1) } .bind(onNext: { value, cellModel in let result: Decimal = with(cellModel.amount + value) { guard value != Constant.hotKeyAllAmountTag else { return Decimal(cellModel.withdrawAccountBalance.intValue) } return $0 } self.amountChangedProperty.onNext(result) }).disposed(by: disposeBag) currentAccountProperty .asObservable() .distinctUntilChanged() .withLatestFrom(payParamProperty) { ($0, $1) } .withLatestFrom(disbursalLimitRelay) { ($0, $1) } .bind(onNext: { [weak self] info, limit in guard let self = self, let param = info.1, let limit = limit else { return } self.makeCellModel(limit, param, account: .init(model: info.0)) if let amount = param.transactionAmount { self.amountChangedProperty.onNext(amount.decimalValue) self.enableAmountSubject.onNext(false) } }).disposed(by: disposeBag) createParamProperty .withLatestFrom(payParam) { ($0, $1) } .withLatestFrom(currentAccountProperty) { ($0.0, $0.1, $1) } .map { [weak self] in self?.makeRequestParam($0.0, $0.1, $0.2)?.asDictionary } .filterNil() .bind(onNext: createdParamSubject.onNext) .disposed(by: disposeBag) payProperty .do(onNext: { [weak self] _ in self?.isLoadingRelay.accept(true) }) .flatMapLatest { payload in Remote<QrisPayAPIModel.PayResult>.QrisPayment .pay(payloadRequest: payload) .useErrorLog() .asObservable() } .do(onNext: { [weak self] _ in self?.isLoadingRelay.accept(false) }) .bind(onNext: { [weak self] result in guard let self = self else { return } switch result { case let .success(response): self.completeTransferSubject.onNext(self.makeTransaction(receiver: response)) case let .failure(error): self.errorSubject.onNext(.serverErrorWithPay(error: error)) } }).disposed(by: disposeBag) showResultProperty .do(onNext: { [weak self] _ in self?.isLoadingRelay.accept(true) }) .withLatestFrom(qrisPending) .flatMapLatest { payload in Remote<QrisPayAPIModel.PayResult>.QrisPayment .showResult(payload.0) .useErrorLog() .asObservable() } .do(onNext: { [weak self] _ in self?.isLoadingRelay.accept(false) }) .bind(onNext: { [weak self] result in guard let self = self else { return } switch result { case let .success(response): self.completeTransferSubject.onNext(self.makeTransaction(receiver: response)) case let .failure(error): self.errorSubject.onNext(.serverError(error: error)) } }).disposed(by: disposeBag) } } // MARK: - Private private extension QrisPayAmountViewModel { func validation(to value: Decimal) -> QrisPayAmountResult.Validation { guard let formModel = cellModelRelay.value else { return .ready } if value < 0 { return .invalid(message: "You should be valid amount.") } if let tips = try? tipsSubject.value() { switch tips.0 { case .percentage: if let percentage = tips.1?.decimalValue, percentage > 0 { tipAmountProperty.onNext(Decimal((value * percentage / 100).intValue)) } case .amount: tipAmountProperty.onNext(tips.1?.decimalValue ?? 0) default: break } } if value == 0 { return .ready } let tipAmount: Decimal = (try? tipAmountProperty.value()) ?? 0 // if !formModel.canWithdrawAmount(to: value + tipAmount) { // return .overAccountBalance(message: LocalizableString.amountExceedamountErrorDesc) // } // // if formModel.isUnderOneTimeAmountLimit(amount: value) { // // formModel.representMinimumOneTimeAmount // return .underMinimumLimit(message: LocalizableString.amountMinimumamountErrorDesc(formModel.minTransferOneTimeLimit.intValue)) // } // // if formModel.isOverOneTimeAmountLimit(amount: value) { // // formModel.representMaximumOneTimeAmount // return .overOnetimeLimit(message: LocalizableString.amountOvertxnlimitErrorDesc(formModel.maxTransferOneTimeLimit.intValue)) // } return .ok } func makeCellModel(_ limit: QrisPayAPIModel.QRISPaymentDisbursalLimitResponse, _ param: QrisPayParams, account: AccountPresentModel) { let cellModel = QrisPayAmountCellModel(limit, param, account: account) if let cell = cellModelRelay.value { cellModel.amount = cell.amount cellModel.memo = cell.memo } cellModelRelay.accept(cellModel) } func makeRequestParam(_ payInfo: PayInfo, _ payParam: QrisPayParams?, _ currentAccount: AccountAPIModel.AccountSimpleInfo) -> QrisPay? { guard let payParam = payParam else { return nil } let amount = "\((payInfo.amount))"//.leftPadding(toLength: 14, withPad: "0") let tip = payInfo.tip let dbAcctNm = BankUserService.shared.currentUser?.userName ?? "" return .init(acctIdentification1: nil, acquInstId: payParam.acquInstId, addtnlData: payParam.addtnlData, addtnlDataNatnl: payParam.addtnlDataNatnl, apprCode: nil, cardAcceptId: payParam.cardAcceptId, cardAcceptNmLoc: payParam.cardAcceptNmLoc, cardAcceptTermId: payParam.cardAcceptTermId, ccy: "360", convFee: makeConvFee(tip, payParam), crAcctNm1: nil, crAcctNm2: payParam.crAcctNm2, crAcctNo: payParam.merchantPan, crAcctType: nil, crBankCd: nil, crCardNo: nil, dbAcctNm: dbAcctNm, //currentAccount.acctTitle, dbAcctNo: currentAccount.acctNo, fwdInstId: "360002", issuerId: "93600484 ", merchantCity: payParam.merchantCity, merchantName: payParam.merchantName ?? "", merchantType: payParam.merchantType, reserved2: nil, reserved3: nil, svcEntryMode: "012", tipsAmount: "\(tip)", trxAmt: amount, quickCreditDisbursalYn: payInfo.loanInfo.quickCreditDisbursalYn, loanAcctNo: payInfo.loanInfo.loanAcctNo, loanAmt: payInfo.loanInfo.loanAmt ) } func makeTransaction(receiver: QrisPayAPIModel.PayResult) -> QrisPayment.Transaction { .init(refNo: receiver.refNo ?? "", hisNo: receiver.hisNo, dbAcctNm: [receiver.dbAcctNm1, receiver.dbAcctNm2].compactMap { $0 }.joined(), dbAcctNo: receiver.dbAcctNo ?? "", crAcctNo: receiver.crAcctNo ?? "", trxAmt: receiver.trxAmt ?? "", tipAmount: receiver.tipsAmount ?? "", crAcctNm1: receiver.crAcctNm1, crAcctNm2: receiver.crAcctNm2, merchantName: receiver.merchantName ?? "", convFee: receiver.convFee ?? "", date: receiver.localTrxTimeStamp.date ?? Date(), disbursalAmount: receiver.loanAmt, totalUsedCredit: receiver.loanBalance, availableCredit: receiver.creditLimit, disburseFee: receiver.disburseFee ) } private func makeConvFee(_ tip: Decimal, _ payParam: QrisPayParams?) -> String? { guard let payParam = payParam else { return "" } switch payParam.tipIndicator { case .input: let tipAmount: Decimal = (try? tipAmountProperty.value()) ?? 0 return "C" + "\(tipAmount)00".leftPadding(toLength: 8, withPad: "0") case .amount: guard let tipValue = payParam.tipValueOfFixed else { return "" } return "D" + "\(tipValue)00".leftPadding(toLength: 8, withPad: "0") case .percentage: return "D" + "\(tip)00".leftPadding(toLength: 8, withPad: "0") default: return nil } } private func makeAddtnlData(_ dbAcctNm: String, _ mc: String) -> String { let count: Int let title: String if dbAcctNm.count > 30 { count = 30 title = String(dbAcctNm[dbAcctNm.startIndex..<dbAcctNm.index(dbAcctNm.startIndex, offsetBy: 30)]) } else { count = dbAcctNm.count title = dbAcctNm } return "PI04Q001CD\(String(format: "%02d", count))\(title)MC\(String(format: "%02d", mc.count))\(mc)" } }
Editor is loading...
Leave a Comment