using Edge.Core.Processor;
using Edge.Core.IndustryStandardInterface.Pump;
using Dfs.WayneChina.CardTrxMonitor.Models;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using Wayne.FDCPOSLibrary;
using System.Threading.Tasks;
using System.Threading;
using Dfs.WayneChina.CardTrxManager;
using Dfs.WayneChina.CardTrxManager.TrxSubmitter;
namespace Dfs.WayneChina.CardTrxMonitor
{
///
/// Entity that pulls a finished IC card transaction from MySQL and publishes it to FdcServer.
///
public class CardTrxMonitorApp : IAppProcessor, IFdcPumpController
{
#region Properties
public string Name => "CardTrxMonitor";
public int PumpId { get; private set; }
public byte NozzleId { get; private set; }
//This is a fake pump.
public int PumpPhysicalId => 0;
private List nozzles = new List();
public IEnumerable Nozzles => nozzles;
//China domestic standard
public int AmountDecimalDigits => 2;
public int VolumeDecimalDigits => 2;
public int PriceDecimalDigits => 2;
public int VolumeTotalizerDecimalDigits => 2;
public string MetaConfigName { get; set; }
#endregion
#region Fields
private System.Timers.Timer _timer;
private int scanInterval;
private int siteNozzleNo;
private int bindingBarcode;
private CloudCredential cloudCredential;
private TrxSubmitter submitter;
#endregion
#region Logger
NLog.Logger logger = NLog.LogManager.LoadConfiguration("NLog.config").GetLogger("CardTrxMonitor");
#endregion
#region Constructor
public CardTrxMonitorApp(int pumpId, int nozzleId, int siteNozzleNo, int barcode, int scanInterval,
string username, string password, string authServiceBaseUrl, string transactionServiceBaseUrl, string deviceSN)
{
PumpId = pumpId;
NozzleId = Convert.ToByte(nozzleId);
this.siteNozzleNo = siteNozzleNo;
bindingBarcode = barcode;
nozzles.Add(new LogicalNozzle(pumpId, 1, NozzleId, null));
this.scanInterval = scanInterval;
cloudCredential = new CloudCredential
{
UserName = username,
Password = password,
AuthServiceBaseUrl = authServiceBaseUrl,
TransactionServiceBaseUrl = transactionServiceBaseUrl,
DeviceSN = deviceSN
};
submitter = new TrxSubmitter(PumpId, cloudCredential);
}
#endregion
#region IApplication implementation
public void Init(IEnumerable processors)
{
}
public Task Start()
{
_timer = new System.Timers.Timer();
_timer.Interval = scanInterval * 1000;
_timer.Elapsed += TimeElapsed;
_timer.Start();
return Task.FromResult(true);
}
private void TimeElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Log("Timer reset...");
try
{
FindTransaction();
}
catch (Exception ex)
{
Log($"{ex}");
}
}
private void Log(string message)
{
logger.Info($"Monitor{PumpId}, {message}");
}
private void FindTransaction()
{
Log("start to check db...");
try
{
using (var _context = new SpsDbContext())
{
var cardTrx = _context.TCardtrx.FirstOrDefault(t => t.PumpNo == PumpId);
if (cardTrx != null && IsTrdTypeAllowed(cardTrx.TrdType) && cardTrx.Mon != 0)
{
//Before processing is done against the found transaction, stop the timer in case that
//it takes a while and the timer is triggerred for a second time and exception raised.
_timer.Stop();
if (cardTrx.TrdType == 6)
{
Log("Non-card fuelling");
}
else if (cardTrx.TrdType == 1)
{
Log("Gray card transaction, remove it otherwise it will block further transactions");
RemoveTransaction(cardTrx, _context);
}
//103, Operator card
if (cardTrx.PaymodeId == 103)
{
Log($"Found finished IC card transaction: Pump: {cardTrx.PumpNo}, Volume: {cardTrx.Vol}, Amount: {cardTrx.Mon}");
FdcTransaction fdcTransaction = new FdcTransaction();
fdcTransaction.Amount = cardTrx.Mon.Value;
fdcTransaction.Volumn = Convert.ToInt32(cardTrx.Vol.Value);
fdcTransaction.VolumeTotalizer = Convert.ToInt32(cardTrx.EndPumpId.Value);
fdcTransaction.Price = Convert.ToInt32(cardTrx.Prc.Value);
fdcTransaction.SequenceNumberGeneratedOnPhysicalPump = Convert.ToInt32(cardTrx.Gid);
fdcTransaction.Nozzle = new LogicalNozzle(cardTrx.PumpNo, 0, Convert.ToByte(NozzleId), 0);
fdcTransaction.Finished = true;
OnCurrentFuellingStatusChange?.Invoke(this, new FdcTransactionDoneEventArg(fdcTransaction));
RemoveTransaction(cardTrx, _context);
}
else if (cardTrx.PaymodeId == 100) //100, Customer card 定位卡问题
{
Log($"Found customer card transaction: Pump: {cardTrx.PumpNo}, Volume: {cardTrx.Vol}, Amount: {cardTrx.Mon}");
var submitResult = Task.Run(async () =>
{
var result = await SubmitTrxAsync(cardTrx, bindingBarcode);
return result;
});
Log($"submit transaction, result: {submitResult.Result}");
RemoveTransaction(cardTrx, _context);
}
else
{
//105:
//108:
}
}
else if (cardTrx != null && cardTrx.Mon == 0)
{
Log($"Zero amount transaction, Pump No: {cardTrx.PumpNo}, SeqNo: {cardTrx.SeqNo}, delete it!");
RemoveTransaction(cardTrx, _context);
}
else if (cardTrx != null && cardTrx.Gid != 0)
{
Log($"Trd Type: {cardTrx?.TrdType}");
RemoveTransaction(cardTrx, _context);
}
//Reacitivate the timer.
_timer.Start();
}
}
catch (Exception ex)
{
Log($"Database operation: {ex}");
}
}
///
///00:正常卡交易
///01:灰卡交易
///02:解灰交易(解灰后即为正常交易)
///04:现金后台授权交易
///05:撤消授权卡交易
///06:非卡交易
///07:撤消授权非卡交易
///08:油价下载记录
///
///
///
private bool IsTrdTypeAllowed(byte trdType)
{
if (trdType == 0 || trdType == 2 || trdType == 6)
return true;
return false;
}
private void RemoveTransaction(TCardtrx cardTrx, SpsDbContext context)
{
try
{
context.Remove(cardTrx);
context.SaveChanges();
}
catch (Exception ex)
{
Log($"Exception in removing trx: {ex}");
}
}
private async Task SubmitTrxAsync(TCardtrx cardTrx, int barcode)
{
var clientTrxInfo = new ClientTrxInfo
{
CardNo = cardTrx.CardNo,
CurrentCardBalance = Convert.ToDecimal(cardTrx.CardBal.Value) / 100,
UnitPrice = Convert.ToDecimal(cardTrx.Prc) / 100,
Amount = Convert.ToDecimal(cardTrx.Mon) / 100,
PayAmount = Convert.ToDecimal(cardTrx.RealMon) / 100,
Volume = Convert.ToDecimal(cardTrx.Vol) / 100,
PumpId = cardTrx.PumpNo,
NozzleId = Convert.ToByte(cardTrx.NozNo),
SiteNozzleNo = siteNozzleNo,
Barcode = barcode,
FuelingStartTime = cardTrx.Ttctime,
FuelingFinishedTime = cardTrx.TtctimeEnd.Value,
SeqNo = Convert.ToInt32(cardTrx.SeqNo)
};
var result = await submitter.SubmitTrxAsync(clientTrxInfo);
return result;
}
public Task Stop()
{
if (_timer != null)
{
_timer.Dispose();
}
return Task.FromResult(true);
}
#endregion
#region Event handlers
public event EventHandler OnStateChange;
public event EventHandler OnCurrentFuellingStatusChange;
#endregion
#region Methods, not useful
public bool Authorize(byte logicalNozzleId)
{
return false;
}
public bool AuthorizeWithAmount(int moneyAmountWithoutDecimalPoint, byte logicalNozzleId)
{
return false;
}
public bool AuthorizeWithVolumn(int volumnWithoutDecimalPoint, byte logicalNozzleId)
{
return false;
}
public bool ChangeFuelPrice(int newPriceWithoutDecimalPoint, byte logicalNozzleId)
{
return false;
}
public bool FuelingRoundUpByAmount(int amount)
{
return false;
}
public bool FuelingRoundUpByVolumn(int volume)
{
return false;
}
public void OnFdcServerInit(Dictionary parameters)
{
//the parameters don't make any sense for this fake pump handler.
}
public LogicalDeviceState QueryStatus()
{
return LogicalDeviceState.FDC_READY;
}
public Tuple QueryTotalizer(byte logicalNozzleId)
{
return new Tuple(-1, -1);
}
public bool ResumeFuelling()
{
return false;
}
public bool SuspendFuelling()
{
return false;
}
public bool UnAuthorize(byte logicalNozzleId)
{
return false;
}
public Task QueryStatusAsync()
{
throw new NotImplementedException();
}
public Task> QueryTotalizerAsync(byte logicalNozzleId)
{
return Task.FromResult(new Tuple(-1, -1));
}
public Task SuspendFuellingAsync()
{
throw new NotImplementedException();
}
public Task ResumeFuellingAsync()
{
throw new NotImplementedException();
}
public Task ChangeFuelPriceAsync(int newPriceWithoutDecimalPoint, byte logicalNozzleId)
{
throw new NotImplementedException();
}
public Task AuthorizeAsync(byte logicalNozzleId)
{
throw new NotImplementedException();
}
public Task UnAuthorizeAsync(byte logicalNozzleId)
{
throw new NotImplementedException();
}
public Task AuthorizeWithAmountAsync(int moneyAmountWithoutDecimalPoint, byte logicalNozzleId)
{
throw new NotImplementedException();
}
public Task AuthorizeWithVolumeAsync(int volumnWithoutDecimalPoint, byte logicalNozzleId)
{
throw new NotImplementedException();
}
public Task FuelingRoundUpByAmountAsync(int amount)
{
throw new NotImplementedException();
}
public Task FuelingRoundUpByVolumeAsync(int volume)
{
throw new NotImplementedException();
}
public async Task LockNozzleAsync(byte logicalNozzleId)
{
return false;
}
public async Task UnlockNozzleAsync(byte logicalNozzleId)
{
return false;
}
#endregion
}
}