123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- 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";
- /// <summary>
- /// Sample: http://url:8698
- /// DO NOT end with slash
- /// </summary>
- 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<ILoggerFactory>();
- 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<IProcessor> processors)
- {
- var universalApiHub = this.services.GetRequiredService<UniversalApiHub>();
- var pumpGroupHandlers = processors.WithHandlerOrApp<PetroChinaSilentPumpGroupHandler>().SelectHandlerOrAppThenCast<PetroChinaSilentPumpGroupHandler>();
- this.fdcServerApp = processors.WithHandlerOrApp<FdcServerHostApp>().SelectHandlerOrAppThenCast<FdcServerHostApp>().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<SqliteDbContext>();
- dbContext.GenericDatas.Add(data);
- await dbContext.SaveChangesAsync();
- }
- };
- }
- [UniversalApi]
- public async Task<bool> 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<bool> 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<UniversalApiHub>();
- 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<ServerSideTrx>();
- //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<SqliteDbContext>();
- 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<bool> Stop()
- {
- this.timelyUploadTimer?.Dispose();
- return Task.FromResult(true);
- }
- }
- }
|