diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000000000000000000000000000000000000..1a7f6f71a3445c4823da741a6ecd978759142bcb
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,6 @@
+{
+ "editor.formatOnType": true,
+ "[lisp]": {
+ "editor.wordSeparators": "`|;:'\",()"
+ }
+}
\ No newline at end of file
diff --git a/addItem.json b/addItem.json
new file mode 100644
index 0000000000000000000000000000000000000000..2f7c6b0f68b567b58a89db0e6e6b718ca582ef39
--- /dev/null
+++ b/addItem.json
@@ -0,0 +1,92 @@
+{
+ "operationConfiguration": {
+ "forceQuantityInput": false,
+ "pricePositionLimit": 10000,
+ "pricePositionZeroAllowed": true,
+ "priceTransactionLimit": -1,
+ "priceDifferencePercentPositionLimit": 100,
+ "priceDifferenceAbsolutePositionLimit": 999999,
+ "priceDifferenceLimitExceedAction": "Warn",
+ "priceNegDifferenceLimitExceedAction": "Warn",
+ "closeCurrent": "Required",
+ "closePrevious": "Required",
+ "filterResult": true,
+ "allowedWithWeight": true,
+ "allowedWithLength": true,
+ "allowedWithArea": true,
+ "allowedWithVolume": true,
+ "allowedWithMeasure": true,
+ "maximumQuantity": 999999,
+ "minimumQuantity": 1,
+ "quantityInputOrder": "BeforeOrAfter",
+ "priceInputOrder": "BeforeOrAfter",
+ "quantityLimitExceedAction": "Warn",
+ "amountLimitExceedAction": "Warn",
+ "weightUnitFactor": 0,
+ "measureUnitFactor": 0,
+ "priceDeviationType": "All",
+ "priceNegDeviationType": "All",
+ "xXCustom08": "string",
+ "xXCustom10": "string",
+ "xXCustom09": "string",
+ "xXCustom07": "string",
+ "xXCustom05": "string",
+ "xXCustom06": "string",
+ "xXCustom11": "string",
+ "xXCustom12": "string",
+ "xXCustom13": "string",
+ "xXCustom14": "string",
+ "xXCustom15": "string",
+ "xXCustom03": "string",
+ "xXCustom02": "string",
+ "xXCustom04": "string",
+ "xXCustom01": "string"
+ },
+ "barcode": "7703100270009",
+ "salesRestrictionsCheckNeeded": false,
+ "priceVariant": "Actual",
+ "itemEntryConfig": {
+ "forceQuantityInput": true,
+ "pricePositionLimit": 0,
+ "pricePositionZeroAllowed": true,
+ "priceTransactionLimit": 0,
+ "priceDifferencePercentPositionLimit": 0,
+ "priceDifferenceAbsolutePositionLimit": 0,
+ "priceDifferenceLimitExceedAction": "Warn",
+ "priceNegDifferenceLimitExceedAction": "Warn",
+ "closeCurrent": "Required",
+ "closePrevious": "Required",
+ "filterResult": true,
+ "allowedWithWeight": true,
+ "allowedWithLength": true,
+ "allowedWithArea": true,
+ "allowedWithVolume": true,
+ "allowedWithMeasure": true,
+ "maximumQuantity": 0,
+ "minimumQuantity": 0,
+ "quantityInputOrder": "BeforeOrAfter",
+ "priceInputOrder": "BeforeOrAfter",
+ "quantityLimitExceedAction": "Warn",
+ "weightUnitFactor": 0,
+ "measureUnitFactor": 0,
+ "priceDeviationType": "All",
+ "priceNegDeviationType": "All",
+ "xXCustom01": "string",
+ "xXCustom02": "string",
+ "xXCustom03": "string",
+ "xXCustom04": "string",
+ "xXCustom05": "string",
+ "xXCustom06": "string",
+ "xXCustom07": "string",
+ "xXCustom08": "string",
+ "xXCustom09": "string",
+ "xXCustom10": "string",
+ "xXCustom11": "string",
+ "xXCustom12": "string",
+ "xXCustom13": "string",
+ "xXCustom14": "string",
+ "xXCustom15": "string"
+ },
+ "entryMethodCode": "Keyed",
+ "keyedOnline": true
+}
\ No newline at end of file
diff --git a/gatewayGK/Adaptadores/AdaptadorAddItemRequest.cs b/gatewayGK/Adaptadores/AdaptadorAddItemRequest.cs
index 37bd475736f4a006869ec97a62c150e3bb01cfa6..3a942177345c6b9a7807a7f815fe349199d1e860 100644
--- a/gatewayGK/Adaptadores/AdaptadorAddItemRequest.cs
+++ b/gatewayGK/Adaptadores/AdaptadorAddItemRequest.cs
@@ -25,10 +25,10 @@ namespace EvaPOS_API_FRAME.Adaptadores
public DTOBase ObtieneDTO(int idSesion, TipoMensaje tipoMensaje, XmlElement docXml)
{
XmlNode? nodo = docXml.SelectSingleNode(NombreElementoXMLDatos);
- XmlSerializer serializer = new XmlSerializer(typeof(AddItemRequest));
- AddItemRequest dto;
+ XmlSerializer serializer = new XmlSerializer(typeof(AddItemRequestDTO));
+ AddItemRequestDTO dto;
XmlNodeReader elemento = new XmlNodeReader(nodo);
- dto = (AddItemRequest)serializer.Deserialize(elemento);
+ dto = (AddItemRequestDTO)serializer.Deserialize(elemento);
if (nodo == null)
diff --git a/gatewayGK/ComandosGkPruebas/AddItemRequestCmdGK.cs b/gatewayGK/ComandosGkPruebas/AddItemRequestCmdGK.cs
index 7d11db4f6aca0ea16e3a63bb353c3008ef640663..a7d788c06135f798713a15bd83e4c38bea9773fb 100644
--- a/gatewayGK/ComandosGkPruebas/AddItemRequestCmdGK.cs
+++ b/gatewayGK/ComandosGkPruebas/AddItemRequestCmdGK.cs
@@ -18,7 +18,7 @@ namespace EvaPOS_API_FRAME.Comandos
///
/// DTO con solicitud.
///
- public AddItemRequest Request { get; private set; }
+ public AddItemRequestDTO Request { get; private set; }
///
/// Procesa y responde ReportStatusEventsRequest.
@@ -77,7 +77,7 @@ namespace EvaPOS_API_FRAME.Comandos
public void CargaDTO(DTOBase addItemRequestDTO)
{
- Request = (AddItemRequest)addItemRequestDTO;
+ Request = (AddItemRequestDTO)addItemRequestDTO;
}
}
diff --git a/gatewayGK/ComandosPruebas/AddItemRequestCmd.cs b/gatewayGK/ComandosPruebas/AddItemRequestCmd.cs
index f18ee35cce73275eb72f7b6424d03b53e62e8aa1..9573da80628f304b6346c00635df1c49d9163da0 100644
--- a/gatewayGK/ComandosPruebas/AddItemRequestCmd.cs
+++ b/gatewayGK/ComandosPruebas/AddItemRequestCmd.cs
@@ -25,7 +25,7 @@ namespace EvaPOS_API_FRAME.Comandos
///
/// DTO con solicitud.
///
- public AddItemRequest Request { get; private set; }
+ public AddItemRequestDTO Request { get; private set; }
///
/// Procesa y responde ReportStatusEventsRequest.
@@ -83,7 +83,7 @@ namespace EvaPOS_API_FRAME.Comandos
public void CargaDTO(DTOBase addItemRequestDTO)
{
- Request = (AddItemRequest)addItemRequestDTO;
+ Request = (AddItemRequestDTO)addItemRequestDTO;
}
}
diff --git a/gatewayGK/Comandosgk/AddItemRequestCmdGk.cs b/gatewayGK/Comandosgk/AddItemRequestCmdGk.cs
index 25eec183327512840015e29a3a915c62e3c50f50..214b38c1084b6623817ae81f63c0a9ff013eb9b3 100644
--- a/gatewayGK/Comandosgk/AddItemRequestCmdGk.cs
+++ b/gatewayGK/Comandosgk/AddItemRequestCmdGk.cs
@@ -31,7 +31,7 @@ namespace gatewayGK.ComandosGk
///
/// DTO con solicitud.
///
- public AddItemRequest Request { get; private set; }
+ public AddItemRequestDTO Request { get; private set; }
///
/// Procesa y responde ReportStatusEventsRequest.
@@ -210,7 +210,7 @@ namespace gatewayGK.ComandosGk
var regularUnitPriceTrans = regularUnitPrice.ToString();
Log.Debug($"Transaction ID: {transactionId} ");
- Entorno.Instancia.getDatos().TransactionID = transactionId;
+ Entorno.Instancia.get().TransactionID = transactionId;
string tomarNombreCorto = "";
//Valores que se mandan en chec
@@ -247,7 +247,7 @@ namespace gatewayGK.ComandosGk
public void CargaDTO(DTOBase addItemRequestDTO)
{
- Request = (AddItemRequest)addItemRequestDTO;
+ Request = (AddItemRequestDTO)addItemRequestDTO;
}
}
}
diff --git a/gatewayGK/Comandosgk/AddItemRequestCmdGk2.cs b/gatewayGK/Comandosgk/AddItemRequestCmdGk2.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ff4d8348ca949f56e6d0dbc2e57e1d16e59b6c24
--- /dev/null
+++ b/gatewayGK/Comandosgk/AddItemRequestCmdGk2.cs
@@ -0,0 +1,233 @@
+using EvaPOS_API_FRAME.DTO.Intercambio;
+using EvaPOS_API_FRAME.DTO;
+using EvaPOS_API_FRAME.RespuestasXML;
+using EvaPosSrvDTO;
+using EvaPosSrvResp;
+using Serilog;
+using System.Globalization;
+using RestSharp;
+using gatewayGK.POSGk;
+using System.Text.Json;
+using Newtonsoft.Json.Linq;
+using GatewaySCO;
+
+namespace gatewayGK.ComandosGk
+{
+ ///
+ /// Procesa solicitudes del primer item agregado.
+ ///
+ // TODO - unificar uso de libreria json: using System.Text.Json OR using Newtonsoft.Json.Linq;
+ //
+ public class AddItemRequestCmdGk2 : IComando
+ {
+ public string Referencia { get; set; } = "scsns:AddItem";
+ ///
+ /// DTO con solicitud.
+ ///
+ public AddItemRequestDTO Request { get; private set; }
+
+ ///
+ /// Url servicio autenticación Gk.
+ ///
+ private string _urlRegisterItem = Entorno.Instancia.get().UrlBase
+ + "/com.gk_software.pos.api.service.transaction.LineItemService/registerLineItem";
+
+ ///
+ /// Procesa agregar item y responde ReportStatusEventsRequest.
+ ///
+ public Respuestas Ejecutar()
+ {
+ Log.Debug("Cmd AddItemRequestDTO ejecutado. AddItemRequest : {AddItemRequest}", Request.RequestID);
+
+ //int requestIdGuardado = RequestIdGuardado();
+ POSBCStatusEvent posbcStatus = null;
+ TransactionStatusEvent transactionStatusEvent = null;
+ POSReceiptEventHeaderResponse posReceiptEventHeader = null;
+ POSReceiptEvent pOSReceiptEvent = null;
+ TotalsEventResponse totalEvent = null;
+ AddItemResponse itemResponse = null;
+ //Variables para manejar las respuestas de error - (item con peso, no se encuentra el item,item requiere cantidad)
+ AddItemResponseError addItemResponseError = null;
+ Respuestas respuesta = null;
+ Venta venta = null;
+ //Variables del adaptador de entrada - addItem
+ int requestId = Request.RequestID;
+ long barCode = 0;
+ int quantity = Request.ItemIdentifier.Quantity == 0 ? 1 : Request.ItemIdentifier.Quantity;
+ bool cancelItem = Request.ItemIdentifier.VoidFlag;
+ double peso = Request.ItemIdentifier.ScaleWeight;
+ //Logica para validar el valor del codigo de barras
+ //Si es un item de busqueda o imagen, trae el valor KeyedItemID, si es escaneado trae barcode
+ if (Request.ItemIdentifier.BarCode != null)
+ barCode = Request.ItemIdentifier.BarCode.ScanDataLabel;
+ else
+ barCode = Request.ItemIdentifier.KeyedItemID;
+
+ // --- cliente rest.
+ var options = new RestClientOptions()
+ {
+ // TODO manejar el timeout como un parámetro de configuración.
+ MaxTimeout = -1,
+ RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true
+ };
+ string sessionId = Entorno.Instancia.get().posSessionId;
+ string cookieValue = $"sessionid={sessionId}";
+
+ var client = new RestClient(options);
+ var request = new RestRequest(_urlRegisterItem, Method.Post);
+ request.AddHeader("Accept", "application/json;Format=GK-PLAIN-JSON");
+ request.AddHeader("Content-Type", "application/json;Format=GK-PLAIN-JSON");
+ request.AddHeader("_pos_session_", sessionId);
+ request.AddHeader("Cookie", cookieValue);
+
+ // Record inicializado por nombre de propiedades.
+ var operationConfiguration = new operationConfiguration { pricePositionLimit = 10000000 }; // TODO - controlar este valor, como sacarlo del Smart POS.
+ var datosItem = new registerLineItemReq
+ {
+ barcode = barCode.ToString(),
+ entryMethodCode = "Keyed",
+ operationConfiguration = operationConfiguration
+ };
+ string json = JsonSerializer.Serialize(datosItem);
+ request.AddJsonBody(json);
+ Log.Verbose(">> GK registerLineItem - body {json}", json);
+ Log.Information(">> GK registerLineItem - posSessionId {posSessionId}, barCode {barCode}", sessionId, barCode);
+
+ RestResponse response = client.Execute(request);
+ System.Net.HttpStatusCode statusCode = response.StatusCode;
+ int numericStatusCode = (int)statusCode;
+ Log.Debug("<< GK registerLineItem - StatusCode {StatusCode}, numericStatusCode {numericStatusCode}", response.StatusCode, numericStatusCode);
+ Log.Verbose("<< GK registerLineItem - Headers {Headers}", response.Headers);
+ Log.Verbose("<< GK registerLineItem - Content {Content}", response.Content);
+
+ if (response.IsSuccessful == false)
+ {
+ if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
+ {
+ var jsonRespErr = System.Text.Json.JsonSerializer.Deserialize(response.Content
+ ?? throw new ApplicationException("Null content in response to POST method."));
+
+ var errorCode = jsonRespErr.GetProperty("errorCode").GetProperty("errorCode").GetString();
+ var message = jsonRespErr.GetProperty("errorCode").GetProperty("message").GetString();
+ var posItemID = jsonRespErr.GetProperty("additionalContextInfoMap").GetProperty("posItemID").GetString();
+ Log.Warning("<< GK registerLineItem - errorCode {errorCode}, message {message}, posItemID {posItemID}",
+ errorCode, message, posItemID);
+
+ // Item no encontrado.
+ if (errorCode == "GKR-POS-002075")
+ {
+ addItemResponseError = new AddItemResponseError(1,
+ TipoMensaje.Resp, requestId, "Articulo no encontrado", "ITEM_NOT_FOUND");
+ respuesta = new Respuestas { addItemResponseError };
+ return respuesta;
+ }
+ }
+ // TODO - interpretar la respuesta par amostrar el mensaje de error, ejemplo:
+ // {"errorCode":{"errorCode":"GKR-POS-000001","message":"Invalid session","messageKey":"com.gk_software.pos.utils.error.ErrorCodeMessages.MSG_INVALID_SESSION","arguments":[]},"timestamp":"2023-08-04T07:16:57.066","additionalContextInfoMap":{}}
+ Log.Error("<< GK registerLineItem failed: StatusCode {StatusCode}, Content {Content}",
+ response.StatusCode, response.Content);
+ throw new ApplicationException("Servicio POST 'registerLineItem' en error.");
+ }
+
+ var jsonResp = System.Text.Json.JsonSerializer.Deserialize(response.Content
+ ?? throw new ApplicationException("Null content in response to POST method."));
+ var statusOk = jsonResp.GetProperty("statusOk").GetBoolean();
+
+ // La respuesta puede ser IsSuccessful == true pero aún así se debe validar si hay
+ // mas conediciones de falla o alertas asociadas al atrículo.
+ if (statusOk == false)
+ {
+ // var errorCode = jsonResp.GetProperty("failure").GetProperty("errorCode").GetString();
+ // var message = jsonResp.GetProperty("failure").GetProperty("errorMessage").GetString();
+ // var posItemId = jsonResp.GetProperty("posItemId").GetString();
+ // var itemIdx = jsonResp.GetProperty("itemId").GetString();
+ // var itemName = jsonResp.GetProperty("itemName").GetString();
+ // Log.Warning("<< GK registerLineItem - errorCode {errorCode}, message {message}, posItemID {posItemID}, itemId {itemId}, itemName {itemName}",
+ // errorCode, message, posItemId, itemIdx, itemName);
+
+ Log.Warning("<< GK registerLineItem - statusOk {statusOk}, errorCode {errorCode}, message {message}", statusOk);
+
+ // Position limit exceeded - Price too high!
+ // if (errorCode == "GKR-POS-003031")
+ // {
+ // addItemResponseError = new AddItemResponseError(1,
+ // TipoMensaje.Resp, requestId, "Precio muy alto, límite excedido", "ITEM_NOT_FOUND");
+ // respuesta = new Respuestas { addItemResponseError };
+ // return respuesta;
+ // }
+
+ addItemResponseError = new AddItemResponseError(1,
+ TipoMensaje.Resp, requestId, "Error no reconocido", "ITEM_NOT_FOUND");
+ respuesta = new Respuestas { addItemResponseError };
+ return respuesta;
+ }
+
+
+ var options2 = new JsonSerializerOptions
+ {
+ PropertyNameCaseInsensitive = true
+ };
+
+ var jObject = JObject.Parse(response.Content);
+ var jsonString = jObject["primaryEntry"].ToString();
+ var jsonObject = JsonSerializer.Deserialize(jsonString, options2);
+
+ var transactionId = jsonObject.transaction.key.transactionID;
+ var addedOrModifiedLineItems = jsonObject.addedOrModifiedLineItems;
+ var itemId = addedOrModifiedLineItems[0].saleReturnLineItemList[0].itemID;
+ var regularUnitPrice = addedOrModifiedLineItems[0].saleReturnLineItemList[0].regularUnitPrice;
+ var quantityService = addedOrModifiedLineItems[0].saleReturnLineItemList[0].quantity;
+ var units = addedOrModifiedLineItems[0].saleReturnLineItemList[0].units;
+ var textName = addedOrModifiedLineItems[0].saleReturnLineItemList[0].receiptText;
+
+ //Pasarlo a string
+ var regularUnitPriceTrans = regularUnitPrice.ToString();
+
+ Log.Debug("""
+ << GK registerLineItemTransaction ID:
+ transactionId {transactionId},
+ addedOrModifiedLineItems {addedOrModifiedLineItems},
+ itemId {itemId},
+ regularUnitPrice {regularUnitPrice},
+ quantityService {quantityService},
+ units {units},
+ textName {textName}
+ """,
+ transactionId,
+ addedOrModifiedLineItems,
+ itemId,
+ regularUnitPrice,
+ quantityService,
+ units,
+ textName
+ );
+ Entorno.Instancia.get().TransactionID = transactionId;
+
+ string tomarNombreCorto = "";
+ //Valores que se mandan en chec
+ var date = DateTime.Now.ToString("dd/MM/yyyy");
+ CultureInfo culture = new CultureInfo("en-US");
+ culture.DateTimeFormat.AMDesignator = "AM";
+ culture.DateTimeFormat.PMDesignator = "PM";
+ var time = DateTime.Now.ToString("hh:mm tt", culture);
+
+ transactionStatusEvent = new TransactionStatusEvent(1, TipoMensaje.Event, requestId, "TRANSACTION_START", 1, "regularSale", "sales", date, time);
+ pOSReceiptEvent = new POSReceiptEvent(1, TipoMensaje.Event, requestId, "Customer", 0, "Body", requestId, 1, "center", "LineItem", "ItemSale", itemId + " " + textName + " " + quantityService + " " + regularUnitPrice, "Add");
+ posReceiptEventHeader = new POSReceiptEventHeaderResponse(1, TipoMensaje.Event, requestId);
+ totalEvent = new TotalsEventResponse(1, TipoMensaje.Event, requestId, regularUnitPriceTrans, regularUnitPriceTrans, regularUnitPriceTrans, regularUnitPriceTrans, "0.00", "0.00", "0.00", "0.00", "0.00", 1, 0, "0.00", "0.00");
+ itemResponse = new AddItemResponse(1, TipoMensaje.Resp, requestId, tomarNombreCorto, "false", "false", "true", "1234", "ScannedItemCode", "3200", 1, "3200", 0, "0.00", 0, 1, 0, "unit", "false", 0, "false", "false", "true", "true");
+ respuesta = new Respuestas { transactionStatusEvent, posReceiptEventHeader, pOSReceiptEvent, totalEvent, itemResponse };
+
+ return respuesta;
+ }
+ public IComando CreaCopia()
+ {
+ return (AddItemRequestCmdGk)this.MemberwiseClone();
+ }
+
+ public void CargaDTO(DTOBase addItemRequestDTO)
+ {
+ Request = (AddItemRequestDTO)addItemRequestDTO;
+ }
+ }
+}
diff --git a/gatewayGK/Comandosgk/AddItemRequestCmdGk3.cs b/gatewayGK/Comandosgk/AddItemRequestCmdGk3.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ec949e2a5f3c488121410183a6b0e253b32f5545
--- /dev/null
+++ b/gatewayGK/Comandosgk/AddItemRequestCmdGk3.cs
@@ -0,0 +1,259 @@
+using EvaPOS_API_FRAME.DTO.Intercambio;
+using EvaPOS_API_FRAME.DTO;
+using EvaPOS_API_FRAME.RespuestasXML;
+using EvaPosSrvDTO;
+using EvaPosSrvResp;
+using Serilog;
+using System.Globalization;
+using RestSharp;
+using gatewayGK.POSGk;
+using System.Text.Json;
+using Newtonsoft.Json.Linq;
+using GatewaySCO;
+using Newtonsoft.Json;
+using IO.Swagger.Model;
+
+namespace gatewayGK.ComandosGk
+{
+ ///
+ /// Procesa solicitudes del primer item agregado.
+ ///
+ // TODO - unificar uso de libreria json: using System.Text.Json OR using Newtonsoft.Json.Linq;
+ //
+ public class AddItemRequestCmdGk3 : IComando
+ {
+ public string Referencia { get; set; } = "scsns:AddItem";
+ ///
+ /// DTO con solicitud.
+ ///
+ public AddItemRequestDTO Request { get; private set; }
+
+ ///
+ /// Url servicio autenticación Gk.
+ ///
+ private string _urlRegisterItem = Entorno.Instancia.get().UrlBase
+ + "/com.gk_software.pos.api.service.transaction.LineItemService/registerLineItem";
+
+ ///
+ /// Procesa agregar item y responde ReportStatusEventsRequest.
+ ///
+ public Respuestas Ejecutar()
+ {
+ Log.Debug("Cmd AddItemRequestCmdGk3 ejecutado. AddItemRequest : {AddItemRequest}", Request.RequestID);
+
+ //int requestIdGuardado = RequestIdGuardado();
+ POSBCStatusEvent posbcStatus = null;
+ TransactionStatusEvent transactionStatusEvent = null;
+ POSReceiptEventHeaderResponse posReceiptEventHeader = null;
+ POSReceiptEvent pOSReceiptEvent = null;
+ TotalsEventResponse totalEvent = null;
+ AddItemResponse itemResponse = null;
+ //Variables para manejar las respuestas de error - (item con peso, no se encuentra el item,item requiere cantidad)
+ AddItemResponseError addItemResponseError = null;
+ Respuestas respuesta = null;
+ Venta venta = null;
+ //Variables del adaptador de entrada - addItem
+ int requestId = Request.RequestID;
+ long barCode = 0;
+ int quantity = Request.ItemIdentifier.Quantity == 0 ? 1 : Request.ItemIdentifier.Quantity;
+ bool cancelItem = Request.ItemIdentifier.VoidFlag;
+ double peso = Request.ItemIdentifier.ScaleWeight;
+ //Logica para validar el valor del codigo de barras
+ //Si es un item de busqueda o imagen, trae el valor KeyedItemID, si es escaneado trae barcode
+ if (Request.ItemIdentifier.BarCode != null)
+ barCode = Request.ItemIdentifier.BarCode.ScanDataLabel;
+ else
+ barCode = Request.ItemIdentifier.KeyedItemID;
+
+ // --- cliente rest.
+ var options = new RestClientOptions()
+ {
+ // TODO manejar el timeout como un parámetro de configuración.
+ MaxTimeout = -1,
+ RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true
+ };
+ string sessionId = Entorno.Instancia.get().posSessionId;
+ string cookieValue = $"sessionid={sessionId}";
+
+ var client = new RestClient(options);
+ var request = new RestRequest(_urlRegisterItem, Method.Post);
+ request.AddHeader("Accept", "application/json;Format=GK-PLAIN-JSON");
+ request.AddHeader("Content-Type", "application/json;Format=GK-PLAIN-JSON");
+ request.AddHeader("_pos_session_", sessionId);
+ request.AddHeader("Cookie", cookieValue);
+
+ // Record inicializado por nombre de propiedades.
+ var operationConfiguration = new operationConfiguration { pricePositionLimit = 10000000 }; // TODO - controlar este valor, como sacarlo del Smart POS.
+ var datosItem = new registerLineItemReq
+ {
+ barcode = barCode.ToString(),
+ entryMethodCode = "Keyed",
+ operationConfiguration = operationConfiguration
+ };
+ string json = System.Text.Json.JsonSerializer.Serialize(datosItem);
+ request.AddJsonBody(json);
+ Log.Verbose(">> GK registerLineItem - sessionId {sessionId}", sessionId);
+ Log.Verbose(">> GK registerLineItem - body {body}", json);
+ Log.Information(">> GK registerLineItem - barCode {barCode}", barCode);
+
+ RestResponse response = client.Execute(request);
+ System.Net.HttpStatusCode statusCode = response.StatusCode;
+ int numericStatusCode = (int)statusCode;
+ Log.Information("<< GK registerLineItem - Http.StatusCode {StatusCode}, Http.numericStatusCode {numericStatusCode}", response.StatusCode, numericStatusCode);
+ Log.Verbose("<< GK registerLineItem - Headers {Headers}", response.Headers);
+ Log.Verbose("<< GK registerLineItem - Content {Content}", response.Content);
+
+ if (response.IsSuccessful == false)
+ {
+ if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
+ {
+ var jsonRespErr = System.Text.Json.JsonSerializer.Deserialize(response.Content
+ ?? throw new ApplicationException("Null content in response to POST method."));
+
+ var errorCode = jsonRespErr.GetProperty("errorCode").GetProperty("errorCode").GetString();
+ var message = jsonRespErr.GetProperty("errorCode").GetProperty("message").GetString();
+ var posItemID = jsonRespErr.GetProperty("additionalContextInfoMap").GetProperty("posItemID").GetString();
+ Log.Warning("<< GK registerLineItem - errorCode {errorCode}, message {message}, posItemID {posItemID}",
+ errorCode, message, posItemID);
+
+ // Item no encontrado.
+ if (errorCode == "GKR-POS-002075")
+ {
+ addItemResponseError = new AddItemResponseError(1,
+ TipoMensaje.Resp, requestId, "Articulo no encontrado", "ITEM_NOT_FOUND");
+ respuesta = new Respuestas { addItemResponseError };
+ return respuesta;
+ }
+ }
+ // TODO - interpretar la respuesta par amostrar el mensaje de error, ejemplo:
+ // {"errorCode":{"errorCode":"GKR-POS-000001","message":"Invalid session","messageKey":"com.gk_software.pos.utils.error.ErrorCodeMessages.MSG_INVALID_SESSION","arguments":[]},"timestamp":"2023-08-04T07:16:57.066","additionalContextInfoMap":{}}
+ Log.Error("<< GK registerLineItem failed: StatusCode {StatusCode}, Content {Content}",
+ response.StatusCode, response.Content);
+ throw new ApplicationException("Servicio POST 'registerLineItem' en error.");
+ }
+
+ // En este punto, la respuesta es exitosa a nivel de http.
+
+ var respTransacAddItem = Newtonsoft.Json.JsonConvert.DeserializeObject(
+ response.Content ?? throw new ApplicationException("Null content in response to POST method."))
+ ?? throw new ApplicationException("Null content in response to POST method.");
+ // Log.Verbose("<< GK registerLineItem: respNewtonsoft {respNewtonsoft}", respTransacAddItem);
+
+ // La respuesta puede ser IsSuccessful == true pero aún así se debe validar si hay
+ // mas conediciones de falla o alertas asociadas al atrículo.
+ if (respTransacAddItem.StatusOk == false)
+ {
+ Log.Warning("<< GK registerLineItem - statusOk {statusOk}", respTransacAddItem.StatusOk);
+
+ // Position limit exceeded - Price too high!
+ // if (errorCode == "GKR-POS-003031")
+ // {
+ // addItemResponseError = new AddItemResponseError(1,
+ // TipoMensaje.Resp, requestId, "Precio muy alto, límite excedido", "ITEM_NOT_FOUND");
+ // respuesta = new Respuestas { addItemResponseError };
+ // return respuesta;
+ // }
+
+ addItemResponseError = new AddItemResponseError(1,
+ TipoMensaje.Resp, requestId, "Error no reconocido", "ITEM_NOT_FOUND");
+ respuesta = new Respuestas { addItemResponseError };
+ return respuesta;
+ }
+
+ // En este punto statusOk == True : el item ingreso a la transacción de venta.
+ var transactionId = respTransacAddItem.PrimaryEntry.Transaction.Key.TransactionID;
+ var businessUnitGroupID = respTransacAddItem.PrimaryEntry.Transaction.Key.BusinessUnitGroupID;
+ var addedOrModifiedLineItems = respTransacAddItem.PrimaryEntry.AddedOrModifiedLineItems[0].SaleReturnLineItemList[0];
+ var itemId = addedOrModifiedLineItems.ItemID;
+ var regularUnitPrice = addedOrModifiedLineItems.RegularUnitPrice;
+ var quantityService = addedOrModifiedLineItems.Quantity;
+ var units = addedOrModifiedLineItems.Units;
+ var receiptText = addedOrModifiedLineItems.ReceiptText;
+ var registrationNumber = addedOrModifiedLineItems.RegistrationNumber;
+ var extensionSequenceNumber = addedOrModifiedLineItems.SaleReturnLineItemExtensionList[0].Key.ExtensionSequenceNumber;
+ var retailTransactionList = respTransacAddItem.PrimaryEntry.Transaction.RetailTransactionList;
+ var dtoRetailTransactionTotalList = retailTransactionList[0].RetailTransactionTotalList;
+
+ double? total = 0.0;
+ double? subtotal = 0.0;
+ double? subtotalDcto = 0.0;
+
+ // Recorrer lista de totales y sacar valores
+ foreach (var tipoTotal in dtoRetailTransactionTotalList)
+ {
+ var k = tipoTotal.Key;
+ var valor = tipoTotal.Amount;
+ switch (k.TransactionTotalTypeCode)
+ {
+ case "TOTAL":
+ total = valor;
+ break;
+ case "SUBTOTAL":
+ subtotal = valor;
+ break;
+ case "SUBTOTAL_DISCOUNT":
+ subtotalDcto = valor;
+ break;
+ default:
+ break;
+ // throw new ApplicationException("Null content in response to POST method (TransactionTotalTypeCode).");
+ }
+ }
+
+ //Pasarlo a string
+ var regularUnitPriceTrans = regularUnitPrice.ToString();
+
+ Log.Debug("<< GK TransactionRegistrationResult: transactionId {transactionId}, itemId {itemId}, regularUnitPrice {regularUnitPrice}, quantityService {quantityService}, units {units}, textName {textName}",
+ transactionId,
+ itemId,
+ regularUnitPrice,
+ quantityService,
+ units,
+ receiptText
+ );
+ Log.Information(String.Format("{0,3} | {1,13} | {2,-20} | {3,3}| {4,-5:N2} | {5,12:N2} | {6,12:N2} | {7,12:N2} | {8,12:N2} | {9,3}",
+ addedOrModifiedLineItems.Key.RetailTransactionLineItemSequenceNumber,
+ registrationNumber,
+ receiptText,
+ addedOrModifiedLineItems.UnitOfMeasureCode,
+ addedOrModifiedLineItems.Quantity,
+ addedOrModifiedLineItems.ActualUnitPrice,
+ addedOrModifiedLineItems.ExtendedAmount,
+ addedOrModifiedLineItems.ExtendedDiscountAmount,
+ addedOrModifiedLineItems.GrandExtendedAmount,
+ addedOrModifiedLineItems.TaxGroupID
+ ));
+ Log.Information(String.Format("\t\tSUBTOTAL: {0,12:N2} -- SUBTOTAL_DISCOUNT: {1,12:N2} -- TOTAL: {2,12:N2}",
+ subtotal, subtotalDcto, total));
+
+ Entorno.Instancia.get().TransactionID = transactionId;
+ Entorno.Instancia.get().BusinessUnitGroupID = businessUnitGroupID;
+
+ string tomarNombreCorto = "";
+ //Valores que se mandan en chec
+ var date = DateTime.Now.ToString("dd/MM/yyyy");
+ CultureInfo culture = new CultureInfo("en-US");
+ culture.DateTimeFormat.AMDesignator = "AM";
+ culture.DateTimeFormat.PMDesignator = "PM";
+ var time = DateTime.Now.ToString("hh:mm tt", culture);
+
+ transactionStatusEvent = new TransactionStatusEvent(1, TipoMensaje.Event, requestId, "TRANSACTION_START", 1, "regularSale", "sales", date, time);
+ pOSReceiptEvent = new POSReceiptEvent(1, TipoMensaje.Event, requestId, "Customer", 0, "Body", requestId, 1, "center", "LineItem", "ItemSale", itemId + " " + receiptText + " " + quantityService + " " + regularUnitPrice, "Add");
+ posReceiptEventHeader = new POSReceiptEventHeaderResponse(1, TipoMensaje.Event, requestId);
+ totalEvent = new TotalsEventResponse(1, TipoMensaje.Event, requestId, regularUnitPriceTrans, regularUnitPriceTrans, regularUnitPriceTrans, regularUnitPriceTrans, "0.00", "0.00", "0.00", "0.00", "0.00", 1, 0, "0.00", "0.00");
+ itemResponse = new AddItemResponse(1, TipoMensaje.Resp, requestId, tomarNombreCorto, "false", "false", "true", "1234", "ScannedItemCode", "3200", 1, "3200", 0, "0.00", 0, 1, 0, "unit", "false", 0, "false", "false", "true", "true");
+ respuesta = new Respuestas { transactionStatusEvent, posReceiptEventHeader, pOSReceiptEvent, totalEvent, itemResponse };
+
+ return respuesta;
+ }
+ public IComando CreaCopia()
+ {
+ return (AddItemRequestCmdGk)this.MemberwiseClone();
+ }
+
+ public void CargaDTO(DTOBase addItemRequestDTO)
+ {
+ Request = (AddItemRequestDTO)addItemRequestDTO;
+ }
+ }
+}
diff --git a/gatewayGK/Comandosgk/CalculateTaxtCmdGk.cs b/gatewayGK/Comandosgk/CalculateTaxtCmdGk.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4f689f1b33a45bd74fd846a5120b76a7e39a0b97
--- /dev/null
+++ b/gatewayGK/Comandosgk/CalculateTaxtCmdGk.cs
@@ -0,0 +1,229 @@
+using EvaPOS_API_FRAME.DTO.Intercambio;
+using EvaPOS_API_FRAME.DTO;
+using EvaPOS_API_FRAME.RespuestasXML;
+using EvaPosSrvDTO;
+using EvaPosSrvResp;
+using Serilog;
+using System.Globalization;
+using RestSharp;
+using gatewayGK.POSGk;
+using System.Text.Json;
+using Newtonsoft.Json.Linq;
+using GatewaySCO;
+using Newtonsoft.Json;
+using IO.Swagger.Model;
+
+namespace gatewayGK.ComandosGk
+{
+ ///
+ /// Calcular el impuesto de un item.
+ /// TODO - terminar esto.
+ ///
+ public class CalculateTaxtCmdGk : IComando
+ {
+ public string Referencia { get; set; } = "scsns:AddItem";
+ ///
+ /// DTO con solicitud.
+ ///
+ public AddItemRequestDTO Request { get; private set; }
+
+ ///
+ /// Url servicio autenticación Gk.
+ ///
+ private string _urlRegisterItem = Entorno.Instancia.get().UrlBase
+ + "services/com.gk_software.pos.api.service.taxengine.TaxEngineService/calculateTax";
+
+ ///
+ /// Calcular impuestos.
+ ///
+ public Respuestas Ejecutar()
+ {
+ Log.Debug("Cmd CalculateTaxtCmdGk ejecutado. AddItemRequest : {AddItemRequest}", Request.RequestID);
+
+
+
+ //int requestIdGuardado = RequestIdGuardado();
+ POSBCStatusEvent posbcStatus = null;
+ TransactionStatusEvent transactionStatusEvent = null;
+ POSReceiptEventHeaderResponse posReceiptEventHeader = null;
+ POSReceiptEvent pOSReceiptEvent = null;
+ TotalsEventResponse totalEvent = null;
+
+ // Parámetros de invocación servicios web: TaxEngineServiceCalculateTaxAsync
+ // Var definición de esta clase para sus parámetros requeridos de inicialización.
+ ComGkSoftwareGkrApiTxpoolDtoTransaction dtoTransactionCalculateTax = new()
+ {
+ Key = new()
+ {
+ BusinessUnitGroupID = Entorno.Instancia.get().BusinessUnitGroupID,
+ TransactionID = ""
+ },
+ OperatorID = "",
+ WorkstationID = "",
+ BusinessUnitID = "",
+ BusinessDayDate = "",
+ SequenceNumber = 0,
+ TransactionTypeCode = "",
+ InternalSequenceNumber = 0,
+ FiscalFlag = true,
+ IsocurrencyCode = ""
+ };
+
+
+
+
+ //Variables para manejar las respuestas de error - (item con peso, no se encuentra el item,item requiere cantidad)
+
+ Respuestas respuesta = null;
+
+
+ //Variables del adaptador de entrada - addItem
+ int requestId = Request.RequestID;
+
+
+ // --- cliente rest.
+ var options = new RestClientOptions()
+ {
+ // TODO manejar el timeout como un parámetro de configuración.
+ MaxTimeout = -1,
+ RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true
+ };
+ string sessionId = Entorno.Instancia.get().posSessionId;
+ string cookieValue = $"sessionid={sessionId}";
+
+ var client = new RestClient(options);
+ var request = new RestRequest(_urlRegisterItem, Method.Post);
+ request.AddHeader("Accept", "application/json;Format=GK-PLAIN-JSON");
+ request.AddHeader("Content-Type", "application/json;Format=GK-PLAIN-JSON");
+ request.AddHeader("_pos_session_", sessionId);
+ request.AddHeader("Cookie", cookieValue);
+
+ // Record inicializado por nombre de propiedades.
+ dtoTransactionCalculateTax = new ComGkSoftwareGkrApiTxpoolDtoTransaction();
+ var key = new Key();
+
+ // TODO - usar newtonsoft
+ string json = System.Text.Json.JsonSerializer.Serialize(dtoTransactionCalculateTax);
+ request.AddJsonBody(json);
+ Log.Verbose(">> GK registerLineItem - sessionId {sessionId}", sessionId);
+ Log.Verbose(">> GK registerLineItem - body {body}", json);
+ Log.Information(">> GK calculateTax");
+
+ RestResponse response = client.Execute(request);
+ System.Net.HttpStatusCode statusCode = response.StatusCode;
+ int numericStatusCode = (int)statusCode;
+ Log.Information("<< GK registerLineItem - Http.StatusCode {StatusCode}, Http.numericStatusCode {numericStatusCode}", response.StatusCode, numericStatusCode);
+ Log.Verbose("<< GK registerLineItem - Headers {Headers}", response.Headers);
+ Log.Verbose("<< GK registerLineItem - Content {Content}", response.Content);
+
+ if (response.IsSuccessful == false)
+ {
+ if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
+ {
+ var jsonRespErr = System.Text.Json.JsonSerializer.Deserialize(response.Content
+ ?? throw new ApplicationException("Null content in response to POST method."));
+
+ var errorCode = jsonRespErr.GetProperty("errorCode").GetProperty("errorCode").GetString();
+ var message = jsonRespErr.GetProperty("errorCode").GetProperty("message").GetString();
+ var posItemID = jsonRespErr.GetProperty("additionalContextInfoMap").GetProperty("posItemID").GetString();
+ Log.Warning("<< GK registerLineItem - errorCode {errorCode}, message {message}, posItemID {posItemID}",
+ errorCode, message, posItemID);
+ }
+ // TODO - interpretar la respuesta par amostrar el mensaje de error, ejemplo:
+ // {"errorCode":{"errorCode":"GKR-POS-000001","message":"Invalid session","messageKey":"com.gk_software.pos.utils.error.ErrorCodeMessages.MSG_INVALID_SESSION","arguments":[]},"timestamp":"2023-08-04T07:16:57.066","additionalContextInfoMap":{}}
+ Log.Error("<< GK registerLineItem failed: StatusCode {StatusCode}, Content {Content}",
+ response.StatusCode, response.Content);
+ throw new ApplicationException("Servicio POST 'registerLineItem' en error.");
+ }
+
+ // En este punto, la respuesta es exitosa a nivel de http.
+
+ var respTransacAddItem = Newtonsoft.Json.JsonConvert.DeserializeObject(
+ response.Content ?? throw new ApplicationException("Null content in response to POST method."))
+ ?? throw new ApplicationException("Null content in response to POST method.");
+ // Log.Verbose("<< GK registerLineItem: respNewtonsoft {respNewtonsoft}", respTransacAddItem);
+
+ // La respuesta puede ser IsSuccessful == true pero aún así se debe validar si hay
+ // mas conediciones de falla o alertas asociadas al atrículo.
+ if (respTransacAddItem.StatusOk == false)
+ {
+ Log.Warning("<< GK registerLineItem - statusOk {statusOk}", respTransacAddItem.StatusOk);
+
+ // TODO : esto no corresonde a mensaje a CHEC apropiado.
+ respuesta = new Respuestas { new AddItemResponseError(1,
+ TipoMensaje.Resp, requestId, "Error no reconocido", "ITEM_NOT_FOUND") };
+ return respuesta;
+ }
+
+ // En este punto statusOk == True : el item ingreso a la transacción de venta.
+ var transactionId = respTransacAddItem.PrimaryEntry.Transaction.Key.TransactionID;
+ var businessUnitGroupID = respTransacAddItem.PrimaryEntry.Transaction.Key.BusinessUnitGroupID;
+ var addedOrModifiedLineItems = respTransacAddItem.PrimaryEntry.AddedOrModifiedLineItems[0].SaleReturnLineItemList[0];
+ var itemId = addedOrModifiedLineItems.ItemID;
+ var regularUnitPrice = addedOrModifiedLineItems.RegularUnitPrice;
+ var quantityService = addedOrModifiedLineItems.Quantity;
+ var units = addedOrModifiedLineItems.Units;
+ var receiptText = addedOrModifiedLineItems.ReceiptText;
+ var registrationNumber = addedOrModifiedLineItems.RegistrationNumber;
+ var extensionSequenceNumber = addedOrModifiedLineItems.SaleReturnLineItemExtensionList[0].Key.ExtensionSequenceNumber;
+ var retailTransactionList = respTransacAddItem.PrimaryEntry.Transaction.RetailTransactionList;
+ var dtoRetailTransactionTotalList = retailTransactionList[0].RetailTransactionTotalList;
+
+ double? total = 0.0;
+ double? subtotal = 0.0;
+ double? subtotalDcto = 0.0;
+
+ //Pasarlo a string
+ var regularUnitPriceTrans = regularUnitPrice.ToString();
+
+ Log.Debug("<< GK TransactionRegistrationResult: transactionId {transactionId}, itemId {itemId}, regularUnitPrice {regularUnitPrice}, quantityService {quantityService}, units {units}, textName {textName}",
+ transactionId,
+ itemId,
+ regularUnitPrice,
+ quantityService,
+ units,
+ receiptText
+ );
+ Log.Information(String.Format("{0,3} | {1,13} | {2,-20} | {3,3}| {4,-5:N2} | {5,8:N2} | {6,12:N2} | {7,12:N2} | {8,12:N2} | {9,3}",
+ addedOrModifiedLineItems.Key.RetailTransactionLineItemSequenceNumber,
+ registrationNumber,
+ receiptText,
+ addedOrModifiedLineItems.UnitOfMeasureCode,
+ addedOrModifiedLineItems.Quantity,
+ addedOrModifiedLineItems.ActualUnitPrice,
+ addedOrModifiedLineItems.ExtendedAmount,
+ addedOrModifiedLineItems.ExtendedDiscountAmount,
+ addedOrModifiedLineItems.GrandExtendedAmount,
+ addedOrModifiedLineItems.TaxGroupID
+ ));
+ Log.Information(String.Format("SUBTOTAL: {0,12:N2} // SUBTOTAL_DISCOUNT: {1,12:N2} // TOTAL: {2,12:N2}",
+ subtotal, subtotalDcto, total));
+ Entorno.Instancia.get().TransactionID = transactionId;
+
+ string tomarNombreCorto = "";
+ //Valores que se mandan en chec
+ var date = DateTime.Now.ToString("dd/MM/yyyy");
+ CultureInfo culture = new CultureInfo("en-US");
+ culture.DateTimeFormat.AMDesignator = "AM";
+ culture.DateTimeFormat.PMDesignator = "PM";
+ var time = DateTime.Now.ToString("hh:mm tt", culture);
+
+ transactionStatusEvent = new TransactionStatusEvent(1, TipoMensaje.Event, requestId, "TRANSACTION_START", 1, "regularSale", "sales", date, time);
+ pOSReceiptEvent = new POSReceiptEvent(1, TipoMensaje.Event, requestId, "Customer", 0, "Body", requestId, 1, "center", "LineItem", "ItemSale", itemId + " " + receiptText + " " + quantityService + " " + regularUnitPrice, "Add");
+ posReceiptEventHeader = new POSReceiptEventHeaderResponse(1, TipoMensaje.Event, requestId);
+ totalEvent = new TotalsEventResponse(1, TipoMensaje.Event, requestId, regularUnitPriceTrans, regularUnitPriceTrans, regularUnitPriceTrans, regularUnitPriceTrans, "0.00", "0.00", "0.00", "0.00", "0.00", 1, 0, "0.00", "0.00");
+ respuesta = new Respuestas { transactionStatusEvent, posReceiptEventHeader, pOSReceiptEvent, totalEvent };
+
+ return respuesta;
+ }
+ public IComando CreaCopia()
+ {
+ return (AddItemRequestCmdGk)this.MemberwiseClone();
+ }
+
+ public void CargaDTO(DTOBase addItemRequestDTO)
+ {
+ Request = (AddItemRequestDTO)addItemRequestDTO;
+ }
+ }
+}
diff --git a/gatewayGK/Comandosgk/InitializeRequestCmdGk.cs b/gatewayGK/Comandosgk/InitializeRequestCmdGk.cs
index edc35e3fef50577156e59512a614d440aba60290..6493fca5d13f99c37e09b4f8ed8e438aaa4a1c36 100644
--- a/gatewayGK/Comandosgk/InitializeRequestCmdGk.cs
+++ b/gatewayGK/Comandosgk/InitializeRequestCmdGk.cs
@@ -5,13 +5,7 @@ using GatewaySCO;
using RestSharp;
using SCOGateway.POSGk;
using Serilog;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Net;
-using System.Text;
using System.Text.Json;
-using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
@@ -28,7 +22,8 @@ namespace gatewayGK.ComandosGk
///
/// Url servicio autenticación Gk.
///
- public const string UrlLogin = ConstantesGK.UrlBaseMaquetaProd + "/com.gk_software.pos.api.service.session.PosSessionService/login";
+ private string _urlLogin = Entorno.Instancia.get().UrlBase
+ + "/com.gk_software.pos.api.service.session.PosSessionService/login";
///
/// Procesa y responde el login.
@@ -37,49 +32,49 @@ namespace gatewayGK.ComandosGk
public Respuestas Ejecutar()
{
- // Crea una instancia de IConfiguration para acceder a la configuración
- IConfiguration configuration = new ConfigurationBuilder()
- .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
- .Build();
-
- //Llamar valores del archivo de configuración
- string retailStoreId = configuration["DataGK:RetailStoreId"];
- string workstationId = configuration["DataGK:WorkstationId"];
- string workstationAddress = configuration["DataGK:WorkstationAddress"];
- string workstationTypeCode = configuration["DataGK:WorkstationTypeCode"];
- string loginName = configuration["DataGK:LoginName"];
- string businessUnitGroupID = configuration["DataGK:BusinessUnitGroupID"];
- string tillID = configuration["DataGK:TillID"];
- string password = configuration["DataGK:Password"];
-
- string jSessionId = configuration["DataGK:SessionID"]; ;
- string cookieValue = $"JSESSIONID={jSessionId}";
-
- Respuestas respuestaChec = null;
+ string cookieValue = $"JSESSIONID=";
+
+ string banner =
+ """
+
+ _____ _ _ ______ ____ _____ _ _____ _ __ _____ _ _____ ____ _____
+ / ____ | | | | ____/ ____| / ____| | / ____| |/ / / ____| | | | __ \ / __ \ / ____|
+ | | | |__| | |__ | | ______ | | __| |___ ____ _ _ _ ______ | | __| ' / | (___ _ __ ___ __ _ _ __| |_ | |__) | | | | (___
+ | | | __ | __|| | |______| | | |_ | __\ \ /\ / / _` | | | | |______| | | |_ | < \___ \| '_ ` _ \ / _` | '__| __| | ___/| | | |\___ \
+ | |___ | | | | |___| |____ | |__| | |_ \ V V / (_| | |_| | | |__| | . \ ____) | | | | | | (_| | | | |_ | | | |__| |____) |
+ \_____ |_| |_|______\_____| \_____|\__| \_/\_/ \__,_|\__, | \_____|_|\_\ |_____/|_| |_| |_|\__,_|_| \__| |_| \____/|_____/
+ __/ |
+ |___/
+
+ """;
+
+ Log.Information(banner);
+
int terminalNumber = Request.TerminalNumber;
- Log.Debug("Cmd InitializeRequestCmd ejecutado - Gk pruebas. Request id: {id}, terminal: {terminal}, recovery: {recovery}", Request.OperatorID, Request.TerminalNumber, Request.Recovery);
+ Log.Debug("Cmd InitializeRequestCmd ejecutado: OperatorID {OperatorID}, TerminalNumber {TerminalNumber}, Recovery {Recovery}", Request.OperatorID, Request.TerminalNumber, Request.Recovery);
// Contactar Smart POS Gk.
- var options = new RestClientOptions(UrlLogin)
+ var options = new RestClientOptions()
{
+ // TODO manejar el timeout como un parámetro de configuración.
MaxTimeout = -1,
RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true
};
-
+
var client = new RestClient(options);
- var request = new RestRequest(UrlLogin, Method.Post);
+ var request = new RestRequest(_urlLogin, Method.Post);
request.AddHeader("Accept", "application/json;Format=GK-PLAIN-JSON");
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Cookie", cookieValue);
var datosAutenticacion = new AutenticationReq
{
- RetailStoreId = retailStoreId,
- WorkstationId = workstationId,
- WorkstationAddress = workstationAddress,
- WorkstationTypeCode = workstationTypeCode,
- LoginName = loginName,
- Password = password,
+ RetailStoreId = Entorno.Instancia.get().ConfigGk.RetailStoreId,
+ WorkstationId = Entorno.Instancia.get().ConfigGk.WorkstationId,
+ WorkstationAddress = Entorno.Instancia.get().ConfigGk.WorkstationAddress,
+ WorkstationTypeCode = Entorno.Instancia.get().ConfigGk.WorkstationTypeCode,
+ LoginName = Entorno.Instancia.get().ConfigGk.LoginName,
+ Password = Entorno.Instancia.get().ConfigGk.Password,
TrainingMode = false,
FinalizeControlTransactionFlag = false,
UseLoginTypeTechnicalForLoginManager = false,
@@ -87,51 +82,54 @@ namespace gatewayGK.ComandosGk
{
TillDoKey = new TillDoKey
{
- BusinessUnitGroupID = businessUnitGroupID,
- TillID = tillID
+ BusinessUnitGroupID = Entorno.Instancia.get().ConfigGk.BusinessUnitGroupID,
+ TillID = Entorno.Instancia.get().ConfigGk.TillID
}
}
};
-
+
var loginRequestWrapper = new LoginRequestWrapper
{
LoginRequest = datosAutenticacion
};
- string json = JsonSerializer.Serialize(loginRequestWrapper, new JsonSerializerOptions { WriteIndented = true });
+ string json = JsonSerializer.Serialize(loginRequestWrapper);
request.AddJsonBody(json);
+ Log.Information(">> GK login: LoginName {LoginName}, RetailStoreId {RetailStoreId}, WorkstationId {WorkstationId}",
+ datosAutenticacion.LoginName, datosAutenticacion.RetailStoreId, datosAutenticacion.WorkstationId);
var response = client.Execute(request);
- if (response.IsSuccessful)
- {
- Log.Debug($"Gk: Autenticate - POST - response {response}");
-
- var autenticacionResp = JsonSerializer.Deserialize(response.Content);
-
- var transactionId = autenticacionResp.primaryEntry.transaction.key.transactionID;
- var operatorID = autenticacionResp.primaryEntry.transaction.operatorID;
- var posSessionId = autenticacionResp.posSessionId.id;
- //var sessionId = autenticacionResp.primaryEntry.transaction.posSessionId.id;
- Log.Debug($"Transaction ID: {transactionId}, operatorID: {operatorID} ");
- // Salvar Transaccion y id de la session.
- //Entorno.Instancia.getDatos().TransactionID = transactionId;
- Entorno.Instancia.getDatos().posSessionId = posSessionId;
- Entorno.Instancia.getDatos().SeccionId = jSessionId;
- // Respuestas a SCO.
- var posbcStatus1 = new POSBCStatusEvent(1, TipoMensaje.Event, "INFO", "CONNECTING_TO_POS", "Connecting to POS system");
- var posbcStatus2 = new POSBCStatusEvent(1, TipoMensaje.Event, "INFO", "CONNECTED_TO_POS", "Connected to POS system");
- var posbcStatus3 = new POSBCStatusEvent(1, TipoMensaje.Event, "INFO", "POS_RESOURCES_INITIALIZED", "POS Resources Initialized");
- var inicializacionOk = new InitializeResponse(1, TipoMensaje.Resp, terminalNumber);
- respuestaChec = new Respuestas { posbcStatus1, posbcStatus2, posbcStatus3, inicializacionOk };
- }
- else
+ if (response.IsSuccessful == false)
{
- Log.Error($"Failed to connect to GK web service: {response.StatusCode}");
- Log.Error(response.Content);
+ // TODO mejorar manejo como en Logout
+ Log.Error("<< GK login failed: StatusCode {StatusCode}, Content {Content}",
+ response.StatusCode, response.Content);
throw new ApplicationException("Servicio POST 'Login' en error.");
}
+ Log.Debug("<< GK login - StatusCode {StatusCode}", response.StatusCode);
+ Log.Verbose("<< GK login - Headers {Headers}", response.Headers);
+ Log.Verbose("<< GK login - Content {Content}", response.Content);
+
+ var autenticacionResp = JsonSerializer.Deserialize(response.Content
+ ?? throw new ApplicationException("Null content in response to POST method."))
+ ?? throw new ApplicationException("authenticationResp object not found in response POST method.");
+
+ var transactionId = autenticacionResp.primaryEntry.transaction.key.transactionID;
+ var operatorID = autenticacionResp.primaryEntry.transaction.operatorID;
+ var posSessionId = autenticacionResp.posSessionId.id;
+ // Salvar Transaccion y id de la session.
+ Entorno.Instancia.get().posSessionId = posSessionId;
+ Log.Information("<< GK login:operatorID {operatorID}, transactionId {transactionId}, posSessionId {posSessionId}",
+ operatorID, transactionId, Entorno.Instancia.get().posSessionId);
+
+ // Respuestas a SCO.
+ var posbcStatus1 = new POSBCStatusEvent(1, TipoMensaje.Event, "INFO", "CONNECTING_TO_POS", "Connecting to POS system");
+ var posbcStatus2 = new POSBCStatusEvent(1, TipoMensaje.Event, "INFO", "CONNECTED_TO_POS", "Connected to POS system");
+ var posbcStatus3 = new POSBCStatusEvent(1, TipoMensaje.Event, "INFO", "POS_RESOURCES_INITIALIZED", "POS Resources Initialized");
+ var inicializacionOk = new InitializeResponse(1, TipoMensaje.Resp, terminalNumber);
+ Respuestas respuestaChec = new Respuestas { posbcStatus1, posbcStatus2, posbcStatus3, inicializacionOk };
return respuestaChec;
}
diff --git a/gatewayGK/Comandosgk/SubtotalCalculationCmdGk.cs b/gatewayGK/Comandosgk/SubtotalCalculationCmdGk.cs
new file mode 100644
index 0000000000000000000000000000000000000000..af943a5010b228f4a27f7c7591522cee5b4916a1
--- /dev/null
+++ b/gatewayGK/Comandosgk/SubtotalCalculationCmdGk.cs
@@ -0,0 +1,323 @@
+using EvaPOS_API_FRAME.DTO.Intercambio;
+using EvaPOS_API_FRAME.DTO;
+using EvaPOS_API_FRAME.RespuestasXML;
+using EvaPosSrvDTO;
+using EvaPosSrvResp;
+using Serilog;
+using System.Globalization;
+using RestSharp;
+using gatewayGK.POSGk;
+using System.Text.Json;
+using GatewaySCO;
+using Newtonsoft.Json;
+using IO.Swagger.Model;
+using static IO.Swagger.Model.ComGkSoftwarePosApiModelConfigProcessActionPositionOperationConfig;
+
+namespace gatewayGK.ComandosGk
+{
+ ///
+ /// Calcular el impuesto de un item.
+ /// TODO - terminar esto.
+ ///
+ public class SubtotalCalculationCmdGk : IComando
+ {
+ public string Referencia { get; set; } = "scsns:AddItem"; // <-- Arreglar Referencia
+ ///
+ /// DTO con solicitud.
+ ///
+ public AddItemRequestDTO Request { get; private set; } // <-- Buscar el correcto.
+
+ ///
+ /// Url servicio autenticación Gk.
+ ///
+ private readonly string _urlRequest = Entorno.Instancia.get().UrlBase
+ + "/com.gk_software.pos.api.service.subtotal.SubtotalService/processSubtotalCalculation";
+
+ ///
+ /// Calcular subtotal.
+ ///
+ public Respuestas Ejecutar()
+ {
+ Log.Debug("Cmd SubtotalCalculationCmdGk ejecutado. RequestID : {RequestID}", Request.RequestID);
+ //int requestIdGuardado = RequestIdGuardado();
+ POSBCStatusEvent posbcStatus = null;
+ TransactionStatusEvent transactionStatusEvent = null;
+ POSReceiptEventHeaderResponse posReceiptEventHeader = null;
+ POSReceiptEvent pOSReceiptEvent = null;
+ TotalsEventResponse totalEvent = null;
+
+ // Objeto invocación servicio web, SubtotalServiceApi.cs
+ ComGkSoftwarePosApiModelConfigProcessActionPositionOperationConfig configReq = new(
+ false, //(bool? forceQuantityInput = default(bool?)
+ 1000000000, //double? pricePositionLimit = default(double?)
+ true, //bool? pricePositionZeroAllowed = default(bool?)
+ -1.0, // double? priceTransactionLimit = default(double?)
+ 100.0, //priceDifferencePercentPositionLimit = default(double?)
+ 99999999.0, // priceDifferenceAbsolutePositionLimit = default(double?)
+ PriceDifferenceLimitExceedActionEnum.Authorize, //priceDifferenceLimitExceedAction = default(PriceDifferenceLimitExceedActionEnum)
+ PriceNegDifferenceLimitExceedActionEnum.Unchecked, // PriceNegDifferenceLimitExceedActionEnum priceNegDifferenceLimitExceedAction = default(PriceNegDifferenceLimitExceedActionEnum),
+ CloseCurrentEnum.Disabled, // CloseCurrentEnum closeCurrent = default(CloseCurrentEnum),
+ ClosePreviousEnum.Required, // ClosePreviousEnum closePrevious = default(ClosePreviousEnum),
+ false, // bool? filterResult = default(bool?),
+ false, // bool? allowedWithWeight = default(bool?),
+ false, // bool? allowedWithLength = default(bool?),
+ false, // bool? allowedWithArea = default(bool?),
+ false, // bool? allowedWithVolume = default(bool?),
+ false, // bool? allowedWithMeasure = default(bool?),
+ 99999, // int? maximumQuantity = default(int?),
+ 1, // int? minimumQuantity = default(int?),
+ QuantityInputOrderEnum.BeforeOrAfter, // QuantityInputOrderEnum quantityInputOrder = default(QuantityInputOrderEnum),
+ PriceInputOrderEnum.BeforeOrAfter, // PriceInputOrderEnum priceInputOrder = default(PriceInputOrderEnum),
+ QuantityLimitExceedActionEnum.Forbid, // QuantityLimitExceedActionEnum quantityLimitExceedAction = default(QuantityLimitExceedActionEnum),
+ AmountLimitExceedActionEnum.Forbid, // AmountLimitExceedActionEnum amountLimitExceedAction = default(AmountLimitExceedActionEnum),
+ 0.0, // double? weightUnitFactor = default(double?),
+ 0.0, // double? measureUnitFactor = default(double?),
+ PriceDeviationTypeEnum.All, // PriceDeviationTypeEnum priceDeviationType = default(PriceDeviationTypeEnum)
+ PriceNegDeviationTypeEnum.All, // PriceNegDeviationTypeEnum priceNegDeviationType = default(PriceNegDeviationTypeEnum),
+ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "");
+ // string xXCustom08 = default(string), string xXCustom10 = default(string), string xXCustom09 = default(string), string xXCustom07 = default(string),
+ // string xXCustom05 = default(string), string xXCustom06 = default(string), string xXCustom11 = default(string), string xXCustom12 = default(string),
+ // string xXCustom13 = default(string), string xXCustom14 = default(string), string xXCustom15 = default(string), string xXCustom03 = default(string),
+ // string xXCustom02 = default(string), string xXCustom04 = default(string), string xXCustom01 = default(string))
+
+ // Objeto respuesta servicio web, SubtotalServiceApi.cs
+ ComGkSoftwarePosApiServiceTransactionSubtotalOperationResult result;
+
+ // Mensajes respuesta a CHEC.
+ Respuestas respuesta = null;
+
+ //Variables del adaptador de entrada - addItem
+ int requestId = Request.RequestID;
+
+ // --- cliente rest.
+ var options = new RestClientOptions()
+ {
+ // TODO manejar el timeout como un parámetro de configuración.
+ MaxTimeout = -1,
+ RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true
+ };
+ string sessionId = Entorno.Instancia.get().posSessionId;
+ string cookieValue = $"sessionid={sessionId}";
+
+ var client = new RestClient(options);
+ var request = new RestRequest(_urlRequest, Method.Post);
+ request.AddHeader("Accept", "application/json;Format=GK-PLAIN-JSON");
+ request.AddHeader("Content-Type", "application/json;Format=GK-PLAIN-JSON");
+ request.AddHeader("_pos_session_", sessionId);
+ request.AddHeader("Cookie", cookieValue);
+
+ // -- Inicializar request. Nada que inicializar.
+ string jsonReq = JsonConvert.SerializeObject(configReq);
+ string body = $"{{ \"com.gk_software.pos.api.model.config.process.action.PositionOperationConfig\": {jsonReq} }}";
+
+ request.AddJsonBody(body);
+
+ Log.Verbose(">> GK processSubtotalCalculation - sessionId {sessionId}", sessionId);
+ Log.Verbose(">> GK processSubtotalCalculation - body {body}", body);
+ Log.Information(">> GK processSubtotalCalculation");
+
+ RestResponse response = client.Execute(request);
+ System.Net.HttpStatusCode statusCode = response.StatusCode;
+ int numericStatusCode = (int)statusCode;
+
+ Log.Information("<< GK processSubtotalCalculation - Http.StatusCode {StatusCode}, Http.numericStatusCode {numericStatusCode}", response.StatusCode, numericStatusCode);
+ Log.Verbose("<< GK processSubtotalCalculation - Headers {Headers}", response.Headers);
+ Log.Verbose("<< GK processSubtotalCalculation - Content {Content}", response.Content);
+
+ if (response.IsSuccessful == false)
+ {
+ if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
+ {
+ var jsonRespErr = System.Text.Json.JsonSerializer.Deserialize(response.Content
+ ?? throw new ApplicationException("Null content in response to POST method."));
+
+ var errorCode = jsonRespErr.GetProperty("errorCode").GetProperty("errorCode").GetString();
+ var message = jsonRespErr.GetProperty("errorCode").GetProperty("message").GetString();
+ var posItemID = jsonRespErr.GetProperty("additionalContextInfoMap").GetProperty("posItemID").GetString();
+ Log.Warning("<< GK processSubtotalCalculation - errorCode {errorCode}, message {message}, posItemID {posItemID}",
+ errorCode, message, posItemID);
+ }
+ Log.Error("<< GK processSubtotalCalculation failed: StatusCode {StatusCode}, Content {Content}",
+ response.StatusCode, response.Content);
+ throw new ApplicationException("Servicio POST 'processSubtotalCalculation' en error.");
+ }
+
+ // --- En este punto, la respuesta es exitosa a nivel de http.
+
+ result = Newtonsoft.Json.JsonConvert.DeserializeObject(
+ response.Content ?? throw new ApplicationException("Null content in response to POST method."))
+ ?? throw new ApplicationException("Null content in response to POST method.");
+
+ // ------------------------------------------------------------------------------------
+ // En este punto statusOk == True : el item ingreso a la transacción de venta.
+ var transactionId = result.PrimaryEntry.Transaction.Key.TransactionID;
+ var businessUnitGroupID = result.PrimaryEntry.Transaction.Key.BusinessUnitGroupID;
+ var lineItemsList = result.PrimaryEntry.Transaction.RetailTransactionList[0].RetailTransactionLineItemList;
+
+ // Recorrer lista
+ Log.Information("<< GK processSubtotalCalculation: transactionId {transactionId}", transactionId);
+ Log.Information("-------------------------------------------------------------------------------------------------------------------------");
+ Log.Information(String.Format("{0,3} | {1,-13} | {2,-20} | {3,-3}| {4,-5} | {5,-12} | {6,-12} | {7,-12} | {8,-12} | {9,3}",
+ "#",
+ "positemID",
+ "receiptText",
+ "und",
+ "qntty",
+ "actlUntPrice",
+ "extnddAmount",
+ "extnddDiscnt",
+ "grndExtdAmnt",
+ "tax"
+ ));
+ Log.Information("-------------------------------------------------------------------------------------------------------------------------");
+ bool encabezadoTaxImpreso = false;
+ foreach (var lineItem in lineItemsList)
+ {
+ //if (lineItem.SaleReturnLineItemList == null) continue;
+
+ var retailTransactionLineItemTypeCode = lineItem.RetailTransactionLineItemTypeCode;
+ Log.Debug("<< GK processSubtotalCalculation: transactionId {transactionId}, retailTransactionLineItemTypeCode {retailTransactionLineItemTypeCode}",
+ transactionId,
+ retailTransactionLineItemTypeCode
+ );
+
+ switch (retailTransactionLineItemTypeCode)
+ {
+ case "SR":
+ // transaction line item REGISTRO ITEM VENTA
+ var item = lineItem.SaleReturnLineItemList[0];
+ var positemID = item.PositemID;
+ var itemSequenceNumber = item.Key.RetailTransactionLineItemSequenceNumber;
+ var receiptText = item.ReceiptText;
+ var regularUnitPrice = item.RegularUnitPrice;
+ var actualUnitPrice = item.ActualUnitPrice;
+ var unitOfMeasureCode = item.UnitOfMeasureCode;
+ var quantity = item.Quantity;
+ var extendedAmount = item.ExtendedAmount;
+ var extendedDiscountAmount = item.ExtendedDiscountAmount;
+ var grandExtendedAmount = item.GrandExtendedAmount;
+ var taxLineItem = item.SaleReturnTaxLineItemList[0];
+ var taxReceiptPrintCode = taxLineItem.ReceiptPrintCode;
+
+ Log.Debug("<< GK processSubtotalCalculation: transactionId {transactionId}, itemId {itemId}, regularUnitPrice {regularUnitPrice}, quantity {quantity}, unitOfMeasureCode {unitOfMeasureCode}, receiptText {receiptText}",
+ transactionId,
+ positemID,
+ regularUnitPrice,
+ quantity,
+ unitOfMeasureCode,
+ receiptText
+ );
+
+ Log.Information(String.Format("{0,3} | {1,13} | {2,-20} | {3,3}| {4,-5:N2} | {5,12:N2} | {6,12:N2} | {7,12:N2} | {8,12:N2} | {9,3}",
+ itemSequenceNumber,
+ positemID,
+ receiptText,
+ unitOfMeasureCode,
+ quantity,
+ actualUnitPrice,
+ extendedAmount,
+ extendedDiscountAmount,
+ grandExtendedAmount,
+ taxReceiptPrintCode
+ ));
+ break;
+ case "TX":
+ // transaction line item REGISTRO ITEM IMPUESTO
+ var taxLineItemList = lineItem.TaxLineItemList;
+ if (encabezadoTaxImpreso == false)
+ {
+ encabezadoTaxImpreso = true;
+ Log.Information("-------------------------------------------------------------------------------------------------------------------------");
+ Log.Information(String.Format("{0,3} | {1,6} | {2,12} | {3,12} | {4,12} | {5,8}",
+ "tax",
+ "%",
+ "taxAmount",
+ "taxablAmount",
+ "net",
+ "taxName"
+ ));
+ Log.Information("-------------------------------------------------------------------------------------------------------------------------");
+ }
+ foreach (var taxLine in taxLineItemList)
+ {
+ var taxableAmount = taxLine.TaxableAmount;
+ var taxPercent = taxLine.TaxPercent;
+ var taxAmount = taxLine.TaxAmount;
+ var taxAuthorityName = taxLine.TaxAuthorityName;
+ var receiptPrintCode = taxLine.ReceiptPrintCode;
+ Log.Information(String.Format("{0,-3} | {1,6} | {2,12:N2} | {3,12:N2} | {4,12:N2} | {5,8}",
+ receiptPrintCode,
+ taxPercent,
+ taxAmount,
+ taxableAmount,
+ taxableAmount - taxAmount,
+ taxAuthorityName
+ ));
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ var retailTransactionList = result.PrimaryEntry.Transaction.RetailTransactionList;
+ var dtoRetailTransactionTotalList = retailTransactionList[0].RetailTransactionTotalList;
+
+ double? total = 0.0;
+ double? subtotal = 0.0;
+ double? subtotalDcto = 0.0;
+
+ // Recorrer lista de totales y sacar valores
+ foreach (var tipoTotal in dtoRetailTransactionTotalList)
+ {
+ var k = tipoTotal.Key;
+ var valor = tipoTotal.Amount;
+ switch (k.TransactionTotalTypeCode)
+ {
+ case "TOTAL":
+ total = valor;
+ break;
+ case "SUBTOTAL":
+ subtotal = valor;
+ break;
+ case "SUBTOTAL_DISCOUNT":
+ subtotalDcto = valor;
+ break;
+ default:
+ break;
+ // throw new ApplicationException("Null content in response to POST method (TransactionTotalTypeCode).");
+ }
+ }
+
+ Entorno.Instancia.get().TransactionID = transactionId;
+ Log.Information("-------------------------------------------------------------------------------------------------------------------------");
+ Log.Information(String.Format("\t\tSUBTOTAL: {0,12:N2} -- SUBTOTAL_DISCOUNT: {1,12:N2} -- TOTAL: {2,12:N2}",
+ subtotal, subtotalDcto, total));
+ Log.Information("-------------------------------------------------------------------------------------------------------------------------");
+
+ //Valores que se mandan en chec
+ var date = DateTime.Now.ToString("dd/MM/yyyy");
+ CultureInfo culture = new CultureInfo("en-US");
+ culture.DateTimeFormat.AMDesignator = "AM";
+ culture.DateTimeFormat.PMDesignator = "PM";
+ var time = DateTime.Now.ToString("hh:mm tt", culture);
+
+ transactionStatusEvent = new TransactionStatusEvent(1, TipoMensaje.Event, requestId, "TRANSACTION_START", 1, "regularSale", "sales", date, time);
+ pOSReceiptEvent = new POSReceiptEvent(1, TipoMensaje.Event, requestId, "Customer", 0, "Body", requestId, 1, "center", "LineItem", "ItemSale", "XXX", "Add");
+ posReceiptEventHeader = new POSReceiptEventHeaderResponse(1, TipoMensaje.Event, requestId);
+ totalEvent = new TotalsEventResponse(1, TipoMensaje.Event, requestId, "", "", "", "", "0.00", "0.00", "0.00", "0.00", "0.00", 1, 0, "0.00", "0.00");
+ respuesta = new Respuestas { transactionStatusEvent, posReceiptEventHeader, pOSReceiptEvent, totalEvent };
+
+ return respuesta;
+ }
+ public IComando CreaCopia()
+ {
+ return (AddItemRequestCmdGk)this.MemberwiseClone();
+ }
+
+ public void CargaDTO(DTOBase addItemRequestDTO)
+ {
+ Request = (AddItemRequestDTO)addItemRequestDTO;
+ }
+ }
+}
diff --git a/gatewayGK/Comandosgk/TerminateRequestCmdGk.cs b/gatewayGK/Comandosgk/TerminateRequestCmdGk.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c8208a91c8f3da4df0153bc0dd691589da1c6a89
--- /dev/null
+++ b/gatewayGK/Comandosgk/TerminateRequestCmdGk.cs
@@ -0,0 +1,116 @@
+using EvaPOS_API_FRAME.DTO;
+using EvaPOS_API_FRAME.RespuestasXML.TerminateLane;
+using EvaPosSrvDTO;
+using EvaPosSrvResp;
+using Serilog;
+using GatewaySCO;
+using RestSharp;
+using SCOGateway.POSGk;
+using System.Text.Json;
+
+namespace gatewayGK.ComandosGk
+{
+ ///
+ /// Comando para cerrar la lane
+ ///
+ public class TerminateRequestCmdGk : IComando
+ {
+ public string Referencia { get; set; } = "scsns:Terminate";
+ ///
+ /// DTO con solicitud.
+ ///
+ public TerminateRequestDTO Destroy { get; private set; }
+ private string _urlLogout = Entorno.Instancia.get().UrlBase
+ + "/com.gk_software.pos.api.service.session.PosSessionService/logout";
+
+ ///
+ /// Procesa y responde el evento Terminar.
+ ///
+ public Respuestas Ejecutar()
+ {
+ Log.Debug("Cmd TerminateRequestDTO ejecutado. TerminateRequest : {TerminateRequest}", Destroy.DestroySession);
+ var requestId = Destroy.DestroySession;
+
+ // --- cliente rest.
+ string sessionId = Entorno.Instancia.get().posSessionId;
+ var options = new RestClientOptions()
+ {
+ // TODO manejar el timeout como un parámetro de configuración.
+ MaxTimeout = -1,
+ RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true
+ };
+ string cookieValue = $"sessionid={sessionId}";
+ var request = new RestRequest(_urlLogout, Method.Post);
+ request.AddHeader("Accept", "application/json;Format=GK-PLAIN-JSON");
+ request.AddHeader("Content-Type", "application/json");
+ request.AddHeader("_pos_session_", sessionId);
+
+ var logoutReq = new LogoutReq
+ {
+ PosSessionId = new PosSessionId
+ {
+ id = sessionId
+ }
+ };
+
+ string json = JsonSerializer.Serialize(logoutReq);
+ Log.Verbose(">> GK logout - body {json}", json);
+ request.AddJsonBody(json);
+ var client = new RestClient(options);
+ Log.Information(">> GK logout - posSessionId {posSessionId}", sessionId);
+ var response = client.Execute(request);
+ Log.Debug("<< GK Logout - StatusCode {StatusCode}", response.StatusCode);
+ Log.Verbose("<< GK Logout - Headers {Headers}", response.Headers);
+ Log.Verbose("<< GK Logout - Content {Content}", response.Content);
+
+ if (response.IsSuccessful == false)
+ {
+ // TODO - interpretar la respuesta par amostrar el mensaje de error, ejemplo:
+ // {"errorCode":{"errorCode":"GKR-POS-000001","message":"Invalid session","messageKey":"com.gk_software.pos.utils.error.ErrorCodeMessages.MSG_INVALID_SESSION","arguments":[]},"timestamp":"2023-08-04T07:16:57.066","additionalContextInfoMap":{}}
+ Log.Error("<< GK logout failed: StatusCode {StatusCode}, Content {Content}",
+ response.StatusCode, response.Content);
+ throw new ApplicationException("Servicio POST 'Logout' en error.");
+ }
+
+ // var logoutResp = JsonSerializer.Deserialize(response.Content
+ // ?? throw new ApplicationException("Null content in response to POST method."))
+ // ?? throw new ApplicationException("logoutResp object not found in response POST method.");
+
+ // var success = logoutResp.success;
+
+ // ---- Usando JsonElement
+ var jsonElement = System.Text.Json.JsonSerializer.Deserialize(response.Content
+ ?? throw new ApplicationException("Null content in response to POST method."));
+
+ var transactionID = jsonElement
+ .GetProperty("primaryEntry")
+ .GetProperty("transaction")
+ .GetProperty("key")
+ .GetProperty("transactionID")
+ .GetString();
+ var success = jsonElement
+ .GetProperty("success")
+ .GetBoolean();
+
+ if (success)
+ Entorno.Instancia.get().posSessionId = "";
+
+ Log.Information("<< GK logout - success {success}, transactionID {transactionID}",
+ success, transactionID);
+
+ TerminateResponse terminateResponse = new TerminateResponse(1, TipoMensaje.Resp, requestId);
+ return (new Respuestas { terminateResponse });
+ }
+
+ public IComando CreaCopia()
+ {
+ return (TerminateRequestCmdGk)this.MemberwiseClone();
+ }
+
+ public void CargaDTO(DTOBase terminateRequest)
+ {
+ Destroy = (TerminateRequestDTO)terminateRequest;
+ }
+
+ }
+}
diff --git a/gatewayGK/DTO/AddItemRequestDTO_.cs b/gatewayGK/DTO/AddItemRequestDTO.cs
similarity index 91%
rename from gatewayGK/DTO/AddItemRequestDTO_.cs
rename to gatewayGK/DTO/AddItemRequestDTO.cs
index 3342953c0040e12643f1f114e2e35e9a3bfc75b4..250e1a7a505345f95a7879eaa864944de4fe4cfc 100644
--- a/gatewayGK/DTO/AddItemRequestDTO_.cs
+++ b/gatewayGK/DTO/AddItemRequestDTO.cs
@@ -42,12 +42,12 @@ namespace EvaPOS_API_FRAME.DTO
}
[XmlRoot(ElementName = "AddItemRequest")]
- public class AddItemRequest : DTOBase
+ public class AddItemRequestDTO : DTOBase
{
- public AddItemRequest(int idSesion, TipoMensaje tipo) : base(idSesion, tipo)
+ public AddItemRequestDTO(int idSesion, TipoMensaje tipo) : base(idSesion, tipo)
{
}
- public AddItemRequest()
+ public AddItemRequestDTO()
{
}
diff --git a/gatewayGK/GuiaProgramacion.md b/gatewayGK/GuiaProgramacion.md
index cdcfad12960de72ad0c081ee5c41902450f71ec2..f31211da8207ab2bbab464e2721a463deec8452f 100644
--- a/gatewayGK/GuiaProgramacion.md
+++ b/gatewayGK/GuiaProgramacion.md
@@ -26,7 +26,9 @@ En la siguiente lista se presentan los parámetros de configuración definidos.
### Programación de la configuración
-La clase `Config.cs` mantienen los valores permitidos a usar como parámetros predefinidos en el archivo de configuración de la aplicación.
+La clase `Config.cs` mantienen los valores permitidos a usar como parámetros predefinidos en el archivo de configuración de la aplicación.
+
+Cada nuevo parámetro de configuración debe ser agregado a esta clase.
Otras secciones del programa pueden requerir validar los valores recibidos por la configuración y según estos valores tomar acción. La clase `Config` mantiene los valores permitidos.
@@ -49,7 +51,9 @@ La siguiente es la secuencia de pasos que sigue el programa para procesar una so
Para soportar un nuevo tipo de POS, los pasos son:
1. Definir parámetro de configuración que indica el tipo de POS. En la clase `Constantes.cs` crear una constante con el valor esperado en el archivo de configuración `appsettings.json`, por ejemplo `gk_test`.
-2. Editar el archivo `appsettings.json` y asignar al parámetro `GatewayConfig`:`POS` el valor que identifica el tipo de POS, por ejemplo `gk_test`.
+ 1. Si es necesario, crear una clase con parémtros particulares de configuración para la nueva POS, por ejemplo, una clase `ConfigGk` para los parémtros propios de la POS Gk.
+ 2. Crear en el archivo de configuración una sección para estos parámetros de configuración.
+2. Editar el archivo `appsettings.json` y asignar al parámetro `GatewayConfig`:`POS` el valor que identifica el tipo de POS, por ejemplo `gk_test`. Agregar la sección particular de la nueva POS si es el caso, según se indica en el paso anterior.
3. Crear una clase factory de directorio de comandos implementando `IDispensaDirectorioCmds`. Nombrar la clase `DispensaDirectorioCmds.cs`.
4. Editar la clase factory `DirectorioCmdsFactory` y agregar el nuevo dispensador al método `CreaDirectorioCmds` para que según el valor del parámetro de configuración seleccione el factory adecuado. A las clases factory de directorio de comandos se pasa como parámetro el objeto tipo `Config` para brindar acceso a las clases factory a parámetros en el archivo de configuración que puedan ser requeridos.
5. Crear una carpeta para almacenar las clases de comando. Llamar la carpeta `Comandos`, por ejemplo `ComandosGkPruebas`.
diff --git a/gatewayGK/Infraestructura/ConfigGk.cs b/gatewayGK/Infraestructura/ConfigGk.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e74caad1b37abdd886f8b98986b564e6ad551a68
--- /dev/null
+++ b/gatewayGK/Infraestructura/ConfigGk.cs
@@ -0,0 +1,34 @@
+///
+/// Clase que representa los parámetros de configuración de la aplicación
+/// registrados en el archivo appsettings.json asociados a Gk Smart POS.
+///
+public sealed class ConfigGk
+{
+ public required string IpGkSmartPOS { get; set; } = "127.0.0.1";
+ public required int PortGkSmartPOS { get; set; } = 8443;
+ public required string TenantId { get; set; } = "";
+ public required string RetailStoreId { get; set; } = "";
+ public required string WorkstationId { get; set; } = "";
+ public required string WorkstationAddress { get; set; } = "";
+ public required string WorkstationTypeCode { get; set; } = "";
+ public required string LoginName { get; set; } = "";
+ public required string Password { get; set; } = "";
+ public required string BusinessUnitGroupID { get; set; } = "";
+ public required string TillID { get; set; } = "";
+
+ public override string ToString()
+ {
+ return base.ToString() + " - "
+ + $"IpGkSmartPOS: '{IpGkSmartPOS}', "
+ + $"PortGkSmartPOS: '{PortGkSmartPOS}', "
+ + $"TenantId: '{TenantId}', "
+ + $"RetailStoreId: '{RetailStoreId}', "
+ + $"WorkstationId: '{WorkstationId}', "
+ + $"WorkstationAddress: '{WorkstationAddress}', "
+ + $"WorkstationTypeCode: '{WorkstationTypeCode}', "
+ + $"LoginName: '{LoginName}', "
+ + $"Password: '{Password}', "
+ + $"BusinessUnitGroupID: '{BusinessUnitGroupID}', "
+ + $"TillID: '{TillID}'";
+ }
+}
\ No newline at end of file
diff --git a/gatewayGK/Infraestructura/DirectorioCmdsFactory.cs b/gatewayGK/Infraestructura/DirectorioCmdsFactory.cs
index e18f3e224ed97c0575dcd28ce40741a6fe59b3d0..eee50aad0967c8e7085e60e93b9b896c850fd9de 100644
--- a/gatewayGK/Infraestructura/DirectorioCmdsFactory.cs
+++ b/gatewayGK/Infraestructura/DirectorioCmdsFactory.cs
@@ -6,18 +6,18 @@ using GatewaySCO;
///
public class DirectorioCmdsFactory
{
- public static CreaDirectorioCmds CreaDirectorio(Config config)
+ public static CreaDirectorioCmds CreaDirectorio(string tipoPOS)
{
- switch (config.POS)
+ switch (tipoPOS)
{
case "pruebas":
- return DispensaDirectorioCmdsPruebas.Dispensa(config);
+ return DispensaDirectorioCmdsPruebas.Dispensa();
case "evapos":
- return DispensaDirectorioCmdsEvaPOS.Dispensa(config);
+ return DispensaDirectorioCmdsEvaPOS.Dispensa();
case "gk":
- return DispensaDirectorioCmdsGK.Dispensa(config);
+ return DispensaDirectorioCmdsGK.Dispensa();
case "gk_test":
- return DispensaDirectorioCmdsGKPruebas.Dispensa(config);
+ return DispensaDirectorioCmdsGKPruebas.Dispensa();
default:
throw new ArgumentException("TipoPOS no válido", "tipoPOS");
}
diff --git a/gatewayGK/Infraestructura/DispensaDirectorioCmdsEvaPOS.cs b/gatewayGK/Infraestructura/DispensaDirectorioCmdsEvaPOS.cs
index 9690ab3970ab0a992990dcad09a60a5cf9d473c2..23cbafe0fd2fb88a3cad31d5502af392e49e8189 100644
--- a/gatewayGK/Infraestructura/DispensaDirectorioCmdsEvaPOS.cs
+++ b/gatewayGK/Infraestructura/DispensaDirectorioCmdsEvaPOS.cs
@@ -11,7 +11,7 @@ public class DispensaDirectorioCmdsEvaPOS : IDispensaDirectorioCmds
/// Retorna directorio de comandos instanciado y poblado de
/// comandos.
///
- public static CreaDirectorioCmds Dispensa(Config config)
+ public static CreaDirectorioCmds Dispensa()
{
Log.Information("Instancia comandos EvaPOS.");
throw new NotImplementedException();
diff --git a/gatewayGK/Infraestructura/DispensaDirectorioCmdsGK.cs b/gatewayGK/Infraestructura/DispensaDirectorioCmdsGK.cs
index b73431eee6e5eca2c6de37cd049980db6d2ee15d..be548382c399a79bc8d446fda85dda4c3232e90b 100644
--- a/gatewayGK/Infraestructura/DispensaDirectorioCmdsGK.cs
+++ b/gatewayGK/Infraestructura/DispensaDirectorioCmdsGK.cs
@@ -12,7 +12,7 @@ public class DispensaDirectorioCmdsGK : IDispensaDirectorioCmds
/// Retorna directorio de comandos instanciado y poblado de
/// comandos.
///
- public static CreaDirectorioCmds Dispensa(Config config)
+ public static CreaDirectorioCmds Dispensa()
{
Log.Information("Instancia comandos de GK Smart POS.");
return new IniciaDirectorioCmds()
diff --git a/gatewayGK/Infraestructura/DispensaDirectorioCmdsGKPruebas.cs b/gatewayGK/Infraestructura/DispensaDirectorioCmdsGKPruebas.cs
index 4faa8587b68d97bb468aa6b6692e90324ddd97c9..ce57d5f7eeb6585f7289c9c08ea5ec874bd8c9c9 100644
--- a/gatewayGK/Infraestructura/DispensaDirectorioCmdsGKPruebas.cs
+++ b/gatewayGK/Infraestructura/DispensaDirectorioCmdsGKPruebas.cs
@@ -12,13 +12,9 @@ public class DispensaDirectorioCmdsGKPruebas : IDispensaDirectorioCmds
/// Retorna directorio de comandos instanciado y poblado de
/// comandos.
///
- public static CreaDirectorioCmds Dispensa(Config config)
+ public static CreaDirectorioCmds Dispensa()
{
Log.Information("Instancia comandos de GK de prueba.");
- // Inicializa el entorno para los comandos.
- EntornoGK e = new EntornoGK();
- e.Language = config.Language;
- Entorno.Instancia.setDatos(e);
return new IniciaDirectorioCmds()
.AgregaCmd(new Gk.InitializeRequestCmd())
diff --git a/gatewayGK/Infraestructura/DispensaDirectorioCmdsPrueba.cs b/gatewayGK/Infraestructura/DispensaDirectorioCmdsPrueba.cs
index 6707174ea370a5a9a64cffac9f9765c94e43fc8d..21b03e6c7a565e6bf1c9a699d2c812ec1a03d0c1 100644
--- a/gatewayGK/Infraestructura/DispensaDirectorioCmdsPrueba.cs
+++ b/gatewayGK/Infraestructura/DispensaDirectorioCmdsPrueba.cs
@@ -11,7 +11,7 @@ public class DispensaDirectorioCmdsPruebas : IDispensaDirectorioCmds
/// Retorna directorio de comandos instanciado y poblado de
/// comandos.
///
- public static CreaDirectorioCmds Dispensa(Config config)
+ public static CreaDirectorioCmds Dispensa()
{
Log.Information("Instancia comandos de prueba.");
return new IniciaDirectorioCmds()
diff --git a/gatewayGK/Infraestructura/Entorno.cs b/gatewayGK/Infraestructura/Entorno.cs
index b6ab2fe6d62605552d95c417330baf4cbb6d2388..de69d4464ce985cdb4d5b4b2bb4f004bd5f1907b 100644
--- a/gatewayGK/Infraestructura/Entorno.cs
+++ b/gatewayGK/Infraestructura/Entorno.cs
@@ -32,7 +32,7 @@ namespace GatewaySCO
///
/// Obtener datos de entorno.
///
- public T getDatos()
+ public T get()
{
if (_datos == null)
{
@@ -44,7 +44,7 @@ namespace GatewaySCO
///
/// Fijar datos de entorno.
///
- public void setDatos(T datos)
+ public void set(T datos)
{
_datos = datos;
}
diff --git a/gatewayGK/Infraestructura/IDispensaDirectorioCmds.cs b/gatewayGK/Infraestructura/IDispensaDirectorioCmds.cs
index 05faaa0829df5de267228b122cc0d3cd53b0d07c..9ebd14b28a90c89c28e656f111272cf12226e67b 100644
--- a/gatewayGK/Infraestructura/IDispensaDirectorioCmds.cs
+++ b/gatewayGK/Infraestructura/IDispensaDirectorioCmds.cs
@@ -7,5 +7,5 @@
///
/// Dispensa un directorio de comandos inicializados.
///
- static abstract CreaDirectorioCmds Dispensa(Config config);
+ static abstract CreaDirectorioCmds Dispensa();
}
\ No newline at end of file
diff --git a/gatewayGK/Infraestructura/EvaPosUtil.cs b/gatewayGK/Infraestructura/Util.cs
similarity index 73%
rename from gatewayGK/Infraestructura/EvaPosUtil.cs
rename to gatewayGK/Infraestructura/Util.cs
index 8ef4a22768fd86b1447daeb9d9ff32f3ab49114a..36ef902dfc8d8fc50b1af807080426fb1045fbf6 100644
--- a/gatewayGK/Infraestructura/EvaPosUtil.cs
+++ b/gatewayGK/Infraestructura/Util.cs
@@ -1,10 +1,11 @@
+using System.Text.RegularExpressions;
using System.Xml;
namespace GatewaySCO
{
///
- /// Clase Utilistarios para operaciones sobre mensajes.
+ /// Clase Utilitarios para operaciones sobre mensajes.
///
public class Util
{
@@ -53,7 +54,7 @@ namespace GatewaySCO
///
/// Lee valor long de entidad XML indicada por xpath..
///
- public static long LeeLongEnNodo(XmlNode nodo,string xpath)
+ public static long LeeLongEnNodo(XmlNode nodo, string xpath)
{
long valor = 0;
XmlNode? xnodo = nodo.SelectSingleNode(xpath);
@@ -108,5 +109,32 @@ namespace GatewaySCO
throw new Exception($"Nodo '{xpath}' con contenido nulo.");
return valor;
}
+
+ ///
+ /// Remplaza contenido entre caracteres <| y |> por valores pasados como parémtros, en orden.
+ /// Si el número de conenidos y de parámetros no corresponde, lanza excepción.
+ /// Ejemplo: "Texto con <|o1|> para remplazar, junto con <|o2|>", si o1=123 y o2=true
+ /// da como resultado: "Texto con 123 para remplazar, junto con true"
+ ///
+ public static string ReplaceValuesInString(string inputString, params object[] values)
+ {
+ string pattern = @"<\|([^|]+)\|>";
+ Regex regex = new Regex(pattern);
+
+ MatchEvaluator evaluator = (match) =>
+ {
+ string variableName = match.Groups[1].Value;
+ int index = int.Parse(variableName.Substring(1));
+ if (index >= 0 && index < values.Length)
+ {
+ return Convert.ToString(values[index])
+ ?? throw new ArgumentException($"ReplaceValuesInString: values {values}, index {index}");
+ }
+ return match.Value;
+ };
+
+ string result = regex.Replace(inputString, evaluator);
+ return result;
+ }
}
}
\ No newline at end of file
diff --git a/gatewayGK/NotasCambios.md b/gatewayGK/NotasCambios.md
new file mode 100644
index 0000000000000000000000000000000000000000..6207c4f06881ec9f10280e71344669bf334066ec
--- /dev/null
+++ b/gatewayGK/NotasCambios.md
@@ -0,0 +1,12 @@
+# Notas cambios al programa
+
+## 2 Agosto 2023
+
+- Url base de Gk Smart POS se mueve al entorno.
+- Se crea clase ConfigGk.
+
+## 4 agosto
+
+- Manejar errores servicios web, ejemplo:
+ {"errorCode":{"errorCode":"GKR-POS-000001","message":"Invalid session","messageKey":"com.gk_software.pos.utils.error.ErrorCodeMessages.MSG_INVALID_SESSION","arguments":[]},"timestamp":"2023-08-04T07:16:57.066","additionalContextInfoMap":{}}
+- El manejo de headers, la cookie no es obligatoria, para pasar la sessión este es obligatorio: request.AddHeader("_pos_session_", sessionId);
\ No newline at end of file
diff --git a/gatewayGK/POSGk/AddItemRequ.cs b/gatewayGK/POSGk/AddItemRequ.cs
index 1e995c275846d2357a3a46ce509737e69fdc59c1..1164fc4412a3b24c34569c76603d761d865da519 100644
--- a/gatewayGK/POSGk/AddItemRequ.cs
+++ b/gatewayGK/POSGk/AddItemRequ.cs
@@ -1,10 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace gatewayGK.POSGk
+namespace gatewayGK.POSGk
{
using System.Text.Json.Serialization;
diff --git a/gatewayGK/POSGk/AuthenticateResp.cs b/gatewayGK/POSGk/AuthenticateResp.cs
index 71c4ce4411ab3d3c35ffa290ddcef648d1907456..4da30815bf96e6098738041a223f89e17e1e1c16 100644
--- a/gatewayGK/POSGk/AuthenticateResp.cs
+++ b/gatewayGK/POSGk/AuthenticateResp.cs
@@ -5,45 +5,37 @@ namespace SCOGateway.POSGk
{
public class AuthenticateResp
{
- [JsonPropertyName("primaryEntry")]
- public PrimaryEntry primaryEntry { get; set; }
- [JsonPropertyName("posSessionId")]
- public PosSessionId posSessionId { get; set; }
+ [JsonPropertyName("primaryEntry")] public PrimaryEntry primaryEntry { get; set; }
+ [JsonPropertyName("posSessionId")] public PosSessionId posSessionId { get; set; }
}
public class PosSessionId
{
- [JsonPropertyName("id")]
- public string id { get; set; }
+ [JsonPropertyName("id")] public string id { get; set; }
}
public class PrimaryEntry
{
- [JsonPropertyName("transaction")]
- public Transaction transaction { get; set; }
+ [JsonPropertyName("transaction")] public Transaction transaction { get; set; }
}
public class Transaction
{
- [JsonPropertyName("key")]
- public Key key { get; set; }
- [JsonPropertyName("operatorID")]
- public string operatorID { get; set; }
- [JsonPropertyName("posSessionId")]
- public Id posSessionId { get; set; }
+ [JsonPropertyName("key")] public Key key { get; set; }
+ [JsonPropertyName("operatorID")] public string operatorID { get; set; }
+ [JsonPropertyName("posSessionId")] public Id posSessionId { get; set; }
+ [JsonPropertyName("success")] public bool success { get; set; }
}
public class Id
{
[JsonPropertyName("id")]
- public string id { get; set; }
+ public string id { get; set; }
}
public class Key
{
- [JsonPropertyName("transactionID")]
- public string transactionID { get; set; }
- [JsonPropertyName("businessUnitGroupID")]
- public string businessUnitGroupID { get; set; }
+ [JsonPropertyName("transactionID")] public string transactionID { get; set; }
+ [JsonPropertyName("businessUnitGroupID")] public string businessUnitGroupID { get; set; }
}
}
\ No newline at end of file
diff --git a/gatewayGK/POSGk/EntornoGK.cs b/gatewayGK/POSGk/EntornoGK.cs
index 87c3269778b8d7b68a6021883b3cb8dad3e1dc4b..e29a12b5a83f25a6d8f2313be4660ee1a4be035e 100644
--- a/gatewayGK/POSGk/EntornoGK.cs
+++ b/gatewayGK/POSGk/EntornoGK.cs
@@ -17,11 +17,42 @@ public class EntornoGK
public string TransactionID { get; set; } = "";
- public string SeccionId { get; set; } = "";
+ public string SessionId { get; set; } = "";
public string posSessionId { get; set; } = "";
+ ///
+ /// Gk - BusinessUnitGroupID requerido para request a Smart Pos en transacciones
+ /// asociadas a venta.
+ ///
+ public string BusinessUnitGroupID { get; set; } = "";
///
/// GK Language.
///
public string Language { get; set; } = "en";
+
+ private string? _urlBase;
+ private ConfigGk? _configGk;
+
+ ///
+ /// Parámetros de configuración Gk Smart POS.
+ /// Inicializados desde el archivo de configuración.
+ ///
+ public ConfigGk ConfigGk
+ {
+ get => _configGk ?? throw new ApplicationException("ConfigGk no definido.");
+ set
+ {
+ _configGk = value;
+ _urlBase = $"https://{value.IpGkSmartPOS}:{value.PortGkSmartPOS}/smartpos-service/tenants/{value.TenantId}/services";
+ }
+ }
+
+ ///
+ /// Url base de servicios Gk Smart POS.
+ ///
+ public string UrlBase
+ {
+ get => _urlBase ?? throw new ApplicationException("UrlBase no inicializada.");
+ private set { }
+ }
}
\ No newline at end of file
diff --git a/gatewayGK/POSGk/LogoutReq.cs b/gatewayGK/POSGk/LogoutReq.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7bb401b6c88926416ca925a287cb0aacf605aaa4
--- /dev/null
+++ b/gatewayGK/POSGk/LogoutReq.cs
@@ -0,0 +1,16 @@
+using System.Text.Json.Serialization;
+
+namespace SCOGateway.POSGk
+{
+ ///
+ /// Registro para Logout a cliente Smart POS GK.
+ ///
+ public record LogoutReq
+ {
+ [JsonPropertyName("posSessionId")]
+ public PosSessionId PosSessionId { get; set; }
+
+ [JsonPropertyName("posGroupOperatorActive")]
+ public bool PosGroupOperatorActive { get; set; } = true;
+ }
+}
\ No newline at end of file
diff --git a/gatewayGK/POSGk/LogoutResp.cs b/gatewayGK/POSGk/LogoutResp.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9d6bc0422af77db89e65579228706ca0c8fd826f
--- /dev/null
+++ b/gatewayGK/POSGk/LogoutResp.cs
@@ -0,0 +1,13 @@
+using System.Text.Json.Serialization;
+
+namespace SCOGateway.POSGk
+{
+ ///
+ /// Registro para Logout a cliente Smart POS GK.
+ ///
+ public record LogoutResp
+ {
+ [JsonPropertyName("primaryEntry")] public PrimaryEntry primaryEntry { get; set; }
+ public bool success { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/gatewayGK/POSGk/RegisterLineItemReq.cs b/gatewayGK/POSGk/RegisterLineItemReq.cs
new file mode 100644
index 0000000000000000000000000000000000000000..39b268ee969e2a98c220988a133579a0bd84dccf
--- /dev/null
+++ b/gatewayGK/POSGk/RegisterLineItemReq.cs
@@ -0,0 +1,102 @@
+namespace gatewayGK.POSGk
+{
+ public record operationConfiguration
+ {
+ public bool forceQuantityInput { get; init; } = false;
+ public int pricePositionLimit { get; init; } = 10000; // TODO - controlar este valor, como sacarlo del Smart POS.
+ public bool pricePositionZeroAllowed { get; init; } = true;
+ public int priceTransactionLimit { get; init; } = -1;
+ public int priceDifferencePercentPositionLimit { get; init; } = 100;
+ public int priceDifferenceAbsolutePositionLimit { get; init; } = 999999;
+ public string priceDifferenceLimitExceedAction { get; init; } = "Warn";
+ public string priceNegDifferenceLimitExceedAction { get; init; } = "Warn";
+ public string closeCurrent { get; init; } = "Required";
+ public string closePrevious { get; init; } = "Required";
+ public bool filterResult { get; init; } = true;
+ public bool allowedWithWeight { get; init; } = true;
+ public bool allowedWithLength { get; init; } = true;
+ public bool allowedWithArea { get; init; } = true;
+ public bool allowedWithVolume { get; init; } = true;
+ public bool allowedWithMeasure { get; init; } = true;
+ public int maximumQuantity { get; init; } = 999999;
+ public int minimumQuantity { get; init; } = 1;
+ public string quantityInputOrder { get; init; } = "BeforeOrAfter";
+ public string priceInputOrder { get; init; } = "BeforeOrAfter";
+ public string quantityLimitExceedAction { get; init; } = "Warn";
+ public string amountLimitExceedAction { get; init; } = "Warn";
+ public int weightUnitFactor { get; init; } = 0;
+ public int measureUnitFactor { get; init; } = 0;
+ public string priceDeviationType { get; init; } = "All";
+ public string priceNegDeviationType { get; init; } = "All";
+ public string xXCustom08 { get; init; } = "string";
+ public string xXCustom10 { get; init; } = "string";
+ public string xXCustom09 { get; init; } = "string";
+ public string xXCustom07 { get; init; } = "string";
+ public string xXCustom05 { get; init; } = "string";
+ public string xXCustom06 { get; init; } = "string";
+ public string xXCustom11 { get; init; } = "string";
+ public string xXCustom12 { get; init; } = "string";
+ public string xXCustom13 { get; init; } = "string";
+ public string xXCustom14 { get; init; } = "string";
+ public string xXCustom15 { get; init; } = "string";
+ public string xXCustom03 { get; init; } = "string";
+ public string xXCustom02 { get; init; } = "string";
+ public string xXCustom04 { get; init; } = "string";
+ public string xXCustom01 { get; init; } = "string";
+ }
+
+ public record itemEntryConfig
+ {
+ public bool forceQuantityInput { get; init; } = true;
+ public int pricePositionLimit { get; init; } = 0;
+ public bool pricePositionZeroAllowed { get; init; } = true;
+ public int priceTransactionLimit { get; init; } = 0;
+ public int priceDifferencePercentPositionLimit { get; init; } = 0;
+ public int priceDifferenceAbsolutePositionLimit { get; init; } = 0;
+ public string priceDifferenceLimitExceedAction { get; init; } = "Warn";
+ public string priceNegDifferenceLimitExceedAction { get; init; } = "Warn";
+ public string closeCurrent { get; init; } = "Required";
+ public string closePrevious { get; init; } = "Required";
+ public bool filterResult { get; init; } = true;
+ public bool allowedWithWeight { get; init; } = true;
+ public bool allowedWithLength { get; init; } = true;
+ public bool allowedWithArea { get; init; } = true;
+ public bool allowedWithVolume { get; init; } = true;
+ public bool allowedWithMeasure { get; init; } = true;
+ public int maximumQuantity { get; init; } = 0;
+ public int minimumQuantity { get; init; } = 0;
+ public string quantityInputOrder { get; init; } = "BeforeOrAfter";
+ public string priceInputOrder { get; init; } = "BeforeOrAfter";
+ public string quantityLimitExceedAction { get; init; } = "Warn";
+ public int weightUnitFactor { get; init; } = 0;
+ public int measureUnitFactor { get; init; } = 0;
+ public string priceDeviationType { get; init; } = "All";
+ public string priceNegDeviationType { get; init; } = "All";
+ public string xXCustom01 { get; init; } = "string";
+ public string xXCustom02 { get; init; } = "string";
+ public string xXCustom03 { get; init; } = "string";
+ public string xXCustom04 { get; init; } = "string";
+ public string xXCustom05 { get; init; } = "string";
+ public string xXCustom06 { get; init; } = "string";
+ public string xXCustom07 { get; init; } = "string";
+ public string xXCustom08 { get; init; } = "string";
+ public string xXCustom09 { get; init; } = "string";
+ public string xXCustom10 { get; init; } = "string";
+ public string xXCustom11 { get; init; } = "string";
+ public string xXCustom12 { get; init; } = "string";
+ public string xXCustom13 { get; init; } = "string";
+ public string xXCustom14 { get; init; } = "string";
+ public string xXCustom15 { get; init; } = "string";
+ }
+
+ public record registerLineItemReq
+ {
+ public operationConfiguration operationConfiguration { get; init; } = new operationConfiguration();
+ public string barcode { get; init; } = "";
+ public bool salesRestrictionsCheckNeeded { get; init; } = false;
+ public string priceVariant { get; init; } = "Actual";
+ public itemEntryConfig itemEntryConfig { get; init; } = new itemEntryConfig();
+ public string entryMethodCode { get; init; } = "Keyed";
+ public bool keyedOnline { get; init; } = true;
+ }
+}
diff --git a/gatewayGK/POSGkSwaggerModel/Client/ApiClient.cs_ b/gatewayGK/POSGkSwaggerModel/Client/ApiClient.cs_
new file mode 100644
index 0000000000000000000000000000000000000000..ba48325ee299f52647ba4700e0a34af32f03f4cc
--- /dev/null
+++ b/gatewayGK/POSGkSwaggerModel/Client/ApiClient.cs_
@@ -0,0 +1,530 @@
+/*
+ * GK application - OmniPOS Service API
+ *
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
+ *
+ * OpenAPI spec version: 5.21.1-b03
+ *
+ * Generated by: https://github.com/swagger-api/swagger-codegen.git
+ */
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text.RegularExpressions;
+using System.IO;
+using System.Web;
+using System.Linq;
+using System.Net;
+using System.Text;
+using Newtonsoft.Json;
+using RestSharp;
+
+namespace IO.Swagger.Client
+{
+ ///
+ /// API client is mainly responsible for making the HTTP call to the API backend.
+ ///
+ public partial class ApiClient
+ {
+ private JsonSerializerSettings serializerSettings = new JsonSerializerSettings
+ {
+ ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor
+ };
+
+ ///
+ /// Allows for extending request processing for generated code.
+ ///
+ /// The RestSharp request object
+ partial void InterceptRequest(IRestRequest request);
+
+ ///
+ /// Allows for extending response processing for generated code.
+ ///
+ /// The RestSharp request object
+ /// The RestSharp response object
+ partial void InterceptResponse(IRestRequest request, IRestResponse response);
+
+ ///
+ /// Initializes a new instance of the class
+ /// with default configuration.
+ ///
+ public ApiClient()
+ {
+ Configuration = IO.Swagger.Client.Configuration.Default;
+ RestClient = new RestClient("https://localhost:8080/pos-service/tenants//services/_**");
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// with default base path (https://localhost:8080/pos-service/tenants//services/_**).
+ ///
+ /// An instance of Configuration.
+ public ApiClient(Configuration config)
+ {
+ Configuration = config ?? IO.Swagger.Client.Configuration.Default;
+
+ RestClient = new RestClient(Configuration.BasePath);
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// with default configuration.
+ ///
+ /// The base path.
+ public ApiClient(String basePath = "https://localhost:8080/pos-service/tenants//services/_**")
+ {
+ if (String.IsNullOrEmpty(basePath))
+ throw new ArgumentException("basePath cannot be empty");
+
+ RestClient = new RestClient(basePath);
+ Configuration = Client.Configuration.Default;
+ }
+
+ ///
+ /// Gets or sets the default API client for making HTTP calls.
+ ///
+ /// The default API client.
+ [Obsolete("ApiClient.Default is deprecated, please use 'Configuration.Default.ApiClient' instead.")]
+ public static ApiClient Default;
+
+ ///
+ /// Gets or sets an instance of the IReadableConfiguration.
+ ///
+ /// An instance of the IReadableConfiguration.
+ ///
+ /// helps us to avoid modifying possibly global
+ /// configuration values from within a given client. It does not guarantee thread-safety
+ /// of the instance in any way.
+ ///
+ public IReadableConfiguration Configuration { get; set; }
+
+ ///
+ /// Gets or sets the RestClient.
+ ///
+ /// An instance of the RestClient
+ public RestClient RestClient { get; set; }
+
+ // Creates and sets up a RestRequest prior to a call.
+ private RestRequest PrepareRequest(
+ String path, RestSharp.Method method, List> queryParams, Object postBody,
+ Dictionary headerParams, Dictionary formParams,
+ Dictionary fileParams, Dictionary pathParams,
+ String contentType)
+ {
+ var request = new RestRequest(path, method);
+
+ // add path parameter, if any
+ foreach(var param in pathParams)
+ request.AddParameter(param.Key, param.Value, ParameterType.UrlSegment);
+
+ // add header parameter, if any
+ foreach(var param in headerParams)
+ request.AddHeader(param.Key, param.Value);
+
+ // add query parameter, if any
+ foreach(var param in queryParams)
+ request.AddQueryParameter(param.Key, param.Value);
+
+ // add form parameter, if any
+ foreach(var param in formParams)
+ request.AddParameter(param.Key, param.Value);
+
+ // add file parameter, if any
+ foreach(var param in fileParams)
+ {
+ request.AddFile(param.Value.Name, param.Value.Writer, param.Value.FileName, param.Value.ContentType);
+ }
+
+ if (postBody != null) // http body (model or byte[]) parameter
+ {
+ request.AddParameter(contentType, postBody, ParameterType.RequestBody);
+ }
+
+ return request;
+ }
+
+ ///
+ /// Makes the HTTP request (Sync).
+ ///
+ /// URL path.
+ /// HTTP method.
+ /// Query parameters.
+ /// HTTP body (POST request).
+ /// Header parameters.
+ /// Form parameters.
+ /// File parameters.
+ /// Path parameters.
+ /// Content Type of the request
+ /// Object
+ public Object CallApi(
+ String path, RestSharp.Method method, List> queryParams, Object postBody,
+ Dictionary headerParams, Dictionary formParams,
+ Dictionary fileParams, Dictionary pathParams,
+ String contentType)
+ {
+ var request = PrepareRequest(
+ path, method, queryParams, postBody, headerParams, formParams, fileParams,
+ pathParams, contentType);
+
+ // set timeout
+
+ RestClient.Timeout = Configuration.Timeout;
+ // set user agent
+ RestClient.UserAgent = Configuration.UserAgent;
+
+ InterceptRequest(request);
+ var response = RestClient.Execute(request);
+ InterceptResponse(request, response);
+
+ return (Object) response;
+ }
+ ///
+ /// Makes the asynchronous HTTP request.
+ ///
+ /// URL path.
+ /// HTTP method.
+ /// Query parameters.
+ /// HTTP body (POST request).
+ /// Header parameters.
+ /// Form parameters.
+ /// File parameters.
+ /// Path parameters.
+ /// Content type.
+ /// The Task instance.
+ public async System.Threading.Tasks.Task