﻿unit sync_thread;

interface

uses
  System.Classes, System.SysUtils, FireDAC.Stan.Intf, FireDAC.Stan.Option,
  FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def,
  FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Phys.MySQL,
  FireDAC.Phys.MySQLDef, FireDAC.Phys.SQLite, FireDAC.Phys.SQLiteDef,
  FireDAC.VCLUI.Wait, FireDAC.Comp.Client, FireDAC.Comp.DataSet, Data.DB;

type
  TConnectionStatus = (csConnected, csDisconnected);
  TStatusNotifyEvent = procedure(Sender: TObject; Status: TConnectionStatus; const Msg: string) of object;
  TLogoutNotifyEvent = procedure(Sender: TObject; WorkerID: Integer) of object;

  TSyncThread = class(TThread)
  private
    FLocalDBPath: string;
    FRemoteHost: string;
    FRemoteUser: string;
    FRemotePass: string;
    FRemoteDatabase: string;
    FIntervalSeconds: Integer;
    FOnStatusChange: TStatusNotifyEvent;
    FOnLogoutRequest: TLogoutNotifyEvent;
    
    FReportStatus: TConnectionStatus;
    FReportMsg: string;
    FReportWorkerID: Integer;

    procedure DoStatusNotify;
    procedure DoLogoutNotify;
    procedure PerformSync;
  protected
    procedure Execute; override;
  public
    constructor Create(const ALocalDBPath, ARemoteHost, ARemoteUser, ARemotePass, ARemoteDatabase: string; AIntervalSeconds: Integer);
    property OnStatusChange: TStatusNotifyEvent read FOnStatusChange write FOnStatusChange;
    property OnLogoutRequest: TLogoutNotifyEvent read FOnLogoutRequest write FOnLogoutRequest;
  end;

implementation

constructor TSyncThread.Create(const ALocalDBPath, ARemoteHost, ARemoteUser, ARemotePass, ARemoteDatabase: string; AIntervalSeconds: Integer);
begin
  inherited Create(True); // Create suspended
  FLocalDBPath := ALocalDBPath;
  FRemoteHost := ARemoteHost;
  FRemoteUser := ARemoteUser;
  FRemotePass := ARemotePass;
  FRemoteDatabase := ARemoteDatabase;
  FIntervalSeconds := AIntervalSeconds;
  FreeOnTerminate := True;
end;

procedure TSyncThread.DoStatusNotify;
begin
  if Assigned(FOnStatusChange) then
    FOnStatusChange(Self, FReportStatus, FReportMsg);
end;

procedure TSyncThread.DoLogoutNotify;
begin
  if Assigned(FOnLogoutRequest) then
    FOnLogoutRequest(Self, FReportWorkerID);
end;

procedure TSyncThread.Execute;
begin
  while not Terminated do
  begin
    try
      PerformSync;
    except
      on E: Exception do
      begin
        FReportStatus := csDisconnected;
        FReportMsg := 'Error de sincronización: ' + E.Message;
        Synchronize(DoStatusNotify);
      end;
    end;

    if not Terminated then
      Sleep(FIntervalSeconds * 1000);
  end;
end;

procedure TSyncThread.PerformSync;
var
  LLocalConn, LRemoteConn: TFDConnection;
  LQLocal, LQRemote, LQAux: TFDQuery;
  LRemoteID: string;
  LWorkerID: Integer;
  LLocalID: Integer;
begin
  LLocalConn := TFDConnection.Create(nil);
  LRemoteConn := TFDConnection.Create(nil);
  LQLocal := TFDQuery.Create(nil);
  LQRemote := TFDQuery.Create(nil);
  LQAux := TFDQuery.Create(nil);
  try
    // Conectar Local SQLite
    LLocalConn.Params.Clear;
    LLocalConn.Params.Add('DriverID=SQLite');
    LLocalConn.Params.Add('Database=' + FLocalDBPath);
    LLocalConn.LoginPrompt := False;
    LLocalConn.Connected := True;
    
    LQLocal.Connection := LLocalConn;
    LQAux.Connection := LLocalConn;

    // Conectar Remoto MySQL
    LRemoteConn.Params.Clear;
    LRemoteConn.Params.Add('DriverID=MySQL');
    LRemoteConn.Params.Add('Server=' + FRemoteHost);
    LRemoteConn.Params.Add('User=' + FRemoteUser);
    LRemoteConn.Params.Add('Password=' + FRemotePass);
    LRemoteConn.Params.Add('Database=' + FRemoteDatabase);
    LRemoteConn.LoginPrompt := False;
    
    try
      LRemoteConn.Connected := True;
      LQRemote.Connection := LRemoteConn;
      
      FReportStatus := csConnected;
      FReportMsg := 'Conectado a ' + FRemoteHost;
      Synchronize(DoStatusNotify);
    except
      on E: Exception do
      begin
        FReportStatus := csDisconnected;
        FReportMsg := 'Sin conexión: ' + E.Message;
        Synchronize(DoStatusNotify);
        Exit;
      end;
    end;

    // 1. Replicar movimiento_mesas_local (estado=1: INSERT)
    LQLocal.SQL.Text := 'SELECT * FROM movimiento_mesas_local WHERE estado = 1';
    LQLocal.Open;
    while not LQLocal.Eof do
    begin
      LQRemote.SQL.Text := 'SELECT MAX(id)+1 FROM movimiento_mesas';
      LQRemote.Open;
      LRemoteID := LQRemote.Fields[0].AsString;
      if LRemoteID = '' then LRemoteID := '1';
      LQRemote.Close;
      
      LQRemote.SQL.Text := 'INSERT INTO movimiento_mesas (id, fecha, mesa, idt, trabajador, entrada_real, salida_real, ' +
                           'entrada_ajustada, salida_ajustada, horasreales, horasajustadas, puesto, tipotrabajo, articulo, parcela, num_limpiadora) ' +
                           'VALUES (:id, :fecha, :mesa, :idt, :trabajador, :entrada_real, :salida_real, ' +
                           ':entrada_ajustada, :salida_ajustada, :horasreales, :horasajustadas, :puesto, :tipotrabajo, :articulo, :parcela, :num_limpiadora)';
      LQRemote.ParamByName('id').AsString := LRemoteID;
      LQRemote.ParamByName('fecha').AsString := LQLocal.FieldByName('fecha').AsString;
      LQRemote.ParamByName('mesa').AsString := LQLocal.FieldByName('mesa').AsString;
      LQRemote.ParamByName('idt').AsInteger := LQLocal.FieldByName('idt').AsInteger;
      LQRemote.ParamByName('trabajador').AsString := LQLocal.FieldByName('TRABAJADOR').AsString;
      LQRemote.ParamByName('entrada_real').AsString := LQLocal.FieldByName('ENTRADA_REAL').AsString;
      LQRemote.ParamByName('salida_real').AsString := LQLocal.FieldByName('SALIDA_REAL').AsString;
      LQRemote.ParamByName('entrada_ajustada').AsString := LQLocal.FieldByName('ENTRADA_AJUSTADA').AsString;
      LQRemote.ParamByName('salida_ajustada').AsString := LQLocal.FieldByName('SALIDA_AJUSTADA').AsString;
      LQRemote.ParamByName('horasreales').AsString := LQLocal.FieldByName('HORASREALES').AsString;
      LQRemote.ParamByName('horasajustadas').AsString := LQLocal.FieldByName('HORASAJUSTADAS').AsString;
      LQRemote.ParamByName('puesto').AsString := LQLocal.FieldByName('PUESTO').AsString;
      LQRemote.ParamByName('tipotrabajo').AsString := LQLocal.FieldByName('TIPOTRABAJO').AsString;
      LQRemote.ParamByName('articulo').AsString := LQLocal.FieldByName('ARTICULO').AsString;
      LQRemote.ParamByName('parcela').AsString := LQLocal.FieldByName('PARCELA').AsString;
      LQRemote.ParamByName('num_limpiadora').AsString := LQLocal.FieldByName('num_limpiadora').AsString;
      LQRemote.ExecSQL;

      LQAux.SQL.Text := 'UPDATE movimiento_mesas_local SET estado = 0, id = ' + LRemoteID + ' WHERE id = ' + LQLocal.FieldByName('id').AsString;
      LQAux.ExecSQL;
      LQLocal.Next;
    end;

    // 2. Replicar movimiento_mesas_local (estado=2: UPDATE)
    LQLocal.Close;
    LQLocal.SQL.Text := 'SELECT * FROM movimiento_mesas_local WHERE estado = 2';
    LQLocal.Open;
    while not LQLocal.Eof do
    begin
      LQRemote.SQL.Text := 'UPDATE movimiento_mesas SET salida_real = :salida_real, salida_ajustada = :salida_ajustada, ' +
                           'horasreales = :horasreales, horasajustadas = :horasajustadas WHERE id = :id';
      LQRemote.ParamByName('id').AsString := LQLocal.FieldByName('id').AsString;
      LQRemote.ParamByName('salida_real').AsString := LQLocal.FieldByName('SALIDA_REAL').AsString;
      LQRemote.ParamByName('salida_ajustada').AsString := LQLocal.FieldByName('SALIDA_AJUSTADA').AsString;
      LQRemote.ParamByName('horasreales').AsString := LQLocal.FieldByName('HORASREALES').AsString;
      LQRemote.ParamByName('horasajustadas').AsString := LQLocal.FieldByName('HORASAJUSTADAS').AsString;
      LQRemote.ExecSQL;

      LQAux.SQL.Text := 'DELETE FROM movimiento_mesas_local WHERE id = ' + LQLocal.FieldByName('id').AsString;
      LQAux.ExecSQL;
      LQLocal.Next;
    end;

    // 3. Replicar produccion_local (estado=1: INSERT)
    LQLocal.Close;
    LQLocal.SQL.Text := 'SELECT * FROM produccion_local WHERE estado = 1';
    LQLocal.Open;
    while not LQLocal.Eof do
    begin
      LQRemote.SQL.Text := 'INSERT INTO produccion (fecha, hora, mesa, bascula, idt, embasadora, materia_prima, producto, tara, peso_teorico, peso_real) ' +
                           'VALUES (:fecha, :hora, :mesa, :bascula, :idt, :embasadora, :materia_prima, :producto, :tara, :peso_teorico, :peso_real)';
      LQRemote.ParamByName('fecha').AsString := LQLocal.FieldByName('fecha').AsString;
      LQRemote.ParamByName('hora').AsString := LQLocal.FieldByName('hora').AsString;
      LQRemote.ParamByName('mesa').AsString := LQLocal.FieldByName('mesa').AsString;
      LQRemote.ParamByName('bascula').AsString := LQLocal.FieldByName('bascula').AsString;
      LQRemote.ParamByName('idt').AsInteger := LQLocal.FieldByName('idt').AsInteger;
      LQRemote.ParamByName('embasadora').AsString := LQLocal.FieldByName('embasadora').AsString;
      LQRemote.ParamByName('materia_prima').AsString := LQLocal.FieldByName('materia_prima').AsString;
      LQRemote.ParamByName('producto').AsString := LQLocal.FieldByName('producto').AsString;
      LQRemote.ParamByName('tara').AsFloat := LQLocal.FieldByName('tara').AsFloat;
      LQRemote.ParamByName('peso_teorico').AsFloat := LQLocal.FieldByName('peso_teorico').AsFloat;
      LQRemote.ParamByName('peso_real').AsFloat := LQLocal.FieldByName('peso_real').AsFloat;
      LQRemote.ExecSQL;

      LQAux.SQL.Text := 'UPDATE produccion_local SET estado = 0 WHERE id = ' + LQLocal.FieldByName('id').AsString;
      LQAux.ExecSQL;
      LQLocal.Next;
    end;

    // 4. Replicar rendimiento_local (estado=1: INSERT)
    LQLocal.Close;
    LQLocal.SQL.Text := 'SELECT * FROM rendimiento_local WHERE estado = 1';
    LQLocal.Open;
    while not LQLocal.Eof do
    begin
      LQRemote.SQL.Text := 'INSERT INTO rendimiento (fecha, hora, idt, trabajador, materia_prima, peso_bruto, tara, pesoneto, num_limpiadora) ' +
                           'VALUES (:fecha, :hora, :idt, :trabajador, :materia_prima, :peso_bruto, :tara, :pesoneto, :num_limpiadora)';
      LQRemote.ParamByName('fecha').AsString := LQLocal.FieldByName('fecha').AsString;
      LQRemote.ParamByName('hora').AsString := LQLocal.FieldByName('hora').AsString;
      LQRemote.ParamByName('idt').AsInteger := LQLocal.FieldByName('idt').AsInteger;
      LQRemote.ParamByName('trabajador').AsString := LQLocal.FieldByName('trabajador').AsString;
      LQRemote.ParamByName('materia_prima').AsString := LQLocal.FieldByName('materia_prima').AsString;
      LQRemote.ParamByName('peso_bruto').AsFloat := LQLocal.FieldByName('peso_bruto').AsFloat;
      LQRemote.ParamByName('tara').AsFloat := LQLocal.FieldByName('tara').AsFloat;
      LQRemote.ParamByName('pesoneto').AsFloat := LQLocal.FieldByName('pesoneto').AsFloat;
      LQRemote.ParamByName('num_limpiadora').AsInteger := LQLocal.FieldByName('num_limpiadora').AsInteger;
      LQRemote.ExecSQL;

      LQAux.SQL.Text := 'UPDATE rendimiento_local SET estado = 0 WHERE id = ' + LQLocal.FieldByName('id').AsString;
      LQAux.ExecSQL;
      LQLocal.Next;
    end;

    // 5. Replicar desbloqueos_local (estado=1: INSERT)
    LQLocal.Close;
    LQLocal.SQL.Text := 'SELECT * FROM desbloqueos_local WHERE estado = 1';
    LQLocal.Open;
    while not LQLocal.Eof do
    begin
      LQRemote.SQL.Text := 'INSERT INTO desbloqueos (fecha, hora, envasadora, mesa, bascula) ' +
                           'VALUES (:fecha, :hora, :envasadora, :mesa, :bascula)';
      LQRemote.ParamByName('fecha').AsString := LQLocal.FieldByName('fecha').AsString;
      LQRemote.ParamByName('hora').AsString := LQLocal.FieldByName('hora').AsString;
      LQRemote.ParamByName('envasadora').AsString := LQLocal.FieldByName('envasadora').AsString;
      LQRemote.ParamByName('mesa').AsString := LQLocal.FieldByName('mesa').AsString;
      LQRemote.ParamByName('bascula').AsString := LQLocal.FieldByName('bascula').AsString;
      LQRemote.ExecSQL;

      LQAux.SQL.Text := 'UPDATE desbloqueos_local SET estado = 0 WHERE id = ' + LQLocal.FieldByName('id').AsString;
      LQAux.ExecSQL;
      LQLocal.Next;
    end;

    // 6. Replicar trabajo_diario_local (estado=1: INSERT)
    LQLocal.Close;
    LQLocal.SQL.Text := 'SELECT * FROM trabajo_diario_local WHERE estado = 1';
    LQLocal.Open;
    while not LQLocal.Eof do
    begin
      LQRemote.SQL.Text := 'SELECT MAX(id)+1 FROM trabajo_diario';
      LQRemote.Open;
      LRemoteID := LQRemote.Fields[0].AsString;
      if LRemoteID = '' then LRemoteID := '1';
      LQRemote.Close;

      LQRemote.SQL.Text := 'INSERT INTO trabajo_diario (id, fecha, parcela, idt, trabajador, typework, articulo, qhoras, precio, total, estado, origen) ' +
                           'VALUES (:id, :fecha, :parcela, :idt, :trabajador, :typework, :articulo, :qhoras, :precio, :total, :estado, :origen)';
      LQRemote.ParamByName('id').AsString := LRemoteID;
      LQRemote.ParamByName('fecha').AsString := LQLocal.FieldByName('fecha').AsString;
      LQRemote.ParamByName('parcela').AsString := LQLocal.FieldByName('parcela').AsString;
      LQRemote.ParamByName('idt').AsInteger := LQLocal.FieldByName('idt').AsInteger;
      LQRemote.ParamByName('trabajador').AsString := LQLocal.FieldByName('trabajador').AsString;
      LQRemote.ParamByName('typework').AsString := LQLocal.FieldByName('typework').AsString;
      LQRemote.ParamByName('articulo').AsString := LQLocal.FieldByName('articulo').AsString;
      LQRemote.ParamByName('qhoras').AsFloat := LQLocal.FieldByName('qhoras').AsFloat;
      LQRemote.ParamByName('precio').AsFloat := LQLocal.FieldByName('precio').AsFloat;
      LQRemote.ParamByName('total').AsFloat := LQLocal.FieldByName('total').AsFloat;
      LQRemote.ParamByName('estado').AsString := LQLocal.FieldByName('estadotrabajodiario').AsString;
      LQRemote.ParamByName('origen').AsString := LQLocal.FieldByName('origen').AsString;
      LQRemote.ExecSQL;

      LQAux.SQL.Text := 'DELETE FROM trabajo_diario_local WHERE id = ' + LQLocal.FieldByName('id').AsString;
      LQAux.ExecSQL;
      LQLocal.Next;
    end;

    // 8. PULL: calendario_laboral
    try
      LQRemote.Close;
      LQRemote.SQL.Text := 'SELECT * FROM calendario_laboral';
      LQRemote.Open;
      LQAux.SQL.Text := 'DELETE FROM calendario_laboral';
      LQAux.ExecSQL;
      while not LQRemote.Eof do
      begin
        LQAux.SQL.Text := 'INSERT OR REPLACE INTO calendario_laboral (fecha, festivo, almuerzo, merienda, ' +
                          'inicio_almuerzo, fin_almuerzo, inicio_merienda, fin_merienda) ' +
                          'VALUES (:fecha, :festivo, :almuerzo, :merienda, :inicio_almuerzo, :fin_almuerzo, :inicio_merienda, :fin_merienda)';
        LQAux.ParamByName('fecha').AsString := LQRemote.FieldByName('fecha').AsString;
        LQAux.ParamByName('festivo').AsInteger := LQRemote.FieldByName('festivo').AsInteger;
        LQAux.ParamByName('almuerzo').AsInteger := LQRemote.FieldByName('almuerzo').AsInteger;
        LQAux.ParamByName('merienda').AsInteger := LQRemote.FieldByName('merienda').AsInteger;
        LQAux.ParamByName('inicio_almuerzo').AsString := LQRemote.FieldByName('inicio_almuerzo').AsString;
        LQAux.ParamByName('fin_almuerzo').AsString := LQRemote.FieldByName('fin_almuerzo').AsString;
        LQAux.ParamByName('inicio_merienda').AsString := LQRemote.FieldByName('inicio_merienda').AsString;
        LQAux.ParamByName('fin_merienda').AsString := LQRemote.FieldByName('fin_merienda').AsString;
        LQAux.ExecSQL;
        LQRemote.Next;
      end;
    except
    end;

    // 9. PULL: trabajos_almacen
    try
      LQRemote.Close;
      LQRemote.SQL.Text := 'SELECT * FROM trabajos_almacen';
      LQRemote.Open;
      LQAux.SQL.Text := 'DELETE FROM trabajos_almacen';
      LQAux.ExecSQL;
      while not LQRemote.Eof do
      begin
        LQAux.SQL.Text := 'INSERT INTO trabajos_almacen (id, puesto, tipo_trabajo, articulo, parcela, mesas, activo) ' +
                          'VALUES (:id, :puesto, :tipo_trabajo, :articulo, :parcela, :mesas, :activo)';
        LQAux.ParamByName('id').AsInteger := LQRemote.FieldByName('id').AsInteger;
        LQAux.ParamByName('puesto').AsString := LQRemote.FieldByName('puesto').AsString;
        LQAux.ParamByName('tipo_trabajo').AsString := LQRemote.FieldByName('tipo_trabajo').AsString;
        LQAux.ParamByName('articulo').AsString := LQRemote.FieldByName('articulo').AsString;
        LQAux.ParamByName('parcela').AsString := LQRemote.FieldByName('parcela').AsString;
        LQAux.ParamByName('mesas').AsString := LQRemote.FieldByName('mesas').AsString;
        LQAux.ParamByName('activo').AsInteger := LQRemote.FieldByName('activo').AsInteger;
        LQAux.ExecSQL;
        LQRemote.Next;
      end;
    except
    end;

    // 10. PULL: almacen_sector
    try
      LQRemote.Close;
      LQRemote.SQL.Text := 'SELECT * FROM almacen_sector';
      LQRemote.Open;
      LQAux.SQL.Text := 'DELETE FROM almacen_sector';
      LQAux.ExecSQL;
      while not LQRemote.Eof do
      begin
        LQAux.SQL.Text := 'INSERT INTO almacen_sector (ide, id, descripcion, idalmacen, descalmacen) ' +
                          'VALUES (:ide, :id, :descripcion, :idalmacen, :descalmacen)';
        LQAux.ParamByName('ide').AsInteger := LQRemote.FieldByName('ide').AsInteger;
        LQAux.ParamByName('id').AsInteger := LQRemote.FieldByName('id').AsInteger;
        LQAux.ParamByName('descripcion').AsString := LQRemote.FieldByName('descripcion').AsString;
        LQAux.ParamByName('idalmacen').AsInteger := LQRemote.FieldByName('idalmacen').AsInteger;
        LQAux.ParamByName('descalmacen').AsString := LQRemote.FieldByName('descalmacen').AsString;
        LQAux.ExecSQL;
        LQRemote.Next;
      end;
    except
    end;

    // 11. PULL: empresa
    try
      LQRemote.Close;
      LQRemote.SQL.Text := 'SELECT id, cif, nombre, direccion, poblacion, provincia, cp, ajusteentrada, ajustesalida, porcbloqueo, active FROM empresa';
      LQRemote.Open;
      LQAux.SQL.Text := 'DELETE FROM empresa';
      LQAux.ExecSQL;
      while not LQRemote.Eof do
      begin
        LQAux.SQL.Text := 'INSERT INTO empresa (id, cif, nombre, direccion, poblacion, provincia, cp, ajusteentrada, ajustesalida, porcbloqueo, active) ' +
                          'VALUES (:id, :cif, :nombre, :direccion, :poblacion, :provincia, :cp, :ajusteentrada, :ajustesalida, :porcbloqueo, :active)';
        LQAux.ParamByName('id').AsInteger := LQRemote.FieldByName('id').AsInteger;
        LQAux.ParamByName('cif').AsString := LQRemote.FieldByName('cif').AsString;
        LQAux.ParamByName('nombre').AsString := LQRemote.FieldByName('nombre').AsString;
        LQAux.ParamByName('direccion').AsString := LQRemote.FieldByName('direccion').AsString;
        LQAux.ParamByName('poblacion').AsString := LQRemote.FieldByName('poblacion').AsString;
        LQAux.ParamByName('provincia').AsString := LQRemote.FieldByName('provincia').AsString;
        LQAux.ParamByName('cp').AsString := LQRemote.FieldByName('cp').AsString;
        LQAux.ParamByName('ajusteentrada').AsInteger := LQRemote.FieldByName('ajusteentrada').AsInteger;
        LQAux.ParamByName('ajustesalida').AsInteger := LQRemote.FieldByName('ajustesalida').AsInteger;
        LQAux.ParamByName('porcbloqueo').AsInteger := LQRemote.FieldByName('porcbloqueo').AsInteger;
        LQAux.ParamByName('active').AsInteger := LQRemote.FieldByName('active').AsInteger;
        LQAux.ExecSQL;
        LQRemote.Next;
      end;
    except
    end;

    // 12. PULL: productos
    try
      LQRemote.Close;
      LQRemote.SQL.Text := 'SELECT ide, id, codigo, descripcion, tara, peso, errorpeso, pesadomanual, activo, mostrar_boton FROM productos';
      LQRemote.Open;
      LQAux.SQL.Text := 'DELETE FROM productos';
      LQAux.ExecSQL;
      while not LQRemote.Eof do
      begin
        LQAux.SQL.Text := 'INSERT INTO productos (ide, id, codigo, descripcion, tara, peso, errorpeso, pesadomanual, activo, mostrar_boton) ' +
                          'VALUES (:ide, :id, :codigo, :descripcion, :tara, :peso, :errorpeso, :pesadomanual, :activo, :mostrar_boton)';
        LQAux.ParamByName('ide').AsInteger := LQRemote.FieldByName('ide').AsInteger;
        LQAux.ParamByName('id').AsInteger := LQRemote.FieldByName('id').AsInteger;
        LQAux.ParamByName('codigo').AsString := LQRemote.FieldByName('codigo').AsString;
        LQAux.ParamByName('descripcion').AsString := LQRemote.FieldByName('descripcion').AsString;
        LQAux.ParamByName('tara').AsFloat := LQRemote.FieldByName('tara').AsFloat;
        LQAux.ParamByName('peso').AsFloat := LQRemote.FieldByName('peso').AsFloat;
        LQAux.ParamByName('errorpeso').AsFloat := LQRemote.FieldByName('errorpeso').AsFloat;
        LQAux.ParamByName('pesadomanual').AsInteger := LQRemote.FieldByName('pesadomanual').AsInteger;
        LQAux.ParamByName('activo').AsInteger := LQRemote.FieldByName('activo').AsInteger;
        LQAux.ParamByName('mostrar_boton').AsInteger := LQRemote.FieldByName('mostrar_boton').AsInteger;
        LQAux.ExecSQL;
        LQRemote.Next;
      end;
    except
    end;

    // 13. PULL: materias_primas
    try
      LQRemote.Close;
      LQRemote.SQL.Text := 'SELECT idempresa, id, variedad, descripcion, activo, pesopieza FROM materias_primas';
      LQRemote.Open;
      LQAux.SQL.Text := 'DELETE FROM materias_primas';
      LQAux.ExecSQL;
      while not LQRemote.Eof do
      begin
        LQAux.SQL.Text := 'INSERT INTO materias_primas (idempresa, id, variedad, descripcion, activo, pesopieza) ' +
                          'VALUES (:idempresa, :id, :variedad, :descripcion, :activo, :pesopieza)';
        LQAux.ParamByName('idempresa').AsInteger := LQRemote.FieldByName('idempresa').AsInteger;
        LQAux.ParamByName('id').AsString := LQRemote.FieldByName('id').AsString;
        LQAux.ParamByName('variedad').AsString := LQRemote.FieldByName('variedad').AsString;
        LQAux.ParamByName('descripcion').AsString := LQRemote.FieldByName('descripcion').AsString;
        LQAux.ParamByName('activo').AsInteger := LQRemote.FieldByName('activo').AsInteger;
        LQAux.ParamByName('pesopieza').AsFloat := LQRemote.FieldByName('pesopieza').AsFloat;
        LQAux.ExecSQL;
        LQRemote.Next;
      end;
    except
    end;

    // 14. PULL: productos_sector
    try
      LQRemote.Close;
      LQRemote.SQL.Text := 'SELECT * FROM productos_sector';
      LQRemote.Open;
      LQAux.SQL.Text := 'DELETE FROM productos_sector';
      LQAux.ExecSQL;
      while not LQRemote.Eof do
      begin
        LQAux.SQL.Text := 'INSERT INTO productos_sector (ide, idsector, codigo, descripcion) ' +
                          'VALUES (:ide, :idsector, :codigo, :descripcion)';
        LQAux.ParamByName('ide').AsInteger := LQRemote.FieldByName('ide').AsInteger;
        LQAux.ParamByName('idsector').AsInteger := LQRemote.FieldByName('idsector').AsInteger;
        LQAux.ParamByName('codigo').AsString := LQRemote.FieldByName('codigo').AsString;
        LQAux.ParamByName('descripcion').AsString := LQRemote.FieldByName('descripcion').AsString;
        LQAux.ExecSQL;
        LQRemote.Next;
      end;
    except
    end;

    // 15. PULL: materias_primas_sector
    try
      LQRemote.Close;
      LQRemote.SQL.Text := 'SELECT * FROM materias_primas_sector';
      LQRemote.Open;
      LQAux.SQL.Text := 'DELETE FROM materias_primas_sector';
      LQAux.ExecSQL;
      while not LQRemote.Eof do
      begin
        LQAux.SQL.Text := 'INSERT INTO materias_primas_sector (ide, idsector, mprima) ' +
                          'VALUES (:ide, :idsector, :mprima)';
        LQAux.ParamByName('ide').AsInteger := LQRemote.FieldByName('ide').AsInteger;
        LQAux.ParamByName('idsector').AsInteger := LQRemote.FieldByName('idsector').AsInteger;
        LQAux.ParamByName('mprima').AsString := LQRemote.FieldByName('mprima').AsString;
        LQAux.ExecSQL;
        LQRemote.Next;
      end;
    except
    end;

    // 16. PULL: sectores_mesas
    try
      LQRemote.Close;
      LQRemote.SQL.Text := 'SELECT * FROM sectores_mesas';
      LQRemote.Open;
      LQAux.SQL.Text := 'DELETE FROM sectores_mesas';
      LQAux.ExecSQL;
      while not LQRemote.Eof do
      begin
        LQAux.SQL.Text := 'INSERT INTO sectores_mesas (ide, idsector, id, descripcion, descsector) ' +
                          'VALUES (:ide, :idsector, :id, :descripcion, :descsector)';
        LQAux.ParamByName('ide').AsInteger := LQRemote.FieldByName('ide').AsInteger;
        LQAux.ParamByName('idsector').AsInteger := LQRemote.FieldByName('idsector').AsInteger;
        LQAux.ParamByName('id').AsInteger := LQRemote.FieldByName('id').AsInteger;
        LQAux.ParamByName('descripcion').AsString := LQRemote.FieldByName('descripcion').AsString;
        LQAux.ParamByName('descsector').AsString := LQRemote.FieldByName('descsector').AsString;
        LQAux.ExecSQL;
        LQRemote.Next;
      end;
    except
    end;

        // 7. PULL: Cierre remoto de sesión de operarios
    LQLocal.Close;
    LQLocal.SQL.Text := 'SELECT idt, id FROM movimiento_mesas_local WHERE salida_real IS NULL LIMIT 1';
    LQLocal.Open;
    if not LQLocal.Eof then
    begin
      LWorkerID := LQLocal.FieldByName('idt').AsInteger;
      LLocalID := LQLocal.FieldByName('id').AsInteger;
      
      LQRemote.Close;
      LQRemote.SQL.Text := 'SELECT salida_real FROM movimiento_mesas WHERE idt = :idt AND id = :id';
      LQRemote.ParamByName('idt').AsInteger := LWorkerID;
      LQRemote.ParamByName('id').AsInteger := LLocalID;
      LQRemote.Open;
      if not LQRemote.Eof then
      begin
        if LQRemote.FieldByName('salida_real').AsString <> '' then
        begin
          FReportWorkerID := LWorkerID;
          Synchronize(DoLogoutNotify);
        end;
      end;
    end;

  finally
    LQLocal.Free;
    LQRemote.Free;
    LQAux.Free;
    LLocalConn.Free;
    LRemoteConn.Free;
  end;
end;

end.
