using Edge.Core.Processor; using Edge.Core.IndustryStandardInterface.Pump; using Dfs.WayneChina.HengshanPayTerminal; using Dfs.WayneChina.HengshanPayTerminal.MessageEntity; using Dfs.WayneChina.HengshanPayTerminal.MessageEntity.Incoming; using System; using System.Collections.Generic; using System.Text; using System.Linq; using Dfs.WayneChina.HengshanPayTerminal.Support; using Applications.FDC; using Edge.Core.Database; using FdcServerHost; using Dfs.WayneChina.CardTrxManager.TrxSubmitter; using Dfs.WayneChina.CardTrxManager; using System.Threading.Tasks; using Dfs.WayneChina.IPosPlus.ServiceClient; using Dfs.WayneChina.SpsDataCourier; using NLog.LayoutRenderers.Wrappers; using Edge.Core.Configuration; using Edge.Core.Processor.Dispatcher.Attributes; namespace Dfs.WayneChina.IPosPlus { /// /// Serves as an application controller containing the terminal handlers and terminal managers, /// as well as the database access manager. /// [MetaPartsDescriptor( "lang-zh-cn:iPosPlus应用lang-en-us:iPOS Plus App", "lang-zh-cn:用于管理加油机IC卡终端控制" + "lang-en-us:Used for managing all IC card terminals on dispensers across the site", new[] { "lang-zh-cn:加油机lang-en-us:Pump", "lang-zh-cn:IfsfFdcServerlang-en-us:IfsfFdcServer" })] public class IPosPlusApp : IAppProcessor { #region Fields private SpsDbManager.SpsManager spsManager; private List paymentTerminalHandlers = new List(); private List terminalManagers = new List(); private NLog.Logger logger = NLog.LogManager.LoadConfiguration("NLog.config").GetLogger("IPosPlusApp"); private PosInitialData initalData; private object syncObj = new object(); private FdcServerHostApp fdcServerApp; private string fuelProductMapping; private IEnumerable nozzleProductConfig = Configurator.Default.NozzleExtraInfoConfiguration.Mapping; private Dictionary fuelMappingDict = new Dictionary(); private List customerFillings = new List(); private List submitters = new List(); private CloudCredential cloudCredential; private bool onlineDiscount = false; private int discountTimeout = 3; private string promotionCategories = string.Empty; private Dictionary fuelNameDict = new Dictionary(); private Dictionary fuelCodePriceDict = new Dictionary(); public int CardAppType { get; } private int interval; private Dictionary pumpPriceDict = new Dictionary(); private object dictSync = new object(); private SpsDataCourierApp spsDataCourierApp; private StoreForwardManager sfManager; private int stationNo = 0; private string stationName = ""; private int mode = 1; private int reservedBalance = 20; #endregion #region MySQL connection string private string _mysqlConn = "server=localhost;port=3306;user=root;password=HS1205;database=sps_db;TreatTinyAsBoolean=false;Convert Zero Datetime=True"; #endregion #region Constructor [ParamsJsonSchemas("appCtorParamsJsonSchema")] public IPosPlusApp(PosAppContructorParameterV1 config) { PosId = config.PosId; _mysqlConn = FormatConnectionString(config.ConnectionString); spsManager = new SpsDbManager.SpsManager(_mysqlConn); //Current Business Unit Id. var fakeBuId = Configurator.Default .MetaConfiguration .Parameter? .FirstOrDefault(p => p.Name.Equals("serialNumber", StringComparison.OrdinalIgnoreCase))?.Value; cloudCredential = new CloudCredential { UserName = config.Username, Password = config.Password, AuthServiceBaseUrl = config.AuthServiceBaseUrl, TransactionServiceBaseUrl = config.TransactionServiceBaseUrl, DiscountServiceBaseUrl = config.DiscountServiceBaseUrl, DeviceSN = config.DeviceSN, CurrentBuId = fakeBuId }; onlineDiscount = config.OnlineDiscount; discountTimeout = config.DiscountTimeout; if (this.onlineDiscount) { DiscountServiceClient = new DiscountServiceClient(this, cloudCredential, promotionCategories, discountTimeout); } promotionCategories = config.PromoCategories; fuelProductMapping = string.Join(";", config.FuelMappingArr.Select(m => $"{m.Barcode}:{m.FuelNo}")); CardAppType = config.CardAppType; interval = config.Interval; mode = config.PumpMode; stationNo = config.StationNo; stationName = config.StationName; reservedBalance = config.ReservedBalance; SetFuelProductMapping(); pumpPriceDict.Clear(); sfManager = new StoreForwardManager(cloudCredential); } public IPosPlusApp(int posId, string username, string password, string authServiceBaseUrl, string transactionServiceBaseUrl, string discountServiceBaseUrl, bool onlineDiscount, int discountTimeout, string deviceSN, string promoCategories, List fuelMappingArr,/*string fuelMapping,*/ int cardAppType, int reservedBalance, int interval, SpsDbConnectionSetting connectionString) { PosId = posId; _mysqlConn = FormatConnectionString(connectionString);//connectionString; spsManager = new SpsDbManager.SpsManager(_mysqlConn); //Current Business Unit Id. var fakeBuId = Configurator.Default .MetaConfiguration .Parameter? .FirstOrDefault(p => p.Name.Equals("serialNumber", StringComparison.OrdinalIgnoreCase))?.Value; cloudCredential = new CloudCredential { UserName = username, Password = password, AuthServiceBaseUrl = authServiceBaseUrl, TransactionServiceBaseUrl = transactionServiceBaseUrl, DiscountServiceBaseUrl = discountServiceBaseUrl, DeviceSN = deviceSN, CurrentBuId = fakeBuId }; this.onlineDiscount = onlineDiscount;//Convert.ToBoolean(onlineDiscount); this.discountTimeout = discountTimeout; promotionCategories = promoCategories; if (this.onlineDiscount) { DiscountServiceClient = new DiscountServiceClient(this, cloudCredential, promotionCategories, discountTimeout); } fuelProductMapping = string.Join(";", fuelMappingArr.Select(m => $"{m.Barcode}:{m.FuelNo}")); //fuelMapping; CardAppType = cardAppType; this.interval = interval; this.reservedBalance = reservedBalance; SetFuelProductMapping(); pumpPriceDict.Clear(); sfManager = new StoreForwardManager(cloudCredential); } private string FormatConnectionString(SpsDbConnectionSetting spsDbConnectionSetting) { return $"server={spsDbConnectionSetting.Server};port={spsDbConnectionSetting.Port};uid={spsDbConnectionSetting.Username};password={spsDbConnectionSetting.Password};database=sps_db;TreatTinyAsBoolean=false;Convert Zero Datetime=true;"; } #endregion #region IApplication interface implementation public string MetaConfigName { get; set; } public void Init(IEnumerable processors) { foreach (dynamic p in processors) { if (p is IAppProcessor) { FdcServerHostApp fdcServer = p as FdcServerHostApp; if (fdcServer != null) fdcServerApp = p; SpsDataCourierApp dataCourier = p as SpsDataCourierApp; if (dataCourier != null) spsDataCourierApp = dataCourier; continue; } var handler = p.Context.Handler; if (handler is HengshanPayTermHandler) { paymentTerminalHandlers.Add(handler); } } SetupTerminalManagers(); SetupTransactionSubmitters(); GetInitialData(); GetStationInfo(); if (fdcServerApp != null) { fdcServerApp.OnCurrentFuellingStatusChange += FdcServerApp_OnCurrentFuellingStatusChange; } } private bool UpsertSpsConfig() { if (fdcServerApp == null) { logger.Error($"Could not get FdcServer instance"); return false; } var allNozzleExtraInfo = fdcServerApp.GetNozzleExtraInfos(); var productNames = allNozzleExtraInfo.Select(n => n.ProductName).Distinct().ToList(); //filter out the product names foreach (var item in productNames) { var tank = allNozzleExtraInfo.FirstOrDefault(n => n.ProductName == item)?.TankNumber; logger.Info($"Distinct product name: {item}, related tank: {tank}"); } //filter out the tanks var tanks = allNozzleExtraInfo.Select(n => n.TankNumber).Distinct(); foreach (var item in tanks) { logger.Info($"Distinct tank number: {item}"); } var siteProducts = allNozzleExtraInfo.Select(n => new { Barcode = n.ProductBarcode, Name = n.ProductName }).ToList(); var fuelBarcodes = allNozzleExtraInfo.Select(n => n.ProductBarcode).Distinct().ToList(); if (fuelBarcodes.Count > tanks.Count()) { logger.Error($"More fuel product types, less tanks, abort!"); return false; } foreach (var product in siteProducts) { logger.Info($"Update product: {product.Barcode}, {product.Name}"); var fuelCode = fuelMappingDict[product.Barcode]; // Code for fuel product, e.g. 1021, 2001 string fuelClassNo = "1000"; if (fuelCode >= 1000 && fuelCode < 2000) fuelClassNo = "1000"; else if (fuelCode >= 2000) fuelClassNo = "2000"; spsManager.AddOrUpdateFuelProduct(Convert.ToString(fuelCode), fuelClassNo, product.Name, 999); } //Tank product var tankProducts = new Dictionary(); foreach (var tank in tanks) { //product barcode for the tank var productBarcode = allNozzleExtraInfo.First(n => n.TankNumber == tank.Value).ProductBarcode; if (!tankProducts.ContainsKey(tank.Value)) { string fuelNo = Convert.ToString(fuelMappingDict[productBarcode]); logger.Info($"Add to tankProducts Dict, tank.value: {tank.Value}, fuelno: {fuelNo}"); tankProducts.Add(tank.Value, fuelNo); // tank_no, fuel_no } } foreach (var item in tankProducts) { spsManager.AddOrUpdateTankConfig(item.Key, item.Value); logger.Info($"add or update tank config: {item.Key}, {item.Value}"); } foreach (var tankProduct in tankProducts) { logger.Info($"tank id: {tankProduct.Key}, tank product code: {tankProduct.Value}"); } // filter out the pumps var pumps = allNozzleExtraInfo.Select(n => n.PumpId).Distinct(); foreach (var pump in pumps) { logger.Info($"Distinct pump id: {pump}"); foreach (var ptHandler in paymentTerminalHandlers) { if (ptHandler.AssociatedPumpIds.Contains(pump)) { int serialPort = 4; string portName = ptHandler.CommIdentity; logger.Info($"Communicator identity: {portName}"); if (!string.IsNullOrEmpty(portName)) { string name = ""; for (int i = 0; i < portName.Length; i++) { if (Char.IsDigit(portName[i])) name += portName[i]; } if (name.Length > 0) { int.TryParse(name, out serialPort); if (serialPort == 0) serialPort = 4; } if (portName.Contains('.')) { string[] sections = portName.Split(':'); name = sections.LastOrDefault(); int.TryParse(name, out serialPort); int originalPort = serialPort; serialPort = originalPort % 100; logger.Info($"Parsed with dot, original: {originalPort} serialPort: {serialPort}"); if (serialPort == 0) serialPort = 4; } } else { serialPort = ptHandler.AssociatedPumpIds.Max(); } var subAddress = ptHandler.GetSubAddressForPump(pump); logger.Info($"Sub Address: {subAddress}, COM: {serialPort} for Pump: {pump}"); spsManager.AddOrUpdatePump(mode, Convert.ToByte(pump), serialPort, Convert.ToByte(subAddress), 999999); logger.Info($"Updating pump: {pump}, sub address: {subAddress}"); } } } foreach (var nozzleExtraInfo in allNozzleExtraInfo) { logger.Info($"PumpId: {nozzleExtraInfo.PumpId}, NozzleLogicalId: {nozzleExtraInfo.NozzleLogicalId}, " + $"SiteLevelNozzleId: {nozzleExtraInfo.SiteLevelNozzleId}, ProductBarcode: {nozzleExtraInfo.ProductBarcode}, " + $"ProductName: {nozzleExtraInfo.ProductName}, TankNumber: {nozzleExtraInfo.TankNumber}"); byte nozzleId = Convert.ToByte(nozzleExtraInfo.SiteLevelNozzleId); byte pumpId = Convert.ToByte(nozzleExtraInfo.PumpId); byte tankId = Convert.ToByte(nozzleExtraInfo.TankNumber); string fuelNo = tankProducts[nozzleExtraInfo.TankNumber.Value]; spsManager.AddOrUpdateNozzle(nozzleId, pumpId, tankId, fuelNo); logger.Info($"Updating NozzleId: {nozzleId}, PumpId: {pumpId}, TankId: {tankId}, FuelNo: {fuelNo}"); } spsManager.UpdateGeneralInfoVersion(); spsManager.UpdateFuelPriceVersion(); logger.Info($"Updating station no: {stationNo}, station name: {stationName}"); spsManager.UpdateStationInfo(stationNo, stationName); return true; } private void FdcServerApp_OnCurrentFuellingStatusChange(object sender, FdcServerTransactionDoneEventArg e) { if (e.Transaction.Finished) { InfoLog($"There is a finished filling, ReleaseToken: {e.ReleaseToken}, PumpId: {e.Transaction.Nozzle.PumpId}," + $" LogicalNozzleId: {e.Transaction.Nozzle.LogicalId}, SequenceNo: {e.Transaction.SequenceNumberGeneratedOnPhysicalPump}"); Task.Run(async () => await HandleCustomerCardFillings(e)); } } //初步定位在这触发 private async Task HandleCustomerCardFillings(FdcServerTransactionDoneEventArg e) { int nozzleNoForCurrentTrx = e.Transaction.Nozzle.PumpId; byte currentPumpId = Convert.ToByte(e.Transaction.Nozzle.PumpId); var pth = paymentTerminalHandlers.First(h => h.AssociatedPumpIds.Contains(currentPumpId)); if (pth != null) { var nozzleNos = pth.PumpSiteNozzleNoDict[currentPumpId]; foreach (var item in nozzleNos) { if (pth.NozzleLogicIdDict[item] == e.Transaction.Nozzle.LogicalId) { nozzleNoForCurrentTrx = item; } } } //调整当前加油记录List 加上日期的筛选 -45天前的记录 var filling = customerFillings.OrderByDescending(p => p.StartTime).FirstOrDefault(f => f.SequenceNo == e.Transaction.SequenceNumberGeneratedOnPhysicalPump && f.PumpId == e.Transaction.Nozzle.PumpId && f.NozzleId == nozzleNoForCurrentTrx && f.StartTime > DateTime.Now.AddDays(-45)); if (filling != null) { InfoLog("Locking transaction"); var lockedTrx = await fdcServerApp.LockFuelSaleTrxAndNotifyAllFdcClientsAsync(100, e.Transaction.Nozzle.PumpId, filling.SequenceNo, e.ReleaseToken.Value); if (lockedTrx == null) { InfoLog("Amazing, failed to lock transaction in FdcServer, try again in 100 ms"); await Task.Delay(100); lockedTrx = await fdcServerApp.LockFuelSaleTrxAndNotifyAllFdcClientsAsync(100, e.Transaction.Nozzle.PumpId, filling.SequenceNo, e.ReleaseToken.Value); if (lockedTrx == null) { InfoLog("Locking transaction failed in second try"); await Task.Delay(100); lockedTrx = await fdcServerApp .LockFuelSaleTrxAndNotifyAllFdcClientsAsync(100, e.Transaction.Nozzle.PumpId, filling.SequenceNo, e.ReleaseToken.Value); } } InfoLog("Ready to submit the customer card transaction!"); var submitter = GetSubmitter(filling.PumpId); if (submitter != null) { InfoLog("Grabbed instance of submitter"); var cardAccountInfo = spsManager.GetCardAccountInfo(filling.CardNo); var result = await submitter.SubmitTrxAsync(new ClientTrxInfo { PumpId = filling.PumpId, NozzleId = 1, SiteNozzleNo = filling.NozzleId,//filling.PumpId, Barcode = GetBarcode(filling.FuelProductCode), Volume = Convert.ToDecimal(filling.Volume) / 100, Amount = Convert.ToDecimal(filling.FillingAmount) / 100, PayAmount = Convert.ToDecimal(filling.PayAmount) / 100, UnitPrice = Convert.ToDecimal(filling.UnitPrice) / 100, CardNo = filling.CardNo, CurrentCardBalance = Convert.ToDecimal(filling.CardBalance) / 100, FdcSqNo = e.ReleaseToken.Value, SeqNo = filling.SequenceNo, FuelingStartTime = filling.StartTime, FuelingFinishedTime = filling.EndTime, VolumeTotalizer = Convert.ToDecimal(filling.VolumeTotal) / 100, CardHolder = cardAccountInfo?.Holder, AccountName = cardAccountInfo?.BelongTo }); InfoLog($"Submit successfully? {result}"); if (result) { InfoLog("Clearing transaction"); await fdcServerApp.ClearFuelSaleTrxAndNotifyAllFdcClientsAsync(e.Transaction.Nozzle.PumpId, filling.SequenceNo.ToString(), e.ReleaseToken.Value, "100"); //After uploading, remove it. customerFillings.Remove(filling); } } } } public void AddCustomerCardFilling(FillingInfo fillingInfo) { customerFillings.Add(fillingInfo); } private void GetInitialData() { var result = spsManager.GetInitialData(PosId); if (result != null) { initalData = new PosInitialData { BillNo = result.Bill_No, ShiftNo = result.Shift_No, ShiftState = result.Shift_State }; } } private void GetStationInfo() { var stationData = spsManager.GetStationInfo(); if (stationData != null) { StationInfo = new StationInfo { StationNo = stationData.Sno }; } } private void UpdateStationInfo(int stationNo, string name) { spsManager.UpdateStationInfo(stationNo, name); } public int GetNextBillNo() { lock (syncObj) { return ++initalData.BillNo; } } public Task Start() { //Hook up the terminal message event handler foreach (var handler in paymentTerminalHandlers) { handler.OnTerminalMessageReceived += Handler_OnTerminalMessageReceived; handler.OnFuelPriceChangeRequested += Handler_OnFuelPriceChangeRequested; } InitFuelName(); InitFuelPrices(); if (spsDataCourierApp != null) logger.Info("SpsDataCourier instance exists!"); spsManager.Start(); sfManager.Start(); sfManager.OnStoreForwardCompleted += SfManagerStoreForwardCompleted; // Inserting configuration data into sps_db. var result = UpsertSpsConfig(); if (result == false) return Task.FromResult(false); return Task.FromResult(true); } private async void SfManagerStoreForwardCompleted(object sender, StoreForwardCompletedEventArgs e) { logger.Info($"SF completed, clear transaction, pump id: {e.PumpdId}, sq no: {e.SeqNo}, rt: {e.ReleaseToken}"); await fdcServerApp.ClearFuelSaleTrxAndNotifyAllFdcClientsAsync(e.PumpdId, e.SeqNo.ToString(), e.ReleaseToken, "100"); } private void Handler_OnFuelPriceChangeRequested(object sender, FuelPriceChangeRequestEventArgs e) { logger.Info($"PosApp: {e.PumpId}, {e.NozzleId}, {e.Price}"); var result = spsManager.GetFuelPriceConfig(); var fdcServerNozzleProductConfig = fdcServerApp.GetNozzleExtraInfos(); var nozzle = fdcServerNozzleProductConfig.First(c => c.PumpId == e.PumpId && c.NozzleLogicalId == e.NozzleId); logger.Info($"PosApp: Nozzle, barcode: {nozzle.ProductBarcode}"); var fuelNo = GetFuelNo(nozzle.ProductBarcode); logger.Info($"PosApp: Got Fuel No: {fuelNo}"); spsManager.UpdateFuelPrice(Convert.ToString(fuelNo), e.Price); lock (dictSync) { pumpPriceDict[e.PumpId] = true; if (pumpPriceDict.Count(p => p.Value == false) > 1) { return; } else if (pumpPriceDict.Count(p => p.Value == false) == 1) { logger.Info("PosApp: FuelPrice dict, only one pump left, update price version"); spsManager.UpdateFuelPriceVersion(); } else { // After all pumps' requests handled, reset the dictionary foreach (var item in pumpPriceDict.Keys.ToList()) { pumpPriceDict[item] = false; } } } InitFuelPrices(); } public Task Stop() { //Unhook the terminal message event handler foreach (var handler in paymentTerminalHandlers) { handler.OnTerminalMessageReceived -= Handler_OnTerminalMessageReceived; handler.OnFuelPriceChangeRequested -= Handler_OnFuelPriceChangeRequested; } if (fdcServerApp != null) { fdcServerApp.OnCurrentFuellingStatusChange -= FdcServerApp_OnCurrentFuellingStatusChange; } return Task.FromResult(true); } public void LockUnlockPump(int pumpId, LockUnlockOperation operation) { var terminalManager = GetTerminalManager(pumpId); terminalManager.LockUnlockPump(operation); } private async void Handler_OnTerminalMessageReceived(object sender, TerminalMessageEventArgs e) { await HandleTerminalMessage(e); } private async Task HandleTerminalMessage(TerminalMessageEventArgs e) { var message = e.Message; DebugLog($"Incoming terminal message, HandlerGroup:[{e.Identifier}], Source {message.SourceAddress}, " + $"Destination {message.DestinationAddress}, FrameSeqNoByte {message.FrameSqNoByte}"); var terminalManager = GetTerminalManager(e.Identifier, message.DestinationAddress); if (terminalManager == null) { logger.Error($"Could not find TerminalManager for message of identifier: {e.Identifier}, dest addr: {message.DestinationAddress}"); return; } DebugLog($"Terminal Manager {terminalManager.PumpId} handle the message"); if (message is RegisterRequest) { terminalManager.HandleRegiser((RegisterRequest)message); DebugLog($"RegisterRequest handled, Source {message.SourceAddress}, Destination {message.DestinationAddress}"); } else if (message is CheckCmdRequest) { DebugLog($"CheckCmdRequest, Source {message.SourceAddress}, Destination {message.DestinationAddress}"); terminalManager.HandleCheckCmdRequest((CheckCmdRequest)message); DebugLog("Sent checkcmdResponse"); } else if (message is ValidateCardRequest) { terminalManager.HandleCardValidation((ValidateCardRequest)message); DebugLog($"ValidateCardRequest, Source {message.SourceAddress}, Destination {message.DestinationAddress}"); } else if (message is AuthRequest) { terminalManager.HandlAuthorization((AuthRequest)message); DebugLog($"AuthRequest handled, Source {message.SourceAddress}, Destination {message.DestinationAddress}"); } else if (message is FuelingDataRequest) { terminalManager.HandleFuelingData((FuelingDataRequest)message); DebugLog($"FuelingDataRequest handled, Source {message.SourceAddress}, Destination {message.DestinationAddress}"); } else if (message is PaymentRequest) { terminalManager.HandlePaymentRequest((PaymentRequest)message); DebugLog($"PaymentRequest handled, Source {message.SourceAddress}, Destination {message.DestinationAddress}"); } else if (message is TransactionDataRequest) { await terminalManager.HandleTransactionData((TransactionDataRequest)message); DebugLog($"TransactionDataRequest handled, Source {message.SourceAddress}, Destination {message.DestinationAddress}"); } else if (message is LockOrUnlockPumpAck) { terminalManager.HandleLockUnlockPumpResult((LockOrUnlockPumpAck)message); DebugLog($"LockOrUnlock ack, Source: {message.SourceAddress}, Destination: {message.DestinationAddress}, " + $"Operation: {((LockOrUnlockPumpAck)message).OperationType}, Result state: {((LockOrUnlockPumpAck)message).DispenserState}"); } else if (message is DataDownloadRequest) { terminalManager.HandleDataDownloadRequest((DataDownloadRequest)message); } else if (message is DataContentRequest) { terminalManager.HandleDataContentRequest((DataContentRequest)message); } else if (message is ChangeAuthModeAck) { terminalManager.HandleModeChangeResult((ChangeAuthModeAck)message); } else if (message is CancelAuthRequest) { terminalManager.HandleCancelAuth((CancelAuthRequest)message); } else if (message is QueryGrayRecordRequest) { terminalManager.HandleQueryGrayRecord((QueryGrayRecordRequest)message); } else if (message is null) { terminalManager.HandleFakeNullMessage(); } } private void SetupTerminalManagers() { foreach (var ptHandler in paymentTerminalHandlers) { foreach (var pumpId in ptHandler.AssociatedPumpIds) { var mgr = new TerminalManager(this, pumpId, ptHandler.GetSubAddressForPump(pumpId), spsManager, ptHandler, interval, this.CardAppType); terminalManagers.Add(mgr); InfoLog($"Setting up TerminalManager, Pump Id: {mgr.PumpId}, Sub address: {mgr.SubAddress}"); } } } private void InitPumpPriceDict() { foreach (var ptHandler in paymentTerminalHandlers) { foreach (var p in ptHandler.AssociatedPumpIds) { if (!pumpPriceDict.ContainsKey(p)) { pumpPriceDict.Add(p, false); } } } } private void SetupTransactionSubmitters() { foreach (var ptHandler in paymentTerminalHandlers) { foreach (var p in ptHandler.AssociatedPumpIds) { if (submitters.Any(s => s.Id == p)) continue; var s = new TrxSubmitter(p, cloudCredential); submitters.Add(s); InfoLog($"Setting up Transaction submitter, Pump Id: {p}"); } } } private TrxSubmitter GetSubmitter(int pumpId) { return submitters.FirstOrDefault(s => s.Id == pumpId); } private void SetFuelProductMapping() { if (!string.IsNullOrEmpty(fuelProductMapping)) { var sequence = fuelProductMapping.Split(';') .Select(s => s.Split(':')) .Select(a => new { Barcode = int.Parse(a[0]), FuelNo = int.Parse(a[1]) }); foreach (var pair in sequence) { if (!fuelMappingDict.ContainsKey(pair.Barcode)) { fuelMappingDict.Add(pair.Barcode, pair.FuelNo); } } } } private int GetFuelNo(int barcode) { if (fuelMappingDict.ContainsKey(barcode)) return fuelMappingDict[barcode]; return -1; } public int GetBarcode(int fuelNo) { return fuelMappingDict.FirstOrDefault(x => x.Value == fuelNo).Key; } private void InitFuelName() { fuelNameDict.Clear(); var fuelNames = spsManager.GetFuelNames(); foreach (var item in fuelNameDict) { int barcode = GetBarcode(Convert.ToInt32(item.Key)); if (!fuelNameDict.ContainsKey(barcode)) { fuelNameDict.Add(barcode, item.Value); } } } private void InitFuelPrices() { fuelCodePriceDict.Clear(); var fuelPrices = spsManager.GetCurrentFuelPrices(); foreach (var item in fuelPrices) { if (!fuelCodePriceDict.ContainsKey(item.Key)) { fuelCodePriceDict.Add(item.Key, item.Value); } } } public string GetFuelName(int barcode) { string fuelName = string.Empty; fuelNameDict.TryGetValue(barcode, out fuelName); return fuelName; } private TerminalManager GetTerminalManager(int pumpId) { return terminalManagers.FirstOrDefault(t => t.PumpId == pumpId); } private TerminalManager GetTerminalManager(string identifier, int pumpId) { return terminalManagers.FirstOrDefault(t => t.Identifier == identifier && t.SubAddress == pumpId); } private void InfoLog(string info) { logger.Info(info); } private void DebugLog(string debugMsg) { logger.Debug(debugMsg); } #endregion #region Properties public FdcServerHostApp FdcServer { get { return fdcServerApp; } } public SpsDataCourierApp SpsDataCourier => spsDataCourierApp; public int PosId { get; private set; } public long CurrentShiftNo { get { return initalData.ShiftNo; } } public DiscountServiceClient DiscountServiceClient { get; } public Dictionary CurrentFuelPrices => fuelCodePriceDict; public StationInfo StationInfo { get; private set; } public int ReservedBalance => reservedBalance; #endregion } #region Config parameters public class PosAppContructorParameterV1 { public int PosId { get; set; } public string Username { get; set; } public string Password { get; set; } public string AuthServiceBaseUrl { get; set; } public string TransactionServiceBaseUrl { get; set; } public string DiscountServiceBaseUrl { get; set; } public bool OnlineDiscount { get; set; } public int DiscountTimeout { get; set; } public string DeviceSN { get; set; } public string PromoCategories { get; set; } public List FuelMappingArr { get; set; } public int CardAppType { get; set; } public int ReservedBalance { get; set; } public int PumpMode { get; set; } public int Interval { get; set; } public SpsDbConnectionSetting ConnectionString { get; set; } public int StationNo { get; set; } public string StationName { get; set; } } public class FuelMappingV1 { public int Barcode { get; set; } public string FuelNo { get; set; } } public class SpsDbConnectionSetting { public string Server { get; set; } public int Port { get; set; } public string Username { get; set; } public string Password { get; set; } } #endregion }