using System; using System.Collections.Generic; using System.IO.Ports; using System.Linq; using System.Text; using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Xml.Serialization; using System.Windows.Threading; using System.Diagnostics; using System.Collections.ObjectModel; using SafeBagDE70.Model; using HandyControl.Tools; using System.Drawing.Printing; using System.Drawing; using static HandyControl.Tools.Interop.InteropValues; using SafeBagDE70.API; using Newtonsoft.Json; using System.IO; using System.Reflection; using DE70_CMDv2; using System.Configuration; using Serilog; using System.ComponentModel; using SafeBagDE70.StateMachine; using static System.Windows.Forms.VisualStyles.VisualStyleElement.Window; using System.Runtime.Intrinsics.Arm; using SafeBagDE70.Services; using System.Windows.Forms; using Button = System.Windows.Controls.Button; using UserControl = System.Windows.Controls.UserControl; using Application = System.Windows.Application; using Control = System.Windows.Controls.Control; using static Azure.Core.HttpHeader; using System.Net.Http; using Azure; namespace SafeBagDE70 { //Summary public partial class DepositSMUCv2 : UserControl { SerialPort serialPortDE70 = new SerialPort(); SerialPort serialPortSensor= new SerialPort(); List sessions = new List(); public ObservableCollection lvCountItems = new ObservableCollection(); private DispatcherTimer sensorTimer; DispatcherTimer? warningTimer = null; DispatcherTimer? endsessionTimer = null; DispatcherTimer? backToWelcomeTimer = null; public long maxQuantitySheet = 10000; public int quantityStored = 0; public int totalAllDenominations = 0; public int posDenomi; public bool printerFlag = false; public static string? recvDataString; public int countSensorTimer = 0; private PrinterManager printerManager = new PrinterManager(); private NotesInSession notesInSession= new NotesInSession(); //DispatcherTimer? private volatile bool bIsCounted = false; CCmdRsp cCmdRsp = null; bool bInitialized = false; bool bOpenPort = true; bool bIsMaintain = false; MainWindow mainWindow = null; Task taskCounting = null; public DepositSMUCv2() { InitializeComponent(); } private void UserControl_Loaded(object sender, RoutedEventArgs e) { mainWindow=((MainWindow)Application.Current.MainWindow); InitTransaction(); StopTimers(); } public void InitTransaction() { try { lblName.Content= "Vietinbank " + Environment.MachineName; string? transactionCode = null; if (AppData.IsAuthenticated) { transactionCode = AppData.GetTransactionCode(); lblUser.Content = $"Xin chào khách hàng: {AppData.CurrentCustomerAccount.Name} (Gian hàng {AppData.CurrentCustomerAccount.CustomerId})"; lblTransactionCode.Content = $"Mã GD: {transactionCode}"; AppData.IsInTransaction = true; var str = $"MÃ GD: {AppData.GetTransactionCode()} " + $"\r\nMÁY: {Environment.MachineName}" + $"\r\nMÃ NV: {AppData.CurrentCustomerAccount.CustomerId}"; Log.Information(str); } cCmdRsp = new CCmdRsp(serialPortDE70); AppData.cCmdRsp = cCmdRsp; bool bInitSP = InitSerialPorts(); if(bInitSP) { bInitialized = InitSession(); InitTimers(); notesInSession = new NotesInSession(); spNotesInSession.DataContext = notesInSession; ResetButtons(); btnStart.IsEnabled = true; btnLogout.IsEnabled = true; ResetTimers(); var state = GetCDMState(); if (state.GetSR2() == 0x1C) { StopTimers(); ShowError(state.CDMStatus); } var data = AppData.GetCassetteData(); if (transactionCode != null) { AppData.DeviceStatus.Description = $"[CASSETTE]" + AppData.GetNotesString(data); APIModels.SendEvent(AppData.DeviceStatus); } } } catch (Exception ex) { AppData.DeviceStatus.Description = "LỖI KHỞI TẠO GIAO DỊCH"; APIModels.SendEvent(AppData.DeviceStatus); Log.Fatal(ex, "LỖI KHỞI TẠO GIAO DỊCH"); ShowError("LỖI KHỞI TẠO GIAO DỊCH"); } } private bool InitSerialPorts() { var bInitDE70=InitSerialPortDE70(); var bInitSensor = InitSerialPortSensor(); if (bInitDE70) return true; else { AppData.DeviceStatus.CDMStatus = (int)CDMStatusCode.DISCONNECT_SERIALPORT; APIModels.SendEvent(AppData.DeviceStatus); Log.Fatal("LỖI CỔNG KẾT NỐI"); ShowError("LỖI CỔNG KẾT NỐI, VUI LÒNG KIỂM TRA LẠI CỔNG KẾT NỐI"); return false; } } private bool InitSerialPortSensor() { try { if (serialPortSensor.IsOpen) serialPortSensor.Close(); serialPortSensor.PortName = AppData.SensorPort; serialPortSensor.BaudRate = 9600; serialPortSensor.Parity = Parity.None; serialPortSensor.DataBits = 8; serialPortSensor.StopBits = StopBits.One; serialPortSensor.ReadTimeout = 1000; serialPortSensor.WriteTimeout = 1000; if (bOpenPort) { if (!serialPortSensor.IsOpen) serialPortSensor.Open(); } AppData.ADMINDEVICESTATUS.SensorStatus = "Sensor: OK"; return true; }catch(Exception ex) { AppData.DeviceStatus.SensorStatus = (int)SensorStatusCode.ERROR; AppData.DeviceStatus.Description = ex.Message; APIModels.SendEvent(AppData.DeviceStatus); Log.Information(ex, "LỖI KẾT NỐI SENSOR"); AppData.ADMINDEVICESTATUS.SensorStatus = "Sensor: Error"; } return false; } private bool InitSerialPortDE70() { try { if (serialPortDE70.IsOpen) serialPortDE70.Close(); serialPortDE70.ReadBufferSize = 4096; serialPortDE70.WriteBufferSize = 4096; serialPortDE70.PortName = AppData.CDMPort; serialPortDE70.BaudRate = 9600; serialPortDE70.Parity = Parity.Even; serialPortDE70.DataBits = 8; serialPortDE70.StopBits = StopBits.One; serialPortDE70.ReadTimeout = 10000; serialPortDE70.WriteTimeout = 10000; if (bOpenPort) { if (!serialPortDE70.IsOpen) serialPortDE70.Open(); } return true; } catch(Exception ex) { AppData.DeviceStatus.CDMStatus = (int)CDMStatusCode.DISCONNECT_SERIALPORT; AppData.DeviceStatus.Description = ex.Message; APIModels.SendEvent(AppData.DeviceStatus); Log.Information(ex, "LỖI KẾT NỐI CDM"); AppData.CDMSTATE.CDMStatus = "CDM: Error"; } return false; } private void InitTimers() { warningTimer = new DispatcherTimer(); // 30 seconds warningTimer.Interval = new TimeSpan(0, 0, 30); warningTimer.Tick += WarningTimer_Tick; ; warningTimer.Stop(); endsessionTimer = new DispatcherTimer(); // 60 seconds endsessionTimer.Interval = new TimeSpan(0, 0, 60); endsessionTimer.Tick += EndSessionTimer_Tick; endsessionTimer.Stop(); backToWelcomeTimer = new DispatcherTimer(); backToWelcomeTimer.Interval = new TimeSpan(0, 0, 15); backToWelcomeTimer.Tick += BackToWelcomeTimer_Tick; backToWelcomeTimer.Stop(); sensorTimer = new DispatcherTimer(); sensorTimer.Interval = new TimeSpan(0, 0, 1); //1 seconds sensorTimer.Tick += SensorTimer_Tick; sensorTimer.Start(); } public void StopWelcomeTimer() { if(backToWelcomeTimer != null) backToWelcomeTimer.Stop(); } public void StartWelcomeTimer() { if (backToWelcomeTimer != null) backToWelcomeTimer.Start(); } private void BackToWelcomeTimer_Tick(object? sender, EventArgs e) { mainWindow.ShowWelcomeScreen(); } private void EndSessionTimer_Tick(object? sender, EventArgs e) { Log.Information("7. Timeout starting"); mainWindow.ShowEndSessionScreen(); StopTimers(); DoStoreStart(); bIsCounted = false; DoCountStart(); Task.Run(() => { taskCounting.Wait(); DoStoreStart(); Dispatcher.Invoke(() => { EndSession(COUNTINGSTATE.AUTOEND,"Tự động kết thúc"); }); Log.Information("7. Timeout completed"); }); } private void BackToWelcomeScreen() { StopTimers(); var cdmState = GetCDMState(); var state = GetCDMState(); if (state.IsNotesInEscrow > 0) { mainWindow.ShowInformationScreen("ĐỀ NGHỊ BỎ TIỀN TRONG NGĂN PHỤ HOẶC ẤN LƯU TRỮ ĐỂ TIẾP TỤC", false, true); } else if (state.IsNotesInRejectPocket > 0 || state.IsRejectPocketFull > 0) { mainWindow.ShowInformationScreen("ĐỀ NGHỊ BỎ TIỀN KHÔNG HỢP LỆ ĐỂ TIẾP TỤC", false, true); } else if (state.IsNotesInHopper > 0) { mainWindow.ShowInformationScreen("ĐỀ NGHỊ BỎ TIỀN NGĂN NỘP ĐỂ TIẾP TỤC", false, true); } else if (state.IsCassetteFull != 0) { mainWindow.ShowCollectionScreen(); } else { mainWindow.ShowWelcomeScreen(); } } private void WarningTimer_Tick(object? sender, EventArgs e) { mainWindow.ShowTimeoutScreen(); } public void EndTransaction() { try { AppData.IsInTransaction = false; if (sensorTimer != null) { sensorTimer.Tick -= SensorTimer_Tick; sensorTimer.Stop(); } if (warningTimer != null) { warningTimer.Tick -=WarningTimer_Tick; warningTimer.Stop(); } if (endsessionTimer != null) { endsessionTimer.Tick -=EndSessionTimer_Tick; endsessionTimer.Stop(); } } catch (Exception ex) { } } public void InitLvCountItems() { Dispatcher.Invoke(() => { if (lvCount.Items.Count == 11) { foreach (var item in lvCountItems) { item.Quantity = "0"; } } else { lvCountItems = new ObservableCollection() { new LvCountItem{Name = "500",Quantity = "0"}, new LvCountItem{Name = "1000",Quantity = "0"}, new LvCountItem{Name = "2000",Quantity = "0"}, new LvCountItem{Name = "5000",Quantity = "0"}, new LvCountItem{Name = "10000",Quantity = "0"}, new LvCountItem{Name = "20000",Quantity = "0"}, new LvCountItem{Name = "50000",Quantity = "0"}, new LvCountItem{Name = "100000",Quantity = "0"}, new LvCountItem{Name = "200000",Quantity = "0"}, new LvCountItem{Name = "500000",Quantity = "0"}, new LvCountItem{Name = "Tổng",Quantity = "0",Value="0"}, }; } lvCount.ItemsSource = lvCountItems; }); //lvCountItems[0].Quantity = "10"; } int prevPrinterStatus = -1; int prevSensorStatus = -1; int prevCDMState = -1; private void SensorTimer_Tick(object? sender, EventArgs e) { sensorTimer.IsEnabled = false; try { if (countSensorTimer % 10 == 0) { GetPrinterStatus(); GetCDMStatus(); AppData.GetandExecuteCommands(); AppData.DeviceStatus.Description = AppData.CDMSTATE.CDMStatus; AppData.DeviceStatus.DeviceTime = DateTime.Now; APIModels.SendHealthCheck(AppData.DeviceStatus); } if (countSensorTimer%5==0) { AppData.ADMINDEVICESTATUS.DeviceStatus = AppData.IsInternetOk == false ? "Kết nối Internet: Không" : "Kết nối Internet: OK"; } if (countSensorTimer % 300 == 0) { AppData.ResendData(); } countSensorTimer++; sensorTimer.IsEnabled = false; GetSensorValue(); sensorTimer.IsEnabled = true; } catch (Exception ex) { Log.Fatal(ex, "Sensor_Timer"); } sensorTimer.IsEnabled = true; } private void GetCDMStatus() { if (!AppData.IsInTransaction) { AppData.GetCDMState(); if (AppData.cCmdRsp==null || AppData.cCmdRsp.cmd_result == SendStatus.SEND_DAT_ERR || AppData.cCmdRsp.cmd_result == SendStatus.SEND_ERR) { AppData.CDMSTATE.CDMStatus = "CDM: LỖI"; AppData.DeviceStatus.CDMStatus = (int)CDMStatusCode.DISCONNECT_SERIALPORT; } else { AppData.DeviceStatus.CDMStatus = (int)CDMStatusCode.NORMAL; } if (AppData.DeviceStatus.CDMStatus != prevCDMState) { prevCDMState = AppData.DeviceStatus.CDMStatus; APIModels.SendEvent(AppData.DeviceStatus); } } } private void GetPrinterStatus() { var status = printerManager.GetStatus(); var strPrinterMessage = ""; if (status != null) { bool StsNOPAPER = status.StsNOPAPER; bool StsNEARENDPAP = status.StsNEARENDPAP; if (StsNOPAPER || (StsNEARENDPAP && AppData.IsStopPrinting())) { AppData.DeviceStatus.PrinterStatus = (int)PrinterStatusCode.PAPEROUT; StopTimers(); strPrinterMessage = "MÁY IN: HẾT GIẤY! ĐỀ NGHỊ THAY GIẤY"; ShowError(strPrinterMessage); AppData.ADMINDEVICESTATUS.PrinterStatus = strPrinterMessage; } else if (StsNEARENDPAP) { AppData.UpdatePrinterStatus(true); strPrinterMessage = "MÁY IN: GẦN HẾT GIẤY"; AppData.DeviceStatus.PrinterStatus = (int)PrinterStatusCode.NEARPAPEROUT; AppData.ADMINDEVICESTATUS.PrinterStatus = strPrinterMessage; } else if (status.StsPAPERJAM || status.StsCUTERROR || status.StsOVERTEMP) { strPrinterMessage = "MÁY IN: LỖI"; AppData.DeviceStatus.PrinterStatus = (int)PrinterStatusCode.ERROR; AppData.ADMINDEVICESTATUS.PrinterStatus = strPrinterMessage; } else { AppData.UpdatePrinterStatus(false); strPrinterMessage = "MÁY IN: OK"; AppData.DeviceStatus.PrinterStatus = (int)PrinterStatusCode.NORMAL; AppData.ADMINDEVICESTATUS.PrinterStatus = strPrinterMessage; } } else { strPrinterMessage = "MÁY IN: LỖI"; AppData.DeviceStatus.PrinterStatus = (int)PrinterStatusCode.ERROR; AppData.ADMINDEVICESTATUS.PrinterStatus = strPrinterMessage; } if (AppData.DeviceStatus.PrinterStatus != prevPrinterStatus) { Log.Information(strPrinterMessage); AppData.DeviceStatus.Description = strPrinterMessage; APIModels.SendEvent(AppData.DeviceStatus); prevPrinterStatus = AppData.DeviceStatus.PrinterStatus; } } Stopwatch watch = new Stopwatch(); private void GetSensorValue() { try { int state = 0; if (serialPortSensor.IsOpen == true) { //serialPortSensor.DiscardInBuffer(); //serialPortSensor.DiscardOutBuffer(); serialPortSensor.Write(new byte[] { (byte)'S', 13, 10 }, 0, 3); var buffer = new byte[16]; int n = serialPortSensor.Read(buffer, 0, buffer.Length); for (int i = 1; i < n - 1; i++) { if ((buffer[i] == 13) && (buffer[i + 1] == 10)) { state = buffer[i - 1] - 48; if (bInitialized) { if (state != 0) gridMain.IsEnabled = false; else gridMain.IsEnabled = true; } string strSensorMessage = ""; switch (state) { case 0: strSensorMessage = "NGĂN KÉT: ĐÓNG, NGĂN TÚI: ĐÓNG"; break; case 1: strSensorMessage = "NGĂN KÉT: ĐÓNG, NGĂN TÚI: MỞ"; break; case 2: strSensorMessage = "NGĂN KÉT: MỞ, NGĂN TÚI: ĐÓNG"; break; case 3: strSensorMessage = "NGĂN KÉT: MỞ, NGĂN TÚI: MỞ"; break; } lblStatus.Content = strSensorMessage; if (state!=prevSensorStatus) { AppData.DeviceStatus.Description=strSensorMessage; AppData.DeviceStatus.SensorStatus= state; APIModels.SendEvent(AppData.DeviceStatus); prevSensorStatus = state; } if (state > 0) { if (!bIsMaintain) { bIsMaintain = true; DoMaintaince(); } // TransitionToState("Maintainance"); } else { if(bIsMaintain) { bIsMaintain = false; mainWindow.ShowWelcomeScreen(); } } break; } } // the code that you want to measure comes here watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Debug.WriteLine(elapsedMs); watch.Start(); } } catch (Exception ex) { //Log.Fatal(ex,"GetSensorValue"); //if(serialPortSensor.IsOpen) // serialPortSensor.Close(); //serialPortSensor.Open(); //serialPortSensor.DiscardInBuffer(); //serialPortSensor.DiscardOutBuffer(); InitSerialPortSensor(); } } private void DoMaintaince() { StopTimers(); mainWindow.ShowMaintainanceScreen(); } public int UpdateTotalQuantity() { int total = 0; foreach (var item in lvCountItems) { if (item.Name != "Tổng") { int quantity = 0; if (int.TryParse(item.Quantity, out quantity)) { total += quantity; } } } return total; } public int AutoSerialGet() { try { int ret; ushort seri_num = 0; ushort get_num = 0; bool endflg = false; var countSession = new CountSession(); countSession.IsStored = false; sessions.Add(countSession); while (true) { AppData.WDTCount = 0; ret = cCmdRsp.SendSerialSense(); if (ret == Constants.E_OK) { ret = cCmdRsp.GetSerialNum(out seri_num); if (ret == Constants.E_OK) { // Serial number acquisition if (cCmdRsp.ChkCntEnd()) { endflg = true; } while (get_num < seri_num) { AppData.WDTCount = 0; get_num++; Log.Information($"Serial Idx: {get_num}/{seri_num}"); ret = cCmdRsp.SendGetSerial(get_num); Log.Information($"Serial Status: {cCmdRsp.recv_dat.dat[18]}"); byte noteVal = 0; switch (cCmdRsp.recv_dat.dat[18]) { case 0x00: countSession.TempNotes[0]++; break; case 0x02: //TempNote[1] ++; noteVal = cCmdRsp.recv_dat.dat[17]; Log.Information($"Serial Value: {noteVal}"); switch (noteVal) { case 0x00: countSession.QuantityDenomi[0]++; break; case 0x01: countSession.QuantityDenomi[1]++; break; case 0x02: countSession.QuantityDenomi[2]++; break; case 0x03: countSession.QuantityDenomi[3]++; break; case 0x04: countSession.QuantityDenomi[4]++; break; case 0x05: countSession.QuantityDenomi[5]++; break; case 0x06: countSession.QuantityDenomi[6]++; break; case 0x07: countSession.QuantityDenomi[7]++; break; case 0x08: countSession.QuantityDenomi[8]++; break; case 0x09: countSession.QuantityDenomi[9]++; break; } break; case 0x03: countSession.TempNotes[2]++; break; case 0x0b: countSession.TempNotes[3]++; break; case 0x0c: countSession.TempNotes[4]++; break; } UpdateListViewCountItems(); } //Debug.WriteLine("Ellapsed Time: " + timeSpan.TotalSeconds); if (endflg) { break; } } else { break; } } else { break; } } if (countSession.QuantityDenomi.Sum() == 0 && countSession.TempNotes.Sum() == 0) { sessions.Remove(countSession); } }catch(Exception ex) { Log.Fatal(ex, "AutoSerialGet"); } //Log.Information(JsonConvert.SerializeObject(sessions)); return 0; } private static void UpdateCountSession(CountSession countSession, byte noteVal) { switch (noteVal) { case 0x00: countSession.QuantityDenomi[0]++; break; case 0x01: countSession.QuantityDenomi[1]++; break; case 0x02: countSession.QuantityDenomi[2]++; break; case 0x03: countSession.QuantityDenomi[3]++; break; case 0x04: countSession.QuantityDenomi[4]++; break; case 0x05: countSession.QuantityDenomi[5]++; break; case 0x06: countSession.QuantityDenomi[6]++; break; case 0x07: countSession.QuantityDenomi[7]++; break; case 0x08: countSession.QuantityDenomi[8]++; break; case 0x09: countSession.QuantityDenomi[9]++; break; } } private string GetShortInforFromCountItems() { return JsonConvert.SerializeObject(lvCountItems); } private string GetQuantityFromSessions(List countSessions,bool? btoreFlag=null) { var quantFromSession = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };//500.000->500 foreach (var session in countSessions) { if(btoreFlag == null) { for (int i = 0; i < 10; i++) quantFromSession[i] += session.QuantityDenomi[i]; } else if ((session.IsStored == btoreFlag)) { for (int i = 0; i < 10; i++) quantFromSession[i] += session.QuantityDenomi[i]; } } string str = ""; for (int i = 0; i < quantFromSession.Length; i++) { str += quantFromSession[i] + ","; } str = str.Trim(','); return str; } private bool DoCountStart() { bool bSuccess = true; string currentMethod = MethodBase.GetCurrentMethod().Name; if (bOpenPort) { serialPortDE70.DiscardInBuffer(); serialPortDE70.DiscardOutBuffer(); cCmdRsp.SendXXCmd((byte)Command.CMD_DE_CNTSTART); if (cCmdRsp.recv_dat != null && cCmdRsp.recv_dat.dat[2] != 43) { } do { serialPortDE70.DiscardInBuffer(); serialPortDE70.DiscardOutBuffer(); cCmdRsp.SendXXCmd((byte)Command.CMD_SENSE); } while (cCmdRsp.recv_dat != null && cCmdRsp.recv_dat.dat[1] == 0x09); //SR2 = 0x09 : Counting Status } Thread.Sleep(1000); try { taskCounting = Task.Run(() => { var str = "BEFORE COUNT"; str+="\r\nSTORED: "+ GetQuantityFromSessions(sessions,true); str += "\r\nSTACKER: " + GetQuantityFromSessions(sessions, false); AppData.DeviceStatus.Description = str; APIModels.SendEvent(AppData.DeviceStatus); Log.Information("Before AutoCount: " + GetShortInforFromCountItems()); bIsCounted = false; AutoSerialGet(); bIsCounted = true; Log.Information("After AutoCount: " + GetShortInforFromCountItems()); str = "AFTER COUNT"; str+= "\r\nSTORED: " + GetQuantityFromSessions(sessions, true); str += "\r\nSTACKER: " + GetQuantityFromSessions(sessions, false); AppData.DeviceStatus.Description = str; APIModels.SendEvent(AppData.DeviceStatus); }); } catch (Exception ex) { bSuccess = false; Log.Fatal(ex,currentMethod); } return bSuccess; } private int GetNotes(byte[] cassetData) { int notes = 0; int offset = 14; for (int i = 0; i < 10; i++) { notes += cassetData[2 * i + offset] * 256 + cassetData[2 * i + 1 + offset]; } return notes; } private bool CheckStoreValid(byte[] previousCassetData, byte[] newCassetData,List countSessions) { var quantFromSession = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };//500.000->500 foreach (var session in countSessions) { if ((session.IsStored==false)) { for (int i = 0; i < 10; i++) quantFromSession[i] += session.QuantityDenomi[i]; } } var nPreviousCassetData = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; var nNewCassetData = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int offset = 14; bool bValid = true; for(int i=0;i<10;i++) { nPreviousCassetData[i] = previousCassetData[2*i + offset] * 256 + previousCassetData[2*i + 1 + offset]; nNewCassetData[i]=newCassetData[2*i + offset] * 256 + newCassetData[2*i+1+ offset]; if (nNewCassetData[i] - nPreviousCassetData[i]!=quantFromSession[i]) { bValid = false; break; } } return bValid; } private bool CheckPreStoreValid(byte[] previousCassetData, int maxNotes, List countSessions) { var quantFromSession = 0;//500.000->500 var quantFromCasset = 0; bool bValid = true; foreach (var session in countSessions) { if ((session.IsStored == false)) { for (int i = 0; i < 10; i++) quantFromSession += session.QuantityDenomi[i]; } } int offset = 14; for (int i=0;i<10; i++) { quantFromCasset += previousCassetData[2 * i + offset] * 256 + previousCassetData[2 * i + 1 + offset]; } if (quantFromCasset + quantFromSession > maxNotes) bValid = false; return bValid; } private void UpdateListViewCountItems() { Dispatcher.Invoke(DispatcherPriority.Normal, () => { if (lvCountItems != null && lvCountItems.Count > 0) { double sum = 0; if (sessions != null && sessions.Count > 0) { for (int i = 0; i < 10; i++) { int quantity = 0; for (int j = 0; j < sessions.Count; j++) { quantity += sessions[j].QuantityDenomi[9 - i]; } lvCountItems[i].Quantity = quantity.ToString(); sum += lvCountItems[i].getValue(); } //Update amount of money lvCountItems[10].Quantity = UpdateTotalQuantity().ToString(); lvCountItems[10].Value = sum.ToString(); //Update Notes In Sesion notesInSession.GenuineNotes = 0; notesInSession.RejectNotes = 0; for (int j = 0; j < sessions.Count; j++) { if (sessions[j].IsStored == false) { for (int i = 0; i < 10; i++) { notesInSession.GenuineNotes += sessions[j].QuantityDenomi[9 - i]; } notesInSession.RejectNotes += sessions[j].TempNotes.Sum(); } } } else { for (int i = 0; i < 11; i++) { lvCountItems[i].Quantity = "0"; lvCountItems[i].Value = "0"; } } } }); } public bool DoCheck() { bool bSuccess = true; string currentMethod = MethodBase.GetCurrentMethod().Name; try { var str = "BEFORE CHECK"; str += "\r\nSTORED: " + GetQuantityFromSessions(sessions, true); str += "\r\nSTACKER: " + GetQuantityFromSessions(sessions, false); AppData.DeviceStatus.Description = str; APIModels.SendEvent(AppData.DeviceStatus); Log.Information("Before Check: "+GetShortInforFromCountItems()); serialPortDE70.DiscardInBuffer(); serialPortDE70.DiscardOutBuffer(); cCmdRsp.SendXXCmd((byte)Command.CMD_DE_CANCEL); Log.Information(JsonConvert.SerializeObject(sessions)); sessions.RemoveAll(item=>!item.IsStored); Log.Information(JsonConvert.SerializeObject(sessions)); UpdateListViewCountItems(); Log.Information("After Check: "+GetShortInforFromCountItems()); str = "AFTER CHECK"; str += "\r\nSTORED: " + GetQuantityFromSessions(sessions, true); str += "\r\nSTACKER: " + GetQuantityFromSessions(sessions, false); AppData.DeviceStatus.Description = str; APIModels.SendEvent(AppData.DeviceStatus); } catch (Exception ex) { bSuccess = false; Log.Fatal(ex, currentMethod); } return bSuccess; } private bool WaitUntilCountReady(int nSecondTimeout) { CDMSTATE state = null; int nTimes = 0; bool bSuccess = false; while (true) { state = GetCDMState(); if (state.GetSR2() == 0x07) { bSuccess = true; break; } nTimes++; Thread.Sleep(1000); if ((nSecondTimeout > 0) && nTimes >= nSecondTimeout) break; } return bSuccess; } private bool WaitUntilEnscrowEmpty(int nSecondTimeout) { CDMSTATE state = null; int nTimes = 0; bool bSuccess = false; while(true) { state = GetCDMState(); if (state.IsNotesInEscrow == 0) { bSuccess = true; break; } nTimes++; Thread.Sleep(1000); if ((nSecondTimeout > 0) && nTimes >= nSecondTimeout) break; } return bSuccess; } private bool DoStoreStart() { bool bSuccess = true; printerFlag = true; string currentMethod = MethodBase.GetCurrentMethod().Name; try { serialPortDE70.DiscardInBuffer(); serialPortDE70.DiscardOutBuffer(); //sessions.Add(new CountSession()); // sessions[sessions.Count - 1].QuantityDenomi = (int[])TempQuantity.Clone(); //Debug.WriteLine(quantityStored); var previousCassetData = AppData.GetCassetteData(); var str = "BEFORE STORE \r\n[CASSETTE]" + AppData.GetNotesString(previousCassetData); str += "\r\nSTORED: " + GetQuantityFromSessions(sessions, true); str += "\r\nSTACKER: " + GetQuantityFromSessions(sessions, false); Log.Information(str); AppData.DeviceStatus.Description = str; APIModels.SendEvent(AppData.DeviceStatus); if (CheckPreStoreValid(previousCassetData, AppData.MaxNotes, sessions)) { cCmdRsp.SendXXCmd((byte)Command.CMD_DE_STORESTART); bSuccess = WaitUntilCountReady(10); var newCasstData = AppData.GetCassetteData(); str = "AFTER STORE \r\n[CASSETTE]" + AppData.GetNotesString(newCasstData); Log.Information(str); AppData.DeviceStatus.Description = str; APIModels.SendEvent(AppData.DeviceStatus); bool bValid = CheckStoreValid(previousCassetData, newCasstData, sessions); if (bValid) { if (bSuccess) { foreach (var item in sessions) { item.IsStored = true; } quantityStored = UpdateTotalQuantity(); Log.Information("STORE SUCCESS: " + GetShortInforFromCountItems()); } else { Log.Error("STORE FAIL: " + GetShortInforFromCountItems()); } } else { Dispatcher.Invoke(() => { str = $"PHIÊN GIAO DỊCH KHÔNG HỢP LỆ (SỐ TIỀN GIAO DỊCH KHÔNG KHỚP), VUI LÒNG BÁO CÁO LẠI CHI NHÁNH" + $"\r\n MÃ GD: {AppData.GetTransactionCode()} " + $"\r\nMÁY: {Environment.MachineName}" + $"\r\nMÃ NV: {AppData.CurrentCustomerAccount.CustomerId}"; Log.Information(str); ShowError(str); }); } Thread.Sleep(1000); } else { str = "KÉT ĐÃ ĐẦY ĐỀ NGHỊ LẤY LẠI TIỀN VÀ KẾT THÚC GIAO DỊCH, VUI LÒNG BÁO CÁO LẠI CHI NHÁNH"; Log.Information(str); DoCheck(); EndSession(COUNTINGSTATE.FULLIFSTORE,str); } } catch (Exception ex) { bSuccess = false; Log.Fatal(ex, currentMethod); } return bSuccess; } private bool DoStart() { bool bSuccess = true; InitSession(); string currentMethod = MethodBase.GetCurrentMethod().Name; AppData.IsInTransaction = true; try { serialPortDE70.DiscardInBuffer(); serialPortDE70.DiscardOutBuffer(); cCmdRsp.SendXXCmd((byte)Command.CMD_DE_SENSE); var recvData = cCmdRsp.recv_dat; if (recvData.dat[14] == recvData.dat[16]) { cCmdRsp.SendLock(); } else { cCmdRsp.SendEventFix(recvData.dat[16]); cCmdRsp.SendLock(); } if (cCmdRsp.recv_dat.dat[0]!=0x40) { var strRcvData = cCmdRsp.GetRecvDat(); bSuccess = false; var state = GetCDMState(); var str = $"START_ERROR: {strRcvData}, STATUS: {state.GetFullStatus()}"; Log.Error(str); AppData.DeviceStatus.Description = str; APIModels.SendEvent(AppData.DeviceStatus); } } catch (Exception ex) { bSuccess = false; Log.Fatal(ex, currentMethod); } return bSuccess; } private bool DoEnd() { bool bSuccess = false; var state = GetCDMState(); StopTimers(); Log.Information("CDM State: " + JsonConvert.SerializeObject(state)); var lstEnabledControls = new List { btnEnd, btnCountStart }; if (state.IsNotesInEscrow > 0) { btnEnd.IsEnabled = true; mainWindow.ShowInformationScreen("ĐỀ NGHỊ BỎ TIỀN TRONG NGĂN PHỤ HOẶC ẤN LƯU TRỮ ĐỂ TIẾP TỤC", true,true); } else if (state.IsNotesInRejectPocket > 0 || state.IsRejectPocketFull > 0) { btnEnd.IsEnabled = true; mainWindow.ShowInformationScreen("ĐỀ NGHỊ BỎ TIỀN KHÔNG HỢP LỆ ĐỂ TIẾP TỤC", true, true); } else if(state.IsNotesInHopper>0) { btnEnd.IsEnabled = true; mainWindow.ShowInformationScreen("ĐỀ NGHỊ BỎ TIỀN NGĂN NỘP ĐỂ TIẾP TỤC", true, true); } else { bSuccess = true; AppData.WDTCount = 0; EndSession(); btnStart.IsEnabled = true; btnLogout.IsEnabled = true; ResetTimers(); } return bSuccess; } private bool DoLogout() { bool bSuccess = false; var state = GetCDMState(); Log.Information("CDM State: " + JsonConvert.SerializeObject(state)); InitLvCountItems(); if (state.IsNotesInEscrow > 0) { mainWindow.ShowInformationScreen("ĐỀ NGHỊ BỎ TIỀN TRONG NGĂN PHỤ HOẶC ẤN LƯU TRỮ ĐỂ TIẾP TỤC", true); } else if (state.IsNotesInRejectPocket > 0 || state.IsRejectPocketFull > 0) { mainWindow.ShowInformationScreen("ĐỀ NGHỊ BỎ TIỀN KHÔNG HỢP LỆ ĐỂ TIẾP TỤC", true); } else //if (double.Parse(lvCountItems[10].Value)== 0) { bSuccess = true; ResetSessions(); BackToWelcomeScreen(); } return bSuccess; } private void EndSession(COUNTINGSTATE _CountingState =0, string? strMessage=null) { string currentMethod = MethodBase.GetCurrentMethod().Name; //Remove sessions with store flag is false sessions.RemoveAll(item => !item.IsStored);//Xóa các GD chưa lưu UpdateListViewCountItems(); //Cập nhật lại danh sách hiển thị var totalQuantity = lvCountItems[10].Quantity; var totalValue = lvCountItems[10].Value; try { Log.Information(currentMethod); serialPortDE70.DiscardInBuffer(); serialPortDE70.DiscardOutBuffer(); if (double.Parse(totalValue) > 0) { var data2Send = new CountingData2Send { TransactionCode = AppData.GetTransactionCode(), Sessions = sessions, MachineId = Environment.MachineName, UserId = AppData.CurrentCustomerAccount.CustomerId, MachineTime = DateTime.Now.ToString("yyyyMMddHHmmss"), GenuineNotes = quantityStored, CountingState= (int)_CountingState }; SyncData(data2Send);//Lưu CSDL và đồng bộ //Reset all and ready to next session if (printerFlag == true) { if (double.Parse(totalValue) > 0) PrintReceipt(); printerFlag = false; } String strNotify = $"BẠN VỪA THỰC HIỆN NỘP TIỀN VÀO MÁY CDM:\r\n" + $"SỐ LƯỢNG TỜ: {totalQuantity}\r\n" + $"SỐ TIỀN: {totalValue} VND\r\n"; if (AppData.CurrentCustomerAccount != null) { var strTransactionCode = AppData.GetTransactionCode(); strNotify = "MÃ GD: "+strTransactionCode + "\r\n" + strNotify; } if(strMessage!=null) { strNotify += strMessage; } Dispatcher.Invoke(() => { mainWindow.ShowInformationScreen(strNotify, false, false); }); ResetSessions(); StartWelcomeTimer(); } else if(strMessage!=null)//Không nộp tiền nhưng yêu cầu thông báo trước khi kết thúc { var strNotify = ""; if (AppData.CurrentCustomerAccount != null) { var strTransactionCode = AppData.GetTransactionCode(); strNotify = "MÃ GD: "+strTransactionCode + "\r\n" + strNotify; } if (strMessage != null) { strNotify += strMessage; } Dispatcher.Invoke(() => { mainWindow.ShowInformationScreen(strNotify, false, false); }); ResetSessions(); StartWelcomeTimer(); } else//Không nộp tiền và không có thông báo --> kết thúc luôn { mainWindow.ShowWelcomeScreen(); } if (AppData.CurrentCustomerAccount != null) AppData.CurrentCustomerAccount.TransactionCode = ""; AppData.IsInTransaction = false; //SendData2Server } catch (Exception ex) { Log.Fatal(ex, currentMethod); } } private async Task SyncData(CountingData2Send data2Send) { Log.Information("Saving data to DB: " + JsonConvert.SerializeObject(data2Send)); var history = Save2DB(data2Send); Log.Information("Sending data to server: "+JsonConvert.SerializeObject(data2Send)); bool bSuccess = await APIModels.SendCountingData(data2Send); if (bSuccess) { history.IsSent = true; Update2DB(history); Log.Information("Sending data to server successfully"); } else { Log.Information("Sending data to server failed"); } } public History Save2DB(CountingData2Send data2Send) { var data = JsonConvert.SerializeObject(data2Send); var history = new History { Data = data, DepositTime = DateTime.Now, IsSent = false, UserCode = AppData.CurrentCustomerAccount.CustomerId }; try { using (var db = new CDMDbContext()) { db.Histories.Add(history); db.SaveChanges(); } } catch (Exception ex) { Log.Fatal(ex,"Save2DB Exception"); } return history; } public History Update2DB(History history) { try { using (var db = new CDMDbContext()) { db.Histories.Update(history); db.SaveChanges(); } } catch (Exception ex) { Log.Fatal(ex,"Update2DB Exception"); } return history; } private void ShowError(string strError) { //gridMain.IsEnabled = false; //btnCollect2.Visibility=Visibility.Collapsed; //panelError.Visibility = Visibility.Visible; //lblError.Text = strError; //((MainWindow)Application.Current.MainWindow).ShowWelcomeScreen(); mainWindow.ShowErrorScreen(strError); } public CDMSTATE GetCDMState() { return AppData.GetCDMState(); } private bool InitSession() { try { //Check status var cdmState = GetCDMState(); if (cdmState.IsCassetteFull != 0) { mainWindow.ShowCollectionScreen(); return false; } else if (cdmState.IsNotesInEscrow != 0||cdmState.IsNotesInRejectPocket!=0||cdmState.IsNotesInHopper!=0) { mainWindow.ShowInformationScreen("ĐỀ NGHỊ BỎ TIỀN TRONG CÁC NGĂN ĐỂ TIẾP TỤC"); } else { ResetSessions(); return true; } } catch(Exception ex) { Log.Fatal(ex,"InitSession"); } return false; } private void ResetSessions() { InitLvCountItems(); sessions.Clear(); quantityStored = 0; maxQuantitySheet = 0; cCmdRsp.SendXXCmd((byte)Command.CMD_DE_UNLOCK); } private void PrintReceipt() { Log.Information("PrintReceipt"); var shopName = AppData.CurrentCustomerAccount.Name; var shopCode = AppData.CurrentCustomerAccount.CustomerId; var tradingCode = AppData.GetTransactionCode();// "TRA04052024CDM"; var storeAccountNumber = AppData.CurrentCustomerAccount.CustomerId; var currentTime = DateTime.Now; var printDocument = new PrintDocument(); var strLogoAM= System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logo\\logoAeonmall.png"); var strLogoVietin = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logo\\logoVietin.png"); System.Drawing.Image LogoAeonMall = System.Drawing.Image.FromFile(strLogoAM); System.Drawing.Image LogoVietin = System.Drawing.Image.FromFile(strLogoVietin); printDocument.PrinterSettings.PrinterName = "CUSTOM K80"; printDocument.PrintPage += (sender, e) => { int fontSize = 8; int lineSpace = 20; float marginLeft = 25; float marginTop = 5; float width = 275; float height = 280; float LogoAeonWidth = 90; // Chiều rộng của LogoAeon float LogoAeonHeight = 30; // Chiều cao của LogoAeon float LogoAeonX = marginLeft + 25; // Đặt LogoAeon ở giữa theo chiều ngang float LogoAeonY = marginTop + 10; // Khoảng cách từ mép trên của viền đến LogoAeon float LogoVietinWidth = 90; // Chiều rộng của LogoVietin float LogoVietinHeight = 30; // Chiều cao của LogoVietin float LogoVietinX = marginLeft + 165; // Đặt LogoVietin ở giữa theo chiều ngang float LogoVietinY = marginTop + 10; // Khoảng cách từ mép trên của viền đến LogoVietin e.Graphics.DrawImage(LogoVietin, LogoVietinX, LogoVietinY, LogoVietinWidth, LogoVietinHeight); e.Graphics.DrawImage(LogoAeonMall, LogoAeonX, LogoAeonY, LogoAeonWidth, LogoAeonHeight); e.Graphics.DrawImage(LogoVietin, LogoVietinX, LogoVietinY, LogoVietinWidth, LogoVietinHeight); e.Graphics.DrawImage(LogoAeonMall, LogoAeonX, LogoAeonY, LogoAeonWidth, LogoAeonHeight); e.Graphics.DrawRectangle(new System.Drawing.Pen(System.Drawing.Color.Black, 1), marginLeft, marginTop, width, height); e.Graphics.DrawString("Biên nhận nộp tiền", new Font("Arial", 12, System.Drawing.FontStyle.Bold), System.Drawing.Brushes.Black, new PointF(80, 50)); e.Graphics.DrawString("Mã máy CDM: "+Environment.MachineName, new Font("Arial", fontSize), System.Drawing.Brushes.Black, new PointF(50, lineSpace * 1 + 65)); e.Graphics.DrawString("Thời gian giao dịch: " + currentTime.ToString("dd/MM/yyyy HH:mm:ss"), new Font("Arial", fontSize), System.Drawing.Brushes.Black, new PointF(50, lineSpace * 2 + 65)); e.Graphics.DrawString("Mã giao dịch: " + tradingCode, new Font("Arial", fontSize), System.Drawing.Brushes.Black, new PointF(50, lineSpace * 3 + 65)); e.Graphics.DrawString("Mã Gian hàng: " + shopCode, new Font("Arial", fontSize), System.Drawing.Brushes.Black, new PointF(50, lineSpace * 4 + 65)); e.Graphics.DrawString("Tên Gian hàng: " + shopName, new Font("Arial", fontSize), System.Drawing.Brushes.Black, new PointF(50, lineSpace * 5 + 65)); e.Graphics.DrawString("Số tài khoản gian hàng: " + storeAccountNumber, new Font("Arial", fontSize), System.Drawing.Brushes.Black, new PointF(50, lineSpace * 6 + 65)); e.Graphics.DrawString("Nội dung giao dịch: Nop doanh so tien mat_", new Font("Arial", fontSize), System.Drawing.Brushes.Black, new PointF(50, lineSpace * 7 + 65)); e.Graphics.DrawString(AppData.GetNumberPartFromMerchantCode(shopCode), new Font("Arial", fontSize), System.Drawing.Brushes.Black, new PointF(50, lineSpace * 8 + 65)); e.Graphics.DrawString("Số tiền nộp: " + lvCountItems[10].Value, new Font("Arial", fontSize), System.Drawing.Brushes.Black, new PointF(50, lineSpace * 9 + 65)); e.Graphics.DrawString("*****Xin cám ơn*****", new Font("Arial", 7), System.Drawing.Brushes.Black, new PointF(120, lineSpace * 10 + 65)); // To send raw ESC/POS commands, you'd typically use e.Graphics.DrawString() with the command string, // or for more complex scenarios, directly manipulate the byte stream sent to the printer. }; printDocument.Print(); AppData.UpdatePrintingCountToStatusFile(); } private void UserControl_Unloaded(object sender, RoutedEventArgs e) { EndTransaction(); } public void ResetTimers() { StopTimers(); StartTimers(); } public void StartTimers() { if(warningTimer!=null && endsessionTimer != null) { warningTimer.Start(); endsessionTimer.Start(); } } public void StopTimers() { if(warningTimer!=null && endsessionTimer !=null) { warningTimer.Stop(); endsessionTimer.Stop(); } } private void ResetButtons() { btnStart.IsEnabled = false; btnCountStart.IsEnabled = false; btnCheck.IsEnabled = false; btnStoreStart.IsEnabled = false; btnEnd.IsEnabled = false; btnLogout.IsEnabled = false; } private Button _previousClickedButton = null; private void btnCommon_Click(object sender, RoutedEventArgs e) { var btn = sender as Button; if (_previousClickedButton != null) { _previousClickedButton.BorderBrush = System.Windows.Media.Brushes.Transparent; _previousClickedButton.BorderThickness = new Thickness(1); } // Set the border of the currently clicked button btn.BorderBrush = System.Windows.Media.Brushes.DarkRed; btn.BorderThickness = new Thickness(3); // Update the previously clicked button reference _previousClickedButton = btn; SoundManager.StartButtonPressSound(); // Console.Beep(800, 200); StopTimers(); bool bResult = false; if (btn==btnStart) { Log.Information("Deposit starting"); Log.Information("User: " + AppData.CurrentCustomerAccount.CustomerId); Log.Information("1. Start starting"); ResetButtons(); bResult = DoStart(); if (bResult) { btnCountStart.IsEnabled = true; ResetTimers(); Log.Information("1. Start completed"); } else { btnStart.IsEnabled = true; btnLogout.IsEnabled = true; Log.Information("1. Start failed"); } } else if(btn==btnCountStart) { Log.Information("2. Count starting"); ResetButtons(); bResult = DoCountStart(); Task.Run(() => { taskCounting.Wait(); var state = GetCDMState(); if (state.IsError > 0) { string str = "ĐÃ XẢY RA LỖI TRONG QUÁ TRÌNH NỘP TIỀN"; Log.Information(str); AppData.DeviceStatus.Description = "COUNT_ERROR:"+state.GetFullStatus(); APIModels.SendEvent(AppData.DeviceStatus); DoCheck(); EndSession(COUNTINGSTATE.FULLIFSTORE, str); } else if (state.IsStackerFull>0) { Dispatcher.Invoke(() => { btnCheck.IsEnabled = true; btnStoreStart.IsEnabled = true; ResetTimers(); Log.Information("2. Count completed"); }); } else { Dispatcher.Invoke(() => { btnCountStart.IsEnabled = true; btnCheck.IsEnabled = true; btnStoreStart.IsEnabled = true; ResetTimers(); Log.Information("2. Count completed"); }); } }); } else if(btn==btnCheck) { Log.Information($"3. Check starting"); ResetButtons(); bResult = DoCheck(); btnCountStart.IsEnabled= true; ResetTimers(); if (bResult) Log.Information($"3. Check completed"); else Log.Information($"3. Check failed"); } else if (btn == btnStoreStart) { //TransitionToState("Store"); Log.Information("4. Store starting"); ResetButtons(); bResult = DoStoreStart(); btnEnd.IsEnabled= true; btnCountStart.IsEnabled = true; ResetTimers(); if(bResult) Log.Information("4. Store completed"); else Log.Information("4. Store failed"); } else if (btn == btnEnd) { // TransitionToState("End"); Log.Information("5. End starting"); ResetButtons(); bResult = DoEnd(); //btnStart.IsEnabled = true; //btnLogout.IsEnabled = true; //ResetTimers(); if (bResult) Log.Information("5. End Completed"); else Log.Information("5. End failed"); } else if (btn == btnLogout) { Log.Information("6. Exit starting"); bResult = DoLogout(); if (bResult) Log.Information("6. Exit Completed"); else Log.Information("6. Exit failed"); AppData.IsInTransaction = false; } } } }