using Applications.FDC;
using Edge.Core.Configuration;
using Edge.Core.Database;
using Edge.Core.Database.Models;
using Edge.Core.Processor;
using Edge.Core.Processor.Dispatcher.Attributes;
using Edge.Core.UniversalApi;
using HengShan_Pump_TQC_IFSF;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using VBaoProxyApp.Cloud;
namespace Apps.PetroChinaIcCardFuelTrxToSmartFuelCloudUploader
{
public class AppConfigV1
{
public string UserName { get; set; } = "3038";
public string Password { get; set; } = "111111";
///
/// Sample: http://url:8698
/// DO NOT end with slash
///
public string ApiGatewayEntryUrlWithoutLastSlash { get; set; } = "http://47.97.120.160:8698";
public string DeviceSN { get; set; } = "66662e74-d51e-42ae-bc89-2d39312c9c30";
}
[MetaPartsDescriptor(
"中油IC卡交易上传器",
"用于将中油IC卡交易上传至SmartFuelCloud,日志标记为DynamicPrivate_PetroChinaIcCardFuelTrxToSmartFuelCloudUploader,它通过直接采集油机端的交易,并过一步判定交易是否由IC卡授权完成,如果是的话,此交易才会被上传至云端."
, new[] { "中油" })]
public class App : IAppProcessor
{
private const string genericDataType = "PendingForUploadTrxData";
private IServiceProvider services;
private Applications.FDC.FdcServerHostApp fdcServerApp;
private AppConfigV1 appConfig;
private ILogger logger = NullLogger.Instance;
public string MetaConfigName { get; set; }
private System.Threading.Timer timelyUploadTimer;
[ParamsJsonSchemas("appCtorParamsJsonSchema")]
public App(AppConfigV1 appConfig, IServiceProvider services)
{
this.appConfig = appConfig;
var loggerFactory = services.GetRequiredService();
this.logger = loggerFactory.CreateLogger("DynamicPrivate_PetroChinaIcCardFuelTrxToSmartFuelCloudUploader");
this.services = services;
CloudHelper.Default.Credential = new CloudCredential()
{
ApiGatewayEntryUrl = appConfig.ApiGatewayEntryUrlWithoutLastSlash,// "http://wc.shaojun.xyz:8698",
UserName = appConfig.UserName,// "507",
Password = appConfig.Password,//"111111",
DeviceSN = appConfig.DeviceSN,//"1234567890sss",
};
}
public void Init(IEnumerable processors)
{
var universalApiHub = this.services.GetRequiredService();
var pumpGroupHandlers = processors.WithHandlerOrApp().SelectHandlerOrAppThenCast();
this.fdcServerApp = processors.WithHandlerOrApp().SelectHandlerOrAppThenCast().First();
foreach (var p in pumpGroupHandlers)
p.OnPetroChinaIcCardAuthorizedFuelTrxDone += async (s, arg) =>
{
NozzleExtraInfo nzlExtraInfo = null;
nzlExtraInfo = this.fdcServerApp.GetNozzleExtraInfos().FirstOrDefault(ni => ni.PumpId == arg.Transaction.Nozzle.PumpId
&& ni.NozzleLogicalId == arg.Transaction.Nozzle.LogicalId);
if (nzlExtraInfo == null)
{
await universalApiHub.FirePersistGenericAlarmIfNotExists(this,
new GenericAlarm()
{
Title = $"油枪信息配置错误",
Category = $"配置",
Detail = $"由PumpHandler中产生的交易(pumpId:{arg.Transaction.Nozzle.PumpId}, logicalNozzleId: {arg.Transaction.Nozzle.LogicalId}, vol: {arg.Transaction.Volumn}) 无法找到与其对应绑定的Fdc nozzle信息,请检查PumpHandler与FdcServerApp中关于加油点和油枪的配置与映射关系",
Severity = GenericAlarmSeverity.Error
},
ga => ga.Detail,
ga => ga.Detail);
return;
}
string itemId = nzlExtraInfo.ProductBarcode.ToString();
GenericData data = new GenericData()
{
CreatedTimeStamp = DateTime.Now,
Owner = this.GetType().FullName,
Type = genericDataType,
State = "Unfinished",
ComplexData = JsonSerializer.Serialize(new
{
itemId,
SiteLevelNozzleId = nzlExtraInfo.SiteLevelNozzleId ?? -1,
Transaction = new
{
arg.Transaction.Amount,
arg.Transaction.Volumn,
arg.Transaction.SequenceNumberGeneratedOnPhysicalPump,
arg.Transaction.Nozzle.PumpId,
arg.Transaction.Nozzle.LogicalId
}
})
};
using (var scope = this.services.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService();
dbContext.GenericDatas.Add(data);
await dbContext.SaveChangesAsync();
}
};
}
[UniversalApi]
public async Task UploadTrxToCloud(string itemId, decimal amount, decimal volume, int pumpSideTrxSeqNo, int pumpId, int fdcNozzleLogicalId, int siteLevelNozzleId)
{
var postItem = await CloudHelper.Default.GetPosItemAsync(itemId);
if (postItem == null) throw new InvalidOperationException($"Could not find PosItem(itemId: {itemId}) from cloud side");
var createdTrxId = await CloudHelper.Default.CreateTransactionAsync(new ClientFuelTrxInfo()
{
PosItemId = postItem.Id,
PumpId = pumpId,
NozzleId = fdcNozzleLogicalId,
SiteNozzleNo = siteLevelNozzleId,
Amount = amount,
Volume = volume,
SeqNo = pumpSideTrxSeqNo,
Barcode = int.Parse(postItem.BarCode),
PayAmount = amount,
Source = Dfs.WayneChina.PosModelMini.PosTrxSource.Outdoor,
UnitPrice = 4
}, "中油TQC油机上的IC卡交易");
var commitResult = await CloudHelper.Default.CommitTransactionAsync(createdTrxId, new Dfs.WayneChina.PosModelMini.PosTrxMop()
{
Mop = new Dfs.WayneChina.PosModelMini.PosMop()
{
PaymentId = (int)PaymentID.PetroChinaIC,
},
Paid = amount
}, null);
return true;
}
public async Task Start()
{
//var extraInfos = this.fdcServerApp.GetNozzleExtraInfos();
//var fuelItemBarcodes = extraInfos.GroupBy(i => i.ProductBarcode).Select(g => g.Key);
//foreach (var barcode in fuelItemBarcodes)
//{
// try
// {
// var cloudFuelItem = await CloudHelper.Default.GetPosItemAsync(barcode.ToString());
// if (cloudFuelItem == null)
// throw new InvalidOperationException($"Local fuel item with barcode: {barcode} could not find mapping item in cloud side.");
// }
// catch (Exception exxx)
// {
// this.logger.LogError($"Failed to retrieve Cloud side fuel item based on local barcode: {barcode}, make sure local fuel items are all" +
// $" correctly set and mapped(by their item id) in cloud side. error detail: {exxx}");
// throw;
// }
//}
var universalApiHub = this.services.GetRequiredService();
var genericDataOwner = this.GetType().FullName;
this.timelyUploadTimer = new System.Threading.Timer(async (_) =>
{
this.timelyUploadTimer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
try
{
#region handle server side open trx
//var serverSideOpenTrx = await CloudHelper.Default.GeLastTrxWithOpenStatusByUserNameAsync();
//if (serverSideOpenTrx != null && (serverSideOpenTrx.Items == null || !serverSideOpenTrx.Items.Any()))
//{
// /*this is a complex case that items didn't get ringup yet though trx had been created, so need restore items from local db, and ringup again, and then commit*/
// logger.LogInformation($"Queried trx data(id: {serverSideOpenTrx.Id}, grossAmount: {serverSideOpenTrx.GrossAmount}) from GeLastTrxWithOpenStatusByUserNameAsync, will re-ringup and re-commit it...");
//}
//if (serverSideOpenTrx != null && serverSideOpenTrx.Items != null && serverSideOpenTrx.Items.Any())
//{
// try
// {
// logger.LogInformation($"Queried trx data(id: {serverSideOpenTrx.Id}, " +
// $"grossAmount: {serverSideOpenTrx.GrossAmount}, " +
// $"item[0]-> itemName:{serverSideOpenTrx.Items.First().Item?.ItemName ?? ""}" +
// $"-barcode:{serverSideOpenTrx.Items.First().Item?.BarCode ?? ""}-seqNo.:{serverSideOpenTrx.Items.First().FuelItemFdcTransactionSeqNo ?? ""}) " +
// $"from GeLastTrxWithOpenStatusByUserNameAsync, will simply re-commit it...");
// var recommitResult = await CloudHelper.Default.CommitTransactionAsync(serverSideOpenTrx.Id, new Dfs.WayneChina.PosModelMini.PosTrxMop()
// {
// Mop = new Dfs.WayneChina.PosModelMini.PosMop()
// {
// PaymentId = (int)PaymentID.PetroChinaIC,
// },
// Paid = serverSideOpenTrx.GrossAmount
// }, null);
// if (recommitResult)
// logger.LogInformation($" re-commit trx with id: {serverSideOpenTrx.Id} succeed");
// else
// logger.LogInformation($" re-commit trx with id: {serverSideOpenTrx.Id} failed gracefully, will do in next round");
// }
// catch (Exception eee)
// {
// logger.LogInformation($" re-commit trx with id: {serverSideOpenTrx.Id} failed with exception: {eee},{Environment.NewLine} will do again in next round");
// }
//}
#endregion
using (var scope = this.services.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService();
var unfinishedTrxDatas = await dbContext.GenericDatas.Where(gd =>
gd.Owner == genericDataOwner && gd.Type == genericDataType && gd.State == "Unfinished").OrderBy(gd => gd.CreatedTimeStamp).ToListAsync();
foreach (var d in unfinishedTrxDatas)
{
//ComplexData = JsonSerializer.Serialize(new
//{
//itemId,
//SiteLevelNozzleId = nzlExtraInfo.SiteLevelNozzleId ?? -1,
//Transaction = new
//{
// arg.Transaction.Amount,
// arg.Transaction.Volumn,
// arg.Transaction.SequenceNumberGeneratedOnPhysicalPump,
// arg.Transaction.Nozzle.PumpId,
// arg.Transaction.Nozzle.LogicalId
//}
//})
var jd = JsonDocument.Parse(d.ComplexData);
var itemId = jd.RootElement.GetProperty("itemId").GetString();
int siteLevelNozzleId = jd.RootElement.GetProperty("SiteLevelNozzleId").GetInt32();
int amount = jd.RootElement.GetProperty("Transaction").GetProperty("Amount").GetInt32();
int volume = jd.RootElement.GetProperty("Transaction").GetProperty("Volumn").GetInt32();
int seqNo = jd.RootElement.GetProperty("Transaction").GetProperty("SequenceNumberGeneratedOnPhysicalPump").GetInt32();
int pumpId = jd.RootElement.GetProperty("Transaction").GetProperty("PumpId").GetInt32();
int nozzleLogicalId = jd.RootElement.GetProperty("Transaction").GetProperty("LogicalId").GetInt32();
var uploadResult = await this.UploadTrxToCloud(itemId, amount, volume, seqNo, pumpId, nozzleLogicalId, siteLevelNozzleId);
if (uploadResult)
{
d.State = "Finished";
d.ModifiedTimeStamp = DateTime.Now;
await dbContext.SaveChangesAsync();
}
}
}
}
catch (Exception eeee)
{
//await universalApiHub.FirePersistGenericAlarmIfNotExists(this,
// new GenericAlarm()
// {
// Title = $"上传交易至云端失败",
// Category = $"上传",
// Detail = $"由PumpHandler中产生的交易(pumpId:{arg.Transaction.Nozzle.PumpId}, logicalNozzleId: {arg.Transaction.Nozzle.LogicalId}, vol: {arg.Transaction.Volumn}) 上传至云端失败:{eeee}",
// Severity = GenericAlarmSeverity.Error
// },
// ga => ga.Detail,
// ga => ga.Detail);
return;
}
finally
{
this.timelyUploadTimer.Change(0, 5000);
}
}, null, 0, 5000);
return true;
}
public Task Stop()
{
this.timelyUploadTimer?.Dispose();
return Task.FromResult(true);
}
}
}