diff --git a/src/fiskaltrust.AndroidLauncher.Common/PosApiPrint/PosApiHelper.cs b/src/fiskaltrust.AndroidLauncher.Common/PosApiPrint/PosApiHelper.cs new file mode 100644 index 00000000..487d140d --- /dev/null +++ b/src/fiskaltrust.AndroidLauncher.Common/PosApiPrint/PosApiHelper.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using fiskaltrust.ifPOS.v1; +using fiskaltrust.AndroidLauncher.Common.PosApiPrint.Helpers; + +namespace fiskaltrust.AndroidLauncher.Common.PosApiPrint +{ + public class PosApiHelper : IPOS + { + private readonly PosApiProvider _posApiProvider; + private IPOS _targetPOS; + + public PosApiHelper(PosApiProvider provider, IPOS targetPos) + { + _posApiProvider = provider; + _targetPOS = targetPos; + } + + public async Task SignAsync(ReceiptRequest request) + { + var response = await _targetPOS.SignAsync(request); + await _posApiProvider.PrintAsync(request, response); + return response; + } + + public IAsyncEnumerable JournalAsync(JournalRequest request) => _targetPOS.JournalAsync(request); + + public Task EchoAsync(EchoRequest message) => _targetPOS.EchoAsync(message); + + public ifPOS.v0.ReceiptResponse Sign(ifPOS.v0.ReceiptRequest data) => Task.Run(() => SignAsync(data)).Result; + + private async Task SignAsync(ifPOS.v0.ReceiptRequest data) => ReceiptRequestHelper.ConvertToV0(await SignAsync(ReceiptRequestHelper.ConvertToV1(data))); + + private delegate ifPOS.v0.ReceiptResponse Sign_Delegate(ifPOS.v0.ReceiptRequest request); + public IAsyncResult BeginSign(ifPOS.v0.ReceiptRequest data, AsyncCallback callback, object state) + { + var d = new Sign_Delegate(Sign); + var r = d.BeginInvoke(data, callback, d); + return r; + } + + public ifPOS.v0.ReceiptResponse EndSign(IAsyncResult result) + { + var d = (Sign_Delegate)result.AsyncState; + return d.EndInvoke(result); + } + + public Stream Journal(long ftJournalType, long from, long to) => _targetPOS.Journal(ftJournalType, from, to); + + private delegate Stream Journal_Delegate(long ftJournalType, long from, long to); + public IAsyncResult BeginJournal(long ftJournalType, long from, long to, AsyncCallback callback, object state) + { + var d = new Journal_Delegate(Journal); + var r = d.BeginInvoke(ftJournalType, from, to, callback, d); + return r; + } + + public Stream EndJournal(IAsyncResult result) + { + var d = (Journal_Delegate)result.AsyncState; + return d.EndInvoke(result); + } + + public string Echo(string message) => _targetPOS.Echo(message); + + private delegate string Echo_Delegate(string message); + public IAsyncResult BeginEcho(string message, AsyncCallback callback, object state) + { + var d = new Echo_Delegate(Echo); + var r = d.BeginInvoke(message, callback, d); + return r; + } + + public string EndEcho(IAsyncResult result) + { + var d = (Echo_Delegate)result.AsyncState; + return d.EndInvoke(result); + } + } +} diff --git a/src/fiskaltrust.AndroidLauncher.Common/PosApiPrint/PosApiProvider.cs b/src/fiskaltrust.AndroidLauncher.Common/PosApiPrint/PosApiProvider.cs new file mode 100644 index 00000000..a1998c3d --- /dev/null +++ b/src/fiskaltrust.AndroidLauncher.Common/PosApiPrint/PosApiProvider.cs @@ -0,0 +1,49 @@ +using System; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using fiskaltrust.ifPOS.v1; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; + +namespace fiskaltrust.AndroidLauncher.Common.PosApiPrint +{ + public class PosApiProvider + { + private readonly ILogger _logger; + private readonly HttpClient _httpClient; + + public PosApiProvider(Guid cashBoxId, string accessToken, Uri posApiurl, ILogger logger) + { + _logger = logger; + _httpClient = new HttpClient(new HttpClientHandler { }, disposeHandler: true) { BaseAddress = posApiurl }; + _httpClient.DefaultRequestHeaders.Add("cashboxid", cashBoxId.ToString()); + _httpClient.DefaultRequestHeaders.Add("accesstoken", accessToken); + _logger.LogDebug("Communciation with POS API ({PosApiUrl}) for CashBox {CashBoxId}.", posApiurl, cashBoxId); + } + + public async Task PrintAsync(ReceiptRequest receiptRequest, ReceiptResponse receiptResponse) + { + _logger.LogDebug("Try to print receipt with queueitemid {ftqueueitemid}", receiptResponse.ftQueueItemID); + try + { + var printResponse = await _httpClient.PostAsync("v0/print", new StringContent(JsonConvert.SerializeObject(new PrintRequest + { + request = receiptRequest, + response = receiptResponse + }), Encoding.UTF8, "application/json")); + + var result = await printResponse.Content.ReadAsStringAsync(); + if (!printResponse.IsSuccessStatusCode) + { + throw new Exception(result); + } + _logger.LogDebug("Submitted Receipt for printing with queueitemid {ftqueueitemid}", receiptResponse.ftQueueItemID); + } + catch (Exception ex) + { + _logger.LogError(ex, "Failed to print receipt with queueitemid {ftqueueitemid}. Reason: {reason}", receiptResponse.ftQueueItemID, ex.Message); + } + } + } +} diff --git a/src/fiskaltrust.AndroidLauncher.Common/PosApiPrint/PrintRequest.cs b/src/fiskaltrust.AndroidLauncher.Common/PosApiPrint/PrintRequest.cs new file mode 100644 index 00000000..d853f4dd --- /dev/null +++ b/src/fiskaltrust.AndroidLauncher.Common/PosApiPrint/PrintRequest.cs @@ -0,0 +1,11 @@ +using fiskaltrust.ifPOS.v1; +using System; + +namespace fiskaltrust.AndroidLauncher.Common.PosApiPrint.Models +{ + public class PrintRequest + { + public ReceiptRequest request { get; set; } + public ReceiptResponse response { get; set; } + } +} \ No newline at end of file diff --git a/src/fiskaltrust.AndroidLauncher.Common/PosApiPrint/ReceiptRequestHelper.cs b/src/fiskaltrust.AndroidLauncher.Common/PosApiPrint/ReceiptRequestHelper.cs new file mode 100644 index 00000000..5431b559 --- /dev/null +++ b/src/fiskaltrust.AndroidLauncher.Common/PosApiPrint/ReceiptRequestHelper.cs @@ -0,0 +1,221 @@ +using System; +using System.Linq; +using fiskaltrust.ifPOS.v1; + +namespace fiskaltrust.AndroidLauncher.Common.PosApiPrint.Helpers +{ + public static class ReceiptRequestHelper + { + public static ReceiptRequest ConvertToV1(ifPOS.v0.ReceiptRequest data) + { + return new ReceiptRequest + { + cbArea = data.cbArea, + cbCustomer = data.cbCustomer, + cbPreviousReceiptReference = data.cbPreviousReceiptReference, + cbReceiptAmount = data.cbReceiptAmount, + cbReceiptMoment = data.cbReceiptMoment, + cbReceiptReference = data.cbReceiptReference, + cbSettlement = data.cbSettlement, + cbTerminalID = data.cbTerminalID, + cbUser = data.cbUser, + ftCashBoxID = data.ftCashBoxID, + ftPosSystemId = data.ftPosSystemId, + ftQueueID = data.ftQueueID, + ftReceiptCase = data.ftReceiptCase, + ftReceiptCaseData = data.ftReceiptCaseData, + cbChargeItems = data.cbChargeItems?.Select(ConvertToV1).ToArray() ?? Array.Empty(), + cbPayItems = data.cbPayItems?.Select(ConvertToV1).ToArray() ?? Array.Empty(), + }; + } + + public static ChargeItem ConvertToV1(ifPOS.v0.ChargeItem data) + { + return new ChargeItem + { + AccountNumber = data.AccountNumber, + Amount = data.Amount, + CostCenter = data.CostCenter, + Description = data.Description, + ftChargeItemCase = data.ftChargeItemCase, + ftChargeItemCaseData = data.ftChargeItemCaseData, + Moment = data.Moment, + Position = data.Position, + ProductBarcode = data.ProductBarcode, + ProductGroup = data.ProductGroup, + ProductNumber = data.ProductNumber, + Quantity = data.Quantity, + Unit = data.Unit, + UnitPrice = data.UnitPrice, + UnitQuantity = data.UnitQuantity, + VATAmount = data.VATAmount, + VATRate = data.VATRate + }; + } + + public static PayItem ConvertToV1(ifPOS.v0.PayItem data) + { + return new PayItem + { + AccountNumber = data.AccountNumber, + Amount = data.Amount, + CostCenter = data.CostCenter, + Description = data.Description, + ftPayItemCase = data.ftPayItemCase, + ftPayItemCaseData = data.ftPayItemCaseData, + Moment = data.Moment, + Position = data.Position, + MoneyGroup = data.MoneyGroup, + MoneyNumber = data.MoneyNumber, + Quantity = data.Quantity + }; + } + + public static ReceiptResponse ConvertToV1(ifPOS.v0.ReceiptResponse data) + { + return new ReceiptResponse + { + ftCashBoxID = data.ftCashBoxID, + cbReceiptReference = data.cbReceiptReference, + cbTerminalID = data.cbTerminalID, + ftCashBoxIdentification = data.ftCashBoxIdentification, + ftChargeLines = data.ftChargeLines, + ftPayLines = data.ftPayLines, + ftQueueID = data.ftQueueID, + ftQueueItemID = data.ftQueueItemID, + ftQueueRow = data.ftQueueRow, + ftReceiptFooter = data.ftReceiptFooter, + ftReceiptHeader = data.ftReceiptHeader, + ftReceiptIdentification = data.ftReceiptIdentification, + ftReceiptMoment = data.ftReceiptMoment, + ftState = data.ftState, + ftStateData = data.ftStateData, + ftChargeItems = data.ftChargeItems?.Select(ConvertToV1).ToArray(), + ftPayItems = data.ftPayItems?.Select(ConvertToV1).ToArray(), + ftSignatures = data.ftSignatures?.Select(ConvertToV1).ToArray(), + }; + } + + public static ifPOS.v0.ReceiptResponse ConvertToV0(ReceiptResponse data) + { + return new ifPOS.v0.ReceiptResponse + { + ftCashBoxID = data.ftCashBoxID, + cbReceiptReference = data.cbReceiptReference, + cbTerminalID = data.cbTerminalID, + ftCashBoxIdentification = data.ftCashBoxIdentification, + ftChargeLines = data.ftChargeLines, + ftPayLines = data.ftPayLines, + ftQueueID = data.ftQueueID, + ftQueueItemID = data.ftQueueItemID, + ftQueueRow = data.ftQueueRow, + ftReceiptFooter = data.ftReceiptFooter, + ftReceiptHeader = data.ftReceiptHeader, + ftReceiptIdentification = data.ftReceiptIdentification, + ftReceiptMoment = data.ftReceiptMoment, + ftState = data.ftState, + ftStateData = data.ftStateData, + ftChargeItems = data.ftChargeItems?.Select(ConvertToV0).ToArray(), + ftPayItems = data.ftPayItems?.Select(ConvertToV0).ToArray(), + ftSignatures = data.ftSignatures?.Select(ConvertToV0).ToArray(), + }; + } + + public static ifPOS.v0.SignaturItem ConvertToV0(SignaturItem data) + { + return new ifPOS.v0.SignaturItem + { + Caption = data.Caption, + Data = data.Data, + ftSignatureFormat = data.ftSignatureFormat, + ftSignatureType = data.ftSignatureType + }; + } + + public static SignaturItem ConvertToV1(ifPOS.v0.SignaturItem data) + { + return new SignaturItem + { + Caption = data.Caption, + Data = data.Data, + ftSignatureFormat = data.ftSignatureFormat, + ftSignatureType = data.ftSignatureType + }; + } + + public static ifPOS.v0.ChargeItem ConvertToV0(ChargeItem data) + { + return new ifPOS.v0.ChargeItem + { + AccountNumber = data.AccountNumber, + Amount = data.Amount, + CostCenter = data.CostCenter, + Description = data.Description, + ftChargeItemCase = data.ftChargeItemCase, + ftChargeItemCaseData = data.ftChargeItemCaseData, + Moment = data.Moment, + Position = data.Position, + ProductBarcode = data.ProductBarcode, + ProductGroup = data.ProductGroup, + ProductNumber = data.ProductNumber, + Quantity = data.Quantity, + Unit = data.Unit, + UnitPrice = data.UnitPrice, + UnitQuantity = data.UnitQuantity, + VATAmount = data.VATAmount, + VATRate = data.VATRate + }; + } + + public static ifPOS.v0.PayItem ConvertToV0(PayItem data) + { + return new ifPOS.v0.PayItem + { + AccountNumber = data.AccountNumber, + Amount = data.Amount, + CostCenter = data.CostCenter, + Description = data.Description, + ftPayItemCase = data.ftPayItemCase, + ftPayItemCaseData = data.ftPayItemCaseData, + Moment = data.Moment, + Position = data.Position, + MoneyGroup = data.MoneyGroup, + MoneyNumber = data.MoneyNumber, + Quantity = data.Quantity + }; + } + + public static string GetRequestVersion(ReceiptRequest data) + { + if (data.GetType() == typeof(ifPOS.v0.ReceiptRequest)) + { + //TODO change on version update + return "v0"; + } + else + { + var type = data.GetType().ToString(); + var start = type.IndexOf(".ifPOS.") + 7; + var end = type.LastIndexOf('.'); + if (start >= 7 && end >= 0) + { + return type.Substring(start, end - start); + } + else + { + return $"unknown:{type}"; + } + } + } + + public static string GetCountry(ReceiptRequest data) + { + return (0xFFFF000000000000 & (ulong)data.ftReceiptCase) switch + { + 0x4445000000000000 => "DE", + 0x4652000000000000 => "FR", + _ => "AT", + }; + } + } +} diff --git a/src/fiskaltrust.AndroidLauncher.Common/Services/MiddlewareLauncher.cs b/src/fiskaltrust.AndroidLauncher.Common/Services/MiddlewareLauncher.cs index c5f9c4db..9289b63d 100644 --- a/src/fiskaltrust.AndroidLauncher.Common/Services/MiddlewareLauncher.cs +++ b/src/fiskaltrust.AndroidLauncher.Common/Services/MiddlewareLauncher.cs @@ -170,7 +170,7 @@ private async Task InitializeQueueAsync(PackageConfiguration packageConfig) string url = _urlResolver.GetProtocolSpecificUrl(packageConfig); var queueProvider = new SQLiteQueueProvider(); - var pos = await Task.Run(() => queueProvider.CreatePOS(Environment.GetFolderPath(Environment.SpecialFolder.Personal), packageConfig, _cashboxId, _isSandbox, _logLevel, _scus)); + var pos = await Task.Run(() => queueProvider.CreatePOS(Environment.GetFolderPath(Environment.SpecialFolder.Personal), packageConfig, _cashboxId, _accessToken, _isSandbox, _logLevel, _scus)); var host = _hostFactory.CreatePosHost(); _poss.Add(pos); _hosts.Add(host); diff --git a/src/fiskaltrust.AndroidLauncher.Common/Services/Queue/SQLiteQueueProvider.cs b/src/fiskaltrust.AndroidLauncher.Common/Services/Queue/SQLiteQueueProvider.cs index ca128e66..06bee5a3 100644 --- a/src/fiskaltrust.AndroidLauncher.Common/Services/Queue/SQLiteQueueProvider.cs +++ b/src/fiskaltrust.AndroidLauncher.Common/Services/Queue/SQLiteQueueProvider.cs @@ -12,12 +12,14 @@ using fiskaltrust.ifPOS.v1.de; using fiskaltrust.ifPOS.v1.it; using fiskaltrust.Middleware.Abstractions; +using fiskaltrust.AndroidLauncher.Common.PosApiPrint; namespace fiskaltrust.AndroidLauncher.Common.Services.Queue { + public class SQLiteQueueProvider { - public IPOS CreatePOS(string workingDir, PackageConfiguration queueConfiguration, Guid ftCashBoxId, bool isSandbox, LogLevel logLevel, AbstractScuList scus) + public IPOS CreatePOS(string workingDir, PackageConfiguration queueConfiguration, Guid ftCashBoxId, string accessToken, bool isSandbox, LogLevel logLevel, AbstractScuList scus) { var migrationsFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Migrations"); @@ -40,7 +42,14 @@ public IPOS CreatePOS(string workingDir, PackageConfiguration queueConfiguration serviceCollection.AddAppInsights(Helpers.Configuration.GetAppInsightsInstrumentationKey(isSandbox), "fiskaltrust.Middleware.Queue.SQLite", ftCashBoxId); bootstrapper.ConfigureServices(serviceCollection); - return serviceCollection.BuildServiceProvider().GetRequiredService(); + var services = serviceCollection.BuildServiceProvider(); + var pos = services.GetRequiredService(); + if (queueConfiguration.Configuration.ContainsKey("useposapi")) + { + var posApiHelper = new PosApiHelper(new PosApiProvider(ftCashBoxId, accessToken, isSandbox ? new Uri("https://pos-api-sandbox.fiskaltrust.cloud/") : new Uri("https://pos-api.fiskaltrust.cloud/"), services.GetRequiredService>()), pos); + return posApiHelper; + } + return pos; } public static void CopyMigrationsToDataDir(string targetDirectory) diff --git a/src/fiskaltrust.AndroidLauncher.Common/fiskaltrust.AndroidLauncher.Common.csproj b/src/fiskaltrust.AndroidLauncher.Common/fiskaltrust.AndroidLauncher.Common.csproj index d996e44a..d622854d 100644 --- a/src/fiskaltrust.AndroidLauncher.Common/fiskaltrust.AndroidLauncher.Common.csproj +++ b/src/fiskaltrust.AndroidLauncher.Common/fiskaltrust.AndroidLauncher.Common.csproj @@ -76,6 +76,10 @@ + + + + @@ -253,6 +257,7 @@ fiskaltrust.Middleware.SCU.IT.Epson +