625 lines
21 KiB
C#
625 lines
21 KiB
C#
using DE70_CMDv2;
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Linq;
|
|
using SafeBagDE70.API;
|
|
using SafeBagDE70.Model;
|
|
using Serilog;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.ComponentModel;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.ServiceProcess;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Controls;
|
|
|
|
namespace SafeBagDE70
|
|
{
|
|
public static class AppData
|
|
{
|
|
public static string CDMPort = "COM4";
|
|
public static string SensorPort = "COM3";
|
|
public static Version? CurrentVersion = null;
|
|
public static List<CustomerAccount>? customerAccounts = null;
|
|
public static CustomerAccount? CurrentCustomerAccount{get;set;}
|
|
public static CCmdRsp? cCmdRsp=null;
|
|
public static bool IsAuthenticated = false;
|
|
public static bool IsInTransaction = false;
|
|
public static int WDTCount = 0;
|
|
public static ObservableCollection<string> logCollection = new ObservableCollection<string>();
|
|
public static ListView logListView = null;
|
|
public static int MaxLogCount = 500;
|
|
public static int MaxNotes = 300;
|
|
public static string BaseURL = "";
|
|
public static int TenantId = 0;
|
|
public static bool IsInternetOk = false;
|
|
static Task? resendTask = null;
|
|
public static DeviceStatus? _DeviceStatus = null;
|
|
public static DeviceStatus? DeviceStatus
|
|
{
|
|
set { _DeviceStatus = value; }
|
|
get
|
|
{
|
|
if (_DeviceStatus == null)
|
|
{
|
|
InitDeviceStatus();
|
|
}
|
|
else
|
|
{
|
|
_DeviceStatus.DeviceTime = DateTime.Now;
|
|
}
|
|
return _DeviceStatus;
|
|
}
|
|
}
|
|
public static bool bInitUser = false;
|
|
static AppData()
|
|
{
|
|
CDMSTATE = new CDMSTATE();
|
|
ADMINDEVICESTATUS = new ADMINDEVICESTATUS();
|
|
//InitDeviceStatus();
|
|
}
|
|
public static void Init()
|
|
{
|
|
try
|
|
{
|
|
bInitUser = InitUsers();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Fatal(ex, "AppInit: "+ex.Message);
|
|
if(DeviceStatus != null)
|
|
{
|
|
DeviceStatus.Description = "Exception in AppInit: "+ex.Message;
|
|
APIModels.SendEvent(DeviceStatus);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public static void InitDeviceStatus()
|
|
{
|
|
DeviceStatus = new DeviceStatus
|
|
{
|
|
Device = Environment.MachineName,
|
|
TenantId = AppData.TenantId,
|
|
Status = 0,
|
|
CDMStatus = 0,
|
|
PrinterStatus = 0,
|
|
SensorStatus = 0,
|
|
Notes = "",
|
|
OtherError = 0,
|
|
};
|
|
}
|
|
|
|
public static bool InitUsers()
|
|
{
|
|
int retryCount = 0;
|
|
int maxRetries = 20; // Max retries before giving up
|
|
int delay = 5000; // Delay between retries (5 seconds)
|
|
while (retryCount < maxRetries)
|
|
{
|
|
try
|
|
{
|
|
|
|
customerAccounts = new List<CustomerAccount>();
|
|
using (var context = new CDMDbContext())
|
|
{
|
|
var customers = context.Customers;
|
|
foreach (var customer in customers)
|
|
{
|
|
var ca = new CustomerAccount
|
|
{
|
|
Name = customer.TenantName,
|
|
CustomerId = customer.AccountNumber,
|
|
QRCode = customer.AccountNumber,
|
|
PINCode = customer.PinCode
|
|
};
|
|
customerAccounts.Add(ca);
|
|
}
|
|
}
|
|
CurrentCustomerAccount = customerAccounts[0];
|
|
Log.Information("InitUsers thành công");
|
|
bInitUser = true;
|
|
break;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Information($"Retry InitUser: {retryCount}/{maxRetries}");
|
|
retryCount++;
|
|
|
|
if (retryCount >= maxRetries)
|
|
{
|
|
Log.Fatal(ex, "InitUsers: " + ex.Message);
|
|
if (DeviceStatus != null)
|
|
{
|
|
DeviceStatus.Description = "Exception in InitUsers: " + ex.Message;
|
|
APIModels.SendEvent(DeviceStatus);
|
|
}
|
|
break;
|
|
}
|
|
// Wait for the next retry
|
|
Thread.Sleep(delay);
|
|
}
|
|
}
|
|
return bInitUser;
|
|
}
|
|
public static CDMSTATE? CDMSTATE = null;
|
|
public static ADMINDEVICESTATUS? ADMINDEVICESTATUS = null;
|
|
private static DateTime CutOffTime = new DateTime(1, 1, 1, 11, 0, 0); // 11:00 a.m as cut-off time
|
|
|
|
public static string GetNumberPartFromMerchantCode(string merchantCode)
|
|
{
|
|
if (merchantCode == null) return "";
|
|
var match = Regex.Match(merchantCode, @"\d+$");
|
|
string merchantCode_part = match.Value;
|
|
return merchantCode_part;
|
|
}
|
|
public static void CreateNewTransactionCode()
|
|
{
|
|
DateTime transactionDateTime = DateTime.Now;
|
|
|
|
string merchantCode_part = GetNumberPartFromMerchantCode(CurrentCustomerAccount.CustomerId);
|
|
// Adjust transaction date if it's past cut-off time (12:00 noon)
|
|
DateTime prevadjustedDate = CurrentCustomerAccount.TransactionTime.Hour >= CutOffTime.Hour ? transactionDateTime.Date : transactionDateTime.Date.AddDays(-1);
|
|
|
|
DateTime adjustedDate = transactionDateTime.Hour >= CutOffTime.Hour ? transactionDateTime.Date : transactionDateTime.Date.AddDays(-1);
|
|
if ((adjustedDate - prevadjustedDate).Days > 0)
|
|
{
|
|
CurrentCustomerAccount.TransactionCount =1;
|
|
}
|
|
else
|
|
{
|
|
CurrentCustomerAccount.TransactionCount++;
|
|
}
|
|
var transactionCount = CurrentCustomerAccount.TransactionCount;
|
|
string datePart = transactionDateTime.ToString("yyyyMMdd");
|
|
string timePart = transactionDateTime.ToString("HHmmss");
|
|
string transactionCountPart = transactionCount.ToString("D2"); // Ensure 2 digits
|
|
|
|
// Combine all parts to form the transaction ID
|
|
string transactionId = $"{datePart}{timePart}{merchantCode_part}{transactionCountPart}";
|
|
|
|
CurrentCustomerAccount.TransactionCode = transactionId;
|
|
CurrentCustomerAccount.TransactionTime = transactionDateTime;
|
|
}
|
|
public static string GetTransactionCode()
|
|
{
|
|
if (CurrentCustomerAccount != null)
|
|
return CurrentCustomerAccount.TransactionCode;
|
|
else
|
|
return "";
|
|
}
|
|
public static CDMSTATE? GetCDMState()
|
|
{
|
|
try
|
|
{
|
|
if (cCmdRsp != null)
|
|
{
|
|
cCmdRsp.SendDeSense();
|
|
string strSend = cCmdRsp.GetSendDat(false);
|
|
string strRecv = cCmdRsp.GetRecvDat();
|
|
Log.Information($"[SEND] {strSend}");
|
|
Log.Information($"[RECV] {strRecv}");
|
|
var data = cCmdRsp.recv_dat.dat;
|
|
if (AppData.CDMSTATE != null)
|
|
{
|
|
AppData.CDMSTATE.IsCassetteFull = data[17] & 0x08;
|
|
AppData.CDMSTATE.IsNotesInEscrow = data[4] & 0x01;
|
|
AppData.CDMSTATE.IsRejectPocketFull = data[3] & 0x40;
|
|
AppData.CDMSTATE.IsNotesInRejectPocket = data[3] & 0x10;
|
|
AppData.CDMSTATE.IsNotesInHopper = data[3] & 0x01;
|
|
AppData.CDMSTATE.IsStackerFull = (data[2] == 0x43?1:0);
|
|
|
|
if (data[0] == 0x40 && (data[1] == 0x07 || data[1]==0x09))
|
|
AppData.CDMSTATE.IsError = 0;
|
|
else
|
|
AppData.CDMSTATE.IsError = 1;
|
|
|
|
AppData.CDMSTATE.RequestTime = DateTime.Now;
|
|
AppData.CDMSTATE.UpdateCDMStatus(cCmdRsp.recv_dat);
|
|
}
|
|
|
|
}
|
|
return AppData.CDMSTATE;
|
|
}
|
|
catch (Exception ex) {
|
|
Log.Fatal(ex, "GetCDMState");
|
|
return null;
|
|
}
|
|
|
|
}
|
|
public static byte[] GetCassetteData()
|
|
{
|
|
cCmdRsp.SendXXCmd((byte)Command.CMD_DE_READ_CASSETTE);
|
|
var data = cCmdRsp.recv_dat.dat;
|
|
|
|
StringBuilder str = new StringBuilder();
|
|
var recv_dat = cCmdRsp.recv_dat;
|
|
|
|
AppData.DeviceStatus.Notes = GetNotesString(recv_dat.dat);
|
|
str.Append("DATA:");
|
|
for (int i = 0; i < recv_dat.leng - 1; i++)
|
|
{
|
|
var dat = string.Format("{0:X2} ", recv_dat.dat[i]);
|
|
str.Append(dat);
|
|
}
|
|
Log.Information("[CASSETTE]" + str.ToString());
|
|
return (byte[])data.Clone();
|
|
}
|
|
public static string GetNotesString(byte[] cassetData)
|
|
{
|
|
int notes = 0;
|
|
int offset = 14;
|
|
string str = "";
|
|
for (int i = 0; i < 10; i++)
|
|
{
|
|
notes = cassetData[2 * i + offset] * 256 + cassetData[2 * i + 1 + offset];
|
|
str += notes + ",";
|
|
}
|
|
return str.Trim(',');
|
|
}
|
|
public static void ResendData()
|
|
{
|
|
if (!AppData.IsInTransaction && AppData.IsInternetOk)
|
|
{
|
|
|
|
if (resendTask == null || resendTask.IsCompleted)
|
|
{
|
|
resendTask = Task.Run(async () =>
|
|
{
|
|
try
|
|
{
|
|
using (var context = new CDMDbContext())
|
|
{
|
|
var startTime = DateTime.Now.Date.AddDays(-2).Date;
|
|
var unsentHist = context.Histories
|
|
.Where(x => x.DepositTime >= startTime)
|
|
.Where(x => ((x.IsSent == null || x.IsSent == false)))
|
|
.ToList();
|
|
foreach (var item in unsentHist)
|
|
{
|
|
var data2Send = JsonConvert.DeserializeObject<CountingData2Send>(item.Data);
|
|
var bResult = await APIModels.SendCountingData(data2Send);
|
|
if (bResult)
|
|
{
|
|
item.IsSent = true;
|
|
context.Update(item);
|
|
context.SaveChanges();
|
|
Log.Information("Resend: " + item.Data + " successfully");
|
|
}
|
|
else
|
|
{
|
|
Log.Error("Resend: " + item.Data + " failed");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Fatal(ex, "Resend failed");
|
|
}
|
|
});
|
|
}
|
|
else
|
|
{
|
|
Log.Information("Previous resend are running");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Log.Error($"Resend could not start IsInTransaction: {AppData.IsInTransaction} IsInternetOk: {AppData.IsInternetOk}");
|
|
}
|
|
}
|
|
|
|
}
|
|
public class CustomerAccount
|
|
{
|
|
public string? Name { get; set; }
|
|
public string? CustomerId { get; set; }
|
|
public string? QRCode { get; set; }
|
|
public string? PINCode { get; set; }
|
|
public int TransactionCount { get; set; } = 1;
|
|
public DateTime TransactionTime { get; set; }
|
|
public string TransactionCode { get; set; }
|
|
}
|
|
public class CountSession
|
|
{
|
|
public CountSession()
|
|
{
|
|
for (int i = 0; i < QuantityDenomi.Count(); i++)
|
|
{
|
|
QuantityDenomi[i] = 0;
|
|
}
|
|
for (int i = 0; i < SumDenomi.Count(); i++)
|
|
{
|
|
SumDenomi[i] = 0;
|
|
}
|
|
for (int i = 0; i < TempNotes.Count(); i++)
|
|
{
|
|
TempNotes[i] = 0;
|
|
}
|
|
}
|
|
|
|
public int[] QuantityDenomi { get; set; } = new int[10];
|
|
public int[] SumDenomi { get; set; } = new int[10];
|
|
public bool IsStored = false;
|
|
public int[] TempNotes { get; set; } = new int[5];
|
|
|
|
}
|
|
|
|
public class CountingData2Send
|
|
{
|
|
public string? TransactionCode { get; set; }
|
|
public List<CountSession>? Sessions { get; set; }
|
|
public string? UserId { get; set; }
|
|
public string? MachineId { get; set; }
|
|
public string? MachineTime { get; set; }
|
|
public int RejectNotes { get; set; }
|
|
public int GenuineNotes { get; set; }
|
|
public int UnfitNotes { get; set; }
|
|
public int CounterfeitNotes { get; set; }
|
|
public int SuspendNotes { get; set; }
|
|
public int CountingState { get; set; }//0-Normal End, 1-Timeout End
|
|
}
|
|
|
|
public class NotesInSession : INotifyPropertyChanged
|
|
{
|
|
|
|
private int _GenuineNotes;
|
|
public int GenuineNotes
|
|
{
|
|
get
|
|
{
|
|
return _GenuineNotes;
|
|
}
|
|
set
|
|
{
|
|
if (_GenuineNotes != value)
|
|
{
|
|
_GenuineNotes = value;
|
|
OnPropertyChanged(nameof(GenuineNotes));
|
|
}
|
|
}
|
|
}
|
|
private int _RejectNotes;
|
|
public int RejectNotes
|
|
{
|
|
get
|
|
{
|
|
return _RejectNotes;
|
|
}
|
|
set
|
|
{
|
|
if (_RejectNotes != value)
|
|
{
|
|
_RejectNotes = value;
|
|
OnPropertyChanged(nameof(RejectNotes));
|
|
}
|
|
}
|
|
}
|
|
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
protected virtual void OnPropertyChanged(string propertyName)
|
|
{
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
}
|
|
}
|
|
public enum COUNTINGSTATE
|
|
{
|
|
NORMAL=0,
|
|
AUTOEND=1,
|
|
FULLIFSTORE=2
|
|
}
|
|
public class ADMINDEVICESTATUS : INotifyPropertyChanged
|
|
{
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
protected virtual void OnPropertyChanged(string propertyName)
|
|
{
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
}
|
|
private string? _PrinterStatus;
|
|
public string? PrinterStatus
|
|
{
|
|
get
|
|
{
|
|
return _PrinterStatus;
|
|
}
|
|
set
|
|
{
|
|
if (_PrinterStatus != value)
|
|
{
|
|
_PrinterStatus = value;
|
|
|
|
OnPropertyChanged(nameof(PrinterStatus));
|
|
}
|
|
}
|
|
}
|
|
private string? _SensorStatus;
|
|
public string? SensorStatus
|
|
{
|
|
get
|
|
{
|
|
return _SensorStatus;
|
|
}
|
|
set
|
|
{
|
|
if (_SensorStatus != value)
|
|
{
|
|
_SensorStatus = value;
|
|
|
|
OnPropertyChanged(nameof(SensorStatus));
|
|
}
|
|
}
|
|
}
|
|
private string? _DeviceStatus;
|
|
public string? DeviceStatus
|
|
{
|
|
get
|
|
{
|
|
return _DeviceStatus;
|
|
}
|
|
set
|
|
{
|
|
if (_DeviceStatus != value)
|
|
{
|
|
_DeviceStatus = value;
|
|
|
|
OnPropertyChanged(nameof(DeviceStatus));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
public class CDMSTATE : INotifyPropertyChanged
|
|
{
|
|
public int IsCassetteFull = 0;
|
|
public int IsNotesInEscrow = 0;
|
|
public int IsRejectPocketFull = 0;
|
|
public int IsNotesInRejectPocket = 0;
|
|
public int IsNotesInHopper = 0;
|
|
public int IsStackerFull = 0;
|
|
public int IsError = 0;
|
|
public RecvData? RecvDat = null;
|
|
public byte GetSR1()
|
|
{
|
|
if (RecvDat != null)
|
|
return RecvDat.dat[0];
|
|
return 0;
|
|
}
|
|
public byte GetSR2()
|
|
{
|
|
if (RecvDat != null)
|
|
return RecvDat.dat[1];
|
|
return 0;
|
|
}
|
|
public byte GetSR3()
|
|
{
|
|
if (RecvDat != null)
|
|
return RecvDat.dat[2];
|
|
return 0;
|
|
}
|
|
public string GetSRStatus()
|
|
{
|
|
if (RecvDat != null)
|
|
return "SR1/2/3: " + AppData.cCmdRsp.GetSR1Summary(RecvDat.dat[0]) + ", " + AppData.cCmdRsp.GetSR2Summary(RecvDat.dat[1]) + ", " + AppData.cCmdRsp.GetSR3Summary(RecvDat.dat[2]);
|
|
else
|
|
return "";
|
|
}
|
|
public string GetDtatus()
|
|
{
|
|
string strStatus = "";
|
|
if (RecvDat != null)
|
|
{
|
|
if(RecvDat.leng>8)
|
|
{
|
|
var dat=RecvDat.dat;
|
|
strStatus += "D1: "+AppData.cCmdRsp.GetD1Summary(dat[3]);
|
|
strStatus += "\r\nD2: "+AppData.cCmdRsp.GetD2Summary(dat[4]);
|
|
strStatus += "\r\nD3: " + AppData.cCmdRsp.GetD3Summary(dat[5]);
|
|
strStatus += "\r\nD4: " + AppData.cCmdRsp.GetD4Summary(dat[6]);
|
|
strStatus += "\r\nD5: " + AppData.cCmdRsp.GetD5Summary(dat[7]);
|
|
strStatus += "\r\nD6: " + AppData.cCmdRsp.GetD6Summary(dat[8]);
|
|
}
|
|
}
|
|
return strStatus;
|
|
}
|
|
public string GetSStatus()
|
|
{
|
|
string strStatus = "";
|
|
if (RecvDat != null)
|
|
{
|
|
if (RecvDat.leng > 18)
|
|
{
|
|
var dat = RecvDat.dat;
|
|
strStatus += "S1: "+ AppData.cCmdRsp.GetS1Summary(dat[17]);
|
|
strStatus += "\r\nS2: " + AppData.cCmdRsp.GetS2Summary(dat[18]);
|
|
}
|
|
}
|
|
return strStatus;
|
|
}
|
|
public string GetFullStatus()
|
|
{
|
|
string strStatus = "";
|
|
strStatus = GetSRStatus();
|
|
strStatus += "\r\n"+GetDtatus();
|
|
strStatus += "\r\n"+GetSStatus();
|
|
return strStatus;
|
|
}
|
|
public void UpdateCDMStatus(RecvData recv_data)
|
|
{
|
|
RecvDat=recv_data;
|
|
if (AppData.cCmdRsp != null) {
|
|
CDMStatus = RequestTime.ToString("yyyy/MM/dd HH:mm:ss ") + GetSRStatus();
|
|
if (recv_data.leng > 18)
|
|
{
|
|
|
|
}
|
|
}
|
|
}
|
|
private string? _CDMStatus;
|
|
public string? CDMStatus
|
|
{
|
|
get
|
|
{
|
|
return _CDMStatus;
|
|
}
|
|
set
|
|
{
|
|
if (_CDMStatus != value)
|
|
{
|
|
_CDMStatus = value;
|
|
|
|
OnPropertyChanged(nameof(CDMStatus));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public DateTime RequestTime = DateTime.Now;
|
|
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
protected virtual void OnPropertyChanged(string propertyName)
|
|
{
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
}
|
|
}
|
|
public class DeviceStatus
|
|
{
|
|
public int TenantId { get; set; }
|
|
public string Device { get; set; }
|
|
public int Status { get; set; }
|
|
public DateTime DeviceTime { get; set; }
|
|
public int CDMStatus { get; set; }
|
|
public int PrinterStatus { get; set; }
|
|
public int SensorStatus { get; set; }
|
|
public int OtherError { get; set; }
|
|
public string? Notes { get; set; }
|
|
public string? TransactionCode { get; set; }
|
|
public string Description { get; set; }
|
|
}
|
|
public enum DeviceStatusCode {
|
|
NORMAL=0,
|
|
ERROR=1
|
|
}
|
|
public enum PrinterStatusCode
|
|
{
|
|
NORMAL = 0,
|
|
NEARPAPEROUT = 1,
|
|
PAPEROUT=2
|
|
}
|
|
public enum SensorStatusCode
|
|
{
|
|
NORMAL = 0,
|
|
ERROR = 4
|
|
}
|
|
public enum CDMStatusCode
|
|
{
|
|
NORMAL = 0,
|
|
DISCONNECT_SERIALPORT=1,
|
|
}
|
|
}
|