using log4net; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using Wayne.ForecourtControl; using Wayne.ForecourtControl.Fusion; using Wayne.Lib; namespace FdcClient { public class PumpDeliveryProgressInfo { public PumpDeliveryProgressInfo() { CurrentQty = 0; CurrentAmount = 0; LogicalHoseId = 0; GradeFriendlyName = 0; GradeId = string.Empty; } public int PumpId { get; set; } public string GradeId { get; set; } public int LogicalHoseId { get; set; } public int GradeFriendlyName { get; set; } public Decimal CurrentQty { get; set; } public Decimal CurrentAmount { get; set; } } public class MyData { public AuthorizeParameters authParams = null; // pump auth parameters public IPump pump = null; // pump interface public bool authAfterReserve = false; public int pumpId = 0; public EventHandler ResultHandler = null; public EventHandler> TotalizerEventHandler; } public class FdcClient { public EventHandler PumpDeliveryProgressChangedEventHandler; public EventHandler FCConnectionStateChangeEventHandler; public EventHandler FuellingStateEventHandler; private IForecourtControl forecourtControl; static ILog logger = log4net.LogManager.GetLogger("Main"); private void RegisterPumpsEvents() { logger.Info("RegisterPumpsEvents Pumps count:" + forecourtControl.Pumps.Count); for (int i = 0; i < forecourtControl.Pumps.Count; i++) { this.forecourtControl.Pumps[i].OnFuellingDataChange += pump_OnFuellingDataChange; this.forecourtControl.Pumps[i].OnFuellingStateChange += pump_OnFuellingStateChange; this.forecourtControl.Pumps[i].OnNozzleStateChange += pump_OnNozzleStateChange; this.forecourtControl.Pumps[i].OnStateChange += pump_OnPumpStateChange; this.forecourtControl.Pumps[i].OnEventOccured += pump_OnEventOccured; this.forecourtControl.Pumps[i].RunningFuellingUpdates = false; } } private void UnRegisterPumpsEvents() { for (int i = 0; i < forecourtControl.Pumps.Count; i++) { this.forecourtControl.Pumps[i].OnFuellingDataChange -= pump_OnFuellingDataChange; this.forecourtControl.Pumps[i].OnFuellingStateChange -= pump_OnFuellingStateChange; this.forecourtControl.Pumps[i].OnNozzleStateChange -= pump_OnNozzleStateChange; this.forecourtControl.Pumps[i].OnStateChange -= pump_OnPumpStateChange; this.forecourtControl.Pumps[i].OnEventOccured -= pump_OnEventOccured; this.forecourtControl.Pumps[i].RunningFuellingUpdates = false; } } private void pump_OnEventOccured(object sender, PumpEventOccuredEventArgs e) { logger.Info("OnEventOccured, current event is:" + e.EventType); } private void pump_OnNozzleStateChange(object sender, NozzleStateChangeEventArgs e) { logger.Info("Nozzle State changed, current state is:" + e.NozzleState); var pump = sender as FUSIONPump; if (pump != null && pump.State == PumpState.Authorized && e.NozzleState == NozzleState.In) { var myData = new MyData(); myData.pump = pump; pump.UnauthorizeAsync(UnAuthorizePumpComplete, myData); } } private void pump_OnFuellingDataChange(object sender, FuellingDataChangeEventArgs e) { logger.Info("FuellingDataChange"); var gradeId = e.Fuelling.FuelGrade.ToString(); if (PumpDeliveryProgressChangedEventHandler != null) { var pumpDeliveryInfo = new PumpDeliveryProgressInfo() { PumpId = ((FUSIONPump)e.Fuelling.Pump).realId, GradeId = gradeId, LogicalHoseId = ((FUSIONNozzle)e.Fuelling.Nozzle).realId, GradeFriendlyName = int.Parse(gradeId), CurrentQty = e.Quantity, CurrentAmount = e.Amount }; logger.Info("FuellingDataChange - ProcessPumpDeliveryProgressChange CurrentQty:" + pumpDeliveryInfo.CurrentQty + "CurrentAmount:" + pumpDeliveryInfo.CurrentAmount); PumpDeliveryProgressChangedEventHandler.Invoke(this, pumpDeliveryInfo); } } private void pump_OnPumpStateChange(object sender, PumpStateChangeEventArgs e) { logger.Info(string.Format("Pump State Changed -- From FDC, state is: {0}", e.PumpState)); if (e.PumpState == PumpState.Starting) { //according to codes in previous project, when pump in in these state, can set the current fuelling data to 0 if (this.PumpDeliveryProgressChangedEventHandler != null) { var pumpDeliveryInfo = new PumpDeliveryProgressInfo() { PumpId = e.Pump.Id }; PumpDeliveryProgressChangedEventHandler.Invoke(this, pumpDeliveryInfo); } } } private void pump_OnFuellingStateChange(object sender, FuellingStateChangeEventArgs e) { logger.Info("Fuelling State changed, current state is:" + e.State + " PumpId:" + e.Fuelling.Pump.Id); if (e.State.Equals(FuellingState.PayableTransaction)) { //#if DEBUG // var handler = new TransactionHandler(); // var result = handler.Handle(e.Fuelling, "testtransaction", PaymentMethod.IC); // var setting = new JsonSerializerSettings(); // setting.Converters.Add(new PosJsonDateConverter()); // var value = JsonConvert.SerializeObject(result, setting); // scannerLogger.Info(value); // ClearFuelSale(e.Fuelling); //#else //scannerLogger.Info("Fuelling State changed, current state is: " + e.State + " PumpId: " + e.Fuelling.Pump.Id + ", will start Sniffing"); //var icTrxSniffer = new TransactionSniffer(); //icTrxSniffer.OnMatchingTrxScannedFromMySql += (s, a) => //{ // try // { // scannerLogger.Info($"OnMatchingTrxScannedFromMySql, trx was paid by: {a.MOP}"); // var mop = EnumSupport.Parse(a.MOP, true, PaymentMethod.CASH); // scannerLogger.Info($" Parsed MOP is: {mop}"); // if (mop != PaymentMethod.IC) // { // scannerLogger.Info($"Will do nothing since it's not an IC pay or valid Customer IC Card trx"); // return; // } // var handler = new ICTransactionUploader(); // var result = handler.Handle(e.Fuelling, a.QRCode, mop); // scannerLogger.Info("Start ClearFuelSale..."); // ClearFuelSale(e.Fuelling); // } // catch (Exception exp) // { // scannerLogger.Error("Finalize IC trx to cloud exceptioned: " + exp); // } //}; //icTrxSniffer.StartScanAsync(e.Fuelling.Pump.Id, e.Fuelling.FuellingSequenceNumber); ////#endif } if (e.State == FuellingState.PayableTransaction) { e.Fuelling.SetAsPaidAsync(SetAsPaidComplete, new object()); } FuellingStateEventHandler?.Invoke(this, e); } /// /// Process the Close(A6) request from IC /// 1, Pump in IDLE state, do nothing, success response /// 2, Pump in Authorized state, unAuthorize pump /// 3, Pump in Fuelling state, stop fuelling /// /// /// public void ClosePump(byte pumpId, EventHandler resultHandler) { logger.Info("ClosePump Request for Pump:" + pumpId); FUSIONPump pumpToClose = null; var myData = new MyData(); myData.pumpId = pumpId; myData.ResultHandler = resultHandler; foreach (var p in this.forecourtControl.Pumps) { if (p.Id == pumpId) { pumpToClose = (FUSIONPump)p; logger.Info("ClosePump current State:" + pumpToClose.State + " PumpId:" + pumpId); break; } } if (pumpToClose != null) { myData.pump = pumpToClose; if (pumpToClose.State == PumpState.Authorized) { this.UnAuthorizePump(pumpId, resultHandler); } else if (pumpToClose.State == PumpState.Fuelling) { pumpToClose.StopAsync(StopCompleted, myData); } else { if (resultHandler != null) { var e = new AsyncCompletedEventArgs(true, myData); resultHandler.Invoke(this, e); } } return; } if (resultHandler != null) { var e = new AsyncCompletedEventArgs(true, myData); resultHandler.Invoke(this, e); } } private void StopCompleted(object sender, AsyncCompletedEventArgs e) { logger.Info("StopCompleted, result:" + e.Success); var myData = (MyData)e.UserToken; myData.ResultHandler?.Invoke(this, e); } public void AuthPump(byte pumpId, AuthorizeParameters authPara, EventHandler ResultHandler) { logger.Info("AuthPump, Trying to Auth Pump:" + pumpId + " AuthParameter PresetType:" + authPara.PresetType + " Value:" + authPara.PresetValue); if (authPara.PresetValue == decimal.MaxValue) logger.Info("Rounding requested/凑整命令"); FUSIONPump pumpToAuth = null; var myData = new MyData(); myData.pumpId = pumpId; myData.authParams = authPara; foreach (var p in this.forecourtControl.Pumps) { if (p.Id == pumpId) { pumpToAuth = (FUSIONPump)p; logger.Info("AuthPump current State:" + pumpToAuth.State + " PumpId:" + pumpId); break; } } if (pumpToAuth == null) { logger.Info("Ingore the Request, Invalid Pump Id"); if (ResultHandler != null) { AsyncCompletedEventArgs e = new AsyncCompletedEventArgs(false, myData); ResultHandler.Invoke(this, e); } return; } myData.pump = pumpToAuth; myData.ResultHandler = ResultHandler; myData.authAfterReserve = true; logger.Info("AuthPump, reserving pump " + pumpToAuth.Id); pumpToAuth.ReserveAsync(FuellingType.OptCardPaid, pumpId, ReservedCompleted, myData); } public void RoundFueling(byte pumpId, AuthorizeParameters authPara, EventHandler ResultHandler) { logger.Info("RoundingRequest, Trying to round fueling on Pump:" + pumpId + " AuthParameter PresetType:" + authPara.PresetType + " Value:" + authPara.PresetValue); FUSIONPump pumpToAuth = null; var myData = new MyData(); myData.pumpId = pumpId; myData.authParams = authPara; foreach (var p in this.forecourtControl.Pumps) { if (p.Id == pumpId) { pumpToAuth = (FUSIONPump)p; logger.Info("AuthPump current State:" + pumpToAuth.State + " PumpId:" + pumpId); break; } } if (pumpToAuth == null) { logger.Info("Ingore the Request, Invalid Pump Id"); if (ResultHandler != null) { AsyncCompletedEventArgs e = new AsyncCompletedEventArgs(false, myData); ResultHandler.Invoke(this, e); } return; } myData.pump = pumpToAuth; myData.ResultHandler = ResultHandler; myData.authAfterReserve = true; logger.Info("AuthPump, reserving pump " + pumpToAuth.Id); pumpToAuth.ReserveAsync(FuellingType.OptCardPaid, pumpId, RoundingPrepareCompleted, myData); } /// /// Clear trans response /// /// /// private void SetAsPaidComplete(object sender, AsyncCompletedEventArgs e) { logger.Info("SetAsPaidComplete, result:" + e.Success); var myData = (MyData)e.UserToken; if (e.Success && myData.pump != null) { foreach (var f in myData.pump.Fuellings) { logger.Info("Fuelling state is : " + f.State); } //Reserve&Auth or only Reserve if (myData.authAfterReserve || myData.authParams == null) { myData.pump.ReserveAsync(FuellingType.OptCardPaid, (byte)myData.pump.Id, ReservedCompleted, myData); return; } myData.pump.AuthorizeAsync(myData.authParams, AuthPumpComplete, myData); return; } myData.ResultHandler?.Invoke(this, e); } public void ReservePump(byte pumpId, EventHandler ResultHandler) { logger.Info("ReservePump, Trying to Reserve Pump:" + pumpId); FUSIONPump pumpToAuth = null; var myData = new MyData(); myData.pumpId = pumpId; myData.authAfterReserve = false; myData.ResultHandler = ResultHandler; myData.authParams = null; foreach (var p in this.forecourtControl.Pumps) { if (p.Id == pumpId) { pumpToAuth = (FUSIONPump)p; break; } } if (pumpToAuth == null) { logger.Info("Ingore the Request, Invalid Pump Id"); if (ResultHandler != null) { var e = new AsyncCompletedEventArgs(false, myData); ResultHandler.Invoke(this, e); } return; } myData.pump = pumpToAuth; pumpToAuth.ReserveAsync(FuellingType.OptCardPaid, pumpId, ReservedCompleted, myData); } public void UnAuthorizePump(int pumpId, EventHandler ResultHandler) { logger.Info("UnAuthorizePump, Trying to UnAuth Pump:" + pumpId); FUSIONPump pumpToUnAuth = null; var myData = new MyData(); myData.pumpId = pumpId; myData.authAfterReserve = false; myData.ResultHandler = ResultHandler; myData.authParams = null; foreach (var p in this.forecourtControl.Pumps) { if (p.Id == pumpId /*&& p.State == PumpState.Authorized*/) { pumpToUnAuth = (FUSIONPump)p; break; } } if (pumpToUnAuth == null) { logger.Info("Ingore the Request, haven't get the pump required"); if (ResultHandler != null) { AsyncCompletedEventArgs e = new AsyncCompletedEventArgs(false, myData); ResultHandler.Invoke(this, e); } return; } if (pumpToUnAuth.State == PumpState.Authorized) { myData.pump = pumpToUnAuth; pumpToUnAuth.UnreserveAsync(UnReserveComplete, myData); Thread.Sleep(300); pumpToUnAuth.UnauthorizeAsync(UnAuthorizePumpComplete, myData); return; } ResultHandler?.Invoke(this, new AsyncCompletedEventArgs(true, myData)); } public void UnReservePump(int pumpId) { logger.Info("Unreserve the pump"); FUSIONPump pumpToUnReserve = null; var myData = new MyData(); myData.pumpId = pumpId; myData.authAfterReserve = false; myData.ResultHandler = null; myData.authParams = null; foreach (var p in this.forecourtControl.Pumps) { if (p.Id == pumpId && p.State == PumpState.Authorized) { pumpToUnReserve = (FUSIONPump)p; break; } } if (pumpToUnReserve == null) { logger.Info("Ingore the Unreserve Request, Invalid Pump Id"); return; } myData.pump = pumpToUnReserve; pumpToUnReserve.UnreserveAsync(UnReserveComplete, myData); } public void GetTotalizer(int pumpId, EventHandler> resultHandler) { logger.Info("GetTotalizer for Pump:" + pumpId); FUSIONPump targetPump = null; INozzle targetNozzle = null; foreach (var pump in this.forecourtControl.Pumps) { if (pump.Id == pumpId) { targetPump = (FUSIONPump)pump; break; } } if (targetPump == null) { logger.Info("Ingore the GetTotalizer Request, Invalid Pump Id"); return; } var myData = new MyData(); myData.pumpId = pumpId; myData.TotalizerEventHandler = resultHandler; targetPump.Nozzles.First().ReadPumpAccumulatorAsync(PumpAccumulatorRead, myData); } private void PumpAccumulatorRead(object sender, AsyncCompletedEventArgs e) { logger.Info("Totalizer response"); if (!e.Success) logger.Info("Failed to get totalizer"); var myData = e.UserToken as MyData; if (myData != null && myData.TotalizerEventHandler != null) myData.TotalizerEventHandler(this, e); } private void UnAuthorizePumpComplete(object sender, AsyncCompletedEventArgs e) { var myData = (MyData)e.UserToken; logger.Info("UnAuth Pump Cpmplete, Result:" + e.Success + " PumpId" + myData.pump.Id); myData.ResultHandler?.Invoke(this, e); } private void ReservedCompleted(object sender, AsyncCompletedEventArgs e) { logger.Info("Reserve Pump Result:" + e.Success); var myData = (MyData)e.UserToken; if (e.Success && myData.authParams != null && myData.authAfterReserve) { myData.pump.AuthorizeAsync(myData.authParams, AuthPumpComplete, myData); } else { myData.ResultHandler?.Invoke(this, e); } } private void RoundingPrepareCompleted(object sender, AsyncCompletedEventArgs e) { logger.Info("Rounding fuelling Result:" + e.Success); var myData = (MyData)e.UserToken; if (e.Success && myData.authParams != null && myData.authAfterReserve) { myData.pump.AuthorizeAsync(myData.authParams, RoundingResultComplete, myData); } else { myData.ResultHandler?.Invoke(this, e); } } private void AuthPumpComplete(object sender, AsyncCompletedEventArgs e) { var myData = (MyData)e.UserToken; logger.Info("AuthPumpComplete, result:" + e.Success + " PumpId" + myData.pump.Id); myData.pump.UnreserveAsync(UnReserveComplete, myData); if (e.Success) { //myData.pump.UnreserveAsync(UnReserveComplete, myData); } else { logger.Info("Failed to Authorize Pump"); } myData.ResultHandler?.Invoke(this, e); } private void RoundingResultComplete(object sender, AsyncCompletedEventArgs e) { var myData = (MyData)e.UserToken; logger.Info("AuthPumpComplete, result:" + e.Success + " PumpId" + myData.pump.Id); myData.pump.UnreserveAsync(UnReserveComplete, myData); if (e.Success) { //myData.pump.UnreserveAsync(UnReserveComplete, myData); } else { logger.Info("Failed to Authorize Pump"); } myData.ResultHandler?.Invoke(this, e); } private void UnReserveComplete(object sender, AsyncCompletedEventArgs e) { var myData = (MyData)e.UserToken; logger.Info("UnReserveComplete, result:" + e.Success + " PumpId" + myData.pump.Id); if (e.Success) { } else { logger.Info("Failed to UnReserve Pump"); } } private void ClearFuelSale(IFuelling fueling) { //fueling.ReserveAsync((a, b) => //{ // if (b.Success) // { // scannerLogger.Info(string.Format("Fuel sale locked successfully, will trying to Clear, SeqNO = {0}", fueling.FuellingSequenceNumber)); // fueling.SetAsPaidAsync((c, d) => // { // if (d.Success) // { // scannerLogger.Info(string.Format("Fuel sale paid successfully, SeqNO = {0}", fueling.FuellingSequenceNumber)); // } // else // { // scannerLogger.Info(string.Format("Fuel sale paid failed, SeqNO = {0}", fueling.FuellingSequenceNumber)); // } // }, fueling); // } // else // { // scannerLogger.Info(string.Format("Fuel sale locked failed, will not clear, SeqNO = {0}", fueling.FuellingSequenceNumber)); // } //}, fueling); } public void Dispose() { this.forecourtControl.Dispose(); } } }