using HengshanPaymentTerminal.MessageEntity.Incoming;
using HengshanPaymentTerminal.MessageEntity;
using HengshanPaymentTerminal.Support;
using HengshanPaymentTerminal;
using System;
using System.Collections.Concurrent;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Edge.Core.Processor.Dispatcher.Attributes;
using Edge.Core.IndustryStandardInterface.Pump;
using Edge.Core.IndustryStandardInterface.Pump.Fdc;
using Edge.Core.Processor;
using Edge.Core.Core.database;
using Edge.Core.Domain.FccStationInfo.Output;
using Edge.Core.Domain.FccNozzleInfo;
using Edge.Core.Domain.FccNozzleInfo.Output;
using System.Net.Sockets;
using Edge.Core.Domain.FccOrderInfo;
using Microsoft.EntityFrameworkCore;
using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities;
using static Microsoft.AspNetCore.Hosting.Internal.HostingApplication;
using HengshanPaymentTerminal.Mqtt.Request;
using HengshanPaymentTerminal.Http;
using HengshanPaymentTerminal.Http.Request;
using System.Text.Json;
using Newtonsoft.Json;
using HengshanPaymentTerminal.Http.Response;
using HengshanPaymentTerminal.MessageEntity.Outgoing;
using Microsoft.IdentityModel.Tokens;
using Org.BouncyCastle.Asn1.Ocsp;
using Newtonsoft.Json.Linq;
using System.Net;
using Edge.Core.Domain.FccOrderInfo.Output;
using Microsoft.AspNetCore.Mvc;
using System.Timers;
namespace HengshanPaymentTerminal
{
///
/// Handler that communicates directly with the Hengshan Payment Terminal for card handling and pump handling via serial port.
///
[MetaPartsDescriptor(
"lang-zh-cn:恒山IC卡终端(UI板) App lang-en-us:Hengshan IC card terminal (UI Board)",
"lang-zh-cn:用于与UI板通讯控制加油机" +
"lang-en-us:Used for terminal communication to control pumps",
new[]
{
"lang-zh-cn:恒山IC卡终端lang-en-us:HengshanICTerminal"
})]
public class HengshanPayTermHandler : IEnumerable, IDeviceHandler
{
#region Fields
private string pumpIds;
private string pumpSubAddresses;
private string pumpNozzles;
private string pumpSiteNozzleNos;
private string nozzleLogicIds;
private IContext _context;
private List pumpHandlers = new List();
public Queue queue = new Queue();
public Queue commonQueue = new Queue();
private object syncObj = new object();
private ConcurrentDictionary statusDict = new ConcurrentDictionary();
public ConcurrentDictionary PumpStatusDict => statusDict;
private Dictionary pumpIdSubAddressDict;
public Dictionary> PumpNozzlesDict { get; private set; }
public Dictionary NozzleLogicIdDict { get; private set; }
public Dictionary> PumpSiteNozzleNoDict { get; private set; }
//public MysqlDbContext MysqlDbContext { get; private set; }
public StationInfo stationInfo { get; set; }
public Dictionary stationPayment = new Dictionary();
//记录油枪泵码
public ConcurrentDictionary nozzlePumpCode = new ConcurrentDictionary();
public string buildID = "";
public bool isSendHeart = true;
public List nozzleInfoList { get; private set; }
public TcpClient? client { get; set; }
public int? serverPort { get; set; }
//private readonly ConcurrentDictionary> _tcsDictionary = new ConcurrentDictionary>();
//private TaskCompletionSource checkDisConnectTask = new TaskCompletionSource();
private byte frame = 0x00;
private object lockFrame = new object();
private IHttpClientUtil httpClientUtil;
//记录油枪状态,key-枪号,value:01:离线 02:锁枪 03:空闲 04:提枪 06:开始加油 08:加油中
private ConcurrentDictionary nozzleStatusDic = new ConcurrentDictionary();
#endregion
#region Logger
private static NLog.Logger logger = NLog.LogManager.LoadConfiguration("nlog.config").GetLogger("HengshanPayTermHandler");
#endregion
#region Constructor
//private static List ResolveCtorMetaPartsConfigCompatibility(string incompatibleCtorParamsJsonStr)
//{
// var jsonParams = JsonDocument.Parse(incompatibleCtorParamsJsonStr).RootElement.EnumerateArray().ToArray();
// //sample: "UITemplateVersion":"1.0"
// string uiTemplateVersionRegex = @"(?<=""UITemplateVersion""\:\"").+?(?="")";
// var match = Regex.Match(jsonParams.First().GetRawText(), uiTemplateVersionRegex, RegexOptions.IgnoreCase | RegexOptions.Multiline);
// if (match.Success)
// {
// var curVersion = match.Value;
// if (curVersion == "1.0")
// {
// var existsAppConfigV1 = JsonSerializer.Deserialize(jsonParams.First().GetRawText(), typeof(HengshanPayTerminalHanlderGroupConfigV1));
// }
// else
// {
// }
// }
// return null;
//}
[ParamsJsonSchemas("TermHandlerGroupCtorParamsJsonSchemas")]
public HengshanPayTermHandler(HengshanPayTerminalHanlderGroupConfigV2 config)
: this(config.PumpIds,
string.Join(";", config.PumpSubAddresses.Select(m => $"{m.PumpId}={m.SubAddress}")),
string.Join(";", config.PumpNozzleLogicIds.Select(m => $"{m.PumpId}={m.LogicIds}")),
string.Join(";", config.PumpSiteNozzleNos.Select(m => $"{m.PumpId}={m.SiteNozzleNos}")),
string.Join(";", config.NozzleLogicIds.Select(m => $"{m.NozzleNo}={m.LogicId}")))
//clientUtil)
{
}
public HengshanPayTermHandler(
string pumpIds,
string pumpSubAddresses,
string pumpNozzles,
string pumpSiteNozzleNos,
string nozzleLogicIds)
//IHttpClientUtil clientUtil)
{
this.pumpIds = pumpIds;
this.pumpSubAddresses = pumpSubAddresses;
this.pumpNozzles = pumpNozzles;
this.pumpSiteNozzleNos = pumpSiteNozzleNos;
this.nozzleLogicIds = nozzleLogicIds;
AssociatedPumpIds = GetPumpIdList(pumpIds);
pumpIdSubAddressDict = InitializePumpSubAddressMapping();
PumpNozzlesDict = ParsePumpNozzlesList(pumpNozzles);
PumpSiteNozzleNoDict = ParsePumpSiteNozzleNoList(pumpSiteNozzleNos);
NozzleLogicIdDict = InitializeNozzleLogicIdMapping(nozzleLogicIds);
InitializePumpHandlers();
}
#endregion
public void OnFdcServerInit(Dictionary parameters)
{
logger.Info("OnFdcServerInit called");
if (parameters.ContainsKey("LastPriceChange"))
{
// nozzle logical id:rawPrice
var lastPriceChanges = parameters["LastPriceChange"] as Dictionary;
foreach (var priceChange in lastPriceChanges)
{
}
}
}
#region Event handler
public event EventHandler OnTerminalMessageReceived;
public event EventHandler OnTotalizerReceived;
public event EventHandler OnFuelPriceChangeRequested;
public event EventHandler OnTerminalFuelPriceDownloadRequested;
public event EventHandler OnCheckCommandReceived;
public event EventHandler OnLockUnlockCompleted;
#endregion
#region Properties
public List AssociatedPumpIds { get; private set; }
public IContext Context
{
get { return _context; }
}
public string PumpIdList => pumpIds;
//public LockUnlockOperation LockUnlockOperationType { get; set; } = LockUnlockOperation.Undefined;
#endregion
#region Methods
public int GetSubAddressForPump(int pumpId)
{
return pumpIdSubAddressDict.First(d => d.Key == pumpId).Value;
}
private List GetPumpIdList(string pumpIds)
{
var pumpIdList = new List();
if (!string.IsNullOrEmpty(pumpIds) && pumpIds.Contains(',')) //multiple pumps per serial port, Hengshan TQC pump
{
var arr = pumpIds.Split(',');
foreach (var item in arr)
{
pumpIdList.Add(int.Parse(item));
}
return pumpIdList;
}
else if (!string.IsNullOrEmpty(pumpIds) && pumpIds.Length == 1 || pumpIds.Length == 2) //only 1 pump per serial port, Hengshan pump
{
return new List { int.Parse(pumpIds) };
}
else
{
throw new ArgumentException("Pump id list not specified!");
}
}
private Dictionary InitializePumpSubAddressMapping()
{
var dict = new Dictionary();
if (!string.IsNullOrEmpty(pumpSubAddresses))
{
var sequence = pumpSubAddresses.Split(';')
.Select(s => s.Split('='))
.Select(a => new { PumpId = int.Parse(a[0]), SubAddress = int.Parse(a[1]) });
foreach (var pair in sequence)
{
if (!dict.ContainsKey(pair.PumpId))
{
dict.Add(pair.PumpId, pair.SubAddress);
}
}
return dict;
}
else
{
throw new ArgumentException("Pump id and sub address mapping does not exist");
}
}
private Dictionary> ParsePumpNozzlesList(string pumpNozzles)
{
Dictionary> pumpNozzlesDict = new Dictionary>();
if (!string.IsNullOrEmpty(pumpNozzles) && pumpNozzles.Contains(';'))
{
var arr = pumpNozzles.Split(';');
foreach (var subMapping in arr)
{
var pair = new KeyValuePair(int.Parse(subMapping.Split('=')[0]), int.Parse(subMapping.Split('=')[1]));
Console.WriteLine($"{pair.Key}, {pair.Value}");
if (!pumpNozzlesDict.ContainsKey(pair.Key))
{
pumpNozzlesDict.Add(pair.Key, new List { pair.Value });
}
else
{
List nozzlesForThisPump;
pumpNozzlesDict.TryGetValue(pair.Key, out nozzlesForThisPump);
if (nozzlesForThisPump != null && !nozzlesForThisPump.Contains(pair.Value))
{
nozzlesForThisPump.Add(pair.Value);
}
}
}
}
else if (!string.IsNullOrEmpty(pumpNozzles) && pumpNozzles.Count(c => c == '=') == 1) // only one pump per serial port
{
try
{
pumpNozzlesDict.Add(
int.Parse(pumpNozzles.Split('=')[0]),
new List { int.Parse(pumpNozzles.Split('=')[1]) });
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
else
{
throw new ArgumentException("Wrong mapping between pump and its associated nozzles!");
}
return pumpNozzlesDict;
}
static Dictionary> ParsePumpSiteNozzleNoList(string pumpSiteNozzleNos)
{
Dictionary> pumpSiteNozzleNoDict = new Dictionary>();
if (!string.IsNullOrEmpty(pumpSiteNozzleNos) && pumpSiteNozzleNos.Contains(';'))
{
var arr = pumpSiteNozzleNos.Split(';');
foreach (var subMapping in arr)
{
var pair = new KeyValuePair>(
int.Parse(subMapping.Split('=')[0]), subMapping.Split('=')[1].Split(',').Select(a => int.Parse(a)).ToList());
Console.WriteLine($"{pair.Key}, {pair.Value}");
if (!pumpSiteNozzleNoDict.ContainsKey(pair.Key))
{
pumpSiteNozzleNoDict.Add(pair.Key, pair.Value);
}
}
}
else if (!string.IsNullOrEmpty(pumpSiteNozzleNos) && pumpSiteNozzleNos.Count(c => c == '=') == 1)
{
try
{
string[] strArr = pumpSiteNozzleNos.Split('=');
pumpSiteNozzleNoDict.Add(
int.Parse(strArr[0]), new List { int.Parse(strArr[1]) });
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
else
{
throw new ArgumentException("Wrong mapping between pump and its associated nozzles!");
}
return pumpSiteNozzleNoDict;
}
private Dictionary InitializeNozzleLogicIdMapping(string nozzleLogicIds)
{
var dict = new Dictionary();
if (!string.IsNullOrEmpty(nozzleLogicIds))
{
var sequence = nozzleLogicIds.Split(';')
.Select(s => s.Split('='))
.Select(a => new { NozzleNo = int.Parse(a[0]), LogicId = int.Parse(a[1]) });
foreach (var pair in sequence)
{
if (!dict.ContainsKey(pair.NozzleNo))
{
Console.WriteLine($"nozzle, logic id: {pair.NozzleNo} - {pair.LogicId}");
dict.Add(pair.NozzleNo, pair.LogicId);
}
}
return dict;
}
else if (!string.IsNullOrEmpty(nozzleLogicIds) && nozzleLogicIds.Count(c => c == '=') == 1)
{
try
{
string[] sequence = nozzleLogicIds.Split('=');
dict.Add(int.Parse(sequence[0]), int.Parse(sequence[1]));
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
return dict;
}
else
{
throw new ArgumentException("Pump id and sub address mapping does not exist");
}
}
private void InitializePumpHandlers()
{
var pumpIdList = GetPumpIdList(pumpIds);
foreach (var item in pumpIdList)
{
var nozzleList = GetNozzleListForPump(item);
var siteNozzleNoList = PumpSiteNozzleNoDict[item];
HengshanPumpHandler pumpHandler = new HengshanPumpHandler(this, $"Pump_{item}", item, nozzleList, siteNozzleNoList);
pumpHandler.OnFuelPriceChangeRequested += PumpHandler_OnFuelPriceChangeRequested;
pumpHandlers.Add(pumpHandler);
}
}
private List GetNozzleListForPump(int pumpId)
{
List nozzles;
PumpNozzlesDict.TryGetValue(pumpId, out nozzles);
return nozzles;
}
private void PumpHandler_OnFuelPriceChangeRequested(object sender, FuelPriceChangeRequestEventArgs e)
{
InfoLog($"Change price, Pump {e.PumpId}, Nozzle {e.NozzleId}, Price {e.Price}");
OnFuelPriceChangeRequested?.Invoke(sender, e);
}
IEnumerator IEnumerable.GetEnumerator()
{
return pumpHandlers.GetEnumerator();
}
#endregion
#region IHandler implementation
public void Init(IContext context)
{
CommIdentity = context.Processor.Communicator.Identity;
_context = context;
//this.MysqlDbContext = new MysqlDbContext();
this.httpClientUtil = new HttpClientUtils();
this.serverPort = CommIdentity.Replace("*:", "").ToInt();
GetInfo();
if(stationInfo.CheckOrderInterval > 0)
{
//开启定时任务,每分钟执行一次,检查xx分钟未取消授权的订单,并发起取消授权。xx可配置
System.Timers.Timer timer = new System.Timers.Timer(60000);
timer.Elapsed += (sender, eventArgs) =>
{
Task.Run(() => SendUnAuthorizationTimerAsync());
};
}
}
public string CommIdentity { get; private set; }
public async Task Process(IContext context)
{
logger.Info($"获取到信息:{JsonConvert.SerializeObject(context.Incoming.Message)}");
switch (context.Incoming.Message.Handle)
{
//心跳,带油枪状态信息
case 0x10:
{
//将油枪状态区分为空闲或非空闲,记录在内存。当状态有发生变化,发送到云端
HeartBeatMessage heartBeatMessage = (HeartBeatMessage)context.Incoming.Message;
SendNozzleStatus(heartBeatMessage);
break;
}
//订单
case 0x18:
{
//添加或修改数据库订单
logger.Info($"订单信息");
OrderFromMachine orderFromMachine = (OrderFromMachine)context.Incoming.Message;
if(nozzlePumpCode.TryGetValue(orderFromMachine.nozzleNum, out string pumpCodeAndTTC))
{
if($"{orderFromMachine.pumpCode}_{orderFromMachine.ttc}".Equals(pumpCodeAndTTC))
{
logger.Info($"收到油机订单,泵码与流水号一致,为重复发送");
return;
}
}
logger.Info($"收到油机订单,泵码与流水号不一致,更新信息");
nozzlePumpCode[orderFromMachine.nozzleNum] = $"{orderFromMachine.pumpCode}_{orderFromMachine.ttc}";
FccOrderInfo fccOrderInfo = UpLoadOrder(orderFromMachine);
logger.Info($"receive order from machine,database had change");
CreateOrRedeemTransaction(fccOrderInfo);
break;
}
/**
//普通应答
case 0x55:
{
CommonAnswerBack commonAnswerBack = (CommonAnswerBack)context.Incoming.Message;
if (commonAnswerBack.Command == 0x63) //二维码回复
{
byte[] keyBytes = { commonAnswerBack.Command, (byte)commonAnswerBack.NozzleNum };
var key = BitConverter.ToString(keyBytes).Replace("-", "");
if (_tcsDictionary.TryGetValue(key, out var value))
{
value.SetResult(commonAnswerBack);
}
else
{
logger.Info($"qrcode response:can not get tcs for dictionary");
}
}
break;
}
// 授权回复
case 0x65:
{
AuthorizationResponse authorizationResponse = (AuthorizationResponse)context.Incoming.Message;
byte[] keyBytes = { authorizationResponse.Handle, (byte)authorizationResponse.NozzleNum };
var key = BitConverter.ToString(keyBytes).Replace("-", "");
if (_tcsDictionary.TryGetValue(key, out var value))
{
value.SetResult(authorizationResponse);
}
else
{
logger.Info($"authorization response:can not get tcs for dictionary");
}
break;
}
// 取消授权回复
case 0x66:
{
UnAhorizationResponse unauthorizationResponse = (UnAhorizationResponse)context.Incoming.Message;
byte[] keyBytes = { unauthorizationResponse.Handle, (byte)unauthorizationResponse.NozzleNum };
var key = BitConverter.ToString(keyBytes).Replace("-", "");
if (_tcsDictionary.TryGetValue(key, out var value))
{
value.SetResult(unauthorizationResponse);
}
else
{
logger.Info($"unauthorization response:can not get tcs for dictionary");
}
break;
}
*/
}
//油机的应答不用回复
if (context.Incoming.Message.Handle != 0x55 && isSendHeart) context.Outgoing.Write(context.Incoming.Message);
}
private void CheckStatus(CheckCmdRequest request)
{
if (!statusDict.ContainsKey(request.FuelingPoint.PumpNo))
{
var result = statusDict.TryAdd(request.FuelingPoint.PumpNo,
new PumpStateHolder
{
PumpNo = request.FuelingPoint.PumpNo,
NozzleNo = 1,
State = request,
OperationType = LockUnlockOperation.None
});
logger.Info($"Adding FuelingPoint {request.FuelingPoint.PumpNo} to dict");
if (!result)
{
statusDict.TryAdd(request.FuelingPoint.PumpNo, null);
}
}
else
{
PumpStateHolder stateHolder = null;
statusDict.TryGetValue(request.FuelingPoint.PumpNo, out stateHolder);
if (stateHolder != null)
{
logger.Debug($"State holder, PumpNo: {stateHolder.PumpNo}, dispenser state: {stateHolder.State.DispenserState}, " +
$"operation: {stateHolder.OperationType}");
}
if (stateHolder != null && stateHolder.OperationType != LockUnlockOperation.None)
{
logger.Debug($"PumpNo: {request.FuelingPoint.PumpNo}, Last Dispenser State: {stateHolder.State.DispenserState}, " +
$"Current Dispenser State: {request.DispenserState}");
if (stateHolder.State.DispenserState == 3 && request.DispenserState == 2)
{
//Pump is locked due to lock operation
if (stateHolder.OperationType != LockUnlockOperation.None)
{
logger.Info("Locking done!");
stateHolder.State = request; //Update the state
OnLockUnlockCompleted?.Invoke(this, new LockUnlockEventArgs(stateHolder.OperationType, true));
}
}
else if (stateHolder.State.DispenserState == 2 && request.DispenserState == 3)
{
//Pump is unlocked due to unlock operation
if (stateHolder.OperationType != LockUnlockOperation.None)
{
logger.Info($"Unlocking done!");
stateHolder.State = request; //Update the state
OnLockUnlockCompleted?.Invoke(this, new LockUnlockEventArgs(stateHolder.OperationType, true));
}
}
}
else if (stateHolder != null && stateHolder.OperationType == LockUnlockOperation.None)
{
if (stateHolder.State.DispenserState != request.DispenserState)
{
logger.Warn($"Observed a pump state change, {stateHolder.State.DispenserState} -> {request.DispenserState}");
stateHolder.State = request; //Update the state.
}
}
}
}
public void Write(CommonMessage cardMessage)
{
_context.Outgoing.Write(cardMessage);
}
public async Task WriteAsync(CommonMessage request, Func responseCapture,
int timeout)
{
var resp = await _context.Outgoing.WriteAsync(request, responseCapture, timeout);
return resp;
}
#endregion
#region IEnumerable implementation
public IEnumerator GetEnumerator()
{
return pumpHandlers.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return pumpHandlers.GetEnumerator();
}
#endregion
public void PendMessage(CardMessageBase message)
{
lock (syncObj)
{
queue.Enqueue(message);
}
}
public bool TrySendNextMessage()
{
lock (syncObj)
{
if (queue.Count > 0)
{
DebugLog($"queue count: {queue.Count}");
var message = commonQueue.Dequeue();
Write(message);
return true;
}
}
return false;
}
public void StoreLatestFrameSqNo(int pumpId, byte frameSqNo)
{
var pump = GetPump(pumpId);
if (pump != null)
{
pump.FrameSqNo = frameSqNo;
}
}
public void UpdatePumpState(int pumpId, int logicId, LogicalDeviceState state)
{
var currentPump = GetPump(pumpId);
currentPump?.FirePumpStateChange(state, Convert.ToByte(logicId));
}
public void UpdateFuelingStatus(int pumpId, FdcTransaction fuelingTransaction)
{
var currentPump = GetPump(pumpId);
currentPump?.FireFuelingStatusChange(fuelingTransaction);
}
private HengshanPumpHandler GetPump(int pumpId)
{
return pumpHandlers.FirstOrDefault(p => p.PumpId == pumpId);
}
public void SetRealPrice(int pumpId, int price)
{
var currentPump = GetPump(pumpId);
var nozzle = currentPump?.Nozzles.FirstOrDefault();
if (nozzle != null)
nozzle.RealPriceOnPhysicalPump = price;
}
#region Log methods
private void InfoLog(string info)
{
logger.Info("PayTermHdlr " + info);
}
private void DebugLog(string debugMsg)
{
logger.Debug("PayTermHdlr " + debugMsg);
}
#endregion
#region 二维码加油机相关方法
///
/// 获取站点信息
///
private async void GetInfo()
{
MysqlDbContext mysqlDbContext = new MysqlDbContext();
Edge.Core.Domain.FccStationInfo.FccStationInfo? fccStationInfo = mysqlDbContext.FccStationInfos.FirstOrDefault();
if(fccStationInfo != null)
{
stationInfo = new StationInfo(fccStationInfo);
buildID = stationInfo.BuildId;
string paymentType = stationInfo.PaymentType;
string[] paymentGround = paymentType.Split(",");
foreach (var item in paymentGround)
{
string[] payment = item.Split("+");
if (payment.Length == 2)
{
if (long.TryParse(payment[0], out long id))
{
stationPayment.Add(id, payment[1]);
}
}
}
}
Edge.Core.Domain.FccMachineInfo.FccMachineInfo? fccMachineInfo = await mysqlDbContext.FccMachineInfos.FirstOrDefaultAsync(machine => machine.Port == serverPort);
if(fccMachineInfo == null)
{
nozzleInfoList = new List();
} else
{
nozzleInfoList = mysqlDbContext.NozzleInfos.Where(nozzle => nozzle.MachineId == fccMachineInfo.Id).Select(n => new DetailsNozzleInfoOutput(n)).ToList();
}
}
///
/// 接收到MQTT
///
///
public async void OnReceiveMqttMessage(string topic,string message)
{
logger.Info($"getMqtt topic:{topic},and message is {message}");
MqttRequest? mqttRequest = JsonConvert.DeserializeObject(message);
if (mqttRequest == null)
{
logger.Error($"mqtt message turn on object fail,message:{message}");
return;
}
if ($"authorization/{buildID}".Equals(topic))
{
MqttAuthorizationRequest? mqttAuthorizationRequest = JsonConvert.DeserializeObject(mqttRequest.data);
await SendAuthorizationAsync(mqttAuthorizationRequest, mqttRequest.UserName, mqttRequest.UserPhoneNumber);
}
if($"unAuthorization/{buildID}".Equals(topic))
{
MqttUnAhorizationRequest? mqttUnAhorizationRequest = JsonConvert.DeserializeObject(mqttRequest.data);
await SendUnAuthorizartion(mqttUnAhorizationRequest);
}
if ($"paid/{buildID}".Equals (topic))
{
MqttPaidRequest? mqttPaidRequest = JsonConvert.DeserializeObject(mqttRequest.data);
await SendActuallyPaid(mqttPaidRequest, mqttRequest.UserName, mqttRequest.UserPhoneNumber);
}
if ($"refund/{buildID}".Equals(topic))
{
MqttRefundRequest? mqttRefundRequest = JsonConvert.DeserializeObject(mqttRequest.data);
await OnRecieveOrderRefund(mqttRefundRequest);
}
//switch (mqttRequest.type)
//{
// case MQTT_TYPE.AUTHORIZATION:
// {
// MqttAuthorizationRequest? mqttAuthorizationRequest = JsonConvert.DeserializeObject(mqttRequest.data);
// await SendAuthorizationAsync(mqttAuthorizationRequest);
// break;
// }
// case MQTT_TYPE.UNAUTHORIZATION:
// {
// MqttUnAhorizationRequest? mqttUnAhorizationRequest = JsonConvert.DeserializeObject(mqttRequest.data);
// await SendUnAuthorizartion(mqttUnAhorizationRequest);
// break;
// }
// case MQTT_TYPE.PAID:
// {
// MqttPaidRequest? mqttPaidRequest = JsonConvert.DeserializeObject(mqttRequest.data);
// await SendActuallyPaid(mqttPaidRequest, mqttRequest.UserName, mqttRequest.UserPhoneNumber);
// break;
// }
// case MQTT_TYPE.REFUND:
// {
// MqttRefundRequest? mqttRefundRequest = JsonConvert.DeserializeObject(mqttRequest.data);
// await OnRecieveOrderRefund(mqttRefundRequest);
// break;
// }
//}
}
///
/// 发送二维码信息给油机
///
///
public async void SendQRCodeAsync()
{
string smallProgram = stationInfo?.SmallProgram ?? "";
if (string.IsNullOrEmpty(smallProgram))
{
logger.Info($"can not get smallProgram link");
return;
}
foreach (var item in nozzleInfoList)
{
//List list = new List();
//byte[] commandAndNozzle = { 0x63, (byte)item.NozzleNum };
//string qrCode = smallProgram + "/" + item.NozzleNum;
//byte[] qrCodeBytes = Encoding.ASCII.GetBytes(qrCode);
//list.AddRange(commandAndNozzle);
//list.Add((byte)qrCodeBytes.Length);
//list.AddRange(qrCodeBytes);
//byte[] sendBytes = content2data(list.ToArray(), null);
SendQrCode sendQrCode = new SendQrCode((int)item.CloundNozzleId,item.NozzleNum, smallProgram, getFrame(null));
byte[] commandAndNozzle = { sendQrCode.Handle, (byte)sendQrCode.NozzleNum };
Thread.Sleep(5000);
CommonMessage commonMessage = await SendMessageToMaichine($"发送{sendQrCode.NozzleNum}号枪二维码",(request,response) =>
{
if(response.Handle == (byte)CommonMessage.Command.COMMON)
{
CommonAnswerBack commonAnswerBack = (CommonAnswerBack)response;
return commonAnswerBack.Command == (byte)CommonMessage.Command.SEND_QR_CODE && commonAnswerBack.NozzleNum == sendQrCode.NozzleNum;
}
return false;
}, sendQrCode);
//CommonMessage commonMessage = await SendMessageToMaichine("发送二维码", BitConverter.ToString(commandAndNozzle).Replace("-", ""), sendQrCode);
//CommonMessage commonMessage = await SendRequestToMachine("发送二维码", BitConverter.ToString(commandAndNozzle).Replace("-", ""), sendBytes);
if (commonMessage.IsError && commonMessage.TheErrorType == CommonMessage.ErrorType.DISCONNECT) break;
}
//var testAuthorization = new MqttAuthorizationRequest()
//{
// NozzleNum = 1,
// AuthorizationTime = DateTime.Now,
// AuthorizationType = 1,
// Value = 3.00m
//};
//await SendAuthorization(testAuthorization);
//var testUnAuthorization = new MqttUnAhorizationRequest()
//{
// NozzleNum = 1,
// AuthorizationTime = DateTime.Now,
// Ttc = 111
//};
//await SendUnAuthorizartion(testUnAuthorization);
}
///
/// 发送实付金额给油机
///
///
public async Task SendActuallyPaid(MqttPaidRequest? request,string? userName,string? phoneNumber)
{
MysqlDbContext mysqlDbContext = new MysqlDbContext();
if (request == null)
{
logger.Error($"mqtt get paid request is null");
return;
}
//通知云端当前已收到消息
OnGetPaidInfo onGetPaidInfo = new OnGetPaidInfo()
{
Id = request.Id,
Result = 1
};
HttpResponseMessage httpResponseMessage = await httpClientUtil.SendRecievePaidNotice(JsonConvert.SerializeObject(onGetPaidInfo));
logger.Info($"send actuallyPaid result response:{JsonConvert.SerializeObject(httpResponseMessage.Content.ReadAsStringAsync())}");
FccOrderInfo? fccOrderInfo = mysqlDbContext.FccOrderInfos.FirstOrDefault(order => order.CloundOrderId == request.Id);
if (fccOrderInfo == null)
{
//未找到证明为预支付,这里插入订单
logger.Info($"[mqtt paid order notice]:can not find order by clounid:{request.Id},is perpay");
string paymentName = "未知类型";
if (request.PaymentMethod != null)
{
paymentName = stationPayment[request.PaymentMethod ?? 0] ?? "未知类型";
}
fccOrderInfo = request.ToComponent(userName,phoneNumber, paymentName);
mysqlDbContext.Add(fccOrderInfo);
} else
{
logger.Info($"[mqtt paid order notice]:find order,update order right now");
//后支付,这里更新支付信息
fccOrderInfo.AmountPayable = request.ActualPaymentAmount;
fccOrderInfo.VolumePayable = request.OriginalQty;
fccOrderInfo.PaymentTime = request.TransactionTime;
if (request.PaymentMethod != null)
{
fccOrderInfo.PayType = (int)request.PaymentMethod;
fccOrderInfo.PaymentName = stationPayment[request.PaymentMethod ?? 0] ?? "未知类型";
}
fccOrderInfo.UserName = userName ?? "";
fccOrderInfo.PhoneNumber = phoneNumber ?? string.Empty;
fccOrderInfo.PaymentStatus = 1;
}
mysqlDbContext.SaveChanges();
SendActuallyPaid sendActuallyPaid = new SendActuallyPaid(fccOrderInfo.NozzleNum, fccOrderInfo.Ttc, fccOrderInfo.AmountPayable ?? fccOrderInfo.Amount, getFrame(null));
byte[] commandAndNozzle = { sendActuallyPaid.Handle, (byte)sendActuallyPaid.NozzleNum };
await SendMessageToMaichine("发送实付金额", (request, response) =>
{
if (response.Handle == (byte)CommonMessage.Command.SEND_NEED_AMOUNT)
{
CommonAnswerBack commonAnswerBack = (CommonAnswerBack)response;
return commonAnswerBack.Command == (byte)CommonMessage.Command.SEND_NEED_AMOUNT && commonAnswerBack.NozzleNum == sendActuallyPaid.NozzleNum;
}
return false;
}, sendActuallyPaid);
}
///
/// 发送授权请求给油机
///
///
///
public async Task SendAuthorizationAsync(MqttAuthorizationRequest? request, string? userName, string? phoneNumber)
{
MysqlDbContext mysqlDbContext = new MysqlDbContext();
if(request == null)
{
logger.Error($"mqtt authorization request is null");
return;
}
//添加订单到数据库
DateTime authorizationTime = request.AuthorizationTime ?? DateTime.Now;
FccOrderInfo? fccOrderInfo = await mysqlDbContext.FccOrderInfos.FirstOrDefaultAsync(order => order.CloundOrderId == request.Id);
if(fccOrderInfo == null)
{
logger.Error($"authorization find order by clound id:{request.Id} is null");
return;
}
fccOrderInfo.AuthorizationTime = authorizationTime;
//发送授权申请到油机
SendAuthorization sendAuthorization = new SendAuthorization((int)request.NozzleId, authorizationTime, 1, request.OriginalAmount, getFrame(null));
byte[] commandAndNozzle = { sendAuthorization.Handle, (byte)sendAuthorization.NozzleNum };
CommonMessage commonMessage = await SendMessageToMaichine("发送授权请求", (request, response) =>
{
if (response.Handle == (byte)CommonMessage.Command.ACCREDIT)
{
AuthorizationResponse authorization = (AuthorizationResponse)response;
return authorization.NozzleNum == sendAuthorization.NozzleNum;
}
return false;
}, sendAuthorization);
logger.Info($"获取到授权结果:{JsonConvert.SerializeObject(commonMessage)}");
//发送授权结果给云端
string authorizationResultJson = string.Empty;
SendAuthorizationResult sendAuthorizationResult = new SendAuthorizationResult();
sendAuthorizationResult.NozzleId = request.NozzleId;
if (commonMessage.IsError)
{
ErrorMessage errorMessage = (ErrorMessage)commonMessage;
switch (errorMessage.TheErrorType)
{
case CommonMessage.ErrorType.DISCONNECT:
sendAuthorizationResult.OilMachineStatus = OilMachineStatus.Disconnected;
break;
case CommonMessage.ErrorType.TIMEOUT:
sendAuthorizationResult.OilMachineStatus = OilMachineStatus.AuthorizationTimeout;
break;
}
}
else
{
AuthorizationResponse authorization = (AuthorizationResponse)commonMessage;
if (authorization.Result == 0)
{
sendAuthorizationResult.OilMachineStatus = OilMachineStatus.Failed;
}
else
{
sendAuthorizationResult.OilMachineStatus = OilMachineStatus.Success;
sendAuthorizationResult.TransactionNumber = authorization.Ttc.ToString();
fccOrderInfo.Ttc = authorization.Ttc;
fccOrderInfo.AuthorizationStatus = 1;
}
}
//SendAuthorizationResult sendAuthorizationResult = new SendAuthorizationResult()
//{
// NozzleId = request.NozzleId,
// TransactionNumber = "1",
// OilMachineStatus = OilMachineStatus.Success
//};
logger.Info($"发送授权结果:{JsonConvert.SerializeObject(sendAuthorizationResult)}");
HttpResponseMessage httpResponseMessage = await httpClientUtil.SendAuthorizationResult(JsonConvert.SerializeObject(sendAuthorizationResult));
logger.Info($"send authorization result response:{JsonConvert.SerializeObject(httpResponseMessage.Content.ReadAsStringAsync())}");
//更新订单
mysqlDbContext.SaveChanges();
}
///
/// 发送取消授权请求给油机
///
///
public async Task SendUnAuthorizartion(MqttUnAhorizationRequest? request)
{
MysqlDbContext mysqlDbContext = new MysqlDbContext();
if (request == null)
{
logger.Error($"mqtt unauthorization request is null");
return;
}
//先从数据库查找,查看是否已取消授权
int ttc = 0;
DateTime authorizationTime = request.AuthorizationTime ?? DateTime.Now;
FccOrderInfo? fccOrderInfo = mysqlDbContext.FccOrderInfos.FirstOrDefault(order => order.CloundOrderId == request.Id);
bool isUnauthorization = false;
if (fccOrderInfo != null)
{
ttc = fccOrderInfo.Ttc;
authorizationTime = fccOrderInfo.AuthorizationTime;
isUnauthorization = fccOrderInfo.AuthorizationStatus == 0;
}
SendUnAuthorizationResult sendUnAuthorizationResult = new SendUnAuthorizationResult();
sendUnAuthorizationResult.NozzleId = request.NozzleId;
sendUnAuthorizationResult.OilMachineStatus = OilMachineStatus.Success;
if (ttc != 0 && !isUnauthorization)
{
SendUnAuthorization sendUnAuthorization = new SendUnAuthorization((int)request.NozzleId, authorizationTime, ttc, getFrame(null));
byte[] commandAndNozzle = { sendUnAuthorization.Handle, (byte)sendUnAuthorization.NozzleNum };
//发送取消授权命令并获取响应
CommonMessage commonMessage = await SendMessageToMaichine("发送取消授权请求", (request, response) =>
{
if (response.Handle == (byte)CommonMessage.Command.CANCEL_ACCREDIT)
{
UnAhorizationResponse unauthorization = (UnAhorizationResponse)response;
return unauthorization.NozzleNum == sendUnAuthorization.NozzleNum;
}
return false;
}, sendUnAuthorization);
if (commonMessage.IsError)
{
//响应错误
ErrorMessage errorMessage = (ErrorMessage)commonMessage;
switch (errorMessage.TheErrorType)
{
case CommonMessage.ErrorType.DISCONNECT:
sendUnAuthorizationResult.OilMachineStatus = OilMachineStatus.Disconnected;
break;
case CommonMessage.ErrorType.TIMEOUT:
sendUnAuthorizationResult.OilMachineStatus = OilMachineStatus.AuthorizationTimeout;
break;
}
}
else
{
//正常响应
UnAhorizationResponse unAuthorization = (UnAhorizationResponse)commonMessage;
if (unAuthorization.Result == 0)
{
sendUnAuthorizationResult.OilMachineStatus = OilMachineStatus.Failed;
}
else
{
sendUnAuthorizationResult.OilMachineStatus = OilMachineStatus.Success;
fccOrderInfo.AuthorizationStatus = 0;
}
}
}
else if (!isUnauthorization)
{
//若已经未授权
sendUnAuthorizationResult.OilMachineStatus = OilMachineStatus.Success;
}
else
{ //未找到流水号
sendUnAuthorizationResult.OilMachineStatus = OilMachineStatus.TransactionNumberNotFound;
}
HttpResponseMessage httpResponseMessage = await httpClientUtil.SendUnAuthorizationResult(JsonConvert.SerializeObject(sendUnAuthorizationResult));
logger.Info($"send Unauthorization result response:{JsonConvert.SerializeObject(httpResponseMessage.Content.ReadAsStringAsync())}");
}
///
/// 接收到云端发送订单退款信息
///
///
///
private async Task OnRecieveOrderRefund(MqttRefundRequest? request)
{
MysqlDbContext mysqlDbContext = new MysqlDbContext();
if (request == null)
{
logger.Error($"mqtt OnRecieveOrderRefund request is null");
return;
}
//通知云端当前已收到消息
OnGetRefundInfo onGetRefundInfo = new OnGetRefundInfo()
{
Id = request.Id,
Result = 1
};
HttpResponseMessage httpResponseMessage = await httpClientUtil.SendRecieveRefundNotice(JsonConvert.SerializeObject(onGetRefundInfo));
logger.Info($"send refund result response:{JsonConvert.SerializeObject(httpResponseMessage.Content.ReadAsStringAsync())}");
//通知油机已退款
SendRefund sendRefund = new SendRefund((int)request.NozzleId, request.TransactionNumber, request.OriginalAmount, request.ActualPaymentAmount ?? 0m, request.RefundAmount ?? 0m, getFrame(null));
byte[] commandAndNozzle = { sendRefund.Handle, (byte)sendRefund.NozzleNum };
await SendMessageToMaichine("发送退款信息", (request, response) =>
{
if (response.Handle == (byte)CommonMessage.Command.SEND_NEED_AMOUNT)
{
CommonAnswerBack commonAnswerBack = (CommonAnswerBack)response;
return commonAnswerBack.Command == (byte)CommonMessage.Command.SEND_NEED_AMOUNT && commonAnswerBack.NozzleNum == sendRefund.NozzleNum;
}
return false;
}, sendRefund);
FccOrderInfo? fccOrderInfo = mysqlDbContext.FccOrderInfos.FirstOrDefault(order => order.CloundOrderId == request.Id);
if (fccOrderInfo == null)
{
logger.Error($"[mqtt refund order notice]:can not find order by clounid:{request.Id}");
return;
}
fccOrderInfo.AmountPayable = request.ActualPaymentAmount;
fccOrderInfo.RefundAmount = request.RefundAmount;
fccOrderInfo.PaymentStatus = (int)request.OrderStatus;
fccOrderInfo.RefundStatus = (int)request.RefundStatus;
mysqlDbContext.SaveChanges();
}
//public void SetTcpClient(TcpClient? tcpClient, int? serverPort)
//{
// this.client = tcpClient;
// this.serverPort = serverPort;
// checkDisConnectTask = new TaskCompletionSource();
//}
//public void OnTcpDisconnect()
//{
// this.client = null;
// ErrorMessage errorMessage = new ErrorMessage()
// {
// IsError = true,
// TheErrorType = CommonMessage.ErrorType.DISCONNECT,
// ErrorMessage = $"the client is disconnet"
// };
// checkDisConnectTask.SetResult(errorMessage);
//}
///
/// 发送消息到油机,3秒的超时,重试三次
///
/// 发送的消息类型,用于日志记录
/// 发送的消息key,用于存储 TaskCompletionSource
/// 实际发送消息
///
private async Task SendMessageToMaichine(string sendTag, Func responseCapture,CommonMessage sendMessage)
{
logger.Info($"send request to machine:{sendTag}");
isSendHeart = false;
int retryCount = 0;
while (retryCount < 3)
{
try
{
var response = await this.Context.Outgoing.WriteAsyncAndCheckIsConnect(sendMessage, responseCapture, 3000);
//超时重试
if (response.ResponseType == WriteResponseType.TIME_OUT || response.Data == null)
{
retryCount++;
logger.Info($"{sendTag}: time out,retrying... ({retryCount} / 3)");
continue;
}
//链接断开不再发送
if (response.ResponseType == WriteResponseType.DISCONNECT)
{
var isConnect = (bool)(response.Data ?? false);
if (!isConnect) return new ErrorMessage()
{
IsError = true,
TheErrorType = CommonMessage.ErrorType.DISCONNECT,
ErrorMessage = $"the client is disconnet"
};
}
Console.WriteLine("");
isSendHeart = true;
//返回信息
return (CommonMessage)response.Data;
}
catch (Exception)
{
retryCount++;
logger.Info($"{sendTag}: error,retrying... ({retryCount} / 3)");
}
finally
{
if (retryCount >= 3)
{
logger.Info($"{sendTag}: is time out add retry 3 time");
isSendHeart = true;
}
}
}
isSendHeart = true;
return new ErrorMessage()
{
IsError = true,
TheErrorType = CommonMessage.ErrorType.TIMEOUT,
ErrorMessage = $"{sendTag}: can not receive response after 3 retries"
};
}
///
/// 取消授权
///
///
private async Task SendUnAuthorizationTimerAsync()
{
MysqlDbContext mysqlDbContext = new MysqlDbContext();
DateTime timeOut = DateTime.Now.AddMonths(stationInfo.CheckOrderInterval);
FccOrderInfo? fccOrderInfo = await mysqlDbContext.FccOrderInfos.FirstOrDefaultAsync(order => order.AuthorizationStatus == 1 && order.AuthorizationTime < timeOut);
if (fccOrderInfo == null)
{
logger.Info($"当前没有待取消授权的订单");
return;
}
SendUnAuthorizationResult sendUnAuthorizationResult = new SendUnAuthorizationResult();
sendUnAuthorizationResult.NozzleId = fccOrderInfo.NozzleNum;
sendUnAuthorizationResult.OilMachineStatus = OilMachineStatus.Success;
SendUnAuthorization sendUnAuthorization = new SendUnAuthorization(fccOrderInfo.NozzleNum, fccOrderInfo.AuthorizationTime, fccOrderInfo.Ttc, getFrame(null));
byte[] commandAndNozzle = { sendUnAuthorization.Handle, (byte)sendUnAuthorization.NozzleNum };
//发送取消授权命令并获取响应
CommonMessage commonMessage = await SendMessageToMaichine("定时发送取消授权请求", (request, response) =>
{
if (response.Handle == (byte)CommonMessage.Command.CANCEL_ACCREDIT)
{
UnAhorizationResponse unauthorization = (UnAhorizationResponse)response;
return unauthorization.NozzleNum == sendUnAuthorization.NozzleNum;
}
return false;
}, sendUnAuthorization);
if (commonMessage.IsError)
{
//响应错误
ErrorMessage errorMessage = (ErrorMessage)commonMessage;
switch (errorMessage.TheErrorType)
{
case CommonMessage.ErrorType.DISCONNECT:
sendUnAuthorizationResult.OilMachineStatus = OilMachineStatus.Disconnected;
break;
case CommonMessage.ErrorType.TIMEOUT:
sendUnAuthorizationResult.OilMachineStatus = OilMachineStatus.AuthorizationTimeout;
break;
}
}
else
{
//正常响应
UnAhorizationResponse unAuthorization = (UnAhorizationResponse)commonMessage;
if (unAuthorization.Result == 0)
{
sendUnAuthorizationResult.OilMachineStatus = OilMachineStatus.Failed;
}
else
{
sendUnAuthorizationResult.OilMachineStatus = OilMachineStatus.Success;
fccOrderInfo.AuthorizationStatus = 0;
}
}
mysqlDbContext.SaveChanges();
HttpResponseMessage httpResponseMessage = await httpClientUtil.SendUnAuthorizationResult(JsonConvert.SerializeObject(sendUnAuthorizationResult));
logger.Info($"定时任务取消授权:send Unauthorization timer result response:{JsonConvert.SerializeObject(httpResponseMessage.Content.ReadAsStringAsync())}");
}
///
/// 添加或修改订单
///
/// 接收到油机的订单信息
///
public FccOrderInfo UpLoadOrder(OrderFromMachine order)
{
MysqlDbContext mysqlDbContext = new MysqlDbContext();
//接收到油机发送过来的订单信息
OrderFromMachine orderFromMachine = (OrderFromMachine)order;
string? oilName = mysqlDbContext.OilInfos.Where(oil => orderFromMachine.oilCode.Equals(oil.Code)).Select(oil => oil.Name).FirstOrDefault();
FccOrderInfo orderByMessage = orderFromMachine.ToComponent(oilName);
/** 根据枪号+流水号+授权时间来确定订单,因为冷启动后流水号会从头开始计算
* 后支付时直接将数据库直接插入
* 预支付时由于是云端先创建订单,发起授权响应成功后会插入数据库,响应成功时会回复授权时间,枪号,流水号
*/
FccOrderInfo? fccOrderInfo = mysqlDbContext.FccOrderInfos
.Where(order =>
order.NozzleNum == orderFromMachine.nozzleNum && order.Ttc == orderFromMachine.ttc
&& order.AuthorizationTime == orderFromMachine.dispenserTime)
.FirstOrDefault();
if (fccOrderInfo == null)
{
logger.Info($"receive order from machine,find order from database is null");
mysqlDbContext.FccOrderInfos.Add(orderByMessage);
mysqlDbContext.SaveChanges();
return orderByMessage;
}
else
{
logger.Info($"receive order from machine,padding data right now");
orderFromMachine.PaddingAuthorizationOrderData(fccOrderInfo);
mysqlDbContext.SaveChanges();
return fccOrderInfo;
}
}
private async void CreateOrRedeemTransaction(FccOrderInfo fccOrderInfo)
{
MysqlDbContext mysqlDbContext = new MysqlDbContext();
if (fccOrderInfo.CloundOrderId == null)
{
CreateTransaction createTransaction = new CreateTransaction(fccOrderInfo);
logger.Info($"create transaction, {JsonConvert.SerializeObject(createTransaction)}");
HttpResponseMessage httpResponseMessage = await httpClientUtil.CreateTransaction(JsonConvert.SerializeObject(createTransaction));
string responseStr = await httpResponseMessage.Content.ReadAsStringAsync();
Response? response = JsonConvert.DeserializeObject>(responseStr);
logger.Info($"reveice create transaction response:{JsonConvert.SerializeObject(response)}");
fccOrderInfo.CloundOrderId = response?.data?.Id;
fccOrderInfo.UploadState = response?.data == null ? 0 : 1;
mysqlDbContext.SaveChanges();
} else
{
//MysqlDbContext mysqlDbContext = new MysqlDbContext();
if(fccOrderInfo.Amount == 0 && fccOrderInfo.Volume == 0)
{
//0交易订单,证明为取消授权后产生的订单,不走核销,而是在小程序上显示为授权失败,让其重新发起授权或退款
logger.Info("0交易,取消授权");
fccOrderInfo.AuthorizationStatus = 0; //存在油机手动取消授权的情况,因此这里也要更新授权状态
mysqlDbContext.SaveChanges();
SendUnAuthorizationResult sendUnAuthorizationResult = new SendUnAuthorizationResult();
sendUnAuthorizationResult.NozzleId = fccOrderInfo.NozzleNum;
sendUnAuthorizationResult.TransactionNumber = fccOrderInfo.Ttc.ToString();
sendUnAuthorizationResult.OilMachineStatus = OilMachineStatus.Success;
HttpResponseMessage httpResponseMessage = await httpClientUtil.SendUnAuthorizationResult(JsonConvert.SerializeObject(sendUnAuthorizationResult));
logger.Info($"手动取消授权:send Unauthorization result response:{JsonConvert.SerializeObject(httpResponseMessage.Content.ReadAsStringAsync())}");
}
else
{
//核销
Redeem redeem = new Redeem();
redeem.trxId = (int)fccOrderInfo.CloundOrderId;
redeem.OriginalQty = fccOrderInfo.Volume;
string param = JsonConvert.SerializeObject(redeem);
logger.Info($"Redeem order:{param}");
HttpResponseMessage httpResponseMessage = await httpClientUtil.Redeem(param);
string responseStr = await httpResponseMessage.Content.ReadAsStringAsync();
Response? response = JsonConvert.DeserializeObject>(responseStr);
logger.Info($"Redeem order response:{JsonConvert.SerializeObject(response)}");
//fccOrderInfo.CloundOrderId = response?.data?.Id;
//fccOrderInfo.UploadState = response?.data == null ? 0 : 1;
//mysqlDbContext.SaveChanges();
}
//mysqlDbContext.SaveChanges();
}
}
///
/// 发送油枪状态给云端
///
///
private async void SendNozzleStatus(HeartBeatMessage heartBeatMessage)
{
//提取出状态有变化的油枪,打包成要发送至云端的数据,添加到列表
List sendNozzleStatus = new List();
List fuelingNozzle = new List();
foreach (var nozzleState in heartBeatMessage.NozzleStatus)
{
if (nozzleStatusDic.TryGetValue(nozzleState.NozzleNum, out var value))
{
if (nozzleState.STATU == value) continue;
}
//保存变量
nozzleStatusDic[nozzleState.NozzleNum] = nozzleState.STATU;
if (nozzleState.STATU == 8) fuelingNozzle.Add(nozzleState.NozzleNum);
//查找fcc数据库油枪id
DetailsNozzleInfoOutput? detailsNozzleInfoOutput = nozzleInfoList.Find(nozzle => nozzle.NozzleNum == nozzleState.NozzleNum);
if (detailsNozzleInfoOutput == null)
{
logger.Error($"can not find nozzleInfo from nozzleInfoList:{nozzleState.NozzleNum} ,send nozzle state fail");
continue;
}
SendNozzleStatu sendNozzleStatu = new SendNozzleStatu(detailsNozzleInfoOutput.CloundNozzleId, nozzleState);
sendNozzleStatus.Add(sendNozzleStatu);
}
if (!sendNozzleStatus.IsNullOrEmpty())
{
//发送云端
string reuqestJson = JsonConvert.SerializeObject(sendNozzleStatus);
logger.Info($"send nozzle state to cloud,{reuqestJson}");
try
{
HttpResponseMessage httpResponseMessage = await httpClientUtil.SendNozzleStatu(reuqestJson);
Response? response = JsonConvert.DeserializeObject>(await httpResponseMessage.Content.ReadAsStringAsync());
logger.Info($"reveice send nozzle state response:{JsonConvert.SerializeObject(response)}");
}
catch (Exception ex)
{
logger.Error($"send nozzle stat fail:{ex.Message}");
}
}
//当前油枪为加油态,找到该油枪最近一笔已授权的订单,将其赋为加油中
MysqlDbContext mysqlDbContext = new MysqlDbContext();
foreach(int nozzleNum in fuelingNozzle)
{
FccOrderInfo? fccOrderInfo = await mysqlDbContext.FccOrderInfos
.OrderByDescending(order => order.AuthorizationTime)
.FirstOrDefaultAsync(order => order.NozzleNum == nozzleNum && order.AuthorizationStatus == 1);
if(fccOrderInfo != null)
{
fccOrderInfo.AuthorizationStatus = 3;
}
}
mysqlDbContext.SaveChanges();
}
///
/// 获取发送帧号
///
///
///
private byte getFrame(byte? sendFrame)
{
byte frameNo = 0x00;
if (sendFrame == null)
{
lock (lockFrame)
{
if (frame == 0x3f)
{
frameNo = 0x00;
}
else
{
frameNo = (byte)(frame++);
}
}
}
else
{
frameNo = sendFrame.Value;
}
return frameNo;
}
/////
///// 传入有效数据,拼接为要发送给油机包
/////
/////
/////
//public byte[] content2data(byte[] content, byte? sendFrame)
//{
// List list = new List();
// //目标地址,源地址,帧号
// byte frameNo = 0x00;
// if (sendFrame == null)
// {
// lock (lockFrame)
// {
// if (frame == 0x3f)
// {
// frameNo = 0x00;
// }
// else
// {
// frameNo = (byte)(frame++);
// }
// }
// }
// else
// {
// frameNo = sendFrame.Value;
// }
// byte[] head = new byte[] { 0xFF, 0xE0, frameNo };
// byte[] length = Int2BCD(content.Length);
// list.AddRange(head);
// list.AddRange(length);
// list.AddRange(content);
// byte[] crc = HengshanCRC16.ComputeChecksumToBytes(list.ToArray());
// list.AddRange(crc);
// List addFAList = addFA(list);
// addFAList.Insert(0, 0xFA);
// return addFAList.ToArray();
//}
//public int Bcd2Int(byte byte1, byte byte2)
//{
// // 提取第一个字节的高四位和低四位
// int digit1 = (byte1 >> 4) & 0x0F; // 高四位
// int digit2 = byte1 & 0x0F; // 低四位
// // 提取第二个字节的高四位和低四位
// int digit3 = (byte2 >> 4) & 0x0F; // 高四位
// int digit4 = byte2 & 0x0F; // 低四位
// // 组合成一个整数
// int result = digit1 * 1000 + digit2 * 100 + digit3 * 10 + digit4;
// return result;
//}
//public byte[] Int2BCD(int number)
//{
// // 提取千位、百位、十位和个位
// int thousands = number / 1000;
// int hundreds = (number / 100) % 10;
// int tens = (number / 10) % 10;
// int units = number % 10;
// // 将千位和百位组合成一个字节(千位在高四位,百位在低四位)
// byte firstByte = (byte)((thousands * 16) + hundreds); // 乘以16相当于左移4位
// // 将十位和个位组合成一个字节(十位在高四位,个位在低四位)
// byte secondByte = (byte)((tens * 16) + units);
// // 返回结果数组
// return new byte[] { firstByte, secondByte };
//}
//public List addFA(List list)
//{
// List result = new List();
// foreach (byte b in list)
// {
// if (b == 0xFA)
// {
// result.Add(0xFA);
// result.Add(0xFA);
// }
// else
// {
// result.Add(b);
// }
// }
// return result;
//}
/////
///// 将数值转为byte[]
/////
///// 数值
///// 数组长度,不够高位补0
/////
/////
//public static byte[] NumberToByteArrayWithPadding(int value, int length)
//{
// if (length < 0)
// {
// throw new ArgumentException("Length must be non-negative.");
// }
// // 创建一个指定长度的字节数组
// byte[] paddedBytes = new byte[length];
// // 确保是大端序
// for (int i = 0; i < length && i < 4; i++)
// {
// paddedBytes[length - 1 - i] = (byte)(value >> (i * 8));
// }
// return paddedBytes;
//}
//public static byte[] FormatDecimal(decimal value)
//{
// // 四舍五入到两位小数
// decimal roundedValue = Math.Round(value, 2, MidpointRounding.AwayFromZero);
// int valueInt = (int)(roundedValue * 100m);
// return NumberToByteArrayWithPadding(valueInt, 3); ;
//}
/////
///// 将时间转为 BCD
/////
/////
/////
//public static byte[] ConvertDateTimeToByteArray(DateTime dateTime)
//{
// // 创建byte数组
// byte[] result = new byte[7];
// // 年份处理
// int year = dateTime.Year;
// result[0] = (byte)((year / 1000) * 16 + (year / 100) % 10); // 千年和百年
// result[1] = (byte)((year / 10) % 10 * 16 + year % 10); // 十年和个年
// // 月、日、小时、分钟、秒直接转换为BCD
// result[2] = (byte)(dateTime.Month / 10 * 16 + dateTime.Month % 10);
// result[3] = (byte)(dateTime.Day / 10 * 16 + dateTime.Day % 10);
// result[4] = (byte)(dateTime.Hour / 10 * 16 + dateTime.Hour % 10);
// result[5] = (byte)(dateTime.Minute / 10 * 16 + dateTime.Minute % 10);
// result[6] = (byte)(dateTime.Second / 10 * 16 + dateTime.Second % 10);
// return result;
//}
// CRC16 constants
const ushort CRC_ORDER16 = 16;
const ushort CRC_POLYNOM16 = 0x1021;
const ushort CRC_CRCINIT16 = 0xFFFF;
const ushort CRC_CRCXOR16 = 0x0000;
const ushort CRC_MASK = 0xFFFF;
const ushort CRC_HIGHEST_BIT = (ushort)(1 << (CRC_ORDER16 - 1));
const ushort TGT_CRC_DEFAULT_INIT = 0xFFFF;
public static ushort Crc16(byte[] buffer, ushort length)
{
ushort crc_rc = TGT_CRC_DEFAULT_INIT;
for (int i = 0; i < length; i++)
{
byte c = buffer[i];
for (ushort j = 0x80; j != 0; j >>= 1)
{
ushort crc_bit = (ushort)((crc_rc & CRC_HIGHEST_BIT) != 0 ? 1 : 0);
crc_rc <<= 1;
if ((c & j) != 0)
{
crc_bit = (ushort)((crc_bit == 0) ? 1 : 0);
}
if (crc_bit != 0)
{
crc_rc ^= CRC_POLYNOM16;
}
}
}
return (ushort)((crc_rc ^ CRC_CRCXOR16) & CRC_MASK);
}
#endregion
}
public class HengshanPayTerminalHanlderGroupConfigV1
{
public string PumpIds { get; set; }
public List PumpSubAddresses { get; set; }
}
public class HengshanPayTerminalHanlderGroupConfigV2
{
public string PumpIds { get; set; }
public List PumpSubAddresses { get; set; }
public List PumpNozzleLogicIds { get; set; }
public List PumpSiteNozzleNos { get; set; }
public List NozzleLogicIds { get; set; }
}
public class PumpSubAddress
{
public byte PumpId { get; set; }
public byte SubAddress { get; set; }
}
public class PumpNozzleLogicId
{
public byte PumpId { get; set; }
public string LogicIds { get; set; }
}
public class PumpSiteNozzleNo
{
public byte PumpId { get; set; }
public string SiteNozzleNos { get; set; }
}
public class NozzleLogicId
{
public byte NozzleNo { get; set; }
public byte LogicId { get; set; }
}
}