You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

441 lines
19 KiB

//
// SetupRecipientViewModel.swift
// GME Remit
//
// Created by InKwon James Kim on 09/08/2019.
//Copyright © 2019 Gobal Money Express Co. Ltd. All rights reserved.
//
import RxSwift
import RxCocoa
class SetupRecipientViewModel: ViewModelType {
struct Input {
let initialTrigger: Driver<Void>
let openCountryTrigger: Driver<Void>
let openPaymentTrigger: Driver<Void>
let openBankTrigger: Driver<Void>
let openBranchTrigger: Driver<Void>
let openIDTypeTrigger: Driver<Void>
let openStateProvinceTrigger: Driver<Void>
let openDistrictTrigger: Driver<Void>
let openRelationTrigger: Driver<Void>
let openReasonTrigger: Driver<Void>
let openNativeCountryTrigger: Driver<Void>
let saveTrigger: Driver<Recipient>
}
struct Output {
let isError: Driver<Error>
let isProgress: Driver<Bool>
let success: Driver<ResponseContainerObject<Recipient>>
let models: Models
let selectedRecipient: Driver<Recipient?>
let selectedCountry: Driver<CountryAndServiceModel?>
let selectedPaymentMode: Driver<PaymentServiceType?>
let selectedBank: Driver<SendMoneyBank?>
let selectedBranch: Driver<SendMoneyBankBranch?>
let selectedIDType: Driver<ReceiverIdType?>
let selectedStateProvince: Driver<Provience?>
let selectedDistrict: Driver<District?>
let selectedRelation: Driver<Relation?>
let selectedReason: Driver<TransferReason?>
let selectedNativeCountry: Driver<NativeCountryModel?>
}
struct Models {
let countryServicesModel: Driver<[CountryAndServiceModel]>
let paymentModel: Driver<[PaymentServiceType]>
let dynamicFieldsModel: Driver<[FieldModel]>
}
// Linker
private let progressLinker = PublishSubject<Bool>()
private let errorLinker = PublishSubject<Error>()
private let successLinker = PublishSubject<ResponseContainerObject<Recipient>>()
private let dynamicFieldsLinker = PublishSubject<[FieldModel]>()
// Models Linker
private let countryServicesLinker = PublishSubject<[CountryAndServiceModel]>()
private let paymentModeTypesLinker = PublishSubject<[PaymentServiceType]>()
private let banksLinker = PublishSubject<[SendMoneyBank]>()
private let idTypeLinker = PublishSubject<[ReceiverIdType]>()
private let stateProvincesLinker = PublishSubject<[Provience]>()
private let relationsLinker = PublishSubject<[Relation]>()
private let reasonsLinker = PublishSubject<[TransferReason]>()
private let nativeCountiresLinker = PublishSubject<[NativeCountryModel]>()
// Selected Model Linker
private let selectedRecipientLinker = BehaviorSubject<Recipient?>(value: nil)
private let selectedCountryServicesLinker = BehaviorSubject<CountryAndServiceModel?>(value: nil)
private let selectedPaymentModeTypesLinker = BehaviorSubject<PaymentServiceType?>(value: nil)
private let selectedBankLinker = BehaviorSubject<SendMoneyBank?>(value: nil)
private let selectedBranchLinker = BehaviorSubject<SendMoneyBankBranch?>(value: nil)
private let selectedIDTypeLinker = BehaviorSubject<ReceiverIdType?>(value: nil)
private let selectedStateProvinceLinker = BehaviorSubject<Provience?>(value: nil)
private let selectedDistrictLinker = BehaviorSubject<District?>(value: nil)
private let selectedRelationLinker = BehaviorSubject<Relation?>(value: nil)
private let selectedReasonLinker = BehaviorSubject<TransferReason?>(value: nil)
private let selectedNativeCountryLinker = BehaviorSubject<NativeCountryModel?>(value: nil)
// Properties
var presenter: SetupRecipientModuleInterface?
var isFirst = true
var payoutPartner: String?
private let disposeBag = DisposeBag()
func transform(input: Input) -> Output {
let countryServicesModel = countryServicesLinker.asDriverOnErrorJustComplete()
let paymentModeModel = paymentModeTypesLinker.asDriverOnErrorJustComplete()
let dynamicModel = dynamicFieldsLinker.asDriverOnErrorJustComplete()
let banksModel = banksLinker.asDriverOnErrorJustComplete()
let idTypesModel = idTypeLinker.asDriverOnErrorJustComplete()
let stateProvicesModel = stateProvincesLinker.asDriverOnErrorJustComplete()
let relationsModel = relationsLinker.asDriverOnErrorJustComplete()
let reasonsModel = reasonsLinker.asDriverOnErrorJustComplete()
let branchesModel = Observable.combineLatest(selectedCountryServicesLinker, selectedBankLinker)
.asDriverOnErrorJustComplete()
let districtsModel = selectedStateProvinceLinker.flatMap {Observable.just($0?.districts ?? [])}
.asDriverOnErrorJustComplete()
let nativeCountrisModel = nativeCountiresLinker.asDriverOnErrorJustComplete()
let model = Models(
countryServicesModel: countryServicesModel,
paymentModel: paymentModeModel,
dynamicFieldsModel: dynamicModel
)
// FetchCountriesAndServiceTypes
input.initialTrigger.drive(onNext: { [weak self] in guard let `self` = self else { return }
self.presenter?.fetchCountriesAndServiceTypes()
}).disposed(by: disposeBag)
// Handle open select country
input.openCountryTrigger.withLatestFrom(countryServicesModel) {$1}
.drive(onNext: { [weak self] in guard let `self` = self else { return }
self.presenter?.openSelectMode(with: $0, type: .country)
}).disposed(by: disposeBag)
// Handle open select payment mode
input.openPaymentTrigger.withLatestFrom(paymentModeModel) {$1}
.drive(onNext: { [weak self] in guard let `self` = self else { return }
self.presenter?.openSelectMode(with: $0, type: .paymentMode)
}).disposed(by: disposeBag)
// Handle open select bank
input.openBankTrigger.withLatestFrom(banksModel) {$1}
.drive(onNext: { [weak self] in guard let `self` = self else { return }
self.presenter?.openSelectMode(with: $0, type: .bank)
}).disposed(by: disposeBag)
// Handle open select branch
input.openBranchTrigger.withLatestFrom(branchesModel) { $1 }
.drive(onNext: { [weak self] in guard let `self` = self else { return }
self.presenter?.openBranches(countryCode: $0.0?.countryCode ?? "", bankID: $0.1?.id ?? "")
}).disposed(by: disposeBag)
// Handle open select id type
input.openIDTypeTrigger.withLatestFrom(idTypesModel) {$1}
.drive(onNext: { [weak self] in guard let `self` = self else { return }
self.presenter?.openSelectMode(with: $0, type: .idType)
}).disposed(by: disposeBag)
// Handle open select state
input.openStateProvinceTrigger.withLatestFrom(stateProvicesModel) {$1}
.drive(onNext: { [weak self] in guard let `self` = self else { return }
self.presenter?.openSelectMode(with: $0, type: .stateProvince)
})
.disposed(by: disposeBag)
// Handle open select district
input.openDistrictTrigger.withLatestFrom(districtsModel) {$1}
.drive(onNext: { [weak self] in guard let `self` = self else { return }
self.presenter?.openSelectMode(with: $0, type: .district)
}).disposed(by: disposeBag)
// Handle open select relation
input.openRelationTrigger.withLatestFrom(relationsModel) {$1}
.drive(onNext: { [weak self] in guard let `self` = self else { return }
self.presenter?.openSelectMode(with: $0, type: .relation)
}).disposed(by: disposeBag)
// Handle open select reason
input.openReasonTrigger.withLatestFrom(reasonsModel) {$1}
.drive(onNext: { [weak self] in guard let `self` = self else { return }
self.presenter?.openSelectMode(with: $0, type: .reason)
}).disposed(by: disposeBag)
input.openNativeCountryTrigger.withLatestFrom(nativeCountrisModel) {$1}
.drive(onNext: { [weak self] in guard let `self` = self else { return }
self.presenter?.openSelectMode(with: $0, type: .nativeCountry)
})
.disposed(by: disposeBag)
// // Handle save event
input.saveTrigger
.drive(onNext: { [weak self] in guard let `self` = self else { return }
let selectedCountry = try? self.selectedCountryServicesLinker.value()
let selectedPaymentMode = try? self.selectedPaymentModeTypesLinker.value()
let selectedBank = try? self.selectedBankLinker.value()
let selectedBranch = try? self.selectedBranchLinker.value()
let selectedIDType = try? self.selectedIDTypeLinker.value()
let selectedStateProvince = try? self.selectedStateProvinceLinker.value()
let selectedDistrict = try? self.selectedDistrictLinker.value()
// let selectedRelation = try? self.selectedRelationLinker.value()
// let selectedReason = try? self.selectedReasonLinker.value()
let selectedRecipient = try? self.selectedRecipientLinker.value()
let selectedNativeCountry = try? self.selectedNativeCountryLinker.value()
var recipient = $0
recipient.receiverID = selectedRecipient?.receiverID
recipient.country = selectedCountry?.countryName
recipient.countryID = selectedCountry?.countryId
recipient.countryCode = selectedCountry?.countryCode
recipient.paymentMethod?.id = selectedPaymentMode?.id
recipient.paymentMethod?.name = selectedPaymentMode?.type
recipient.paymentMethod?.localizedName = selectedPaymentMode?.subtitle
recipient.paymentMethod?.currency = selectedPaymentMode?.currency
recipient.agent = selectedBank?.toAgentModel()
recipient.agent?.accountNumber = $0.agent?.accountNumber
recipient.agent?.branch = selectedBranch?.toBranchModel()
recipient.idType = selectedIDType?.id
recipient.state = selectedStateProvince?.name
recipient.stateID = selectedStateProvince?.id
recipient.district = selectedDistrict?.name
recipient.districtID = selectedDistrict?.id
// recipient.relationship = selectedRelation?.title
// recipient.relationshipID = selectedRelation?.id
// recipient.purposeOfRemit = selectedReason?.title
// recipient.purposeOfRemitID = selectedReason?.id
recipient.nativeCountry = selectedNativeCountry?.text
recipient.nativeCountryID = selectedNativeCountry?.id
recipient.nativeCountryCode = selectedNativeCountry?.code
if selectedBank?.accountValidationRequired == "True" {
guard
let firstName = recipient.firstName,
let lastName = recipient.lastName else { return }
let name: String
if firstName == "" {
name = recipient.fullName ?? ""
} else if let middleName = recipient.middleName, middleName != "" {
name = "\(firstName) \(middleName)"
} else {
name = firstName
}
let validateModel = ValidateAccountRequest(
firstName: name,
lastName: lastName,
accountType: "1",
accountNumber: recipient.agent?.accountNumber ?? "",
amount: "10000.0",
processID: "",
payoutPartner: self.payoutPartner ?? "",
country: selectedCountry,
paymentMethod: selectedPaymentMode,
bank: selectedBank,
branch: recipient.agent?.branch
)
self.presenter?.validateAccount(with: validateModel, recipient: recipient)
} else {
self.presenter?.saveRecipient(at: recipient)
}
})
.disposed(by: disposeBag)
return Output(
isError: errorLinker.asDriverOnErrorJustComplete(),
isProgress: progressLinker.asDriverOnErrorJustComplete(),
success: successLinker.asDriverOnErrorJustComplete(),
models: model,
selectedRecipient: selectedRecipientLinker.asDriverOnErrorJustComplete(),
selectedCountry: selectedCountryServicesLinker.asDriverOnErrorJustComplete(),
selectedPaymentMode: selectedPaymentModeTypesLinker.asDriverOnErrorJustComplete(),
selectedBank: selectedBankLinker.asDriverOnErrorJustComplete(),
selectedBranch: selectedBranchLinker.asDriverOnErrorJustComplete(),
selectedIDType: selectedIDTypeLinker.asDriverOnErrorJustComplete(),
selectedStateProvince: selectedStateProvinceLinker.asDriverOnErrorJustComplete(),
selectedDistrict: selectedDistrictLinker.asDriverOnErrorJustComplete(),
selectedRelation: selectedRelationLinker.asDriverOnErrorJustComplete(),
selectedReason: selectedReasonLinker.asDriverOnErrorJustComplete(),
selectedNativeCountry: selectedNativeCountryLinker.asDriverOnErrorJustComplete()
)
}
}
// MARK: SetupRecipient view interface
extension SetupRecipientViewModel: SetupRecipientViewModelInterface {
func setCoutryServices(with model: [CountryAndServiceModel], recipient: Recipient?) {
countryServicesLinker.onNext(model)
guard let recipient = recipient else { return }
selectedRecipientLinker.onNext(recipient)
// If exist selected recipient, auto select country and payment mode of selected recipient.
setSelectedData(with: model.filter({$0.countryCode == recipient.countryCode}).first, type: .country)
let selectedCountry = try? selectedCountryServicesLinker.value()
setSelectedData(
with: selectedCountry?.availableServices?.filter({$0.id == recipient.paymentMethod?.id}).first,
type: .paymentMode
)
}
func setDynamicFields(with model: DynamicFieldModel, nativeCountires: [NativeCountryModel]) {
dynamicFieldsLinker.onNext(model.dynamicField ?? [])
reasonsLinker.onNext(model.transferReasons ?? [])
relationsLinker.onNext(model.relations ?? [])
idTypeLinker.onNext(model.idTypes ?? [])
banksLinker.onNext(model.banks ?? [])
stateProvincesLinker.onNext(model.provinces ?? [])
nativeCountiresLinker.onNext(nativeCountires)
payoutPartner = model.payoutPartner
let country = try? selectedCountryServicesLinker.value()
// Default native country setting as selected country
let nativeCountry = nativeCountires.filter({$0.code == country?.countryCode}).first
setSelectedData(with: nativeCountry, type: .nativeCountry)
guard let recipient = try? selectedRecipientLinker.value() else { return }
let selectedBank = model.banks?.filter({$0.id == recipient.agent?.id}).first
// let selectedBranch = selectedBank?.branches?.filter({$0.id == recipient.agent?.branch?.id}).first
let selectedIDType = model.idTypes?.filter({$0.id == recipient.idType}).first
let selectedStateProvince = model.provinces?.filter({$0.id == recipient.stateID}).first
let selectedDistrict = selectedStateProvince?.districts?.filter({$0.id == recipient.districtID}).first
// let selectedRelation = model.relations?.filter({$0.title == recipient.relationshipID}).first
// let selectedReason = model.transferReasons?.filter({$0.title == recipient.purposeOfRemitID}).first
let selectedNativeCountry = nativeCountires.filter({$0.text == recipient.nativeCountry}).first
setSelectedData(with: selectedBank, type: .bank)
setSelectedData(with: recipient.agent?.branch?.toSendMoneyBankBranch(), type: .branch)
setSelectedData(with: selectedIDType, type: .idType)
setSelectedData(with: selectedStateProvince, type: .stateProvince)
setSelectedData(with: selectedDistrict, type: .district)
// setSelectedData(with: selectedRelation, type: .relation)
// setSelectedData(with: selectedReason, type: .reason)
setSelectedData(with: selectedNativeCountry, type: .nativeCountry)
}
func setSelectedData(with model: TablePresenterProtocol?, type: SetupOpenType) {
switch type {
case .country:
guard let model = model as? CountryAndServiceModel else { return }
selectedCountryServicesLinker.onNext(model)
selectedPaymentModeTypesLinker.onNext(nil)
paymentModeTypesLinker.onNext(model.availableServices ?? [])
guard var selectedRecipient = try? selectedRecipientLinker.value() else {
return
}
if model.countryCode != selectedRecipient.countryCode {
let countryEnum = CountryEnum(rawValue: selectedRecipient.countryCode?.lowercased() ?? "")
selectedRecipient.countryCode = model.countryCode
selectedRecipient.country = model.countryName
selectedRecipient.countryID = model.countryId
selectedRecipient.mobile = selectedRecipient.mobile?.replacingOccurrences(
of: countryEnum?.phoneCode ?? "",
with: ""
)
selectedRecipientLinker.onNext(selectedRecipient)
}
case .paymentMode:
guard let model = model as? PaymentServiceType else { return }
selectedPaymentModeTypesLinker.onNext(model)
if var recipient = try? selectedRecipientLinker.value(), recipient.agent != nil, !isFirst {
recipient.agent = nil
selectedRecipientLinker.onNext(recipient)
}
if (try? selectedBankLinker.value()) != nil {
selectedBankLinker.onNext(nil)
}
if (try? selectedBranchLinker.value()) != nil {
selectedBranchLinker.onNext(nil)
}
let selectedCountry = try? selectedCountryServicesLinker.value()
let selectedPaymentMode = try? selectedPaymentModeTypesLinker.value()
presenter?.fetchDynamicRecipientFields(country: selectedCountry, paymentMode: selectedPaymentMode)
isFirst = false
case .bank:
guard let model = model as? SendMoneyBank else { return }
selectedBankLinker.onNext(model)
if let code = model.payoutPartner {
payoutPartner = code
}
if model.branchRequired?.lowercased() == "true" {
selectedBranchLinker.onNext(nil)
}
case .branch:
guard let model = model as? SendMoneyBankBranch else { return }
selectedBranchLinker.onNext(model)
case .idType:
guard let model = model as? ReceiverIdType else { return }
selectedIDTypeLinker.onNext(model)
case .stateProvince:
guard let model = model as? Provience else { return }
selectedStateProvinceLinker.onNext(model)
let count = model.districts?.count ?? 0
if count != 0 {
selectedBranchLinker.onNext(nil)
}
selectedDistrictLinker.onNext(nil)
case .district:
guard let model = model as? District else { return }
selectedDistrictLinker.onNext(model)
case .relation:
guard let model = model as? Relation else { return }
selectedRelationLinker.onNext(model)
case .reason:
guard let model = model as? TransferReason else { return }
selectedReasonLinker.onNext(model)
case .nativeCountry:
guard let model = model as? NativeCountryModel else { return }
selectedNativeCountryLinker.onNext(model)
}
}
func setError(with error: Error) {
errorLinker.onNext(error)
}
func progress(isShow: Bool) {
progressLinker.onNext(isShow)
}
func success(with model: ResponseContainerObject<Recipient>) {
successLinker.onNext(model)
}
}