12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145 |
- 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
- {
- /// <summary>
- /// Manages fueling transaction with Pump and IC terminal.
- /// </summary>
- 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
- /// <summary>
- /// Rounding up amount(金额凑整)
- /// </summary>
- /// <returns></returns>
- 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;
- }
- /// <summary>
- /// Rounding up by volume(升凑整)
- /// </summary>
- /// <returns>Return failure for now, since DART doesn't support this.</returns>
- 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
- /// <summary>
- /// Authorize the current pump associated with this fueling manager.
- /// </summary>
- /// <returns>Authorization result, true = success, false = failure</returns>
- 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
- /// <summary>
- /// Handles the GetNozzleStatusRequest from terminal, better do nothing when FDC is offline.
- /// </summary>
- /// <param name="response">The GetNozzleStatus response for terminal</param>
- 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");
- }
- }
- /// <summary>
- /// 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
- /// </summary>
- /// <param name="response">The nozzle status response.</param>
- 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");
- }
- /// <summary>
- /// Set the pump transaction details
- /// </summary>
- /// <param name="response"></param>
- /// <param name="seqNo"></param>
- /// <param name="volume"></param>
- /// <param name="unitPrice"></param>
- /// <param name="amount"></param>
- 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}");
- }
- }
- /// <summary>
- /// Set the pump profile fields as it's idle
- /// </summary>
- /// <param name="response"></param>
- 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.金额加油);
- }
- /// <summary>
- /// Set the pump profile fields as it's fueling.
- /// </summary>
- /// <param name="response"></param>
- 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.金额加油);
- }
- /// <summary>
- /// Set the pump profile fields as it's ready to start a fueling, waiting for IC terminal's
- /// Reserve and Open requests.
- /// </summary>
- /// <param name="response">The nozzle status response.</param>
- 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();
- }
- /// <summary>
- /// Gets the next possible preset amount.
- /// </summary>
- /// <param name="fdcTransaction">Current Fdc filling transaction.</param>
- /// <returns></returns>
- 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<FuelDiscount> ActiveDiscounts { get; private set; }
- public CampaignEngine(List<FuelDiscount> discounts)
- {
- ActiveDiscounts = discounts;
- }
- public CampaignEngine(string discountConfig)
- {
- LoadDiscounts(discountConfig);
- }
- private void LoadDiscounts(string discountConfig)
- {
- ActiveDiscounts = new List<FuelDiscount>();
- 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));
- }
- /// <summary>
- /// Get the discounted price of a particular fuel.
- /// </summary>
- /// <param name="barcode">the fuel product barcode.</param>
- /// <param name="unitPrice">the original unit price of that fuel.</param>
- /// <returns></returns>
- 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
- }
- }
|