using Applications.FDC; using Edge.Core.Database; using Edge.Core.Database.Models; using Edge.Core.Processor;using Edge.Core.IndustryStandardInterface.Pump; using Dfs.WayneChina.HengshanFPos.FPosDbManager; using Dfs.WayneChina.HengshanTerminalWrapper.MessageEntity.Base; using Dfs.WayneChina.HengshanTerminalWrapper.MessageEntity.Outgoing; using System; using System.Collections.Generic; using System.Linq; using System.Text; using Wayne.FDCPOSLibrary; namespace Dfs.WayneChina.HengshanPos { /// /// Manages fueling transaction with Pump and IC terminal. /// public class FuelingManager { #region Fields private SqliteDbContext fdcDbContext; private FPosDbManager fPosDbManager; private FdcServerHostApp fdcServer; private object syncObj = new object(); private int tempAuthAmount; private int tempAuthVolume; private CampaignEngine campaignEngine; private Fueling activeFueling; private object syncObjAF = new object(); private bool? pumpUnauthorized = null; #endregion #region Logger static NLog.Logger logger = NLog.LogManager.LoadConfiguration("NLog.config").GetLogger("FuelingManager"); #endregion #region Constructor public FuelingManager(int pumpId, IFdcPumpController fdcPump, FdcServerHostApp fdcServer, SqliteDbContext fdcDbContext, FPosDbManager fPosDbManager, CampaignEngine campaignEngine) { PumpId = pumpId; FdcPump = fdcPump; this.fdcDbContext = new SqliteDbContext(); //fdcDbContext; this.fPosDbManager = fPosDbManager; this.fdcServer = fdcServer; this.campaignEngine = campaignEngine; } #endregion #region Properties public int PumpId { get; } public IFdcPumpController FdcPump { get; } public Fueling ActiveFueling { get { //lock (syncObjAF) { return activeFueling; } } set { //lock (syncObjAF) { activeFueling = value; } } } public Fueling LastFueling { get; private set; } #endregion #region Nozzle status public GetNozzleStatusResponse GetNozzleStatus() { DebugLog($"fueling manager {PumpId} handles nozzle status\n"); var response = new GetNozzleStatusResponse(); var pumpState = FdcPump.QueryStatusAsync().Result; DebugLog($"FdcPump: {PumpId}, State: {pumpState}"); if (pumpState == LogicalDeviceState.FDC_READY) { HandleNozzleStatusFdcIsReady(response); } else if (pumpState == LogicalDeviceState.FDC_CALLING || pumpState == LogicalDeviceState.FDC_STARTED || pumpState == LogicalDeviceState.FDC_AUTHORISED) { HandleNozzleStatusReadyForFueling(response); } else if (pumpState == LogicalDeviceState.FDC_FUELLING) { HandleNozzleStatusFdcFuelling(response); } else if (pumpState == LogicalDeviceState.FDC_OFFLINE) { HandleNozzleStatusFdcOffline(response); } else { DebugLog("No-, entering shithole..."); HandleNozzleStatusFdcOtherStates(response); } return response; } #endregion #region Get accumulator public GetAccumulateResponse GetAccumulator(byte logicalNozzleId) { InfoLog($"Pump {PumpId}, Query totalizer"); //var pumpState = FdcPump.QueryStatus(); ////If the pump is idle, the query totalizer request must be from PIN-pad //if (pumpState != LogicalDeviceState.FDC_CALLING) //{ // int volumeTotal = 0; // foreach (var nozzle in FdcPump.Nozzles) // { // var result = FdcPump.QueryTotalizer(nozzle.LogicalId); // volumeTotal += result.Item2; // } // if (volumeTotal > 99999999) // { // InfoLog($"Volume totalizer exceeding max length limit"); // string vt = Convert.ToString(volumeTotal); // volumeTotal = Convert.ToInt32(vt.Substring(vt.Length - 8)); // } // return new GetAccumulateResponse // { // 升累计 = volumeTotal, // 金额累计 = 0 // }; //} GetAccumulateResponse accumulatorResponse; if (LastFueling == null) { InfoLog("Get totalizer directly from pump"); var result = FdcPump.QueryTotalizerAsync(logicalNozzleId).Result; if (result != null) { //Interim solution because Hengshan IC terminal supports max 4 bytes BCD int volumeTotal = 0; if (result.Item2 > 99999999) { string vt = Convert.ToString(result.Item2); volumeTotal = Convert.ToInt32(vt.Substring(vt.Length - 8)); } else { volumeTotal = result.Item2; } accumulatorResponse = new GetAccumulateResponse { 升累计 = volumeTotal < 0 ? 0 : volumeTotal, 金额累计 = result.Item1 == -1 ? 6 : result.Item1 }; } else { accumulatorResponse = new GetAccumulateResponse { 升累计 = 0, 金额累计 = 0 }; } } else { InfoLog("Used totalizer from last fueling"); accumulatorResponse = new GetAccumulateResponse { 金额累计 = 0, 升累计 = LastFueling.FdcTransaction.VolumeTotalizer ?? -1 }; } logger.Debug($"Pump {PumpId}, {accumulatorResponse.ToLogString()}"); return accumulatorResponse; } #endregion #region Rounding /// /// Rounding up amount(金额凑整) /// /// public RoundingResponse GetRoundingResult() { InfoLog("Amount rounding"); RoundingResponse response = new RoundingResponse(); if (ActiveFueling != null && ActiveFueling.FdcTransaction != null) { bool success = FdcPump.FuelingRoundUpByAmountAsync(GetRoundingAmount(ActiveFueling.FdcTransaction)).Result; response.EnumResult = success ? NonCardDispenserMessageTemplateBase.Result.成功 : NonCardDispenserMessageTemplateBase.Result.失败; } else { response = new RoundingResponse { EnumResult = NonCardDispenserMessageTemplateBase.Result.失败 }; } return response; } /// /// Rounding up by volume(升凑整) /// /// Return failure for now, since DART doesn't support this. public RoundUpByVolumeResponse HandleVolumeRounding() { InfoLog("Volume rounding"); RoundUpByVolumeResponse response = new RoundUpByVolumeResponse { EnumResult = NonCardDispenserMessageTemplateBase.Result.失败 }; return response; } #endregion #region Reserve pump with amount public ReservePumpWithAmountResponse ReservePumpWithAmount(int amount) { InfoLog($"ReservePumpWithAmount request, amount : {amount} for pump id: {PumpId}"); ReservePumpWithAmountResponse response = new ReservePumpWithAmountResponse(); if (ActiveFueling != null) { lock (syncObj) { InfoLog($"Pump id: {PumpId}, setting AuthAmount = {amount}"); tempAuthVolume = 0; ActiveFueling.Gallon = 0; ActiveFueling.AuthAmount = amount; } response.EnumResult = NonCardDispenserMessageTemplateBase.Result.成功; } else { InfoLog($"No ActiveFueling now, store auth amount {amount} to tempAuthAmount"); tempAuthVolume = 0; tempAuthAmount = amount; response.EnumResult = NonCardDispenserMessageTemplateBase.Result.成功; } return response; } #endregion #region Reserve pump with volume public ReservePumpWithGallonResponse ReservePumpWithGallon(int volume) { InfoLog($"ReservePumpWithGallon request, Gallon(volume) : {volume} for pump id: {PumpId}"); ReservePumpWithGallonResponse response = new ReservePumpWithGallonResponse(); if (ActiveFueling != null) { lock (syncObj) { InfoLog($"Pump id: {PumpId}, setting Gallon = {volume}"); tempAuthAmount = 0; ActiveFueling.AuthAmount = 0; ActiveFueling.Gallon = volume; } response.EnumResult = NonCardDispenserMessageTemplateBase.Result.成功; } else { InfoLog($"No ActiveFueling now, store auth gallon {volume} to tempAuthVolume"); tempAuthAmount = 0; tempAuthVolume = volume; response.EnumResult = NonCardDispenserMessageTemplateBase.Result.成功; } return response; } #endregion #region Authorize pump /// /// Authorize the current pump associated with this fueling manager. /// /// Authorization result, true = success, false = failure public bool AuthorizePump() { InfoLog($"Authorize current pump id {PumpId}"); if (fdcServer != null) { var pumpState = FdcPump.QueryStatusAsync().Result; //If the pump is authorized, no need to authorize it again. if (pumpState == LogicalDeviceState.FDC_AUTHORISED || pumpState == LogicalDeviceState.FDC_FUELLING) { return true; } else if (pumpState == LogicalDeviceState.FDC_READY) { InfoLog("There is no pump calling, abort auth"); return false; } InfoLog($"Pump id: {PumpId}, ActiveFueling, AuthAmount: {ActiveFueling.AuthAmount}"); if (ActiveFueling.AuthAmount == 0) { InfoLog($"Used tempAuthAmount {tempAuthAmount} as AuthAmount"); ActiveFueling.AuthAmount = tempAuthAmount; tempAuthAmount = 0; } if (ActiveFueling.Gallon == 0) { InfoLog($"Used tempAuthVolume {tempAuthVolume} as Gallon"); ActiveFueling.Gallon = tempAuthVolume; tempAuthVolume = 0; } if (ActiveFueling.AuthAmount != 0 && ActiveFueling.Gallon == 0) { bool success = fdcServer.AuthorizePumpAsync(FdcPump.PumpId, (double)ActiveFueling.AuthAmount / 100, 0).Result; InfoLog($"AuthorizePump {PumpId} with amount, success? {success}"); return success; } else if (ActiveFueling.AuthAmount == 0 && ActiveFueling.Gallon != 0) { bool success = fdcServer.AuthorizePumpAsync(FdcPump.PumpId, 0, (double)ActiveFueling.Gallon / 100).Result; InfoLog($"AuthorizePump {PumpId} with volume, success? {success}"); return success; } else { InfoLog($"Authorize with default amount 9999 for pump {FdcPump.PumpId}"); bool success = fdcServer.AuthorizePumpAsync(FdcPump.PumpId, 9998, 0).Result; InfoLog($"AuthorizePump {PumpId} with amount, success? {success}"); return success; } } else { logger.Info("No FdcServer instance"); return false; } } #endregion #region Unauthorize pump public bool UnauthorizePump() { InfoLog("Unauthorize pump"); var currentFdcState = FdcPump.QueryStatusAsync().Result; if (currentFdcState == LogicalDeviceState.FDC_FUELLING || currentFdcState == LogicalDeviceState.FDC_STARTED || currentFdcState == LogicalDeviceState.FDC_AUTHORISED) { //if the pump is not unauthorized, we need to unauthorize it if (pumpUnauthorized.HasValue && pumpUnauthorized.Value == false) { pumpUnauthorized = FdcPump.UnAuthorizeAsync(FdcPump.Nozzles.First().LogicalId).Result; return pumpUnauthorized.Value; } else { return true; } } else { InfoLog($"Current pump status is not in a state where we have to Unauthorize it {currentFdcState}"); return true; } } #endregion #region Fueling handling public void CreateFueling(byte activeNozzle) { DebugLog($"Start to create fueling for pump id {PumpId}, active nozzle {activeNozzle}"); lock (syncObj) { if (ActiveFueling == null) { ActiveFueling = new Fueling { FdcTransaction = null, PumpId = PumpId, ActiveNozzle = activeNozzle, AuthorizedByCard = false, FuelingState = FuelingState.Ready, AuthAmount = 0, FuelingSqNo = 0, NozzleReturnedTime = null }; InfoLog("Creating fueling..."); } else { InfoLog("Active fueling exists"); } } InfoLog($"Fueling created for pump id {PumpId}, active nozzle {activeNozzle}"); } public void UpdateFueling(FdcTransaction fdcTransaction) { if (ActiveFueling != null) { DebugLog($"Start to update fueling"); lock (syncObj) { if (ActiveFueling.FuelingState == FuelingState.Running) { ActiveFueling.FdcTransaction = fdcTransaction; } else if (ActiveFueling.FuelingState == FuelingState.Authorized) { if (ActiveFueling.FdcTransaction == null) { if (activeFueling.FuelingSqNo == 0) { ActiveFueling.FuelingSqNo = fPosDbManager.GetNewSqNo(fdcTransaction.Nozzle.PumpId, fdcTransaction.Nozzle.LogicalId); } ActiveFueling.FuelingState = FuelingState.Running; InfoLog("First time got FdcTransaction"); } } } DebugLog("Update fueling...done"); } else { throw new Exception("Active fueling does not exist!"); } } public void SetFuelingCompleted(FdcTransaction fdcTransaction) { if (ActiveFueling.FuelingState == FuelingState.Completed) { var sqNo = fPosDbManager.SetFillingDone(fdcTransaction.Nozzle.PumpId, fdcTransaction.Nozzle.LogicalId); InfoLog($"Fueling completed, set filling done, FPos SqNo = {sqNo}"); } } public void StoreLastFueling(FdcTransaction fdcTransaction) { lock (syncObj) { ActiveFueling.FdcTransaction = fdcTransaction; LastFueling = ActiveFueling; ActiveFueling = null; } InfoLog("Transfer active fueling to last fueling, drop active fueling"); } public void UpdateFuelingState(FuelingState state) { InfoLog("Trying to update the fueling state"); //lock (syncObj) { if (ActiveFueling != null && ActiveFueling.FuelingState == state) { return; } else { InfoLog($"Set Fueling state to: {state}"); ActiveFueling.FuelingState = state; } } InfoLog("Fueling state updated"); } public void SetFuelingAsAuthorizedByCard() { InfoLog("start to set fueling as authorized by card"); lock (syncObj) { if (ActiveFueling != null) { ActiveFueling.AuthorizedByCard = true; } } InfoLog("Already set fueling as authorized by card"); } #endregion #region Private methods /// /// Handles the GetNozzleStatusRequest from terminal, better do nothing when FDC is offline. /// /// The GetNozzleStatus response for terminal private void HandleNozzleStatusFdcOffline(GetNozzleStatusResponse response) { DebugLog("Pump is offline"); } private void HandleNozzleStatusFdcOtherStates(GetNozzleStatusResponse response) { DebugLog($"FdcOtherStates enter"); InfoLog($"Fueling manager {PumpId}, FDC State abnormal"); //TryPullTransaction(response); //SetPumpProfileReadyForFueling(response); DebugLog($"Pump {PumpId}, FdcOtherStates exit"); } private void HandleNozzleStatusReadyForFueling(GetNozzleStatusResponse response) { DebugLog($"Pump {PumpId}, ReadyForFueling enter"); if (ActiveFueling != null) { if (ActiveFueling.FdcTransaction != null) { InfoLog("Oops, something is wrong, the active fueling is not null"); } else { InfoLog("Waiting for fueling to be started on pump"); } } TryPullTransaction(response); ////Assume pump is already authorized if (ActiveFueling != null && ActiveFueling.FuelingState == FuelingState.Authorized) { DebugLog("Active fueling, pump authorized"); if (ActiveFueling.FuelingSqNo == 0) { ActiveFueling.FuelingSqNo = fPosDbManager.GetNewSqNo(PumpId, ActiveFueling.ActiveNozzle); InfoLog($"Pump fake auth, retrieve new SqNo {ActiveFueling.FuelingSqNo}"); } response.流水号 = ActiveFueling.FuelingSqNo; response.单价 = 600; response.加油量 = 0; response.加油金额 = 0; SetPumpProfileFueling(response); } else if (ActiveFueling != null && ActiveFueling.FuelingState == FuelingState.Ready) { SetPumpProfileReadyForFueling(response); } logger.Debug($"Pump {PumpId}, ReadyForFueling exit"); } private void HandleNozzleStatusFdcFuelling(GetNozzleStatusResponse response) { if (ActiveFueling != null && ActiveFueling.FdcTransaction != null) { pumpUnauthorized = false; tempAuthVolume = 0; tempAuthAmount = 0; DebugLog($"Fueling, FdcTrx pump id: {ActiveFueling.FdcTransaction.Nozzle.PumpId} " + $"nozzle id: {ActiveFueling.FdcTransaction.Nozzle.LogicalId} " + $"volume: {ActiveFueling.FdcTransaction.Volumn} " + $"amount: {ActiveFueling.FdcTransaction.Amount}"); response.流水号 = ActiveFueling.FuelingSqNo; response.加油量 = ActiveFueling.FdcTransaction.Volumn; //if (ActiveFueling.FdcTransaction.Price > 100) //{ int price = ActiveFueling.FdcTransaction.Price; int total = ActiveFueling.FdcTransaction.Amount; campaignEngine.ApplyDiscount(ActiveFueling.FdcTransaction.Barcode, ActiveFueling.FdcTransaction.Volumn, ref price, ref total); DebugLog($"Price: {price}, Amount: {total}"); response.单价 = price; response.加油金额 = total; //} //else //{ // response.单价 = ActiveFueling.FdcTransaction.Price; // response.加油金额 = ActiveFueling.FdcTransaction.Amount; //} if (ActiveFueling != null && ActiveFueling.AuthAmount != 0) { response.定量 = Convert.ToInt32(ActiveFueling.AuthAmount * 100); DebugLog($"ActiveFueling AuthAmount: {ActiveFueling.AuthAmount}"); } else if (ActiveFueling != null && ActiveFueling.Gallon != 0) { response.定量 = ActiveFueling.Gallon; DebugLog($"ActiveFueling AuthVolume: {ActiveFueling.AuthAmount}"); } response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.允许加油); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.加油过程); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.油枪打开); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.电机打开); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.金额加油); //SetTransactionDetails(response, ActiveFueling.FdcTransaction.Barcode, ActiveFueling.FuelingSqNo, // ActiveFueling.FdcTransaction.Volumn, ActiveFueling.FdcTransaction.Price, ActiveFueling.FdcTransaction.Amount); //SetPumpProfileFueling(response); } else if (ActiveFueling != null && ActiveFueling.FdcTransaction == null) { DebugLog("Fdc transaction not received yet..."); //TryPullTransaction(response); response.流水号 = ActiveFueling.FuelingSqNo; response.单价 = 600; response.加油量 = 0; response.加油金额 = 0; if (ActiveFueling != null && ActiveFueling.AuthAmount != 0) { response.定量 = Convert.ToInt32(ActiveFueling.AuthAmount * 100); DebugLog($"ActiveFueling AuthAmount: {ActiveFueling.AuthAmount}"); } else if (ActiveFueling != null && ActiveFueling.Gallon != 0) { response.定量 = ActiveFueling.Gallon; DebugLog($"ActiveFueling AuthVolume: {ActiveFueling.AuthAmount}"); } //SetPumpProfileReadyForFueling(response); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.允许加油); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.加油过程); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.油枪打开); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.电机打开); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.金额加油); } else if (ActiveFueling == null) { InfoLog("Unbelievable, the current fueling is null"); } } /// /// Handle the nozzle status request when pump is in state FDC_Ready (idle) /// Strategy: /// 1. Check if there is a running fueling /// 2. If no running fueling, check if there is a previous transaction /// 3. If no previous transaction, try pulling a paid transaction from FDC database /// 4. If no transaction from FC database, use false fueling data to make IC terminal happy /// /// The nozzle status response. private void HandleNozzleStatusFdcIsReady(GetNozzleStatusResponse response) { DebugLog($"Pump {PumpId}, FdcIsReady enter"); if (ActiveFueling != null) { DebugLog("ActiveFueling is not null"); } DebugLog($"Fueling manager for pump id: {PumpId}"); //Fueling completed event not received yet if (ActiveFueling != null && ActiveFueling.FdcTransaction != null) { if (ActiveFueling.NozzleReturnedTime == null) ActiveFueling.NozzleReturnedTime = DateTime.Now; SetTransactionDetails(response, ActiveFueling.FdcTransaction.Barcode, ActiveFueling.FuelingSqNo, ActiveFueling.FdcTransaction.Volumn, ActiveFueling.FdcTransaction.Price, ActiveFueling.FdcTransaction.Amount); //Terminate the fueling if the 'Done event' is not received after nozzle replace for 5 minutes if (DateTime.Now - ActiveFueling.NozzleReturnedTime > TimeSpan.FromMinutes(5)) { response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.不允许加油); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.加油结束); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.油枪关); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.电机关); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.金额加油); LastFueling = ActiveFueling; ActiveFueling = null; } else { response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.允许加油); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.加油过程); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.油枪打开); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.电机打开); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.金额加油); //SetPumpProfileFueling(response); } return; } DebugLog($"Try pull trx"); TryPullTransaction(response); SetPumpProfileFdcIsReady(response); DebugLog($"Pump {PumpId}, FdcIsReady exit"); } private void TryPullTransaction(GetNozzleStatusResponse response) { DebugLog($"Pump {PumpId}, TryPullTransaction enter"); //Fueling transaction stored in memory if (LastFueling != null) { DebugLog("Using data from LastFueling"); SetTransactionDetails(response, LastFueling.FdcTransaction.Barcode, LastFueling.FuelingSqNo, LastFueling.FdcTransaction.Volumn, LastFueling.FdcTransaction.Price, LastFueling.FdcTransaction.Amount); } //This is probably after a restart of this software if (ActiveFueling == null && LastFueling == null) { DebugLog($"Fueling manager {PumpId}, Current and last fueling are both null"); var lastFdcTransaction = GetFdcFuelSaleTransaction(); if (lastFdcTransaction != null) { DebugLog($"Fueling manager {PumpId}, Found a transaction in Fdc database for this pump id= {PumpId}"); var posSqNo = fPosDbManager.GetSqNoByMapping( lastFdcTransaction.PumpId, lastFdcTransaction.LogicalNozzleId, Convert.ToInt32(lastFdcTransaction.TransactionSeqNumberFromPhysicalPump)); if (posSqNo == 0) { InfoLog("Probably last paid transaction in FC database was not authorized by card or didn't finish correctly"); } SetTransactionDetails(response, -1, posSqNo, lastFdcTransaction.Volumn, lastFdcTransaction.UnitPrice, lastFdcTransaction.Amount); } else { DebugLog($"Fueling manager {PumpId}, No FdcTransaction found"); //This is a fresh delopyment of the software SetTransactionDetails(response, -1, 0, 0, 1000, 0); } //SetTransactionDetails(response, 0, 1, 2, 2); } else if (ActiveFueling != null && ActiveFueling.FdcTransaction == null && LastFueling == null) { DebugLog("Using 0-0-1000-0"); //Pump calling, fresh deployment SetTransactionDetails(response, -1, 0, 0, 1000, 0); } else if (ActiveFueling != null && ActiveFueling.FdcTransaction != null) { InfoLog("Nozzle returned and lifted before amount deducted"); SetTransactionDetails(response, ActiveFueling.FdcTransaction.Barcode, ActiveFueling.FuelingSqNo, ActiveFueling.FdcTransaction.Volumn, ActiveFueling.FdcTransaction.Price, ActiveFueling.FdcTransaction.Amount); } DebugLog($"Pump {PumpId}, TryPullTransaction exit"); } /// /// Set the pump transaction details /// /// /// /// /// /// private void SetTransactionDetails( GetNozzleStatusResponse response, int barcode, int seqNo, int volume, int unitPrice, int amount) { response.流水号 = seqNo; response.加油量 = volume; if (unitPrice > 100) { int price = unitPrice; int total = amount; campaignEngine.ApplyDiscount(barcode, volume, ref price, ref total); DebugLog($"Price: {price}, Amount: {total}"); response.单价 = price; response.加油金额 = total; return; } response.单价 = unitPrice; response.加油金额 = amount; if (ActiveFueling != null && ActiveFueling.AuthAmount != 0) { response.定量 = Convert.ToInt32(ActiveFueling.AuthAmount * 100); DebugLog($"ActiveFueling AuthAmount: {ActiveFueling.AuthAmount}"); } else if (ActiveFueling != null && ActiveFueling.Gallon != 0) { response.定量 = ActiveFueling.Gallon; DebugLog($"ActiveFueling AuthVolume: {ActiveFueling.Gallon}"); } } /// /// Set the pump profile fields as it's idle /// /// private void SetPumpProfileFdcIsReady(GetNozzleStatusResponse response) { DebugLog("Set pump profile idle"); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.不允许加油); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.加油结束); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.油枪关); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.电机关); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.金额加油); } /// /// Set the pump profile fields as it's fueling. /// /// private void SetPumpProfileFueling(GetNozzleStatusResponse response) { response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.允许加油); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.加油过程); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.油枪打开); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.电机打开); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.金额加油); } /// /// Set the pump profile fields as it's ready to start a fueling, waiting for IC terminal's /// Reserve and Open requests. /// /// The nozzle status response. private void SetPumpProfileReadyForFueling(GetNozzleStatusResponse response) { try { response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.不允许加油); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.加油结束); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.油枪打开); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.电机关); response.AddPumpStatus(GetNozzleStatusResponse.PumpStatus.金额加油); } catch (Exception ex) { DebugLog($"{ex}"); } DebugLog(response.ToLogString()); } private FuelSaleTransaction GetFdcFuelSaleTransaction() { //Fow now return null, for performance reasons. return null; //return fdcDbContext.PumpTransactionModels // .Where(t => t.PumpId == PumpId) // .OrderByDescending(s => s.SaleStartTime) // .FirstOrDefault(); } /// /// Gets the next possible preset amount. /// /// Current Fdc filling transaction. /// private int GetRoundingAmount(FdcTransaction fdcTransaction) { int currentFillingAmount = fdcTransaction.Amount; int nextRoundedAmount = currentFillingAmount; do { nextRoundedAmount++; } while (nextRoundedAmount % 100 != 0); InfoLog($"Current amount: {currentFillingAmount}, rounded amount: {nextRoundedAmount}"); return nextRoundedAmount; } #endregion #region Log methods private void InfoLog(string log) { if (logger.IsInfoEnabled) logger.Info($"{PumpId} " + log); } private void DebugLog(string log) { if (logger.IsDebugEnabled) logger.Debug($"{PumpId} " + log); } private void ErrorLog(string log) { if (logger.IsErrorEnabled) logger.Error($"{PumpId} " + log); } #endregion } public enum DiscountType { FixedAmount = 1, Percentage = 2 } public class FuelDiscount { public int FuelBarcode { get; set; } public DiscountType DiscountType { get; set; } public int Deduction { get; set; } } public class CampaignEngine { static NLog.Logger logger = NLog.LogManager.LoadConfiguration("NLog.config").GetLogger("FuelingManager"); public List ActiveDiscounts { get; private set; } public CampaignEngine(List discounts) { ActiveDiscounts = discounts; } public CampaignEngine(string discountConfig) { LoadDiscounts(discountConfig); } private void LoadDiscounts(string discountConfig) { ActiveDiscounts = new List(); string[] discounts = discountConfig.Split(';'); foreach (var d in discounts) { string[] part = d.Split(','); ActiveDiscounts.Add(new FuelDiscount { FuelBarcode = Convert.ToInt32(part[0]), DiscountType = (DiscountType)Convert.ToInt32(part[1]), Deduction = Convert.ToInt32(part[2]) }); } InfoLog($"Active discounts count: {ActiveDiscounts.Count}"); } #region Discount version 1.0 //public void ApplyDiscount(int barcode, int volume, ref int unitPrice, ref int amount) //{ // if (barcode < 0) // return; // int originalPrice = unitPrice; // unitPrice = GetDiscountedPrice(barcode, unitPrice); // if (originalPrice == unitPrice) // { // if (logger.IsErrorEnabled) // logger.Error("Price after discount equals original price"); // return; // } // amount = unitPrice * volume / 100; //} //private int GetDiscountedPrice(int barcode, int unitPrice) //{ // foreach (var fd in ActiveDiscounts) // { // DebugLog($"FD barcode: {fd.FuelBarcode}, barcode: {barcode}"); // if (fd.FuelBarcode == barcode) // { // if (fd.DiscountType == DiscountType.FixedAmount) // return unitPrice - fd.Deduction; // else if (fd.DiscountType == DiscountType.Percentage) // return unitPrice * (100 - fd.Deduction) / 100; // } // } // if (logger.IsErrorEnabled) // logger.Error("No discount on price applied"); // //No discount is applied // return unitPrice; //} #endregion public void ApplyDiscount(int barcode, int volume, ref int unitPrice, ref int amount) { if (barcode < 0) return; int originalPrice = unitPrice; decimal realUnitPrice = unitPrice; realUnitPrice = GetDiscountedPrice(barcode, realUnitPrice); if (originalPrice == realUnitPrice) { ErrorLog("Price after discount equals original price"); return; } amount = Convert.ToInt32(Math.Round(realUnitPrice * volume / 100, 0)); unitPrice = Convert.ToInt32(Math.Round(realUnitPrice, 0)); } /// /// Get the discounted price of a particular fuel. /// /// the fuel product barcode. /// the original unit price of that fuel. /// private decimal GetDiscountedPrice(int barcode, decimal unitPrice) { foreach (var fd in ActiveDiscounts) { DebugLog($"FD barcode: {fd.FuelBarcode}, barcode: {barcode}"); if (fd.FuelBarcode == barcode) { if (fd.DiscountType == DiscountType.FixedAmount) return unitPrice - fd.Deduction; else if (fd.DiscountType == DiscountType.Percentage) return unitPrice * (100 - fd.Deduction) / 100; } } ErrorLog("No discount on price applied"); //No discount is applied return unitPrice; } #region Log methods private void DebugLog(string log) { if (logger.IsDebugEnabled) logger.Debug(log); } private void InfoLog(string log) { if (logger.IsInfoEnabled) logger.Info(log); } private void ErrorLog(string log) { if (logger.IsErrorEnabled) logger.Error(log); } #endregion } }