123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277 |
- using Dfs.WayneChina.HengshanPayTerminal;
- using Dfs.WayneChina.HengshanPayTerminal.MessageEntity;
- using Dfs.WayneChina.HengshanPayTerminal.MessageEntity.Incoming;
- using Dfs.WayneChina.HengshanPayTerminal.MessageEntity.Outgoing;
- using Dfs.WayneChina.SpsDbManager;
- using Dfs.WayneChina.SpsDbManager.ResultSet;
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Linq;
- using Wayne.FDCPOSLibrary;
- using Edge.Core.Processor;using Edge.Core.IndustryStandardInterface.Pump;
- using Dfs.WayneChina.HengshanPayTerminal.Support;
- using System.Timers;
- using Dfs.WayneChina.IPosPlus.ServiceClient;
- using System.Threading.Tasks;
- using System.Collections.Concurrent;
- namespace Dfs.WayneChina.IPosPlus
- {
- /// <summary>
- /// An entity that manages the IC card terminal.
- /// </summary>
- public class TerminalManager
- {
- #region Fields
- private readonly byte STX = 0xFA;
- /// <summary>
- /// Sps_db database manager.
- /// </summary>
- private readonly SpsManager _dbManager;
- /// <summary>
- /// The terminal handler.
- /// </summary>
- private readonly HengshanPayTermHandler _terminal;
- /// <summary>
- /// IPosPlusApp instance.
- /// </summary>
- private readonly IPosPlusApp _posApp;
- /// <summary>
- /// Internally maintained pump state.
- /// </summary>
- private HengshanPumpState _pumpState;
- private HengshanPumpState _lastPumpState;
- /// <summary>
- /// All listed cards (Newly-added blacklist, base blacklist, newly-deleted blacklist, whitelist)
- /// </summary>
- public VersionedListedCard VersionedListedCard;
- /// <summary>
- /// Connection detection timer.
- /// </summary>
- private Timer timer;
- private int interval;
- private HengshanPayTerminal.Parser parser = new HengshanPayTerminal.Parser();
- private CardAppType _cardAppType = CardAppType.CpuCard;
- private WorkMode currentWorkMode = WorkMode.Disabled;
- private IList<DataVersion> currentDataVersions = null;
- #endregion
- #region Filling control state data
- private FillingInfo currentFilling;
- private FillingInfo lastFilling;
- #endregion
- #region Logger
- private static NLog.Logger logger = NLog.LogManager.LoadConfiguration("NLog.config").GetLogger("IPosPlusApp");
- #endregion
-
- #region Queue
- private Queue<CardMessageBase> activeSendQueue = new Queue<CardMessageBase>();
- private object sendQueueSyncObj = new object();
- #endregion
- #region Payment queue
- private System.Threading.Thread thread;
- private ConcurrentQueue<PaymentRequest> paymentRequestQueue = new ConcurrentQueue<PaymentRequest>();
- private System.Threading.ManualResetEvent mre = new System.Threading.ManualResetEvent(false);
- #endregion
- #region Reserved balance
- private readonly int reservedBalance = 0;
- #endregion
- #region Constructor
- public TerminalManager(IPosPlusApp posApp, int pumpId, int subAddress, SpsManager spsManager, HengshanPayTermHandler terminal,
- int interval, int cardAppType)
- {
- _posApp = posApp;
-
- PumpId = pumpId;
- SubAddress = subAddress;
- _dbManager = spsManager;
- _terminal = terminal;
- _pumpState = HengshanPumpState.Idle;
- _lastPumpState = HengshanPumpState.Idle;
- this.interval = interval;
- if (cardAppType == 1)
- _cardAppType = CardAppType.RfCard;
- else if (cardAppType == 2)
- _cardAppType = CardAppType.CpuCard;
- reservedBalance = posApp.ReservedBalance;
- RegisterEncodingProvider();
- InitializeTimer();
- thread = new System.Threading.Thread(() => HandleCardPayment());
- thread.Start();
- }
- private void RegisterEncodingProvider()
- {
- EncodingProvider provider = CodePagesEncodingProvider.Instance;
- Encoding.RegisterProvider(provider);
- }
- #endregion
- #region Properties
- public string TerminalId { get; private set; }
- public string Identifier => _terminal.PumpIdList;
- public int PumpId { get; private set; }
- public int SubAddress { get; }
- public DiscountServiceClient DiscountClient => _posApp.DiscountServiceClient;
- #endregion
- #region Timer
- private void InitializeTimer()
- {
- timer = new Timer();
- timer.Interval = interval * 1000;
- timer.Elapsed += Timer_Elapsed;
- timer.Start();
- }
- private void Timer_Elapsed(object sender, ElapsedEventArgs e)
- {
- logger.Error($"*** Terminal {PumpId}, no incoming command from terminal/pump for {interval} seconds! Probably communication lost.");
- _pumpState = HengshanPumpState.Offline;
- if (_pumpState != _lastPumpState)
- {
- _terminal.UpdatePumpState(PumpId, 1, LogicalDeviceState.FDC_OFFLINE);
- _lastPumpState = _pumpState;
- }
- // When pump is offline, it's offline.
- if (_lastPumpState == HengshanPumpState.Offline)
- {
- timer.Stop();
- }
- }
- private void ResetTimer()
- {
- timer.Stop();
- logger.Debug($"terminal {PumpId.ToString()} timer stopped");
- timer.Start();
- logger.Debug($"terminal {PumpId.ToString()} timer started");
- }
- #endregion
- #region Methods
- #region Register 油机上电注册
- public void HandleRegiser(RegisterRequest request)
- {
- logger.Info($"Terminal registration from pump {PumpId}, Terminal Id: {request.TerminalId}");
- CheckTerminalId(request.TerminalId);
- var registerResults = _dbManager.RegisterTerminal(request.TerminalId);
- RegisterTerminalResult currentResult = null;
- if (registerResults.Count > 0)
- {
- currentResult = registerResults[0];
- }
- SendRegisterResult(request, currentResult);
- }
- private void SendRegisterResult(RegisterRequest request, RegisterTerminalResult registerResult)
- {
- if (registerResult == null)
- {
- }
- RegisterResult result = new RegisterResult
- {
- Prefix = STX,
- SourceAddress = request.SourceAddress,
- DestinationAddress = request.DestinationAddress,
- FrameSqNoByte = request.FrameSqNoByte,
- Handle = Convert.ToByte(Command.RegisterResult),
- Result = Convert.ToByte(registerResult.RegisterResultCode),
- TerminalId = request.TerminalId,
- SystemKey = registerResult.SystemKey
- };
- if (!string.IsNullOrEmpty(registerResult.StationName))
- {
- result.StationNameLength = Convert.ToInt32(registerResult.StationNameLength);
- result.StationName = Encoding.GetEncoding("GB2312").GetBytes(registerResult.StationName).ToList();
- }
- _terminal.Write(result);
- }
- #endregion
- #region REGURLAR CHECK 油机普通查询命令处理
- /// <summary>
- /// Handles the Check_cmd request.
- /// 处理油机普通查询命令。
- /// </summary>
- /// <param name="request">The Check_cmd request.</param>
- public void HandleCheckCmdRequest(CheckCmdRequest request)
- {
- CheckTerminalId(request.TerminalId);
- ResetTimer();
- if (request.WorkMode != (byte)currentWorkMode)
- {
- currentWorkMode = (WorkMode)_dbManager.GetPumpWorkMode(Convert.ToByte(PumpId));
- if (request.WorkMode != 0x05)
- {
- ChangeAuthMode(request, currentWorkMode);
- }
- if (IsMessagePendingForSend())
- {
- var message = PickAndSendCardMessage();
- logger.Info($"Active send queue, pending message exists, send it, MessageHandle={message.Handle}");
- message.FrameSqNoByte = request.FrameSqNoByte;
- _terminal.Write(message);
- return;
- }
- }
- //Reset the `Versioned listed cards`
- VersionedListedCard = null;
- logger.Debug($"Pump {PumpId}, Amount: {request.Amount}, Volume: {request.Volume}, Price: {request.Price}");
- _terminal.StoreLatestFrameSqNo(PumpId, request.FrameSqNoByte);
- if (_terminal.TrySendNextMessage())
- {
- //Really sent something, return!
- logger.Debug("Will not send the CheckCmdResponse");
- return;
- }
- var versions = _dbManager.GetDataVersions();
- if (currentDataVersions == null)
- {
- currentDataVersions = versions;
- }
- if (currentDataVersions != null && versions != null)
- {
- var storedGeneralInfo = versions.FirstOrDefault(v => v.VersionType == VersionType.GeneralInfoVersion);
- var currentGeneralInfo = currentDataVersions.FirstOrDefault(v => v.VersionType == VersionType.GeneralInfoVersion);
- if (storedGeneralInfo != null && currentGeneralInfo != null)
- {
- if (currentGeneralInfo.VersionNo != storedGeneralInfo.VersionNo)
- {
- byte currentMode = _dbManager.GetPumpWorkMode(Convert.ToByte(PumpId));
- if (currentMode != (byte)currentWorkMode)
- {
- ChangeAuthMode(request, (WorkMode)currentMode);
- logger.Warn($"Auth mode changed!, {currentWorkMode} -> {currentMode}");
- }
- if (IsMessagePendingForSend())
- {
- var message = PickAndSendCardMessage();
- logger.Info($"Active send queue, pending message exists, send it, MessageHandle={message.Handle}");
- message.FrameSqNoByte = request.FrameSqNoByte;
- _terminal.Write(message);
- return;
- }
- }
- }
- }
- SendCheckCmdResult(versions, request);
- var currentNozzleNo = request.FuelingPoint.NozzleNo;
- int currentLogicId;
- bool getLogicIdResult = _terminal.NozzleLogicIdDict.TryGetValue(currentNozzleNo, out currentLogicId);
- if (getLogicIdResult == false)
- currentLogicId = 1;
- //Get dispenser station from check cmd
- if (request.DispenserState == 0x08)
- {
- _pumpState = HengshanPumpState.Fueling;
- if (request.WorkMode == 0x05 && _lastPumpState != _pumpState)
- {
- EmulatePumpStateSequentialChange();
- }
- if (_lastPumpState != _pumpState)
- {
- logger.Info($"Pump {PumpId} aleady in fuelling, but last state was not, trigger a state change");
- _terminal.UpdatePumpState(PumpId, currentLogicId, LogicalDeviceState.FDC_FUELLING);
- }
- _lastPumpState = _pumpState;
- }
- else if (request.DispenserState == 0x03)
- {
- _pumpState = HengshanPumpState.Idle;
- if (_lastPumpState == HengshanPumpState.Fueling && _lastPumpState != _pumpState)
- {
- logger.Info($"Pump {PumpId}, Nozzle {currentNozzleNo}, fueling => ready");
- _terminal.UpdatePumpState(PumpId, currentLogicId, LogicalDeviceState.FDC_READY);
- }
- else if (_lastPumpState == HengshanPumpState.Offline && _pumpState == HengshanPumpState.Idle)
- {
- logger.Info($"Pump {PumpId}, Nozzle {currentNozzleNo}, offline => ready");
- _terminal.UpdatePumpState(PumpId, currentLogicId, LogicalDeviceState.FDC_READY);
- }
- }
- if (_pumpState == HengshanPumpState.Idle)
- {
- //If the pump is idle, it's idle.
- _lastPumpState = _pumpState;
- }
- else if (_pumpState == HengshanPumpState.Offline)
- {
- _pumpState = HengshanPumpState.Idle;
- _terminal.UpdatePumpState(PumpId, currentLogicId, LogicalDeviceState.FDC_READY);
- _lastPumpState = _pumpState;
- }
- else if (_pumpState == HengshanPumpState.Authorized)
- {
- if (request.Amount >= 0 || request.Volume >= 0)
- {
- logger.Info($"Pump {PumpId}, Nozzle {currentNozzleNo}, authorized => fuelling");
- _pumpState = HengshanPumpState.Fueling;
- _terminal.UpdatePumpState(currentNozzleNo, currentLogicId, LogicalDeviceState.FDC_FUELLING);
- _lastPumpState = _pumpState;
- }
- }
- else if (_pumpState == HengshanPumpState.Fueling)
- {
- logger.Info($"Pump {PumpId}, Nozzle {currentNozzleNo}, fueling in progress, Amount: {request.Amount}, Volume: {request.Volume}, Price: {request.Price}");
- _terminal.UpdateFuelingStatus(PumpId, new FdcTransaction
- {
- Nozzle = new LogicalNozzle(PumpId, 1, Convert.ToByte(currentLogicId), null),
- Amount = request.Amount,
- Volumn = request.Volume,
- Price = request.Price,
- Finished = false
- });
- _lastPumpState = _pumpState;
- }
- }
- private void EmulatePumpStateSequentialChange()
- {
- logger.Info("Emulating pump state sequential changes...");
- _terminal.UpdatePumpState(PumpId, 1, LogicalDeviceState.FDC_CALLING);
- System.Threading.Thread.Sleep(50);
- _terminal.UpdatePumpState(PumpId, 1, LogicalDeviceState.FDC_AUTHORISED);
- System.Threading.Thread.Sleep(50);
- _terminal.UpdatePumpState(PumpId, 1, LogicalDeviceState.FDC_STARTED);
- System.Threading.Thread.Sleep(50);
- _terminal.UpdatePumpState(PumpId, 1, LogicalDeviceState.FDC_FUELLING);
- System.Threading.Thread.Sleep(50);
- }
- /// <summary>
- /// Sends result of the Check_cmd.
- /// 返回油机普通查询命令结果。
- /// </summary>
- private void SendCheckCmdResult(IList<DataVersion> dataVersions, CheckCmdRequest request)
- {
- if(dataVersions == null)
- {
- logger.Error("Retrieved empty version information");
- return;
- }
- InquiryResult result = new InquiryResult
- {
- Prefix = STX,
- SourceAddress = request.SourceAddress,
- DestinationAddress = request.DestinationAddress,
- FrameSqNoByte = request.FrameSqNoByte,
- Handle = Convert.ToByte(Command.Ver_info),
- BaseBlacklistVersion = dataVersions.First(d => d.VersionType == VersionType.BaseBlacklistVersion).VersionNo,
- NewlyAddedBlacklistVersion = dataVersions.First(d => d.VersionType == VersionType.NewlyAddedBlacklistVersion).VersionNo,
- NewlyDeletedBlacklistVersion = dataVersions.First(d => d.VersionType == VersionType.NewlyDeletedBlacklistVersion).VersionNo,
- WhitelistVersion = dataVersions.First(d => d.VersionType == VersionType.WhitelistVersion).VersionNo,
- FuelPriceVersion = dataVersions.First(d => d.VersionType == VersionType.FuelPriceChangeVersion).VersionNo,
- StationGeneralInfoVersion = dataVersions.First(d => d.VersionType == VersionType.GeneralInfoVersion).VersionNo,
- PrinterReceiptInfoVersion = 0x00,
- SoftwareDownloadFlag = 0x00,
- UnspecifiedField1 = 0x00,
- };
- result.SetTime(DateTime.Now);
- _terminal.Write(result);
- }
- #endregion
- #region Validate card 验卡
- public void HandleCardValidation(ValidateCardRequest request)
- {
- ResetTimer();
- var results = _dbManager.GetCheckCardResult(GetCardNo(request.Asn),
- long.Parse(request.PhysicalCardNo, System.Globalization.NumberStyles.HexNumber), request.FuelingPoint.PumpNo);
- var blacklistedCard = _dbManager.IsCardBlackListed(GetCardNo(request.Asn));
- if (results!= null && results.Count == 1)
- {
- var currentResult = results[0];
- var cardInfo = _dbManager.GetCardInfoByCardNo(GetCardNo(request.Asn));
- if (cardInfo != null)
- {
- byte cardClass = cardInfo.CardClass.Value;
- byte cardType = cardInfo.CardType.Value;
-
- SendValidateCardResult(currentResult, request, blacklistedCard, cardClass, cardType, cardInfo.Holder, cardInfo.Carno);
- }
- else
- {
- SendValidateCardResult(currentResult, request, blacklistedCard, 0, 0, string.Empty, string.Empty);
- }
- }
- }
- private void SendValidateCardResult(CardResult checkResult, ValidateCardRequest request, bool blacklistedCard, byte cardClass,
- byte cardType, string holder, string carNo)
- {
- var cardState = checkResult.CardStatus;
- if (blacklistedCard)
- cardState = SpsDbManager.ResultSet.CardState.AccountFrosen;
- ValidateCardResult result = new ValidateCardResult();
- result.Prefix = STX;
- result.SourceAddress = request.SourceAddress;
- result.DestinationAddress = request.DestinationAddress;
- result.Handle = Convert.ToByte(Command.ValidateCardResult);
- result.FrameSqNoByte = request.FrameSqNoByte;
- result.Asn = request.Asn;
- result.DiscountNo = Convert.ToUInt16(checkResult.DiscountNo);
- result.CardState = (HengshanPayTerminal.Support.CardState)Convert.ToByte(cardState);
-
- result.AdditionalInfo = GenerateAdditionalInfo(cardState);
- result.AdditionalInfoLength = Convert.ToByte(result.AdditionalInfo.Count);
- if (result.AdditionalInfoLength == 0)
- {
- List<byte> addInfo = new List<byte>();
- if (cardClass == 1 || cardClass == 2)
- {
- addInfo.Add(1);
- if (!string.IsNullOrEmpty(carNo))
- addInfo.AddRange(Encoding.GetEncoding("GB2312").GetBytes(carNo));
- else
- addInfo.AddRange(Encoding.GetEncoding("GB2312").GetBytes(holder));
- }
- if (_cardAppType == CardAppType.CpuCard)
- {
- if (cardClass == 3 && cardType == 1)
- {
- addInfo.Add(1);
- addInfo.AddRange(Encoding.GetEncoding("GB2312").GetBytes(holder));
- }
- }
- else if (_cardAppType == CardAppType.RfCard)
- {
- if (cardClass == 3 && cardType == 3)
- {
- addInfo.Add(1);
- addInfo.AddRange(Encoding.GetEncoding("GB2312").GetBytes(holder));
- }
- }
-
- result.AdditionalInfo = addInfo;
- result.AdditionalInfoLength = Convert.ToByte(addInfo.Count);
- }
- int reserveAmount = reservedBalance * 100;
- result.CardBalance = request.Balance - reserveAmount;
- int maxAllowedAmount = Convert.ToInt32(checkResult.MaxAllowedAmount);
- result.MaxAllowedAmount = request.Balance - reserveAmount > maxAllowedAmount ? maxAllowedAmount : request.Balance - reserveAmount;
- result.PhysicalCardNo = long.Parse(
- ByteArrayToString(
- StringToByteArray(request.PhysicalCardNo).Reverse().ToArray()), System.Globalization.NumberStyles.HexNumber);
- _terminal.Write(result);
- }
- private List<byte> GenerateAdditionalInfo(SpsDbManager.ResultSet.CardState cardState)
- {
- if (cardState == SpsDbManager.ResultSet.CardState.NoInfo)
- {
- return Encoding.GetEncoding("GB2312").GetBytes("验卡失败,无此卡").ToList();
- }
- else if (cardState == SpsDbManager.ResultSet.CardState.Lost)
- {
- return Encoding.GetEncoding("GB2312").GetBytes("卡已锁定!").ToList();
- }
- return new List<byte>();
- }
- #endregion
- #region Authorization 授权处理
- public void HandlAuthorization(AuthRequest request)
- {
- ResetTimer();
- var currentNozzleNo = request.FuelingPoint.NozzleNo;
- int logicId;
- bool getResult = _terminal.NozzleLogicIdDict.TryGetValue(currentNozzleNo, out logicId);
- if (!getResult)
- logicId = 1;
- //var logicId = _terminal.NozzleLogicIdDict[currentNozzleNo];
- _pumpState = HengshanPumpState.Calling;
- _terminal.UpdatePumpState(PumpId, logicId, LogicalDeviceState.FDC_CALLING);
- _lastPumpState = _pumpState;
- SendAuthResult(request);
- _pumpState = HengshanPumpState.Authorized;
- _terminal.UpdatePumpState(PumpId, logicId, LogicalDeviceState.FDC_AUTHORISED);
- _lastPumpState = _pumpState;
- }
- private void SendAuthResult(AuthRequest request)
- {
- var result = new AuthResult
- {
- Prefix = STX,
- SourceAddress = request.SourceAddress,
- DestinationAddress = request.DestinationAddress,
- FrameSqNoByte = request.FrameSqNoByte,
- Handle = Convert.ToByte(Command.AuthResult),
- Asn = request.Asn,
- PosTtc = request.PosTtc,
- SeqNo = request.SeqNo,
- FuelCode = request.FPCode.ToUInt16(),
- ResultCode = HengshanPayTerminal.Support.AuthResultCode.Passed,
- AdditionalInfoLength = 0
- };
- _terminal.Write(result);
- }
- #endregion
- #region Fueling Data 加油数据
- public void HandleFuelingData(FuelingDataRequest request)
- {
- ResetTimer();
- var currentNozzleNo = request.FuelingPoint.NozzleNo;
- int logicId;
- bool getResult = _terminal.NozzleLogicIdDict.TryGetValue(currentNozzleNo, out logicId);
- if (!getResult)
- logicId = 1;
- //var logicId = _terminal.NozzleLogicIdDict[currentNozzleNo];
- var cardNo = GetCardNo(request.Asn);
- var cardAccount = _dbManager.GetCardAccountInfo(cardNo);
- var correctFuelPrice =
- GetCorrectFuelPrice(Convert.ToString(request.ProductCode), request.Price, request.Volume, request.Amount);
- if (request.CurrentCardInfo == null)
- logger.Error("Card info is null!!!");
- if (cardAccount == null)
- {
- logger.Error("card account is null");
- _terminal.UpdateFuelingStatus(PumpId, new FdcTransaction
- {
- Nozzle = new LogicalNozzle(PumpId, 1, Convert.ToByte(logicId), null),
- Amount = request.Amount,
- Volumn = request.Volume,
- Price = correctFuelPrice,//request.Price,
- VolumeTotalizer = request.VolumeTotal,
- SequenceNumberGeneratedOnPhysicalPump = request.PosTtc//, //I would like to use SeqNo, but TQC pumps always use 0 for it.
- //Finished = true //Set FDC transaction as FINISHED
- });
- }
- currentFilling = new FillingInfo
- {
- PumpId = this.PumpId,
- NozzleId = request.FuelingPoint.NozzleNo,//1,
- SequenceNo = request.PosTtc,
- CardNo = cardNo,
- CardType = request.CurrentCardInfo.CardType,
- CardBalance = cardAccount == null ? 0 : Convert.ToInt32(cardAccount.Money),
- FillingAmount = request.Amount,
- Volume = request.Volume,
- UnitPrice = correctFuelPrice,
- //UnitPrice = request.Price,
- FuelProductCode = request.ProductCode,
- StartTime =GetDateTime(request.DispenserTime),
- EndTime = GetDateTime(request.TransactionEndTime)
- };
- if (request.CurrentCardInfo.CardType != 0)
- {
- bool result = _dbManager.InsertAuthInfo(_posApp.PosId, 0, cardNo, request.Amount, request.Volume,
- request.DispenserTime, request.TransactionEndTime, request.PosTtc, request.SeqNo, 0x50,
- request.ProductCode, correctFuelPrice, request.CurrentCardInfo.CardCtc, 00, Convert.ToByte(PumpId),
- Convert.ToByte(PumpId), Convert.ToInt32(cardAccount.Money), request.CurrentCardInfo.CardType,
- cardAccount.DiscountNo, 1, request.VolumeTotal);
- logger.Debug($"Insert auth info, success? {result}");
- }
- SendFuelingDataAck(request);
- logger.Info($"Filling done, Amount: {request.Amount}, Volume: {request.Volume}, " +
- $"corrected price: {correctFuelPrice}, pump price: {request.Price}, ready for payment");
- }
- private void SendFuelingDataAck(FuelingDataRequest request)
- {
- var result = new FuelingDataProcessingResult
- {
- Prefix = STX,
- SourceAddress = request.SourceAddress,
- DestinationAddress = request.DestinationAddress,
- FrameSqNoByte = request.FrameSqNoByte,
- Handle = Convert.ToByte(Command.FuelingDataResult),
- PosTtc = request.PosTtc,
- SeqNo = request.SeqNo,
- FPCode = request.FPCode.ToUInt16()
- };
- _terminal.Write(result);
- }
- #endregion
- #region Payment 支付
- private void HandleCardPayment()
- {
- while (true)
- {
- logger.Info($"Terminal {PumpId}, in the loop");
- if (paymentRequestQueue.Count > 0)
- {
- logger.Info($"Terminal {PumpId}, Payment request exists, send it! Queue item count: {paymentRequestQueue.Count}");
- PaymentRequest request;
- if (paymentRequestQueue.TryDequeue(out request))
- {
- SendPaymentData(request);
- }
- logger.Info($"Terminal {PumpId}, Payment request queue, item count: {paymentRequestQueue.Count}");
- }
- else
- {
- logger.Info($"Terminal {PumpId}, nothing in payment queue, put thread on hold");
- mre.Reset();
- mre.WaitOne();
- }
- }
- }
- public void HandlePaymentRequest(PaymentRequest request)
- {
- ResetTimer();
- if (paymentRequestQueue.Count > 0)
- {
- if (paymentRequestQueue.Any(r => r.Asn == request.Asn && r.PosTtc == request.PosTtc))
- {
- logger.Info("Payment request already in the queue");
- return;
- }
- }
- else
- {
- paymentRequestQueue.Enqueue(request);
- }
- logger.Info($"Terminal {PumpId}, releasing payment request processing thread");
- mre.Set();
- //SendPaymentData(request);
- }
- private void SendPaymentData(PaymentRequest request)
- {
- int paymentAmount = 0;
- int fillingAmount = 0;
- int fillingPrice = 0;
- int productCode = 0;
- int volume = 0;
- if (DiscountClient != null && currentFilling != null &&
- (_posApp.CardAppType == 1 && currentFilling.CardType == 3 || _posApp.CardAppType == 2 && currentFilling.CardType == 1))
- {
- fillingAmount = currentFilling.FillingAmount;
- fillingPrice = currentFilling.UnitPrice;
- productCode = currentFilling.FuelProductCode;
- volume = currentFilling.Volume;
-
- logger.Info($"Applying fuel discount against customer card, amount: {fillingAmount}, price: {fillingPrice}, code: {productCode}");
- DiscountRequest discountRequest = new DiscountRequest();
- discountRequest.Barcode = _posApp.GetBarcode(currentFilling.FuelProductCode).ToString();
- discountRequest.FillingAmount = Convert.ToDecimal(currentFilling.FillingAmount) / 100;
-
- discountRequest.UnitPrice =
- currentFilling.UnitPrice == 151 ?
- Convert.ToDecimal( _posApp.CurrentFuelPrices[currentFilling.FuelProductCode.ToString()]) / 100
- : Convert.ToDecimal(currentFilling.UnitPrice) / 100;
- discountRequest.Volume = Convert.ToDecimal(currentFilling.Volume) / 100;
- discountRequest.TimeStamp = DateTime.Now;
- discountRequest.CardNo = GetCardNo(request.Asn);
- var discountResponse = DiscountClient.CalculatDiscount(discountRequest).Result;
- if (discountResponse != null)
- {
- paymentAmount = Convert.ToInt32(discountResponse.PayAmount * 100);
- }
- }
- else
- {
- logger.Info($"Possible crash 1");
- //var amountAfterDiscount = _dbManager.GetDiscountedAmount(request.Asn, fillingAmount, volume, fillingPrice, productCode);
- if (currentFilling != null)
- paymentAmount = currentFilling.FillingAmount;//amountAfterDiscount.Real_Mon;
- }
- if (currentFilling == null)
- {
- logger.Info($"Current Filling missing, could be reset");
- return;
- }
- if (paymentAmount > currentFilling.FillingAmount)
- {
- logger.Warn($"This is absurd, payment amount {paymentAmount.ToString()} larger than filling amount");
- paymentAmount = fillingAmount;
- }
- logger.Info($"payment amount is: {paymentAmount}");
- PaymentData data = new PaymentData
- {
- Prefix = STX,
- SourceAddress = request.SourceAddress,
- DestinationAddress = request.DestinationAddress,
- FrameSqNoByte = request.FrameSqNoByte,
- Handle = Convert.ToByte(Command.PaymentData),
- Asn = request.Asn,
- PosTtc = request.PosTtc,
- FillingAmount = fillingAmount,
- PayAmount = paymentAmount == 0? fillingAmount : paymentAmount,
- FillingVolume = volume,
- Price = Convert.ToUInt16(fillingPrice),
- ProductCode = Convert.ToUInt16(productCode),
- C_Name = "00000000000000000000000000000000",
- FPCode = request.FPCode.ToUInt16(),
- Result = HengshanPayTerminal.Support.PaymentProcessingResult.Ok,
- AdditionalInfoLength = 0
- };
- _terminal.Write(data);
- mre.WaitOne();
- }
- #endregion
- #region Transaction Data 交易数据
- public async Task HandleTransactionData(TransactionDataRequest request)
- {
- ResetTimer();
- var currentNozzleNo = request.FuelingPoint.NozzleNo;
- int logicId;
- bool getResult = _terminal.NozzleLogicIdDict.TryGetValue(currentNozzleNo, out logicId);
- if (!getResult)
- logicId = 1;
- //var logicId = _terminal.NozzleLogicIdDict[currentNozzleNo];
- logger.Info($"*** Handle TransactionData {request.Handle}, Pump {PumpId} ***");
- byte trxType = request.TrxType;
- var cardNo = GetCardNo(request.Asn);
- var cardAccount = _dbManager.GetCardAccountInfo(cardNo);
- if (cardAccount == null)
- {
- logger.Info($"Terminal {PumpId}, card account queried for card no: {cardNo}");
- }
- var creditResult = _dbManager.GetCredits(request.ProductCode, cardNo, request.FillingAmount, request.Volume);
- logger.Debug("Credit queried");
- bool trxExists = _dbManager.CheckIfTransactionExists(request.TrxTime, request.DitTTC, request.FuelingPoint.PumpNo, trxType);
- logger.Debug($"Transaction Existence checked, Exists? {trxExists}");
- var operatorCardNo = GetCardNo(request.PsamAsn);
- bool ackSent = false;
- var correctedFuelPrice =
- GetCorrectFuelPrice(Convert.ToString(request.ProductCode), request.Price, request.Volume, request.FillingAmount);
- //Make sure there is not an existing payment trx record.
- if (!trxExists)
- {
- logger.Info("No existing record");
- int payModeId = request.PaymentMethodLocation; //100;
- string payModeNo = string.Empty;
- int stationNo = 1;
- if (_posApp.StationInfo != null)
- stationNo = _posApp.StationInfo.StationNo;
- uint volumeTotal = request.VolumeTotal < 0 ? 0 : Convert.ToUInt32(request.VolumeTotal);
- var newGid = _dbManager.AddTrade(
- stationNo,
- cardNo,
- operatorCardNo,
- payModeId,
- payModeNo,
- trxType,
- Convert.ToString(request.ProductCode),
- correctedFuelPrice,//request.Price,
- request.Volume,
- request.FillingAmount,
- request.PaymentAmount,
- request.CardBalance,
- request.CurrentCardInfo.CardType,
- request.CurrentCardInfo.CardCtc,
- GetDateTime(request.TrxTime),
- GetDateTime(request.TrxEndTime),
- request.DitTTC,
- request.SeqNo,
- _posApp.GetNextBillNo(), //billNo
- request.FuelingPoint.NozzleNo,
- request.FuelingPoint.PumpNo,
- Convert.ToInt32(request.TerminalId.TrimStart('0')),
- volumeTotal,
- 0, //discountNo
- 1001,
- 1,
- request.PsamAsn, //PsamAsn
- uint.Parse(request.PsamTac, System.Globalization.NumberStyles.HexNumber),//PsamTac
- request.PsamTid,//psam tid
- uint.Parse(request.PsamTtc, System.Globalization.NumberStyles.HexNumber),//psam ttc
- uint.Parse(request.Tac, System.Globalization.NumberStyles.HexNumber),//tac
- uint.Parse(request.Gmac, System.Globalization.NumberStyles.HexNumber),//gmac
- uint.Parse(request.Tmac, System.Globalization.NumberStyles.HexNumber),//tmac
- 0, //Integral
- Convert.ToInt32(_posApp.CurrentShiftNo),
- "000000",
- "000000",
- "",
- 0);
- logger.Info($"Trdinfo added, new Gid: {newGid}, TrdType: {trxType}, CardNo: {request.Asn}, CTC: {request.CurrentCardInfo.CardCtc}");
- if (trxType == 0x01)
- {
- _dbManager.InsertGrayInfo(
- cardNo,
- payModeId,
- trxType,
- Convert.ToString(request.ProductCode),
- correctedFuelPrice,//request.Price
- request.Volume,
- request.FillingAmount,
- request.PaymentAmount,
- request.CardBalance,
- request.CurrentCardInfo.CardCtc,
- request.TrxTime,
- request.TrxEndTime,
- Convert.ToUInt32(request.DitTTC),
- request.SeqNo,
- request.FuelingPoint.NozzleNo,
- request.FuelingPoint.PumpNo,
- request.TerminalId,
- Convert.ToUInt64(request.VolumeTotal),
- 0,
- request.PsamAsn,
- uint.Parse(request.PsamTac, System.Globalization.NumberStyles.HexNumber),//PsamTac//request.PsamTac,
- request.PsamTid,
- uint.Parse(request.PsamTtc, System.Globalization.NumberStyles.HexNumber),//psam ttc
- uint.Parse(request.Tac, System.Globalization.NumberStyles.HexNumber),//tac
- uint.Parse(request.Gmac, System.Globalization.NumberStyles.HexNumber),//gmac
- uint.Parse(request.Tmac, System.Globalization.NumberStyles.HexNumber),//tmac
- 0);
- logger.Info("Gray info inserted");
- }
- else if (trxType == 0x02)
- {
- var releaseResult = _dbManager.ReleaseGrayCard(cardNo, request.CurrentCardInfo.CardCtc, request.TrxTime);
- logger.Info($"Gray info deleted, card released success? {releaseResult}");
- }
- _dbManager.UpdateCardInfo(cardNo, request.FillingAmount, request.CardBalance, request.CurrentCardInfo.CardType,
- creditResult.IntegralResult, 1);
- logger.Debug("Card Info updated");
- _dbManager.DeleteAuthInfo(request.FuelingPoint.PumpNo, request.DitTTC, request.TrxTime);
- logger.Debug("Auth Info deleted");
- if (trxType == 2)
- {
- logger.Info($"Trying to find the gray trade, ASN: {request.Asn}, CTC: {request.CurrentCardInfo.CardCtc}");
- var grayTrd = _dbManager.GetGrayTrdInfo(request.Asn, request.CurrentCardInfo.CardCtc, request.FuelingPoint.PumpNo);
- if (grayTrd != null)
- {
- logger.Info($"Found gray trade for card: {request.Asn}");
- currentFilling = new FillingInfo
- {
- PumpId = this.PumpId,
- NozzleId = request.FuelingPoint.NozzleNo,//1,
- SequenceNo = request.DitTTC,
- CardNo = cardNo,
- CardBalance = request.CardBalance,//Convert.ToInt32(cardAccount.Money),
- FillingAmount = grayTrd.Mon.HasValue ? grayTrd.Mon.Value : request.FillingAmount,
- PayAmount = request.PaymentAmount,
- Volume = request.Volume,
- UnitPrice = correctedFuelPrice,//request.Price,
- FuelProductCode = int.Parse(grayTrd.CommId), //request.ProductCode,
- StartTime = GetDateTime(request.TrxTime),
- EndTime = GetDateTime(request.TrxEndTime),
- VolumeTotal = Convert.ToInt32(grayTrd.EndPumpId)//request.VolumeTotal
- };
- }
- else
- {
- currentFilling = new FillingInfo
- {
- PumpId = this.PumpId,
- NozzleId = request.FuelingPoint.NozzleNo,//1,
- SequenceNo = request.DitTTC,
- CardNo = cardNo,
- CardBalance = request.CardBalance,//Convert.ToInt32(cardAccount.Money),
- FillingAmount = request.FillingAmount,
- PayAmount = request.PaymentAmount,
- Volume = request.Volume,
- UnitPrice = correctedFuelPrice,//request.Price,
- FuelProductCode = request.ProductCode,
- StartTime = GetDateTime(request.TrxTime),
- EndTime = GetDateTime(request.TrxEndTime),
- VolumeTotal = request.VolumeTotal
- };
- }
- }
- else
- {
- currentFilling = new FillingInfo
- {
- PumpId = this.PumpId,
- NozzleId = request.FuelingPoint.NozzleNo,//1,
- SequenceNo = request.DitTTC,
- CardNo = cardNo,
- CardBalance = request.CardBalance,//Convert.ToInt32(cardAccount.Money),
- FillingAmount = request.FillingAmount,
- PayAmount = request.PaymentAmount,
- Volume = request.Volume,
- UnitPrice = correctedFuelPrice,//request.Price,
- FuelProductCode = request.ProductCode,
- StartTime = GetDateTime(request.TrxTime),
- EndTime = GetDateTime(request.TrxEndTime),
- VolumeTotal = request.VolumeTotal
- };
- }
- //Customer card, submit it.
- if ((_posApp.CardAppType == 1 && request.CurrentCardInfo.CardType == 3
- || _posApp.CardAppType == 2 && request.CurrentCardInfo.CardType == 1) && request.TrxType != 2)
- {
- logger.Info($"Pump {PumpId}, there is a customer card transaction pending for upload, ttc: {currentFilling.SequenceNo}");
- if (request.FillingAmount != 0)
- _posApp.AddCustomerCardFilling(currentFilling);
- }
- if (request.FillingAmount != 0 && request.TrxType != 2)
- {
- if (_posApp != null)
- {
- //2023-08-22
- SendTrasactionDataAck(request);
- ackSent = true;
- logger.Info("TransactionData ack sent");
- //Should first upload the record to cloud...
- logger.Info("Start force upload");
- //_ = _posApp?.SpsDataCourier.TriggerTransacationLookup(newGid);
- await _posApp?.SpsDataCourier.ForceTransactionUploadAsync(newGid).ContinueWith(t =>
- {
- logger.Info("Push transaction to FDC Server");
- _terminal.UpdateFuelingStatus(PumpId, new FdcTransaction
- {
- Nozzle = new LogicalNozzle(PumpId, 1, Convert.ToByte(logicId), null),
- Amount = request.FillingAmount,
- Volumn = request.Volume,
- Price = correctedFuelPrice,//request.Price,
- VolumeTotalizer = request.VolumeTotal,
- SequenceNumberGeneratedOnPhysicalPump = request.DitTTC, //I would like to use SeqNo, but TQC pumps always use 0 for it.
- Finished = true //Set FDC transaction as FINISHED
- });
- _pumpState = HengshanPumpState.Idle;
- _terminal.UpdatePumpState(PumpId, logicId, LogicalDeviceState.FDC_READY);
- _lastPumpState = _pumpState;
- });
- }
- //logger.Info("Push transaction to FDC Server");
- //_terminal.UpdateFuelingStatus(PumpId, new FdcTransaction
- //{
- // Nozzle = new LogicalNozzle(PumpId, 1, 1, null),
- // Amount = request.FillingAmount,
- // Volumn = request.Volume,
- // Price = request.Price,
- // VolumeTotalizer = request.VolumeTotal,
- // SequenceNumberGeneratedOnPhysicalPump = request.DitTTC, //I would like to use SeqNo, but TQC pumps always use 0 for it.
- // Finished = true //Set FDC transaction as FINISHED
- //});
- }
- //_pumpState = HengshanPumpState.Idle;
- //_terminal.UpdatePumpState(PumpId, LogicalDeviceState.FDC_READY);
- //_lastPumpState = _pumpState;
- }
- if (!ackSent)
- {
- logger.Info($"Pump {PumpId}, TransactionData ack not sent, send it now");
- SendTrasactionDataAck(request);
- }
- if (currentFilling != null)
- {
- lastFilling = new FillingInfo
- {
- FillingAmount = currentFilling.FillingAmount,
- Volume = currentFilling.Volume,
- UnitPrice = currentFilling.UnitPrice,
- FuelProductCode = currentFilling.FuelProductCode
- };
- }
- else
- {
- logger.Info($"Pump {PumpId}, currentFilling is null");
- }
- if (currentFilling != null)
- {
- //重置当前的Filling
- if (currentFilling.SequenceNo == request.DitTTC)
- {
- logger.Info($"Pump {PumpId}, reset current filling, ttc: {currentFilling.SequenceNo}");
- currentFilling = null;
- }
- }
- }
- private void CheckTransactionType(byte trxType)
- {
- if (trxType == 0x00)
- {
- logger.Info("Normal card transaction");
- }
- else if (trxType == 0x01)
- {
- logger.Info("Gray card transaction");
- }
- else if (trxType == 0x02)
- {
- logger.Info("Ungray card transaction");
- }
- else if (trxType == 0x03)
- {
- logger.Info("Indoor card payment transaction");
- }
- else if (trxType == 0x04)
- {
- logger.Info("POS auth transaction (cash)");
- }
- else if (trxType == 0x05)
- {
- logger.Info("Cancel auth card transaction");
- }
- else if (trxType == 0x06)
- {
- logger.Info("Non card transaction");
- }
- else if (trxType == 0x07)
- {
- logger.Info("Cancel auth non card transaction");
- }
- else if (trxType == 0x08)
- {
- logger.Info("Fuel price download transaction");
- }
- else if (trxType == 0x09)
- {
- logger.Info("Other card release transaction");
- }
- else if (trxType == 0x0A)
- {
- logger.Info("Change fuel type transaction");
- }
- else if (trxType == 0x0B)
- {
- logger.Info("POS bank card transaction");
- }
- else
- {
- logger.Info("Unknown transaction type");
- }
- }
- private void SendTrasactionDataAck(TransactionDataRequest request)
- {
- TransactionDataAck ack = new TransactionDataAck
- {
- Prefix = STX,
- SourceAddress = request.SourceAddress,
- DestinationAddress = request.DestinationAddress,
- FrameSqNoByte = request.FrameSqNoByte,
- Handle = Convert.ToByte(Command.TransactionDataAck),
- TerminalId = request.TerminalId,
- Result = 0,
- UnspecifiedField1 = 0
- };
- _terminal.Write(ack);
- }
- private ushort GetCorrectFuelPrice(string fuelNo, int price, int volume, int amount)
- {
- try
- {
- var recordedPrice = Convert.ToInt32(_posApp.CurrentFuelPrices[fuelNo]);
- if (recordedPrice != price)
- {
- logger.Info($"Price: {price} on pump: {PumpId}, is different from system recorded price: {recordedPrice}");
- int calculatedAmount = price * volume;
- int candidateAmount = recordedPrice * volume;
- double calculatedDiff = Math.Abs(calculatedAmount - amount * 100);
- double candidateDiff = Math.Abs(candidateAmount - amount * 100);
- if (candidateDiff < calculatedDiff)
- {
- logger.Info($"Returning system recorded price: {recordedPrice}");
- return Convert.ToUInt16(recordedPrice);
- }
- return Convert.ToUInt16(price);
- }
- }
- catch (Exception ex)
- {
- logger.Error("Error in getting correct fuel price ", ex.ToString());
- }
- return Convert.ToUInt16(price);
- }
- #endregion
- #region Lock/Unlock Pump 锁定/解锁油机
- public void LockUnlockPump(LockUnlockOperation operation)
- {
- var request = new LockOrUnlockPumpRequest
- {
- Prefix = STX,
- Handle = Convert.ToByte(Command.LockOrUnlockPump),
- FPCode = EncodeFPCodeString(PumpId, PumpId),
- OperationType = operation
- };
- PrepareSendMessage(request);
- }
- public void HandleLockUnlockPumpResult(LockOrUnlockPumpAck lockUnlockPumpResult)
- {
- if (lockUnlockPumpResult.DispenserState == DispenserState.Closed)
- {
- logger.Info($"Current pump {PumpId} is locked!");
- //... should notify POS then.
- }
- else if (lockUnlockPumpResult.DispenserState == DispenserState.Idle)
- {
- logger.Info($"Current pump {PumpId} is idle (unlocked)!");
- //... should notify POS then.
- }
- }
- #endregion
- #region Request Data 加油机请求下载数据
- public void HandleDataDownloadRequest(DataDownloadRequest request)
- {
- ResetTimer();
- //Reset
- VersionedListedCard = null;
- if (request.DataContentType == DataContentType.FuelPriceList)
- {
- logger.Info($"Terminal {PumpId} initiates fuel price list download");
- }
- else if (request.DataContentType == DataContentType.StationGeneralInfo)
- {
- logger.Info($"Terminal {PumpId} initiates station general info download");
- }
- else if (request.DataContentType == DataContentType.Whitelist)
- {
- logger.Info($"Terminal {PumpId} initiates whitelist download");
- }
- else if (request.DataContentType == DataContentType.NewlyAddedBlacklist)
- {
- logger.Info($"Terminal {PumpId} initiates newly added blacklist download");
- }
- else if (request.DataContentType == DataContentType.NewlyDeletedBlacklist)
- {
- logger.Info($"Terminal {PumpId} initiates newly deleted blacklist download");
- }
- else if (request.DataContentType == DataContentType.BaseBlacklist)
- {
- logger.Info($"Terminal {PumpId} initiates base blacklist download");
- }
- else if (request.DataContentType == DataContentType.StationGeneralInfo)
- {
- logger.Info($"Terminal {PumpId} initiates station general info download");
- }
- SendDataLength(request);
- }
- public void SendDataLength(DataDownloadRequest request)
- {
- DataBytesLength response = new DataBytesLength();
- response.Prefix = STX;
- response.SourceAddress = request.SourceAddress;
- response.DestinationAddress = request.DestinationAddress;
- response.Handle = (byte)Command.DataBytesLength;
- response.FrameSqNoByte = request.FrameSqNoByte;
- if (request.DataContentType == DataContentType.FuelPriceList)
- {
- response.DataContentType = request.DataContentType;
- response.DataLength = 0x32;
- logger.Info($"Fuel Price Update, Data Length: {response.DataLength}");
- }
- else if (request.DataContentType == DataContentType.Whitelist)
- {
- response.DataContentType = DataContentType.Whitelist;
- var result = _dbManager.GetWhitelistedCards(_cardAppType);
- if (result != null)
- {
- response.DataLength = 16 + 10 * result.Count;
- logger.Info($"WhiteList, Data Length: {response.DataLength}");
- }
- }
- else if (request.DataContentType == DataContentType.NewlyAddedBlacklist)
- {
- response.DataContentType = DataContentType.NewlyAddedBlacklist;
- var result = _dbManager.GetNewlyAddedBlacklistedCards(_cardAppType);
- if (result != null)
- {
- response.DataLength = 16 + 10 * result.Count;
- logger.Info($"Incremental Black List, Data Length: {response.DataLength}");
- }
- }
- else if (request.DataContentType == DataContentType.NewlyDeletedBlacklist)
- {
- response.DataContentType = DataContentType.NewlyDeletedBlacklist;
- var result = _dbManager.GetNewlyDeletedBlacklistedCards(_cardAppType);
- if (result != null)
- {
- response.DataLength = 16 + 10 * result.Count;
- logger.Info($"Decremental Black List, Data Length: {response.DataLength}");
- }
- }
- else if (request.DataContentType == DataContentType.BaseBlacklist)
- {
- response.DataContentType = DataContentType.BaseBlacklist;
- var result = _dbManager.GetBaseBlacklistedCards(_cardAppType);
- if (result != null)
- {
- response.DataLength = 16 + 10 * result.Count;
- logger.Info($"Base Black List, Data Length: {response.DataLength}");
- }
- }
- else if (request.DataContentType == DataContentType.StationGeneralInfo)
- {
- response.DataContentType = DataContentType.StationGeneralInfo;
- var result = _dbManager.GetPumpInfo(Convert.ToByte(PumpId));
- if (result != null && result.Count > 0)
- {
- response.DataLength = 6;
- }
- logger.Info($"Station General Info, Data Length: {response.DataLength}");
- }
- _terminal.Write(response);
- }
- #endregion
- #region Request Data Content 加油机申请下载数据的内容
- public void HandleDataContentRequest(DataContentRequest request)
- {
- ResetTimer();
- if (request.DataContentType == DataContentType.FuelPriceList)
- {
- logger.Info($"Terminal {PumpId} downloads fuel price list content");
- }
- SendDataContent(request);
- }
- public void SendDataContent(DataContentRequest request)
- {
- DataContent response = new DataContent();
- response.Prefix = STX;
- response.SourceAddress = request.SourceAddress;
- response.DestinationAddress = request.DestinationAddress;
- response.FrameSqNoByte = request.FrameSqNoByte;
- response.Handle = (byte)Command.DataContent;
- //Fuel price, 油品油价列表
- if (request.DataContentType == DataContentType.FuelPriceList)
- {
- logger.Info($"Terminal downloads fuel price, Source: {request.SourceAddress}");
- response.DataContentType = DataContentType.FuelPriceList;
- response.SegmentOffset = request.SegmentOffset;
- var result = _dbManager.GetFuelPriceChangeConfig(PumpId);
- if (result.Count > 0)
- {
- var priceChangeRecordCount = result.Count;
- if (priceChangeRecordCount <= 1)
- {
- var priceChangeRecord = result.First();
- FuelPriceRecord record = new FuelPriceRecord();
- record.Version = Convert.ToByte(priceChangeRecord.Ver);
- record.EffectiveTime = priceChangeRecord.EffeTime;
- record.RecordCount = Convert.ToByte(priceChangeRecordCount);
- record.NozzleNo = Convert.ToByte(priceChangeRecord.LogicId);
- record.FuelProductCode = Convert.ToUInt16(priceChangeRecord.OilId);
- record.FuelProductName =
- ByteArrayToString(Encoding.GetEncoding("GB2312").GetBytes(priceChangeRecord.OilName)).PadRight(64, '0');
- record.Density = priceChangeRecord.Density == "" ? 0 : Convert.ToInt32(priceChangeRecord.Density);
- record.ValidPriceCount = 1;
- record.Price1 = priceChangeRecord.Price > UInt16.MaxValue ? UInt16.MaxValue : Convert.ToUInt16(priceChangeRecord.Price);
- _terminal.SetRealPrice(PumpId, Convert.ToInt32(priceChangeRecord.Price));
- response.Content = parser.SerializeInnerElement(record).ToList();
- if (response.Content.Count % 16 == 0)
- {
- response.SegmentCount = Convert.ToByte(response.Content.Count / 16);
- }
- else
- {
- response.SegmentCount = Convert.ToByte(response.Content.Count / 16 + 1);
- }
- }
- else
- {
- logger.Info("There are multiple price change records, seriously? ...");
- var first = result.First();
- MultiFuelPriceRecord record = new MultiFuelPriceRecord();
- record.Version = Convert.ToByte(first.Ver);
- record.EffectiveTime = first.EffeTime;
- record.RecordCount = Convert.ToByte(result.Count);
- record.FirstNozzleNo = Convert.ToByte(result[0].LogicId);
- record.FirstFuelProductCode = Convert.ToUInt16(result[0].OilId);
- record.FirstFuelProductName =
- ByteArrayToString(Encoding.GetEncoding("GB2312").GetBytes(result[0].OilName)).PadRight(64, '0');
- record.FirstDensity = result[0].Density == "" ? 0 : Convert.ToInt32(result[0].Density);
- record.FirstValidPriceCount = 1;
- record.FirstPrice1 = Convert.ToUInt16(result[0].Price);
- record.SecondNozzleNo = Convert.ToByte(result[1].LogicId);
- record.SecondFuelProductCode = Convert.ToUInt16(result[1].OilId);
- record.SecondFuelProductName =
- ByteArrayToString(Encoding.GetEncoding("GB2312").GetBytes(result[1].OilName)).PadRight(64, '0');
- record.SecondDensity = result[1].Density == "" ? 0 : Convert.ToInt32(result[1].Density);
- record.SecondValidPriceCount = 1;
- record.SecondPrice1 = Convert.ToUInt16(result[1].Price);
- response.Content = new List<byte>();
- response.Content.AddRange(parser.SerializeInnerElement(record).ToList());
- if (response.Content.Count % 16 == 0)
- {
- response.SegmentCount = Convert.ToByte(response.Content.Count / 16);
- }
- else
- {
- response.SegmentCount = Convert.ToByte(response.Content.Count / 16 + 1);
- }
- }
- }
- }
- //Incremental blacklist, 新增(增量)黑名单
- else if (request.DataContentType == DataContentType.NewlyAddedBlacklist)
- {
- logger.Info($"Terminal downloading newly added (incremental) blacklist, Source: {request.SourceAddress}, " +
- $"Segment offset: {request.SegmentOffset}, Segment count: {request.SegmentCount}");
- response.DataContentType = DataContentType.NewlyAddedBlacklist;
- response.SegmentOffset = request.SegmentOffset;
- response.SegmentCount = request.SegmentCount;
- var cards = _dbManager.GetNewlyAddedBlacklistedCards(_cardAppType);
- var versions = _dbManager.GetDataVersions();
- if (versions.Count > 0 && cards.Count > 0)
- {
- var versionInfo = versions.First(v => v.VersionType == VersionType.NewlyAddedBlacklistVersion);
- ListedCardRecord listedCardRecord = null;
- if (versionInfo != null)
- {
- listedCardRecord = new ListedCardRecord();
- listedCardRecord.Version = versionInfo.VersionNo;
- listedCardRecord.ValidStartDate = versionInfo.Effectivetime.ToString("yyyyMMdd");
- listedCardRecord.ExpiryDate = versionInfo.ExpiredTime.ToString("yyyyMMdd");
- listedCardRecord.Region = Convert.ToString(ushort.MaxValue);
- listedCardRecord.CardCount = cards.Count;
- }
- if (VersionedListedCard == null)
- {
- logger.Info("Formatting card list (newly added)");
- VersionedListedCard = new VersionedListedCard(versionInfo.VersionNo, versionInfo.Effectivetime.ToString("yyyyMMdd"),
- versionInfo.ExpiredTime.ToString("yyyyMMdd"), cards.Count, cards.ToList());
- }
- if (request.SegmentOffset == 0)
- {
- if (request.SegmentCount == 1)
- {
- logger.Info("Terminal requesting just one segment of newly added blacklist data");
- response.Content = parser.SerializeInnerElement(listedCardRecord).ToList();
- }
- else
- {
- logger.Info($"Terminal requests Newly-added blacklist, Segment offset: 0000, Segment count: {request.SegmentCount}");
- var versionInfoBytes = parser.SerializeInnerElement(listedCardRecord);
- var cardBytes = StringToByteArray(VersionedListedCard.AllCards);
- if (versionInfoBytes.Length + cardBytes.Length >= 160)
- {
- var bytes = new byte[160];
- Buffer.BlockCopy(versionInfoBytes, 0, bytes, 0, versionInfoBytes.Length);
- Buffer.BlockCopy(cardBytes, 0, bytes, versionInfoBytes.Length, 160 - versionInfoBytes.Length);
- response.Content = bytes.ToList();
- }
- else
- {
- var bytes = new byte[160];
- Buffer.BlockCopy(versionInfoBytes, 0, bytes, 0, versionInfoBytes.Length);
- Buffer.BlockCopy(cardBytes, 0, bytes, versionInfoBytes.Length, cardBytes.Length);
- response.Content = bytes.ToList();
- }
- }
- }
- else
- {
- var bytes = new byte[160];
- int cardsToBeSkipped = request.SegmentOffset > 10 ? request.SegmentOffset / 10 : 0;
- logger.Info($"Newly-added blacklist, Segment Offset: {request.SegmentOffset}, Cards to be skipped: {cardsToBeSkipped * 16}");
- if (VersionedListedCard.CardCount <= 16)
- {
- var cardBytes = StringToByteArray(VersionedListedCard.AllCards);
- Buffer.BlockCopy(cardBytes, 0, bytes, 0, cardBytes.Length);
- response.Content = bytes.ToList();
- }
- else
- {
- IEnumerable<ListedCard> currentCards = VersionedListedCard.ListedCards.Skip(cardsToBeSkipped * 16).Take(16);
- StringBuilder sb = new StringBuilder();
- foreach (var card in currentCards)
- {
- sb.Append(card.CardNo.PadLeft(20, '0'));
- logger.Info(card.CardNo);
- }
- var cardBytes = StringToByteArray(sb.ToString());
- Buffer.BlockCopy(cardBytes, 0, bytes, 0, cardBytes.Length);
- response.Content = bytes.ToList();
- }
- }
- }
- }
- //Decremental blacklist, 新删(减量)黑名单
- else if (request.DataContentType == DataContentType.NewlyDeletedBlacklist)
- {
- logger.Info($"Terminal downloading newly deleted blacklist, Source: {request.SourceAddress}");
- response.DataContentType = DataContentType.NewlyDeletedBlacklist;
- response.SegmentOffset = request.SegmentOffset;
- response.SegmentCount = request.SegmentCount;
- var cards = _dbManager.GetNewlyDeletedBlacklistedCards(_cardAppType);
- var versions = _dbManager.GetDataVersions();
- if (versions.Count > 0 && cards.Count > 0)
- {
- var versionInfo = versions.First(v => v.VersionType == VersionType.NewlyDeletedBlacklistVersion);
- ListedCardRecord record = null;
- if (versionInfo != null)
- {
- record = new ListedCardRecord();
- record.Version = versionInfo.VersionNo;
- record.ValidStartDate = versionInfo.Effectivetime.ToString("yyyyMMdd");
- record.ExpiryDate = versionInfo.ExpiredTime.ToString("yyyyMMdd");
- record.Region = Convert.ToString(ushort.MaxValue);
- record.CardCount = cards.Count;
- }
- if (VersionedListedCard == null)
- {
- logger.Info("Formatting card list (newly deleted)");
- VersionedListedCard = new VersionedListedCard(versionInfo.VersionNo, versionInfo.Effectivetime.ToString("yyyyMMdd"),
- versionInfo.ExpiredTime.ToString("yyyyMMdd"), cards.Count, cards.ToList());
- }
- if (request.SegmentOffset == 0)
- {
- if (request.SegmentCount == 1)
- {
- response.Content = parser.SerializeInnerElement(record).ToList();
- }
- else
- {
- var versionInfoBytes = parser.SerializeInnerElement(record);
- var cardBytes = StringToByteArray(VersionedListedCard.AllCards);
- if (versionInfoBytes.Length + cardBytes.Length >= 160)
- {
- var bytes = new byte[160];
- Buffer.BlockCopy(versionInfoBytes, 0, bytes, 0, versionInfoBytes.Length);
- Buffer.BlockCopy(cardBytes, 0, bytes, versionInfoBytes.Length, 160 - versionInfoBytes.Length);
- response.Content = bytes.ToList();
- }
- else
- {
- var bytes = new byte[160];
- Buffer.BlockCopy(versionInfoBytes, 0, bytes, 0, versionInfoBytes.Length);
- Buffer.BlockCopy(cardBytes, 0, bytes, versionInfoBytes.Length, cardBytes.Length);
- response.Content = bytes.ToList();
- }
- }
- }
- else
- {
- var bytes = new byte[160];
- int segmentsToBeSkipped = request.SegmentOffset > 10 ? request.SegmentOffset / 10 : 0;
- logger.Info($"Newly-deleted blacklist, Segment Offset: {request.SegmentOffset.ToString("X")}, " +
- $"Cards to be skipped: {segmentsToBeSkipped * 16}");
- if (VersionedListedCard.CardCount <= 16)
- {
- var cardBytes = StringToByteArray(VersionedListedCard.AllCards);
- Buffer.BlockCopy(cardBytes, 0, bytes, 0, cardBytes.Length);
- response.Content = bytes.ToList();
- }
- else
- {
- var currentCards = VersionedListedCard.ListedCards.Skip(segmentsToBeSkipped * 16).Take(16);
- StringBuilder sb = new StringBuilder();
- foreach (var card in currentCards)
- {
- sb.Append(card.CardNo.PadLeft(20, '0'));
- logger.Info(card.CardNo);
- }
- var cardBytes = StringToByteArray(sb.ToString());
- Buffer.BlockCopy(cardBytes, 0, bytes, 0, cardBytes.Length);
- response.Content = bytes.ToList();
- }
- }
- }
- }
- //White list, 白名单数据
- else if (request.DataContentType == DataContentType.Whitelist)
- {
- logger.Info($"Terminal downloads whitelist, Source: {request.SourceAddress}");
- response.DataContentType = DataContentType.Whitelist;
- response.SegmentOffset = request.SegmentOffset;
- response.SegmentCount = request.SegmentCount;
- var cards = _dbManager.GetWhitelistedCards(_cardAppType);
- var versions = _dbManager.GetDataVersions();
- if (versions.Count > 0 && cards.Count > 0)
- {
- logger.Info($"Whitelist, card count: {cards.Count}");
- var versionInfo = versions.First(v => v.VersionType == VersionType.WhitelistVersion);
- ListedCardRecord record = null;
- if (versionInfo != null)
- {
- logger.Info($"Whitelist, version: {versionInfo.VersionNo}");
- record = new ListedCardRecord();
- record.Version = versionInfo.VersionNo;
- record.ValidStartDate = versionInfo.Effectivetime.ToString("yyyyMMdd");
- record.ExpiryDate = versionInfo.ExpiredTime.ToString("yyyyMMdd");
- record.Region = Convert.ToString(ushort.MaxValue);
- record.CardCount = cards.Count;
- }
- if (VersionedListedCard == null)
- {
- logger.Info("Formatting card list (whitelist)");
- VersionedListedCard = new VersionedListedCard(versionInfo.VersionNo, versionInfo.Effectivetime.ToString("yyyyMMdd"),
- versionInfo.ExpiredTime.ToString("yyyyMMdd"), cards.Count, cards.ToList());
- }
- if (request.SegmentOffset == 0)
- {
- logger.Info("Segment offset is: 0");
- if (request.SegmentCount == 1)
- {
- logger.Info("Segment count is: 1");
- response.Content = parser.SerializeInnerElement(record).ToList();
- }
- else
- {
- logger.Info($"Segment count is: {request.SegmentCount}");
- var versionInfoBytes = parser.SerializeInnerElement(record);
- var cardBytes = StringToByteArray(VersionedListedCard.AllCards);
- if (versionInfoBytes.Length + cardBytes.Length >= 160)
- {
- logger.Info($"Version Info serialized: {ByteArrayToString(versionInfoBytes)}, Length: {versionInfoBytes.Length}, ");
- logger.Info($"More than 160 bytes, Cards bytes Length: {cardBytes.Length}");
- var bytes = new byte[160];
- try
- {
- Buffer.BlockCopy(versionInfoBytes, 0, bytes, 0, versionInfoBytes.Length);
- Buffer.BlockCopy(cardBytes, 0, bytes, versionInfoBytes.Length, 160 - versionInfoBytes.Length);
- }
- catch (Exception ex)
- {
- logger.Info($"{ex.ToString()}");
- }
- response.Content = bytes.ToList();
- }
- else
- {
- logger.Info("Less than 160 bytes");
- var bytes = new byte[160];
- Buffer.BlockCopy(versionInfoBytes, 0, bytes, 0, versionInfoBytes.Length);
- Buffer.BlockCopy(cardBytes, 0, bytes, versionInfoBytes.Length - 1, cardBytes.Length);
- response.Content = bytes.ToList();
- }
- }
- }
- else
- {
- logger.Info($"Segment offset is: {request.SegmentOffset}");
- var bytes = new byte[160];
- int segmentsToBeSkipped = request.SegmentOffset > 10 ? request.SegmentOffset / 10 : 0;
- logger.Info($"Whitelist, Segment Offset: {request.SegmentOffset.ToString("X")}, " +
- $"Cards to be skipped: {segmentsToBeSkipped * 16}");
- if (VersionedListedCard.CardCount <= 16)
- {
- var currentCards = VersionedListedCard.ListedCards.Skip((request.SegmentOffset - 1) * 15).Take(15);
- StringBuilder sb = new StringBuilder();
- foreach (var card in currentCards)
- {
- sb.Append(card.CardNo.PadLeft(20, '0'));
- logger.Info(card.CardNo);
- }
- var cardBytes = StringToByteArray(sb.ToString());
- Buffer.BlockCopy(cardBytes, 0, bytes, 0, cardBytes.Length);
- response.Content = bytes.ToList();
- }
- else
- {
- var currentCards = VersionedListedCard.ListedCards.Skip(segmentsToBeSkipped * 16).Take(16);
- StringBuilder sb = new StringBuilder();
- foreach (var card in currentCards)
- {
- sb.Append(card.CardNo.PadLeft(20, '0'));
- logger.Info(card.CardNo);
- }
- var cardBytes = StringToByteArray(sb.ToString());
- Buffer.BlockCopy(cardBytes, 0, bytes, 0, cardBytes.Length);
- response.Content = bytes.ToList();
- //var cardBytes = StringToByteArray(VersionedListedCard.AllCards);
- //Buffer.BlockCopy(cardBytes, 0, bytes, 0, cardBytes.Length);
- //response.Content = bytes.ToList();
- }
- }
- }
- else if (cards.Count == 0)
- {
- logger.Info("No cards for whitelist");
- var versionInfo = versions.First(v => v.VersionType == VersionType.WhitelistVersion);
- ListedCardRecord record = null;
- if (versionInfo != null)
- {
- record = new ListedCardRecord();
- record.Version = versionInfo.VersionNo;
- record.ValidStartDate = versionInfo.Effectivetime.ToString("yyyyMMdd");
- record.ExpiryDate = versionInfo.ExpiredTime.ToString("yyyyMMdd");
- record.Region = Convert.ToString(ushort.MaxValue);
- record.CardCount = 0;
- }
- if (VersionedListedCard == null)
- {
- logger.Info("Formatting card list (whitelist)");
- VersionedListedCard = new VersionedListedCard(versionInfo.VersionNo, versionInfo.Effectivetime.ToString("yyyyMMdd"),
- versionInfo.ExpiredTime.ToString("yyyyMMdd"), 0, null);
- }
- response.Content = parser.SerializeInnerElement(record).ToList();
- }
- }
- //Base blacklist, 基础黑名单
- else if (request.DataContentType == DataContentType.BaseBlacklist)
- {
- logger.Info($"Terminal downloads base blacklist, Source: {request.SourceAddress}");
- response.DataContentType = DataContentType.BaseBlacklist;
- response.SegmentOffset = request.SegmentOffset;
- response.SegmentCount = request.SegmentCount;
- var cards = _dbManager.GetBaseBlacklistedCards(_cardAppType);
- var versions = _dbManager.GetDataVersions();
- if (versions.Count > 0 && cards.Count > 0)
- {
- var versionInfo = versions.First(v => v.VersionType == VersionType.BaseBlacklistVersion);
- ListedCardRecord record = null;
- if (versionInfo != null)
- {
- record = new ListedCardRecord();
- record.Version = versionInfo.VersionNo;
- record.ValidStartDate = versionInfo.Effectivetime.ToString("yyyyMMdd");
- record.ExpiryDate = versionInfo.ExpiredTime.ToString("yyyyMMdd");
- record.Region = Convert.ToString(ushort.MaxValue);
- record.CardCount = cards.Count;
- }
- if (VersionedListedCard == null)
- {
- logger.Info("Formatting card list (base blacklist)");
- VersionedListedCard = new VersionedListedCard(versionInfo.VersionNo, versionInfo.Effectivetime.ToString("yyyyMMdd"),
- versionInfo.ExpiredTime.ToString("yyyyMMdd"), cards.Count, cards.ToList());
- }
- if (request.SegmentOffset == 0)
- {
- if (request.SegmentCount == 1)
- {
- response.Content = parser.SerializeInnerElement(record).ToList();
- }
- else
- {
- var versionInfoBytes = parser.SerializeInnerElement(record);
- var cardBytes = StringToByteArray(VersionedListedCard.AllCards);
- if (versionInfoBytes.Length + cardBytes.Length >= 160)
- {
- var bytes = new byte[160];
- Buffer.BlockCopy(versionInfoBytes, 0, bytes, 0, versionInfoBytes.Length);
- Buffer.BlockCopy(cardBytes, 0, bytes, versionInfoBytes.Length, 160 - versionInfoBytes.Length);
- response.Content = bytes.ToList();
- }
- else
- {
- var bytes = new byte[160];
- Buffer.BlockCopy(versionInfoBytes, 0, bytes, 0, versionInfoBytes.Length);
- Buffer.BlockCopy(cardBytes, 0, bytes, versionInfoBytes.Length - 1, cardBytes.Length);
- response.Content = bytes.ToList();
- }
- }
- }
- else
- {
- var bytes = new byte[160];
- int cardsToBeSkipped = request.SegmentOffset > 10 ? request.SegmentOffset / 10 : 0;
- logger.Info($"Base blacklist, Segment Offset: {request.SegmentOffset}, Cards to be skipped: {cardsToBeSkipped * 16}");
- if (VersionedListedCard.CardCount <= 16)
- {
- var cardBytes = StringToByteArray(VersionedListedCard.AllCards);
- Buffer.BlockCopy(cardBytes, 0, bytes, 0, cardBytes.Length);
- response.Content = bytes.ToList();
- }
- else
- {
- IEnumerable<ListedCard> currentCards = VersionedListedCard.ListedCards.Skip(cardsToBeSkipped * 16).Take(16);
- StringBuilder sb = new StringBuilder();
- foreach (var card in currentCards)
- {
- sb.Append(card.CardNo.PadLeft(20, '0'));
- logger.Info(card.CardNo);
- }
- var cardBytes = StringToByteArray(sb.ToString());
- Buffer.BlockCopy(cardBytes, 0, bytes, 0, cardBytes.Length);
- response.Content = bytes.ToList();
- }
- }
- }
- }
- //Station general info, 油站通用信息
- else if (request.DataContentType == DataContentType.StationGeneralInfo)
- {
- logger.Info($"Terminal downloads Station general info (油站通用信息内容), Source: {request.SourceAddress}");
- response.DataContentType = DataContentType.StationGeneralInfo;
- response.SegmentOffset = request.SegmentOffset;
- var result = _dbManager.GetPumpInfo(Convert.ToByte(PumpId));
- List<byte> data = new List<byte>();
- var pumpInfo = result.First();
- data.Add(Convert.ToByte(pumpInfo.VersionId));
- data.Add(Convert.ToByte(pumpInfo.PosId));
- data.Add(Convert.ToByte(PumpId));
- if (result != null && result.Count > 0)
- {
- data.Add(Convert.ToByte(result.Count()));
- foreach (var item in result)
- data.Add(Convert.ToByte(item.LogicId));
- data.AddRange(new byte[10]);
- }
- response.SegmentCount = 1;
- response.Content = data;
- }
- if (response.Content != null && response.Content.Count > 0)
- logger.Info($"ContentType: {response.DataContentType}, Content: {ByteArrayToString(response.Content.ToArray())}");
- else
- logger.Info($"ContentType: {response.DataContentType}, Content emtpy");
- _terminal.Write(response);
- }
- #endregion
- #region Change Auth Mode 修改授权模式
- private void ChangeAuthMode(CheckCmdRequest checkCmd, WorkMode workMode)
- {
- var request = new ChangeAuthMode
- {
- Prefix = STX,
- SourceAddress = checkCmd.SourceAddress,
- DestinationAddress = checkCmd.DestinationAddress,
- FrameSqNoByte = checkCmd.FrameSqNoByte,
- Handle = Convert.ToByte(Command.ChangeAuthMode),
- FPCode = EncodeFPCodeString(PumpId, PumpId),
- WorkMode = workMode
- };
- PrepareSendMessage(request);
- }
- public void HandleModeChangeResult(ChangeAuthModeAck response)
- {
- logger.Info($"Mode change result: {response.ModeChangeResult}, current mode: {response.WorkMode}");
- }
- #endregion
- #region Cancel Auth request 撤销授权
- public void HandleCancelAuth(CancelAuthRequest cancelAuthRequest)
- {
- logger.Info("Handling CancelAuth (0x19)");
- //There is no special handling for cancel auth.
- SendCancelAuthResult(cancelAuthRequest);
- }
- private void SendCancelAuthResult(CancelAuthRequest request)
- {
- var result = new CancelAuthResult();
- result.Prefix = STX;
- result.DestinationAddress = request.DestinationAddress;
- result.SourceAddress = request.SourceAddress;
- result.FrameSqNoByte = request.FrameSqNoByte;
- result.Handle = Convert.ToByte(Command.CancelAuthResult);
- result.Asn = request.Asn;
- result.PosTtc = request.PosTtc;
- result.SeqNo = request.SeqNo;
- result.FPCode = request.FPCode.ToUInt16();
- result.Result = 0;
- result.AdditionalInfoLength = 0;
- _terminal.Write(result);
- }
- #endregion
- #region Query gray record 查询灰记录
- public void HandleQueryGrayRecord(QueryGrayRecordRequest request)
- {
- logger.Info($"Query gray record, info, ASN: {request.Asn}, CTC: {request.Ctc}, Time: {request.Time}");
- SendGrayRecord(request);
- }
- private void SendGrayRecord(QueryGrayRecordRequest request)
- {
- var record = _dbManager.SelectGrayInfo(request.Asn, request.Ctc, request.Time);
- QueryGrayRecordResult result = new QueryGrayRecordResult();
- result.Prefix = STX;
- result.SourceAddress = request.SourceAddress;
- result.DestinationAddress = request.DestinationAddress;
- result.FrameSqNoByte = request.FrameSqNoByte;
- result.Handle = Convert.ToByte(Command.GrayRecord);
- if (record != null)
- {
- result.Match = 0;
- result.Asn = request.Asn;
- result.Balance = Convert.ToInt32(record.CardBal);
- //result.Amount = Convert.ToInt32(record.Mon);
- result.Amount1 = Convert.ToInt32(record.RealMon);
- result.Ctc = request.Ctc;
- result.Time = record.Ttctime;
- result.Gmac = record.Gmac.ToString("X");
- result.PsamTid = record.Psamtid;
- result.PsamTtc = Convert.ToInt32(record.Psamttc);
- result.Volume = Convert.ToInt32(record.Vol);
- }
- else
- {
- result.Match = 1;
- }
- _terminal.Write(result);
- }
- #endregion
- public void HandleFakeNullMessage()
- {
- logger.Info($"Terminal {PumpId} Handling Fake null message");
- ResetTimer();
- }
- #region Message sent to terminal from System
- private bool IsMessagePendingForSend()
- {
- lock (sendQueueSyncObj)
- {
- logger.Debug($"Current send queue count: {activeSendQueue.Count}");
- return activeSendQueue.Count > 0;
- }
- }
- private void PrepareSendMessage(CardMessageBase cardMessage)
- {
- lock (sendQueueSyncObj)
- {
- activeSendQueue.Enqueue(cardMessage);
- }
- }
- private CardMessageBase PickAndSendCardMessage()
- {
- lock (sendQueueSyncObj)
- {
- if (activeSendQueue.Count > 0)
- {
- logger.Info("Dequeued message from SendQueue");
- return activeSendQueue.Dequeue();
- }
- }
- return null;
- }
- #endregion
- #region Check terminal id
- private void CheckTerminalId(string terminalId)
- {
- int tid;
- if (int.TryParse(terminalId, out tid))
- {
- if (tid <= 0 || tid >= 99)
- {
- logger.Error($"Invalid terminal id: {tid}");
- }
- }
- else
- {
- logger.Error("Invalid terminal id, unrecognized");
- }
- }
- #endregion
- #endregion
- #region Helper methods
- public byte[] StringToByteArray(string hex)
- {
- int numberChars = hex.Length;
- byte[] bytes = new byte[numberChars / 2];
- for (int i = 0; i < numberChars; i += 2)
- bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
- return bytes;
- }
- public static string ByteArrayToString(byte[] ba)
- {
- return BitConverter.ToString(ba).Replace("-", "");
- }
- private DateTime GetDateTime(string time)
- {
- if (time == "00000000000000")
- return new DateTime(0001, 01, 01, 00, 00, 00);
- var timeFormat = "yyyyMMddHHmmss";
- return DateTime.ParseExact(time, timeFormat, null);
- }
- private string EncodeFPCodeString(int nozzleId, int pumpId)
- {
- return nozzleId.ToString("X").PadLeft(2, '0') + pumpId.ToString("X").PadLeft(2, '0');
- }
- #endregion
- #region Save non card trade
- private long AddTradeFromFuelingData(FuelingDataRequest request)
- {
- int payModeId = 102;
- string payModeNo = string.Empty;
- byte trxType = 6;
- string asn = string.Empty;
- if (request.Asn.Any(c => c > 48))
- asn = request.Asn;
- int stationNo = 1;
- if (_posApp.StationInfo != null)
- stationNo = _posApp.StationInfo.StationNo;
- var newGid = _dbManager.AddTrade(
- stationNo,
- asn,
- asn,
- payModeId,
- payModeNo,
- trxType,
- Convert.ToString(request.ProductCode),
- request.Price,
- request.Volume,
- request.Amount,
- request.Amount,
- 0, //Card Balance,
- 0, //card type, use 0 for non-card transaction
- 0, //card ctc use 0 for non-card transaction
- GetDateTime(request.DispenserTime),
- GetDateTime(request.TransactionEndTime),
- request.PosTtc,
- request.SeqNo,
- _posApp.GetNextBillNo(), //billNo
- request.FuelingPoint.NozzleNo,
- request.FuelingPoint.PumpNo,
- Convert.ToInt32(request.TerminalId.TrimStart('0')),
- request.VolumeTotal,
- 0, //discountNo
- 1001,
- 1,
- string.Empty,//request.PsamAsn, //PsamAsn
- 0,//uint.Parse(request.PsamTac, System.Globalization.NumberStyles.HexNumber),//PsamTac
- string.Empty,//request.PsamTid,//psam tid
- 0,//uint.Parse(request.PsamTtc, System.Globalization.NumberStyles.HexNumber),//psam ttc
- 0,//uint.Parse(request.Tac, System.Globalization.NumberStyles.HexNumber),//tac
- 0,//uint.Parse(request.Gmac, System.Globalization.NumberStyles.HexNumber),//gmac
- 0,//uint.Parse(request.Tmac, System.Globalization.NumberStyles.HexNumber),//tmac
- 0, //Integral
- Convert.ToInt32(_posApp.CurrentShiftNo),
- string.Empty,
- string.Empty,
- string.Empty,
- 0);
- return newGid;
- }
- #endregion
- private string GetCardNo(string asn)
- {
- if (_cardAppType == CardAppType.CpuCard)
- {
- string leftOver = asn.TrimStart('0');
- return leftOver.PadLeft(20, '0');
- }
- else if (_cardAppType == CardAppType.RfCard)
- {
- string leftOver = asn.TrimStart('0');
- return leftOver.PadLeft(8, '0');
- }
- return asn;
- }
- }
- }
|