// // TapCashApi.swift // Emoney Info // // Created by Wira Irawan on 26/07/24. // import Foundation import CoreNFC public class TapCashApi : UnifiedNfcApi { var emoney : Emoney = Emoney() var tapCashData : TapCashData = TapCashData() var riwayatList: [RiwayatCard] = [] var start = 0 var totalLog = 0 public override init() {} public func checkBalance(){ apduRunner.exchangeApdu(apduCommand: EmoneyApduCommands.TAPCASH_APDU01, completionHandler: {response in if (response.sw1 == 0x90 && response.sw2 == 0x00){ self.emoney.setCardLabel("BNI TapCash") self.tapCashData.setPurseData(response.getData().bytes) let balance = self.tapCashData.getPurseBalance()?.hexString().hex2decimal() self.emoney.setBalance(balance!) self.emoney.setCardNumber(self.tapCashData.getCAN()!.hexString()) self.totalLog = (self.tapCashData.getTotalRecords()?.hexString().hex2decimal())! if (self.totalLog > 10){ self.totalLog = 10 } debugLog("total log " + String(self.totalLog)) self.getHistory(index: 0) } else { self.emoney.setTampilRiwayat(false) self.updateScreen() self.apduRunner.sessionEx?.alertMessage = "readFinish".localizeString(string: self.langCode!) self.apduRunner.invalidateSession() } }) } private func getHistory(index : Int){ let st = String(index).leftPad(with: "0", length: 2) //90 32 03 00 01 00 10 let TAPCASH_LOG = NFCISO7816APDU(instructionClass : 0x90, instructionCode : 0x32, p1Parameter : 0x03, p2Parameter : 0x00, data : Data(_ : st.stringToBytes()!), expectedResponseLength : 16) debugLog(TAPCASH_LOG.toHexString()) apduRunner.exchangeApdu(apduCommand: TAPCASH_LOG, completionHandler: {response in if (response.sw1 == 0x90 && response.sw2 == 0x00){ self.addRiwayatTransaksi(data: response.getData().bytes) } self.start+=1 if (self.start < (self.totalLog)){ self.getHistory(index: self.start) } else { self.updateScreen() self.riwayatList = self.riwayatList.sorted(by: { $0.getTransationTime()?.compare($1.getTransationTime()!) == .orderedDescending }) if (self.riwayatList.count > 0){ self.emoney.setRiwayatList(self.riwayatList) self.emoney.setTampilRiwayat(true) } self.apduRunner.sessionEx?.alertMessage = "readFinish".localizeString(string: self.langCode!) self.apduRunner.invalidateSession() } }) } private func updateScreen(){ if (self.apduRunner.callback != nil){ self.apduRunner.callback?.complete(emoney: self.emoney) } } private func addRiwayatTransaksi(data: [UInt8]) { let trxType = Array(data[0..<1]) let trxAmount = Array(data[1..<4]) let trxDateTimes = Array(data[4..<8]) //let trxUserData = Array(data[8..<16]) let title = trxType.hexString() var amount: Int if title.lowercased() == "01" || title.lowercased() == "05" || title.lowercased() == "07" || title.lowercased() == "10" || title.lowercased() == "20" { amount = trxAmount.hexString().secondComplementsAmount() } else { amount = trxType.hexString().hex2decimal() } let riwayatCard = RiwayatCard() riwayatCard.setTitle(getStatementTitle(header: trxType.hexString())) riwayatCard.setProsesTipe(getTranscationType(header: trxType.hexString())) riwayatCard.setAmount(amount) let transactionTime = self.getTransactionTime(julian: trxDateTimes.hexString()) riwayatCard.setTransactionTime(transactionTime) riwayatList.append(riwayatCard) } private func getStatementTitle(header: String) -> String { var title = "" switch header.uppercased() { case "01": title = "payment".localizeString(string: self.langCode!) case "02": title = "Black List Card" case "03": title = "topup".localizeString(string: self.langCode!) case "04": title = "topup".localizeString(string: self.langCode!) case "05": title = "statementFee".localizeString(string: self.langCode!) case "06": title = "updateBalance".localizeString(string: self.langCode!) case "07": title = "gracePeriod".localizeString(string: self.langCode!) case "10": title = "refund".localizeString(string: self.langCode!) case "20": title = "refund".localizeString(string: self.langCode!) case "22": title = "close".localizeString(string: self.langCode!) case "F0": title = "atu".localizeString(string: self.langCode!) default: break } return title } private func getTranscationType(header: String) -> Int { switch header.uppercased() { case "01": return 1 case "02": return 2 case "03": return 0 case "04": return 0 case "05": return 1 case "06": return 6 case "07": return 7 case "10": return 10 case "20": return 20 case "22": return 22 default: break } return 0 } func getTransactionTime(julian: String) -> Date { let dec = julian.hex2decimal() let cal = Calendar.current // set to 1st January 1995 var dateComponents = DateComponents() dateComponents.year = 1995 dateComponents.month = 1 dateComponents.day = 1 dateComponents.hour = 0 dateComponents.minute = 0 dateComponents.second = 0 if let date = cal.date(from: dateComponents) { let newDate = date.addingTimeInterval(Double(dec)) return newDate } return Date() } }