FuelingPoint.cs 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259
  1. using Edge.Core.Processor;using Edge.Core.IndustryStandardInterface.Pump;
  2. using Edge.Core.Parser.BinaryParser.Util;
  3. using SinochemCarplateService.Models;
  4. using SinochemCloudClient.Models;
  5. using SinochemPosClient.Models;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Configuration;
  9. using System.Linq;
  10. using System.Text;
  11. using System.Threading;
  12. using System.Threading.Tasks;
  13. using Wayne.Lib.StateEngine;
  14. using WayneChina_IcCardReader_SinoChem.MessageEntity;
  15. using WayneChina_IcCardReader_SinoChem.MessageEntity.Incoming;
  16. using WayneChina_IcCardReader_SinoChem.MessageEntity.Outgoing;
  17. namespace SinochemInternetPlusApp
  18. {
  19. public class ReceiptLine
  20. {
  21. public ReceiptLine(byte[] bytes, int lineWidth)
  22. {
  23. Line = new byte[lineWidth];
  24. bytes.CopyTo(Line, 0);
  25. }
  26. public byte[] Line { get; set; }
  27. }
  28. public class FuelingPoint : StateManager
  29. {
  30. #region Fields
  31. //Immutable after construction
  32. public int FuelingPointId { get; }
  33. private byte initialSqNo = 0;
  34. private byte sqNo;
  35. private object syncObj = new object();
  36. private Queue<IcCardReaderMessageBase> outboundMsgQueue = new Queue<IcCardReaderMessageBase>();
  37. private object queueSyncObj = new object();
  38. private object evSyncObj = new object();
  39. private object operantionSyncObj = new object();
  40. private List<int> requestIdList = new List<int>();
  41. private object reqIdSyncObj = new object();
  42. private bool printerIdle = true;
  43. private object printerSyncObj = new object();
  44. private byte currentSqNo { get; set; }
  45. private object sqNoSyncObj = new object();
  46. private IFdcPumpController callingPump;
  47. #endregion
  48. #region Timeout values
  49. //in seconds
  50. public int CardReaderDisplayTimeout { get { return 10; } }
  51. //in milliseconds
  52. public int CardReaderBackToIdleTimeout { get { return 2000; } }
  53. #endregion
  54. #region Properties
  55. /// <summary>
  56. /// Current physical nozzle id, reflecting the running nozzle of this FP.
  57. /// </summary>
  58. public int CurrentNozzleId { get; set; }
  59. /// <summary>
  60. /// The physical nozzles associated with this fueling point
  61. /// </summary>
  62. public IEnumerable<int> AssociatedNozzles { get; set; }
  63. public Eps Eps { get; set; }
  64. public EpsTransaction NewEpsTrx { get; set; }
  65. public EpsTransaction CurrentEpsTrx { get; set; }
  66. public EpsTransactionMode CurrentTrxMode { get; set; }
  67. public long? AuthorizationId { get; set; }
  68. public byte ResetSqNo;
  69. public override string EntityType => "FuelingPoint";
  70. public override string EntitySubType => "";
  71. public IEnumerable<EpsTransactionModel> ActiveTrx { get; set; }
  72. public CardOnlineVerificationRequest OnlineVerificationRequest { get; set; }
  73. public WayneChina_IcCardReader_SinoChem.Handler CurrentCardReader => Eps.GetHandler(FuelingPointId);
  74. public SignDataResponse SignedData { get; internal set; }
  75. public List<ReceiptLine> CurrentReceipt { get; set; }
  76. public bool CardReaderDisabled { get; set; } = false;
  77. public byte IdleStateCardReaderSqNo { get; set; }
  78. public int GetPrinterCount { get; set; }
  79. private Dictionary<int, string> NozzeIdGradeNameDictOnThisSide = new Dictionary<int, string>();
  80. /// <summary>
  81. /// Site id aka Station number
  82. /// </summary>
  83. public string StationNo => GenericSinochemEpsApp.AppSettings["SinochemSiteId"];
  84. /// <summary>
  85. /// Site name aka Station name
  86. /// </summary>
  87. public string StationName => GenericSinochemEpsApp.AppSettings["SinochemSiteName"];
  88. private bool printReceiptEnabled => Convert.ToBoolean(GenericSinochemEpsApp.AppSettings["PrintReceiptEnabled"]);
  89. private bool printQRCodeEnabled => Convert.ToBoolean(GenericSinochemEpsApp.AppSettings["PrintQrCodeOnReceiptEnabled"]);
  90. private int? liftedNozzleId = null;
  91. #endregion
  92. #region Request Id operations
  93. public void AddRequestId(int reqIid)
  94. {
  95. lock (reqIdSyncObj)
  96. {
  97. requestIdList.Add(reqIid);
  98. }
  99. }
  100. public void RemoveRequestId(int reqIid)
  101. {
  102. lock (reqIdSyncObj)
  103. {
  104. requestIdList.Remove(reqIid);
  105. }
  106. }
  107. public bool ContainsRequestId(int reqIid)
  108. {
  109. lock (reqIdSyncObj)
  110. {
  111. return requestIdList.Contains(reqIid);
  112. }
  113. }
  114. public void ClearAllRequestIds()
  115. {
  116. lock (reqIdSyncObj)
  117. {
  118. foreach (var id in requestIdList)
  119. {
  120. debugLogger.Add($"Clearing RequestId: {id}");
  121. }
  122. requestIdList.Clear();
  123. }
  124. }
  125. #endregion
  126. #region Constructor
  127. public FuelingPoint(int fuelingPointId, IEnumerable<int> associatedNozzles, Eps eps) : base(fuelingPointId, "FuelingPoint")
  128. {
  129. FuelingPointId = fuelingPointId;
  130. AssociatedNozzles = associatedNozzles;
  131. Eps = eps;
  132. }
  133. #endregion
  134. public override void Start()
  135. {
  136. base.Start();
  137. Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
  138. }
  139. #region DB & Trx handling
  140. /// <summary>
  141. /// Create an eps trx given the mop type.
  142. /// </summary>
  143. /// <param name="mop"></param>
  144. internal void CreateEpsTransaction(EpsTransactionMode mop)
  145. {
  146. CurrentEpsTrx = EpsTransaction.CreateEpsTrx(CurrentNozzleId, mop, debugLogger);
  147. }
  148. internal void LockTrxInXiaofei2AsEpsTrx()
  149. {
  150. if (CurrentEpsTrx.MoveFromXiaofei2(debugLogger))
  151. {
  152. }
  153. else
  154. {
  155. debugLogger.Add("trx in xiaofei2 not found!!!!");
  156. }
  157. }
  158. #endregion
  159. #region Cloud & POS interactions
  160. internal void NotifyPosAync()
  161. {
  162. ThreadPool.QueueUserWorkItem(_ =>
  163. {
  164. TrxNotificationResponse response = Eps.NotifySuccessfulTrxToPos(CurrentEpsTrx.Model, debugLogger);
  165. if (response != null && response.IsSuccessful())
  166. {
  167. stateMachine.IncomingEvent(new StateEngineEvent(EventType.PosNotifyOk));
  168. }
  169. else
  170. {
  171. stateMachine.IncomingEvent(new StateEngineEvent(EventType.PosNotifyFailed));
  172. }
  173. });
  174. }
  175. internal void SendPaymentToCloudAsync()
  176. {
  177. ThreadPool.QueueUserWorkItem(_ =>
  178. {
  179. if (CurrentEpsTrx != null)
  180. {
  181. PaymentResponse response = Eps.SendPaymentToCloud(CurrentEpsTrx.Model, debugLogger);
  182. if (response != null)
  183. {
  184. switch (response.code)
  185. {
  186. case PaymentResponse.SuccessResponse:
  187. {
  188. stateMachine.IncomingEvent(GenericEvent.Create(EventType.CloudPaymentOk, this, response));
  189. break;
  190. }
  191. //CarPlate User, need print the pay_url
  192. case PaymentResponse.QRCodeResponse:
  193. {
  194. if (response.result != null && !string.IsNullOrEmpty(response.result.pay_url))
  195. stateMachine.IncomingEvent(GenericEvent.Create(EventType.QRCodePayment, this, response));
  196. else
  197. stateMachine.IncomingEvent(GenericEvent.Create(EventType.CloudPaymentFailed, this, response));
  198. break;
  199. }
  200. //普通车主
  201. case PaymentResponse.PlainUserResponse:
  202. {
  203. stateMachine.IncomingEvent(GenericEvent.Create(EventType.PlainUser_Unpaid, this, response));
  204. break;
  205. }
  206. default:
  207. {
  208. if (response.result != null && !string.IsNullOrEmpty(response.result.pay_url))
  209. stateMachine.IncomingEvent(GenericEvent.Create(EventType.CloudPaymentFailed, this, response));
  210. else
  211. stateMachine.IncomingEvent(GenericEvent.Create(EventType.PlainUser_Unpaid, this, response));
  212. break;
  213. }
  214. }
  215. }
  216. }
  217. else
  218. {
  219. stateMachine.IncomingEvent(new StateEngineEvent(EventType.CloudPaymentFailed));
  220. }
  221. });
  222. }
  223. internal void NotifyPaymentFailedAsync()
  224. {
  225. ThreadPool.QueueUserWorkItem(_ =>
  226. {
  227. stateMachine.IncomingEvent(new StateEngineEvent(EventType.CloudPaymentFailed));
  228. });
  229. }
  230. internal void SendBalanceQueryToCloudAsync(string cardNo, string encryptedPin, string tid, int nozzleId)
  231. {
  232. ThreadPool.QueueUserWorkItem(_ =>
  233. {
  234. BalanceInquiryResponse response = Eps.SendBalanceInquiryToCloud(cardNo, encryptedPin, tid, nozzleId, debugLogger);
  235. if (response != null && response.IsSuccessful())
  236. {
  237. stateMachine.IncomingEvent(GenericEvent.Create(EventType.CloudBalanceOk, this, response));
  238. }
  239. else
  240. {
  241. stateMachine.IncomingEvent(new StateEngineEvent(EventType.CloudBalanceFailed));
  242. }
  243. });
  244. }
  245. #endregion
  246. #region Pump interactions
  247. internal void AuthorizePumpAsync(decimal authAmount)
  248. {
  249. Eps.AuthorizePumpAsync(callingPump, CurrentNozzleId, authAmount);
  250. }
  251. internal List<int> GetAllNozzlesOnThisSide()
  252. {
  253. List<int> nozzles = new List<int>();
  254. if (CurrentCardReader.NumberOfNozzlesPerSide != 1)
  255. {
  256. foreach (var fp in CurrentCardReader.SupportedNozzles)
  257. {
  258. var fuelingPoint = this.Eps.GetFuelingPoint(fp);
  259. if (fuelingPoint != null)
  260. nozzles.AddRange(fuelingPoint.AssociatedNozzles);
  261. }
  262. }
  263. else
  264. {
  265. nozzles.AddRange(AssociatedNozzles);
  266. }
  267. return nozzles;
  268. }
  269. internal bool HasBigSreen()
  270. {
  271. return CurrentCardReader.HasBigScreen;
  272. }
  273. #endregion
  274. #region Eps state config and signal
  275. protected override void ConfigStates()
  276. {
  277. States.CONFIGURATION.Config(stateMachine.StateTransitionLookup);
  278. }
  279. public void SignalShutdown()
  280. {
  281. Console.Out.WriteLine("SignalShutdown");
  282. stateMachine.IncomingEvent(new StateEngineEvent(EventType.ShutdownRequest));
  283. }
  284. public void FinalStateReached(string name)
  285. {
  286. Console.Out.WriteLine(name + " FinalStateReached");
  287. }
  288. #endregion
  289. #region Card Plate
  290. public void SignalNewCarplate(CarPlateTrxRequest request)
  291. {
  292. lock (evSyncObj)
  293. {
  294. if (request != null && AssociatedNozzles.Contains(Convert.ToInt32(request.gun)))
  295. {
  296. debugLogger.AddIfActive
  297. ($"New car plate info arrived: Gun: {request.gun}, License plate No: {request.car_Number}, Balance: {request.amount}");
  298. stateMachine.IncomingEvent(GenericEvent.Create(EventType.CarPlateScanned, this, request));
  299. }
  300. }
  301. }
  302. #endregion
  303. #region Display on dispenser interactions
  304. public void SignalDisplayResponseReceived(DisplayResponse response)
  305. {
  306. debugLogger.AddIfActive("DisplayResponse from big screen");
  307. stateMachine.IncomingEvent(new GenericEvent<DisplayResponseEventArgs>(
  308. EventType.DisplayResponseReceived, this, new DisplayResponseEventArgs(response)));
  309. }
  310. public bool SignalTrxOpRequest(TransactionOperation request)
  311. {
  312. debugLogger.AddIfActive($"Transaction operation request from big screen, Trx id: {request?.TrxId}, Op:{request?.OpType}");
  313. bool result = false;
  314. if (request != null)
  315. {
  316. int trxId = request.TrxId;
  317. var validTrx = EpsTransactionQuery.GetValidCarPlateEpsTrxModels(
  318. GetAllNozzlesOnThisSide(),
  319. ConfigurationValues.AlreadyDoneEpsTrxCountPerDisplay,
  320. DebugLogger);
  321. if (request.OpType == OpType.NozzleSelect)
  322. {
  323. int selectedNozzleNo = int.Parse(request.NozzleNo);
  324. string gradeName = Eps.NozzleMappingGradeName()?.Where(i => i.Key == selectedNozzleNo).Select(n => n.Value).FirstOrDefault();
  325. foreach (var trx in validTrx)
  326. {
  327. if (trx.id == trxId)
  328. {
  329. lock (operantionSyncObj)
  330. {
  331. debugLogger.Add($"Current selected nozzle, number = {selectedNozzleNo}");
  332. //ICCard sale, need to remove the trx created when carplate scanned
  333. if (CurrentEpsTrx != null && CurrentEpsTrx.Model.mop == EpsTransactionMode.ICCardMode)
  334. {
  335. debugLogger.Add("nozzleSelected CurrentEpsTrx is ICCardMode, ICCardEpsTrxId:" + CurrentEpsTrx.Model.id);
  336. CurrentEpsTrx.Model.mop = EpsTransactionMode.CarPlateMode;
  337. CurrentEpsTrx.Model.car_number = trx.car_number;
  338. CurrentEpsTrx.Model.jihao = selectedNozzleNo;
  339. CurrentEpsTrx.Model.youpin = gradeName;
  340. CurrentEpsTrx.Model.nozzleSelected = 1;
  341. CurrentEpsTrx.SaveToDb();
  342. //Remove the epsTrx for carplate scanned
  343. EpsTransaction.RestroeEpsTrxFrom(trx).UpdateTrxStatusToDb(trx, EpsTrxStatus.Removed);
  344. }
  345. else if (CurrentEpsTrx != null && CurrentEpsTrx.Model.id == trx.id)
  346. {
  347. trx.jihao = selectedNozzleNo;
  348. CurrentEpsTrx.Model.jihao = selectedNozzleNo;
  349. trx.youpin = gradeName;
  350. CurrentEpsTrx.Model.youpin = gradeName;
  351. trx.nozzleSelected = 1;
  352. CurrentEpsTrx.Model.nozzleSelected = 1;
  353. var fp = Eps.GetFp(selectedNozzleNo);
  354. PumpState fpStatus = Eps.GetFPState(fp.Id);
  355. debugLogger.Add($"CurrentEpsTrx not null 1, currentEpsTrx Id = {CurrentEpsTrx.Model.id}, " +
  356. $"request trx id: {trx.id}, fpStattus = {fpStatus}, jihao = {trx.jihao}");
  357. if (fpStatus == PumpState.Fuelling)
  358. {
  359. debugLogger.Add("setting pump state to fuelling");
  360. trx.trx_status = EpsTrxStatus.Fueling;
  361. CurrentEpsTrx.Model.trx_status = EpsTrxStatus.Fueling;
  362. }
  363. else if (fpStatus == PumpState.Idle)
  364. {
  365. debugLogger.Add("setting pump state to BeforeFueling");
  366. trx.trx_status = EpsTrxStatus.BeforeFueling;
  367. CurrentEpsTrx.Model.trx_status = EpsTrxStatus.BeforeFueling;
  368. }
  369. var restoredTrx = EpsTransaction.RestroeEpsTrxFrom(trx);
  370. if (restoredTrx != null)
  371. {
  372. debugLogger.Add($"restored trx, jihao = {restoredTrx.Model.jihao}");
  373. restoredTrx.SaveToDb();
  374. debugLogger.Add("Restored Eps transaction and saved to database");
  375. }
  376. CurrentEpsTrx.SaveToDb();
  377. }
  378. else
  379. {
  380. if (CurrentEpsTrx != null)
  381. {
  382. var RestoredCurrentEpsTrxModel = EpsTransactionQuery.RefreshEpsTrx(CurrentEpsTrx.Model.id);
  383. //1 nozzle, Only 1 trx that the status is Fueling
  384. if (RestoredCurrentEpsTrxModel != null
  385. && RestoredCurrentEpsTrxModel.trx_status == EpsTrxStatus.Fueling
  386. && RestoredCurrentEpsTrxModel.jihao == selectedNozzleNo
  387. && RestoredCurrentEpsTrxModel.id != trx.id)
  388. {
  389. CurrentEpsTrx.UpdateTrxStatusToDb(CurrentEpsTrx.Model, EpsTrxStatus.BeforeFueling);
  390. }
  391. }
  392. CurrentEpsTrx = EpsTransaction.RestroeEpsTrxFrom(trx);
  393. CurrentEpsTrx.Model.jihao = selectedNozzleNo;
  394. CurrentEpsTrx.Model.youpin = gradeName;
  395. CurrentEpsTrx.Model.nozzleSelected = 1;
  396. var fp = Eps.GetFp(selectedNozzleNo);
  397. PumpState fpStatus = Eps.GetFPState(fp.Id);
  398. debugLogger.Add($"CurrentEpsTrx not null 3, currentEpsTrx Id = {CurrentEpsTrx.Model.id}, request trx id: {trx.id}, fpStattus = {fpStatus}");
  399. if (fpStatus == PumpState.Fuelling)
  400. {
  401. CurrentEpsTrx.Model.trx_status = EpsTrxStatus.Fueling;
  402. }
  403. else if (fpStatus == PumpState.Idle)
  404. {
  405. CurrentEpsTrx.Model.trx_status = EpsTrxStatus.BeforeFueling;
  406. }
  407. CurrentEpsTrx.SaveToDb();
  408. }
  409. BroadcastTrxListChanged(true);
  410. result = true;
  411. DebugLogger.Add(string.Format("Nozzle {0} Selected, update db", selectedNozzleNo));
  412. break;
  413. }
  414. }
  415. }
  416. }
  417. else if (request.OpType == OpType.Delete)
  418. {
  419. debugLogger.AddIfActive($"Delete Transaction operation request: {trxId}");
  420. foreach (var trx in validTrx)
  421. {
  422. if (trx.id == trxId)
  423. {
  424. lock (operantionSyncObj)
  425. {
  426. //Remove the epsTrx for carplate scanned
  427. EpsTransaction.RestroeEpsTrxFrom(trx).UpdateTrxStatusToDb(trx, EpsTrxStatus.Removed);
  428. if (CurrentEpsTrx != null && CurrentEpsTrx.Model.id == trx.id)
  429. {
  430. debugLogger.AddIfActive($"Delete Transaction operation request3: {CurrentEpsTrx.Model.id}");
  431. CurrentEpsTrx = null;
  432. }
  433. result = true;
  434. BroadcastTrxListChanged();
  435. break;
  436. }
  437. }
  438. }
  439. }
  440. }
  441. return result;
  442. //stateMachine.IncomingEvent(new GenericEvent<TransactionOperationEventArgs>(EventType.TrxOpRequest, this, new TransactionOperationEventArgs(request)));
  443. }
  444. private void BroadcastTrxListChanged(bool nozzleSelected = false)
  445. {
  446. var validTrx = EpsTransactionQuery.GetValidCarPlateEpsTrxModels(
  447. GetAllNozzlesOnThisSide(),
  448. ConfigurationValues.AlreadyDoneEpsTrxCountPerDisplay,
  449. DebugLogger);
  450. var availableNozzleInfo = GetAvailableNozzleInfo();
  451. if (availableNozzleInfo != null)
  452. {
  453. foreach (var trx in validTrx)
  454. {
  455. if (trx.trx_status == EpsTrxStatus.BeforeFueling || trx.trx_status == EpsTrxStatus.Fueling)
  456. {
  457. trx.AvailableNozzleGrade = availableNozzleInfo;
  458. }
  459. }
  460. }
  461. int trxOpRequestId;
  462. //Refresh 15" screen
  463. var text = Eps.CreateDisplayTrxCommand(validTrx, out trxOpRequestId, 0);
  464. if (Eps.CarPlateHandler != null)
  465. {
  466. DebugLogger.AddIfActive("NozzleSelected broadcast text:" + text);
  467. Eps.CarPlateHandler.BroadcastMessageViaFdc(text);
  468. }
  469. }
  470. #endregion
  471. #region Card reader signals
  472. public void SingalAckReceived(ACK cardReaderMessage)
  473. {
  474. lock (sqNoSyncObj)
  475. {
  476. if (cardReaderMessage.MessageSeqNumber == currentSqNo)
  477. {
  478. debugLogger.AddIfActive($"Received card reader message with MsgSqNo = {cardReaderMessage.MessageSeqNumber}");
  479. outboundMsgQueue.Dequeue();
  480. debugLogger.AddIfActive($"Removed the message from the queue");
  481. }
  482. }
  483. stateMachine.IncomingEvent(new GenericEvent<CardReaderAckEventArgs>(EventType.CardReaderAck, this, new CardReaderAckEventArgs(cardReaderMessage)));
  484. }
  485. public void SignalCardReaderDisconnected()
  486. {
  487. stateMachine.IncomingEvent(new StateEngineEvent(EventType.CardReaderDisconnected));
  488. }
  489. public void SignalCardReaderDisabled()
  490. {
  491. stateMachine.IncomingEvent(new StateEngineEvent(EventType.ICCardReaderDisabled));
  492. }
  493. public void SignalCardReaderHeartbeat(HeartBeat heartBeat)
  494. {
  495. SendNextCardReaderMessage(heartBeat);
  496. }
  497. public void SignalRepeatedMessageRecieved(IcCardReaderMessageBase message)
  498. {
  499. SendAckToCardReader(message.SourceAddress, message.MessageSeqNumber);
  500. }
  501. public void SignalSignedDataArrived(SignDataResponse cardReaderMessage)
  502. {
  503. debugLogger.AddIfActive("sending ack for SignDataResponse");
  504. SendAckToCardReader(cardReaderMessage.SourceAddress, cardReaderMessage.MessageSeqNumber);
  505. stateMachine.IncomingEvent(new GenericEvent<SignedDataEventArgs>(EventType.DataSigned, this, new SignedDataEventArgs(cardReaderMessage)));
  506. }
  507. public void SingalCardReaderStateEvent(CardReaderStateEvent cardReaderStateEvent)
  508. {
  509. debugLogger.AddIfActive($"CardReaderStateEvent \n source address: {cardReaderStateEvent.SourceAddress} \n SqNo: {cardReaderStateEvent.MessageSeqNumber} \n Reader state: {cardReaderStateEvent.State.ToString()}");
  510. SendAckToCardReader(cardReaderStateEvent.SourceAddress, cardReaderStateEvent.MessageSeqNumber);
  511. stateMachine.IncomingEvent(new GenericEvent<CardReaderStateEventArgs>(EventType.ReaderStateChanged, this, new CardReaderStateEventArgs(cardReaderStateEvent)));
  512. }
  513. private void SendAckToCardReader(byte srcAddress, byte sqNo)
  514. {
  515. ACK ack = new ACK { SourceAddress = srcAddress, MessageSeqNumber = sqNo };
  516. if (CurrentCardReader != null)
  517. CurrentCardReader.Write(ack);
  518. }
  519. public void SignalCardExternalCheckFailure(CardExternalCheckErrorRequest cardReaderMessage)
  520. {
  521. debugLogger.AddIfActive($"IC Card check failure, Error reason: {cardReaderMessage.ErrorType.ToString()}");
  522. SendAckToCardReader(cardReaderMessage.SourceAddress, cardReaderMessage.MessageSeqNumber);
  523. stateMachine.IncomingEvent(new GenericEvent<ExternalCheckFailedEventArgs>(EventType.ExternalCheckFailure, this, new ExternalCheckFailedEventArgs(cardReaderMessage)));
  524. }
  525. public void SignalCardOnlineVerification(CardOnlineVerificationRequest cardReaderMessage)
  526. {
  527. debugLogger.AddIfActive($"IC Card online verification request, Card No: {cardReaderMessage.CardNo}, Encrypted PIN: {cardReaderMessage.EncryptedPIN}, TID: {cardReaderMessage.TID}");
  528. SendAckToCardReader(cardReaderMessage.SourceAddress, cardReaderMessage.MessageSeqNumber);
  529. stateMachine.IncomingEvent(new GenericEvent<CardOnlineVerificationEventArgs>(EventType.OnlineVerification, this, new CardOnlineVerificationEventArgs(cardReaderMessage)));
  530. }
  531. #endregion
  532. #region Pump signals
  533. // phase out, 2020/02/17
  534. //internal void SignalNozzleLifted(IPump callingPump, int sitewiseNozzleId)
  535. //{
  536. // debugLogger.Add("SignalNozzleLifted, nozzleid -- " + sitewiseNozzleId);
  537. // this.callingPump = callingPump;
  538. // stateMachine.IncomingEvent(
  539. // new GenericEvent<NozzleLiftedEventArgs>(
  540. // EventType.NozzleLifted,
  541. // this,
  542. // new NozzleLiftedEventArgs() { NozzleId = sitewiseNozzleId }));
  543. //}
  544. internal void SignalNozzleLifted(IFdcPumpController callingPump, int sitewiseNozzleId)
  545. {
  546. debugLogger.Add("SignalNozzleLifted, nozzleid -- " + sitewiseNozzleId);
  547. this.callingPump = callingPump;
  548. this.liftedNozzleId = sitewiseNozzleId;
  549. stateMachine.IncomingEvent(
  550. new GenericEvent<NozzleLiftedEventArgs>(
  551. EventType.NozzleLifted,
  552. this,
  553. new NozzleLiftedEventArgs() { NozzleId = sitewiseNozzleId }));
  554. }
  555. internal void SignalNozzleReplaced(int sitewiseNozzleId, int pumpId)
  556. {
  557. if (sitewiseNozzleId != 0)
  558. {
  559. debugLogger.Add("SignalNozzleReplaced, nozzleid -- " + sitewiseNozzleId);
  560. stateMachine.IncomingEvent(new GenericEvent<NozzleReplacedEventArgs>
  561. (EventType.NozzleReplaced, this, new NozzleReplacedEventArgs() { NozzleId = sitewiseNozzleId }));
  562. }
  563. else
  564. {
  565. debugLogger.Add($"SignalNozzleReplaced, nozzleid -- {sitewiseNozzleId}, use last lifted nozzle id: {liftedNozzleId}");
  566. if (liftedNozzleId.HasValue)
  567. {
  568. stateMachine.IncomingEvent(new GenericEvent<NozzleReplacedEventArgs>
  569. (EventType.NozzleReplaced, this, new NozzleReplacedEventArgs() { NozzleId = liftedNozzleId.Value }));
  570. }
  571. }
  572. }
  573. internal void SignalAuthOk(long? authId)
  574. {
  575. debugLogger.Add("SignalAuthOk -- " + authId);
  576. AuthorizationId = authId;
  577. var arg = new GenericEventArg<string>(DateTime.Now.ToString("HH:mm:ss"));
  578. stateMachine.IncomingEvent(GenericEvent.Create(EventType.PumpAuthOk, this, arg));
  579. }
  580. internal void SignalAuthFailed()
  581. {
  582. debugLogger.Add("SignalAuthFailed");
  583. stateMachine.IncomingEvent(new StateEngineEvent(EventType.PumpAuthFailed));
  584. }
  585. internal void SignalFuelingDone(int nozzleId, int seqNum, decimal fuelAmount, decimal fuelingQty, long authId)
  586. {
  587. debugLogger.Add("SignalFuelingDone -- " + authId);
  588. stateMachine.IncomingEvent(new GenericEvent<FuelingDoneEventArgs>(EventType.FuelingDone, this,
  589. new FuelingDoneEventArgs
  590. {
  591. NozzleId = nozzleId,
  592. FuelingSqNo = seqNum,
  593. Amount = fuelAmount,
  594. Quantity = fuelingQty,
  595. AuthId = authId
  596. }));
  597. }
  598. #endregion
  599. #region Card reader support
  600. /// <summary>
  601. /// Sender side's sequence number, 01H-0FH, when program restarted, use 00H.
  602. /// </summary>
  603. /// <returns>The sequence number byte.</returns>
  604. public byte GetSenderSideSqNo()
  605. {
  606. lock (syncObj)
  607. {
  608. if (initialSqNo == 0)
  609. {
  610. sqNo = initialSqNo;
  611. initialSqNo = 1;
  612. return sqNo;
  613. }
  614. byte nextSqNo = (byte)(sqNo++ % 16);
  615. if (nextSqNo == 0)
  616. {
  617. sqNo++;
  618. return initialSqNo;
  619. }
  620. return nextSqNo;
  621. }
  622. }
  623. public byte CardReaderSrcAddr
  624. {
  625. get
  626. {
  627. return (byte)(CurrentCardReader?.GetAddressForNozzleId(FuelingPointId));
  628. }
  629. }
  630. public void SendCommand(IcCardReaderMessageBase command, out byte sqNo)
  631. {
  632. command.MessageSeqNumber = GetSenderSideSqNo();
  633. command.SourceAddress = CardReaderSrcAddr;
  634. sqNo = command.MessageSeqNumber;
  635. PendMessage(command);
  636. }
  637. public void PendMessage(IcCardReaderMessageBase msg)
  638. {
  639. lock (queueSyncObj)
  640. {
  641. outboundMsgQueue.Enqueue(msg);
  642. }
  643. }
  644. public void RemovePendingBalanceResult()
  645. {
  646. lock (queueSyncObj)
  647. {
  648. var result = outboundMsgQueue.FirstOrDefault(m => m is CardOnlineVerificationResultRequest);
  649. if (result != null)
  650. {
  651. debugLogger.AddIfActive($"Removing item: {result.ToLogString()}");
  652. outboundMsgQueue = new Queue<IcCardReaderMessageBase>(outboundMsgQueue.Where(m => m != result));
  653. }
  654. }
  655. }
  656. public void SendNextCardReaderMessage(HeartBeat heartBeat)
  657. {
  658. lock (queueSyncObj)
  659. {
  660. if (outboundMsgQueue.Count > 0)
  661. {
  662. var msgToSend = outboundMsgQueue.Peek();
  663. lock (sqNoSyncObj)
  664. {
  665. currentSqNo = msgToSend.MessageSeqNumber;
  666. }
  667. debugLogger.AddIfActive($"Peek and send Card reader message {msgToSend.GetType().ToString()} with MsgSqNo = {msgToSend.MessageSeqNumber}");
  668. CurrentCardReader?.Write(msgToSend);
  669. }
  670. else
  671. {
  672. var eot = new EOT
  673. {
  674. SourceAddress = CardReaderSrcAddr,
  675. MessageSeqNumber = 0
  676. };
  677. CurrentCardReader?.Write(eot);
  678. }
  679. }
  680. }
  681. #endregion
  682. #region Receipt
  683. public void BuildReceipt()
  684. {
  685. if (CurrentReceipt == null)
  686. CurrentReceipt = new List<ReceiptLine>();
  687. else
  688. CurrentReceipt.Clear();
  689. List<string> bodyLines = new List<string>();
  690. List<string> header = new List<string>();
  691. List<string> product = new List<string>();
  692. List<string> payment = new List<string>();
  693. ReceiptModel receiptModel = ReceiptModelBuilder.BuildReceiptModel(CurrentEpsTrx, CurrentTrxMode);
  694. string lineSeparator = "------------------------------";
  695. string emptyLine = " ";
  696. //string receiptHeaderReceiptType = string.Format($" {receiptModel.TrxModeName}小票 ");
  697. string stationName = "油站名称:" + StationName;
  698. string trxTimeStamp = "时间:" + Utilities.ConvertDateTimeToReadble(DateTime.Now);
  699. string runningNumberLine = "流水号:" + receiptModel.RunningNumber;
  700. string cardNoLine = "卡号:" + receiptModel.CardNo;
  701. string gradeNameLine = "油品:" + receiptModel.GradeName;
  702. string nozzleIdLine = "枪号:" + receiptModel.NozzleId;
  703. string ppuLine = "单价:" + receiptModel.PPU + "元/升";
  704. string qtyLine = "数量:" + receiptModel.Qty + "升";
  705. string amountLine = "金额:" + receiptModel.Amount + "元";
  706. string dueAmountLine = string.Format($"应付: {receiptModel.DueAmount}元");
  707. string discountLine = string.Format($"优惠: {receiptModel.DiscountAmount}元");
  708. string payAmountLine = string.Format($"实付: {receiptModel.PayAmount}元");
  709. //header.Add(receiptHeaderReceiptType);
  710. header.Add(emptyLine);
  711. header.Add(stationName);
  712. header.Add(trxTimeStamp);
  713. header.Add(runningNumberLine);
  714. header.Add(cardNoLine);
  715. header.Add(lineSeparator);
  716. //Add header
  717. bodyLines.AddRange(header);
  718. product.Add(gradeNameLine);
  719. product.Add(nozzleIdLine);
  720. product.Add(ppuLine);
  721. product.Add(qtyLine);
  722. product.Add(amountLine);
  723. product.Add(lineSeparator);
  724. //Add product details
  725. bodyLines.AddRange(product);
  726. payment.Add(dueAmountLine);
  727. payment.Add(discountLine);
  728. payment.Add(payAmountLine);
  729. payment.Add(lineSeparator);
  730. //Add payment details
  731. bodyLines.AddRange(payment);
  732. //QR code
  733. if (printQRCodeEnabled && !string.IsNullOrEmpty(receiptModel.PayUrl))
  734. {
  735. string invoicePromptLine = string.Format(" 微信支付二维码 ");
  736. bodyLines.Add(invoicePromptLine);
  737. bodyLines.Add(emptyLine);
  738. }
  739. else if (printQRCodeEnabled && !string.IsNullOrEmpty(receiptModel.InvoiceUrl))
  740. {
  741. string invoicePromptLine = string.Format(" 电子发票二维码 ");
  742. bodyLines.Add(invoicePromptLine);
  743. bodyLines.Add(emptyLine);
  744. }
  745. //Thanks line
  746. string thanksLine = " 谢谢惠顾,欢迎再次光临 ";
  747. CreateReceiptLine(bodyLines);
  748. if (printQRCodeEnabled)
  749. {
  750. debugLogger.Add("EInvocie URL: " + receiptModel.PayUrl);
  751. if (!string.IsNullOrEmpty(receiptModel.PayUrl))
  752. CreateQRCode(receiptModel.PayUrl);
  753. else if (!string.IsNullOrEmpty(receiptModel.InvoiceUrl))
  754. CreateQRCode(receiptModel.InvoiceUrl);
  755. }
  756. CreateReceiptEnd(thanksLine);
  757. }
  758. private void CreateReceiptLine(List<string> lines)
  759. {
  760. List<byte> targetBytes = new List<byte>();
  761. foreach (var line in lines)
  762. {
  763. var bytes = Encoding.GetEncoding("GB2312").GetBytes(line);
  764. targetBytes.Add(0x01);
  765. targetBytes.AddRange(EnsureLength(bytes));
  766. CurrentReceipt.Add(new ReceiptLine(targetBytes.ToArray(), 31));
  767. targetBytes.Clear();
  768. }
  769. }
  770. private void CreateQRCode(string url)
  771. {
  772. int frameLen = 80;
  773. byte[] source = Encoding.ASCII.GetBytes(url);
  774. List<byte> target = new List<byte>();
  775. if (source.Length <= frameLen)
  776. {
  777. byte[] buffer = new byte[source.Length];
  778. Buffer.BlockCopy(source, 0, buffer, 0, source.Length);
  779. target.Add(0x04);
  780. target.AddRange(buffer);
  781. CurrentReceipt.Add(new ReceiptLine(target.ToArray(), source.Length + 1));
  782. target.Clear();
  783. }
  784. else
  785. {
  786. for (int i = 0; i < source.Length; i += frameLen)
  787. {
  788. if (source.Length - i < frameLen)
  789. {
  790. byte[] buffer = new byte[source.Length - i];
  791. Buffer.BlockCopy(source, i, buffer, 0, source.Length - i);
  792. target.Add(0x04);
  793. target.AddRange(buffer);
  794. CurrentReceipt.Add(new ReceiptLine(target.ToArray(), source.Length - i + 1));
  795. }
  796. else
  797. {
  798. byte[] buffer = new byte[frameLen];
  799. Buffer.BlockCopy(source, i, buffer, 0, frameLen);
  800. target.Add(0x03);
  801. target.AddRange(buffer);
  802. CurrentReceipt.Add(new ReceiptLine(target.ToArray(), frameLen + 1));
  803. }
  804. target.Clear();
  805. }
  806. }
  807. }
  808. private void CreateReceiptEnd(string endLine)
  809. {
  810. List<byte> targetBytes = new List<byte>();
  811. var bytes = Encoding.GetEncoding("GB2312").GetBytes(endLine);
  812. targetBytes.Add(0x02);
  813. targetBytes.AddRange(bytes);
  814. CurrentReceipt.Add(new ReceiptLine(targetBytes.ToArray(), 31));
  815. targetBytes.Clear();
  816. }
  817. private byte[] EnsureLength(byte[] bytes)
  818. {
  819. if (bytes.Length < 30)
  820. {
  821. List<byte> targetBytes = new List<byte>();
  822. targetBytes.AddRange(bytes);
  823. for (int i = 0; i < 30 - bytes.Length; i++)
  824. {
  825. targetBytes.Add(0x20);
  826. }
  827. return targetBytes.ToArray();
  828. }
  829. else
  830. {
  831. return bytes.Take(30).ToArray();
  832. }
  833. }
  834. public byte[] GetNextReceiptLine(int i)
  835. {
  836. debugLogger.Add("nfe current i = " + i);
  837. debugLogger.Add("nfe total count = " + CurrentReceipt.Count);
  838. if (i <= CurrentReceipt.Count - 1)
  839. return CurrentReceipt.ElementAt(i).Line;
  840. return null;
  841. }
  842. #endregion
  843. #region Card reader trx handling
  844. public void SetICCardReaderToCarPlateIdle(out byte sqNo)
  845. {
  846. StartFuelPresetProcessRequest setCardReaderToIdle = new StartFuelPresetProcessRequest(StartFuelPresetProcessReason.CarPlatePaymentIsInProcessing)
  847. {
  848. MessageSeqNumber = GetSenderSideSqNo(),
  849. SourceAddress = CardReaderSrcAddr
  850. };
  851. sqNo = setCardReaderToIdle.MessageSeqNumber;
  852. PendMessage(setCardReaderToIdle);
  853. }
  854. public void NotifyCardReaderTrxDone(out byte sqNo)
  855. {
  856. NotifyTransactionIsDoneRequest trxDoneRequest = new NotifyTransactionIsDoneRequest()
  857. {
  858. MessageSeqNumber = GetSenderSideSqNo(),
  859. SourceAddress = CardReaderSrcAddr
  860. };
  861. sqNo = trxDoneRequest.MessageSeqNumber;
  862. PendMessage(trxDoneRequest);
  863. }
  864. public void CloseICCardReader(out byte sqNo)
  865. {
  866. CloseCardReaderRequest closeCardReader = new CloseCardReaderRequest
  867. {
  868. MessageSeqNumber = GetSenderSideSqNo(),
  869. SourceAddress = CardReaderSrcAddr
  870. };
  871. sqNo = closeCardReader.MessageSeqNumber;
  872. PendMessage(closeCardReader);
  873. }
  874. public void OpenCardReader(out byte? sqNo)
  875. {
  876. OpenCardReaderRequest openCardReader = new OpenCardReaderRequest
  877. {
  878. MessageSeqNumber = GetSenderSideSqNo(),
  879. SourceAddress = CardReaderSrcAddr
  880. };
  881. sqNo = openCardReader.MessageSeqNumber;
  882. PendMessage(openCardReader);
  883. }
  884. public void SendICCardDisplay(string carPlate, out byte sqNo)
  885. {
  886. string licenseNo = carPlate;
  887. byte[] newbytes = new byte[64];
  888. for (int i = 0; i < 64; i++)
  889. {
  890. newbytes[i] = 0x20;
  891. }
  892. byte[] bytes = Encoding.GetEncoding("gb2312").GetBytes(licenseNo);
  893. if (bytes.Count() < 64)
  894. bytes.CopyTo(newbytes, 0);
  895. DisplayRequest displayRequest = new DisplayRequest(newbytes, CardReaderDisplayTimeout)
  896. {
  897. MessageSeqNumber = GetSenderSideSqNo(),
  898. SourceAddress = CardReaderSrcAddr
  899. };
  900. sqNo = displayRequest.MessageSeqNumber;
  901. PendMessage(displayRequest);
  902. }
  903. public byte[] GetMAC(EpsTransactionModel epsTrxModel)
  904. {
  905. debugLogger.AddIfActive($"fuel amount: {epsTrxModel.amount}");
  906. debugLogger.AddIfActive($"fuel quantity: {epsTrxModel.qty}");
  907. string cardNo = epsTrxModel.card_no;// "8888118001000078417";
  908. string carPlate = "晋A12345";
  909. //string carPlate = string.IsNullOrEmpty(epsTrxModel.car_number) ? "晋A12345" : epsTrxModel.car_number;
  910. byte[] chsByte = Encoding.Unicode.GetBytes(carPlate[0].ToString());
  911. byte[] b1 = { chsByte[1], chsByte[0] };
  912. string asciiBytes = carPlate.Substring(1, 6).PadRight(8, ' ');
  913. byte[] b2 = Encoding.ASCII.GetBytes(asciiBytes);
  914. byte[] newBytes = new byte[b1.Length + b2.Length];
  915. b1.CopyTo(newBytes, 0);
  916. b2.CopyTo(newBytes, 2);
  917. //if (string.IsNullOrEmpty(epsTrxModel.car_number))
  918. newBytes = new byte[10] { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
  919. string ts = epsTrxModel.created_time.ToString("yyyyMMddHHmmss");//"20180425110509";
  920. double fuelAmount = epsTrxModel.amount;//10.00;
  921. double fuelVolume = epsTrxModel.qty;//1.00;
  922. int nozzleNumber = epsTrxModel.jihao;
  923. string tid = epsTrxModel.tid;//"111001000633";
  924. var targetSignBytes = cardNo.PadLeft(20, '0').ToBCD()
  925. .Concat(newBytes)
  926. .Concat(ts.ToBCD()
  927. .Concat(((int)((decimal)fuelAmount * 100)).GetBinBytes(4))
  928. .Concat(((int)((decimal)fuelVolume * 100)).GetBinBytes(4))
  929. .Concat(nozzleNumber.GetBCDBytes(2)));
  930. return targetSignBytes.ToArray();
  931. //string cardNumber = "08888118001000078417";//carPlateTrxRequest.card_No;
  932. ////string carPlate = Encoding.GetEncoding("gbk").GetString(Encoding.GetEncoding("gbk").GetBytes("晋A12345"));//carPlateTrxRequest.car_Number));
  933. //string carPlate = "晋A12345";
  934. //byte[] b = Encoding.Unicode.GetBytes(carPlate[0].ToString());
  935. //byte[] b1 = { b[1], b[0] };
  936. //string sss = carPlate.Substring(0, 6).PadRight(8, ' ');
  937. //byte[] b2 = Encoding.ASCII.GetBytes(sss);
  938. //byte[] newBytes = new byte[b1.Length + b2.Length];
  939. //b1.CopyTo(newBytes, 0);
  940. //b2.CopyTo(newBytes, 2);
  941. //string ts = "20180425110509";
  942. //DateTime fuelingTime = DateTime.Now;
  943. //int fuelAmount = 10;
  944. //int fuelVolume = 1;
  945. //int nozzleNumber = 2;
  946. //var targetSignBytes = cardNumber.PadRight(20, ' ').ToBCD()
  947. // .Concat(newBytes)
  948. // //.Concat(Encoding.GetEncoding("gbk").GetBytes(carPlate))
  949. // .Concat(ts.ToBCD()// fuelingTime.ToString("yyyyMMddHHmmss"))
  950. // .Concat(fuelAmount.GetBinBytes(4))
  951. // .Concat(fuelVolume.GetBinBytes(4))
  952. // .Concat(nozzleNumber.GetBCDBytes(2)));
  953. //return targetSignBytes.ToArray();
  954. //string cardNumber = carPlateTrxRequest.card_No;
  955. //string carPlate = Encoding.GetEncoding("gbk").GetString(Encoding.GetEncoding("gbk").GetBytes(carPlateTrxRequest.car_Number));
  956. //DateTime fuelingTime = DateTime.Now;
  957. //int fuelAmount = 99;
  958. //int fuelVolume = 14;
  959. //int nozzleNumber = 1;
  960. //var targetSignBytes = cardNumber.PadRight(20, ' ').ToBCD()
  961. // .Concat(Encoding.GetEncoding("gbk").GetBytes(carPlate))
  962. // .Concat(ASCIIEncoding.ASCII.GetBytes(fuelingTime.ToString("yyyyMMddHHmmss"))
  963. // .Concat(fuelAmount.GetBinBytes(4))
  964. // .Concat(fuelVolume.GetBinBytes(4))
  965. // .Concat(nozzleNumber.GetBCDBytes(2)));
  966. //var expected = new byte[] { 0xFA, 0xD2, }.Concat((targetSignBytes.Count() + 1).GetBCDBytes(2))
  967. // .Concat(new byte[] { 0x05 })
  968. // .Concat(targetSignBytes)
  969. // .Concat(new byte[] { 0x84, 0xb0 });
  970. var signDataRequest = new SignDataRequest(targetSignBytes.ToArray())
  971. {
  972. MessageSeqNumber = GetSenderSideSqNo(),
  973. SourceAddress = CardReaderSrcAddr
  974. };
  975. sqNo = signDataRequest.MessageSeqNumber;
  976. PendMessage(signDataRequest);
  977. }
  978. #endregion
  979. /// <summary>
  980. /// Get all the Idle nozzle at this side
  981. /// </summary>
  982. /// <returns></returns>
  983. public Dictionary<int, string> GetAvailableNozzleInfo()
  984. {
  985. if (NozzeIdGradeNameDictOnThisSide != null && NozzeIdGradeNameDictOnThisSide.Count > 0)
  986. {
  987. ;
  988. }
  989. else
  990. {
  991. Dictionary<int, string> nozzleIdGradeNameDict = Eps.NozzleMappingGradeName(); //Mapping grade name & nozzleId
  992. foreach (var fpId in CurrentCardReader.SupportedNozzles)
  993. {
  994. var fp = Eps.GetFuelingPoint(fpId);
  995. foreach (var nozzleId in fp.AssociatedNozzles)
  996. {
  997. NozzeIdGradeNameDictOnThisSide.Add(nozzleId, nozzleIdGradeNameDict[nozzleId]);
  998. }
  999. }
  1000. }
  1001. foreach (var item in NozzeIdGradeNameDictOnThisSide)
  1002. {
  1003. debugLogger.Add($"NozzleIdGradeNameDictOnThisSide: Key - {item.Key}, Value - {item.Value}");
  1004. }
  1005. return NozzeIdGradeNameDictOnThisSide;
  1006. }
  1007. #region Printer
  1008. public bool GetPrinter()
  1009. {
  1010. lock (printerSyncObj)
  1011. {
  1012. if (printerIdle == true)
  1013. {
  1014. printerIdle = false;
  1015. return true;
  1016. }
  1017. else
  1018. {
  1019. GetPrinterCount++;
  1020. return false;
  1021. }
  1022. }
  1023. }
  1024. public void ReleasePrinter()
  1025. {
  1026. lock (printerSyncObj)
  1027. {
  1028. printerIdle = true;
  1029. }
  1030. }
  1031. #endregion
  1032. #region Cleanup
  1033. public void Cleanup()
  1034. {
  1035. CurrentEpsTrx = null;
  1036. NewEpsTrx = null;
  1037. CurrentTrxMode = EpsTransactionMode.Unknown;
  1038. AuthorizationId = null;
  1039. CurrentNozzleId = Eps.InvalidNozzleId;
  1040. GetPrinterCount = 0;
  1041. CurrentReceipt = null;
  1042. }
  1043. #endregion
  1044. }
  1045. }