Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2 Worker Services to one thermical printer #251

Open
detectivejd opened this issue Nov 17, 2023 · 2 comments
Open

2 Worker Services to one thermical printer #251

detectivejd opened this issue Nov 17, 2023 · 2 comments

Comments

@detectivejd
Copy link

Hi, how are you? I wait that you are good, I have the next trouble:

I´m using 2 worker services implemented in C# .net7 one to ticket impress and other to bills impress but they don´t found of simultane form.
I show you the images:

ticket impress
image

bills impress
image

The Impress Code is the next:

Ticket Impress

using System.Text;
using ViewParking.Tickets.Raspberry.Entities;
using ViewParking.Tickets.Raspberry.Utilidades;
using Logging = ViewParking.Tickets.Raspberry.Utilidades.Logging;

namespace ViewParking.Tickets.Raspberry.Impresion;

public class EntradaImpresion {
    private string URL_API = "";
    private string RutaArchivoLog = "";
    private bool UsaTicketExtendido = false;
    private long IdClienteTicketEspecial = 0;
    private int TiempoCicloChequeo;
    private EnvioImpresion? prnt;
    //private readonly string carril;
    private List<int> Impresoras = new();
    private bool ImprimoAutomaticos;


    public EntradaImpresion()
    {        
        try
        {
            var configuration = new ConfigurationBuilder()
                .AddJsonFile("appsettings.json", true, true)
                .AddEnvironmentVariables()
                .Build();

            URL_API = configuration.GetValue<string>("URL_API") ?? "";

            var properties = configuration.GetSection("Default");
            RutaArchivoLog = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Log");

            var impresorasConf = properties.GetValue<string>("Impresoras") ?? "";
            Impresoras = CargarImpresoras(impresorasConf.Split(','));

            ImprimoAutomaticos = properties.GetValue<bool>("TomaAutomaticos"); 

            TiempoCicloChequeo = properties.GetValue<int>("TiempoCicloServicioMilisegundos");

            UsaTicketExtendido = properties.GetValue<bool>("UtilizaFormatoTicketExtendido");

            if (UsaTicketExtendido)
            {
                if (properties.GetValue<int>("IdClienteTicketEspecial") > 0)
                    IdClienteTicketEspecial = properties.GetValue<int>("IdClienteTicketEspecial");
                else
                    throw new Exception("La configuracion no tiene el identificador de IdCliente para tickets personalizados");
            }

            prnt = new EnvioImpresion(properties.GetValue<string>("Impresora"))
            {
                CantLineasEnBlancoAntesDelCabezal = properties.GetValue<int>("LineasEnBlancoEnCabezal"),
                CantLineasEnBlancoDespuesDelPie = properties.GetValue<int>("LineasEnBlancoAlPie"),
                ActivarNumeracionTickets = properties.GetValue<bool>("ActivarNumeracionTicket")
            };
        }
        catch (Exception ex)
        {
            Logging.Instancia().LogError(ex,  RutaArchivoLog);
        }
    }

    private List<int> CargarImpresoras(string[] pImpresoras)
    {
        var listaRet = new List<int>();

        foreach(string st in pImpresoras)
        {
            listaRet.Add(Convert.ToInt32(st));
        }

        return listaRet;
    }

    public void Iniciar()    
    {
        try
        {
            Console.WriteLine("--");
            Console.WriteLine("Start");
            TrabajarImpresion();
            //Logging.Instancia().LogMensajeImpresionTickets("OnStart - Se inicio el proceso de impresión de tickets correctamente. Version: " + Assembly.GetEntryAssembly().GetName().Version.ToString(), rutaArchivoLog);
        }
        catch (Exception ex)
        {
            Logging.Instancia().LogError(ex, RutaArchivoLog);
        }
    }

    private void TrabajarImpresion()
    {
        Console.WriteLine("DoWork");
       
        try
        {
            var consume = Consumidor.Instancia().PostAsync<object, Entrada>(
                URL_API  + "ObtenerEntradaServicioTickets",  
                new {
                    Impresoras = Impresoras.ToArray(),
                    ImprimeAutomaticos = ImprimoAutomaticos
                }
            ).Result;

            if(consume.StatusCode == System.Net.HttpStatusCode.OK)
            {              
                if(consume.Response != null){
                    var nuevaEntrada = consume.Response;

                    if (nuevaEntrada.Automatico)
                    {
                        Logging.Instancia().LogMensajeImpresionTickets("Se imprimió un ticket automáticamente: " + nuevaEntrada.Matricula, RutaArchivoLog);
                        EnviarImpresionAutomatica(nuevaEntrada);
                        Console.WriteLine("Se imprimió un ticket automáticamente: " + nuevaEntrada.Matricula);
                    }
                    else
                    {
                        Logging.Instancia().LogMensajeImpresionTickets("Se imprimió un ticket: " + nuevaEntrada.Matricula, RutaArchivoLog);
                        ImprimirTicket(nuevaEntrada);
                        Console.WriteLine("Se imprimió un ticket: " + nuevaEntrada.Matricula);
                    }

                    var borrado = Consumidor.Instancia().PostAsync<string, object>(
                        URL_API  + "EliminarEntrada?idImpresionEntrada=" + nuevaEntrada.IdImpresionEntrada,
                        ""
                    ).Result;

                    if (borrado.StatusCode == System.Net.HttpStatusCode.OK)
                    {
                        var esExito = Convert.ToBoolean(borrado.Response);
                        if (esExito)
                        {
                            Logging.Instancia().LogMensajeImpresionFacturas("Se borró el ticket de la matrícla " + nuevaEntrada.Matricula);
                        }
                    }
                }
            }   
        }
        catch (Exception ex)
        {
            Logging.Instancia().LogError(ex, RutaArchivoLog);
        }
    }

    private void ImprimirTicket(Entrada ticket)
    {
        var configuration = new ConfigurationBuilder()
                .AddJsonFile("appsettings.json", true, true)
                .AddEnvironmentVariables()
                .Build();
        
        var properties = configuration.GetSection("Default");

        try
        {
            for (int i = 0; i < ticket.Cantidad; i++)
            {
                if (UsaTicketExtendido && ticket.ClienteId == properties.GetValue<int>("IdClienteTicketEspecial"))
                    prnt?.RealizarImpresionTicketEspecial(ticket);
                else 
                    prnt?.RealizarImpresionTicketIngreso(ticket);
            }
        }
        catch (Exception ex)
        {
            Logging.Instancia().LogError(ex, RutaArchivoLog);
        }
    }
    ....
}

Bills Impress:

using System;
using ViewParking.Facturas.Raspberry.Entities;
using ViewParking.Facturas.Raspberry.Utilidades;
using Logging = ViewParking.Facturas.Raspberry.Utilidades.Logging;

namespace ViewParking.Facturas.Raspberry.Impresion
{
    public class EntradaImpresion
    {
        private List<int> terminales;
        private string URL_API = "";
        private string RutParking = "";
        private string DireccionParking = "";
        private string TelefonoParking = "";
        private string RazonSocial = "";
        private string RutaArchivoLog = "";
        private bool _parametrosCargados = false;
        private EnvioImpresion prnt;

        public EntradaImpresion()
        {
            var configuration = new ConfigurationBuilder()
                .AddJsonFile("appsettings.json", true, true)
                .AddEnvironmentVariables()
                .Build();

            URL_API = configuration.GetValue<string>("URL_API") ?? "";

            var properties = configuration.GetSection("Factura");
            RutaArchivoLog = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Log");

            var arrTerminales = (properties.GetValue<string>("Terminales") ?? "").Split(',');
            terminales = arrTerminales.Select(Int32.Parse).ToList();           

            prnt = new EnvioImpresion(
                properties.GetValue<string>("Impresora") ?? ""
            ) {
                URL_API = URL_API,
                RutaArchivoLog = RutaArchivoLog
            };

            CargarParametros();
        }

        private void CargarParametros()
        {
            try
            {
                var consume = Consumidor.Instancia().GetAsync<List<Parametro>>(
                    URL_API + "ObtenerTodosParametros"
                ).Result;
                if (consume.StatusCode == System.Net.HttpStatusCode.OK)
                {
                    if (consume.Response != null)
                    {
                        var parametros = consume.Response;

                        RutParking = parametros
                            .Where(p => p.Nombre.Equals("EMPRESA_RUT")
                            ).Select(p => p.Valor
                            ).FirstOrDefault() ?? "";

                        RazonSocial = parametros
                            .Where(p => p.Nombre.Equals("EMPRESA_RAZON_SOCIAL")
                            ).Select(p => p.Valor
                            ).FirstOrDefault() ?? "";

                        DireccionParking = parametros
                            .Where(p => p.Nombre.Equals("EMPRESA_DIRECCION")
                            ).Select(p => p.Valor
                            ).FirstOrDefault() ?? "";

                        TelefonoParking = parametros
                            .Where(p => p.Nombre.Equals("EMPRESA_TELEFONO")
                            ).Select(p => p.Valor
                            ).FirstOrDefault() ?? "";

                        _parametrosCargados = true;
                    }
                }

                string mensajePar = string.Format("Parámetros cargados!\nRUT: {0}, Razón Social: {1}, Dirección: {2}, Teléfono: {3}", RutParking, RazonSocial, DireccionParking, TelefonoParking);
                Logging.Instancia().LogMensajeImpresionFacturas(mensajePar);
                Console.WriteLine(mensajePar);
            }
            catch (Exception ex)
            {
                Logging.Instancia().LogMensajeImpresionFacturas("Error al obtener los parámetros. Probablemente el WS esté fuera de servicio\nRevisar log de errores :)");
                Logging.Instancia().LogError(ex, RutaArchivoLog);
            }
        }

        public void Iniciar()
        {
            try
            {
                Console.WriteLine("--");
                Console.WriteLine("Start");
                TrabajarImpresion();
            }
            catch (Exception ex)
            {
                Logging.Instancia().LogError(ex, RutaArchivoLog);
            }
        }

        private void TrabajarImpresion()
        {
            Console.WriteLine("DoWork");
            
            try
            {
                var listaCFE = new List<ImpresionCFE>();
                var consume = Consumidor.Instancia().PostAsync<List<int>, List<ImpresionCFE>>(
                    URL_API + "ObtenerCFEImprimir", terminales
                ).Result;

                if (consume.StatusCode == System.Net.HttpStatusCode.OK)
                {
                    if (consume.Response != null)
                    {
                        listaCFE = consume.Response;
                    }
                }

                if (listaCFE.Count != 0) //Si tengo algún CFE para imprimir
                {
                    Logging.Instancia().LogMensajeImpresionFacturas("--------------------------------------------------------");
                    //Recorro la lista de elementos recibidos
                    RealizarImpresion(listaCFE);
                }                
            }
            catch (Exception ex)
            {
                Logging.Instancia().LogMensajeImpresionFacturas("Error al obtener los tickets para imprimir. Probablemente el WS esté fuera de servicio\nRevisar log de errores :)");
                Logging.Instancia().LogError(ex, RutaArchivoLog);
            }
        }

        private void RealizarImpresion(List<ImpresionCFE> pListaCFEs)
        {
            if (_parametrosCargados)
            {
                try
                {
                    foreach (ImpresionCFE factTick in pListaCFEs)
                    {
                        Logging.Instancia().LogMensajeImpresionFacturas(string.Format(
                            "Serie: {0}, Número: {1}, Id: {2}", 
                            factTick.Serie, factTick.Numero, factTick.Id
                        ));

                        //Carga de datos principales
                        var tipoCFE = 111;
                        var nombreImpresora = factTick.NombreImpresora;
                        var nombreTerminal = factTick.NombreTerminal;
                        var imprimirTicketSinValor = (factTick.ImprimirTicketSinValor.HasValue && factTick.ImprimirTicketSinValor.Value);

                        //Obtengo el cabezal correspondiente
                        var docCabezal = factTick.Cabezal;

                        if (factTick.IdCabezal.HasValue)
                        {
                            //Cargo los datos principales del Cabezal
                            tipoCFE = docCabezal.TipoComprobante ?? 0;
                        }

                        if (!(factTick.IdCabezal.HasValue) || imprimirTicketSinValor)
                        {
                            //Imprimo ticket sin valor fiscal
                            prnt.ImprimirDocumentoSinProcesar(factTick);
                        }
                        else
                        {
                            var mensaje = string.Format(
                                "Antes de Imprimir \nNúmero: {0}, Serie: {1}, TipoCFE: {2}, " +
                                "Impresora: {3}, Terminal: {4}", 
                                docCabezal.Numero, docCabezal.Serie, docCabezal.TipoComprobante, 
                                factTick.NombreImpresora, factTick.NombreTerminal
                            );

                            Logging.Instancia().LogMensajeImpresionFacturas(mensaje);
                            
                            Logging.Instancia().LogMensajeImpresionFacturas(
                                string.Format(
                                    "Ticket en formato rollo (URUWARE). Número: {0}, Serie: {1}, " +
                                    "TipoCFE: {2}, Impresora: {3}, Terminal: {4}",
                                    docCabezal.Numero, docCabezal.Serie, docCabezal.TipoComprobante, 
                                    factTick.NombreImpresora, factTick.NombreTerminal
                                )
                            );

                            prnt.ImprimirURUWARE(RutParking, tipoCFE, docCabezal.Serie, docCabezal.Numero);
                        }

                        var borrado = Consumidor.Instancia().PostAsync<string, object>(
                            URL_API + "EliminarFacturaTicketImpresion?pIdFactTick=" + factTick.Id,
                            ""
                        ).Result;

                        if (borrado.StatusCode == System.Net.HttpStatusCode.OK)
                        {
                            var esExito = Convert.ToBoolean(borrado.Response);
                            if (esExito)
                            {
                                Logging.Instancia().LogMensajeImpresionFacturas("Se borró la factura " + docCabezal.Numero + docCabezal.Serie);
                            }                            
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logging.Instancia().LogMensajeImpresionFacturas("Error al obtener los tickets para imprimir. Probablemente el WS esté fuera de servicio\nRevisar log de errores :)");
                    Logging.Instancia().LogError(ex, RutaArchivoLog);
                }
            }
        }
    }
}

I have tried delete prnt instantation from the constructor and use it in the impress task but it didn´t work.

I need your help with urgency, if you can answer me, I will appreciate it.
Greetings.

@detectivejd
Copy link
Author

Please!, I need to help with this code, The worker services are different applications and they are installed in a raspberry pi as deamon services in Linux

Service to Ticket Impress
image

Service to Bill Impress
image

I don´t know if on the code have fails or not, I was looking for information in Google but all that I found was useless and I didn´t work it.

Ticket Impress -> Program.cs

using ViewParking.Tickets.Raspberry.Impresion;

IHost host = Host.CreateDefaultBuilder(args)
    .UseSystemd()
    .ConfigureServices(services =>
    {
        services.AddSingleton<IHostedService, Worker>();
    })
    .Build();

await host.RunAsync();

Ticket Impress -> Worker.cs

namespace ViewParking.Tickets.Raspberry.Impresion;

public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;

    public Worker(ILogger<Worker> logger)
    {
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        var configuration = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json", true, true)
            .AddEnvironmentVariables()
            .Build();

        var properties = configuration.GetSection("Default");
        var tiempoCicloChequeo = properties.GetValue<int>("TiempoCicloServicioMilisegundos");
        var entrada = new EntradaImpresion();

        Console.Clear();

        while (!stoppingToken.IsCancellationRequested)
        {
            await Task.Delay(tiempoCicloChequeo, stoppingToken);
            entrada.Iniciar();            
        }
    }
}

Bill Impress -> Program.cs

using ViewParking.Facturas.Raspberry;

IHost host = Host.CreateDefaultBuilder(args)
    .UseSystemd()
    .ConfigureServices(services =>
    {
        services.AddSingleton<IHostedService, Worker>();
    })
    .Build();

await host.RunAsync();

Bill Impress -> Worker.cs

using ViewParking.Facturas.Raspberry.Impresion;

namespace ViewParking.Facturas.Raspberry
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;

        public Worker(ILogger<Worker> logger)
        {
            _logger = logger;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            var configuration = new ConfigurationBuilder()
                .AddJsonFile("appsettings.json", true, true)
                .AddEnvironmentVariables()
                .Build();

            var properties = configuration.GetSection("Default");
            var tiempoCicloChequeo = properties.GetValue<int>("TiempoCicloServicioMilisegundos");
            var entrada = new EntradaImpresion();

            Console.Clear();

            while (!stoppingToken.IsCancellationRequested)
            {
                await Task.Delay(tiempoCicloChequeo, stoppingToken);
                entrada.Iniciar();
            }
        }
    }
}

You response me, please!.

@igorocampos
Copy link
Collaborator

igorocampos commented Dec 5, 2023

Hi, that's too much information, and your code is not even presented with syntax highlight. Very hard to follow, especially with a lot of Spanish embedded in naming and all.
Anyhow, from what I could understand, you have 1 printer connected but 2 different apps running at the same time wishing to use the printer, but only the first application is able to do so, the second one is throwing an error. Is that it?

If that's the case, you have a race condition between your apps when consuming the printer resource. If you really wish to implement it like that (separate applications using the same printer) you would need a printing spooler, where you would have to manage the readiness of the printer, and most likely a printing queue, so there are no conflicts when trying to use it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants