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
}