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
}
}