unit fticados;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.Grids, Vcl.DBGrids,
  Vcl.StdCtrls, Data.DB, ZAbstractRODataset, ZDataset, ZAbstractDataset,
  Vcl.ComCtrls, Vcl.ImgList, frxExportCSV, frxClass, frxExportPDF, frxDBSet,
  Vcl.DBCtrls,comobj,excel2000, Vcl.Mask,math, frxExportBaseDialog, Bde.DBTables,
  dateutils;

type
  TTicadoInfo = record
    Id: Int64;
    Ide: Integer;
    Idt: Integer;
    Fecha: TDate;
    Trabajador: string;
    EntradaM: string;
    SalidaM: string;
    HorasM: Double;
    EntradaT: string;
    SalidaT: string;
    HorasT: Double;
    NumHoras: Double;
    Descuento: Double;
    HorasCobrar: Double;
    Festivo: Integer;
    Observaciones: string;
  end;

  TDiaSemanaData = record
    Horas: Double;
    EntradaM: string;
    SalidaM: string;
    EntradaT: string;
    SalidaT: string;
    Festivo: Integer;
    TieneDatos: Boolean;
    IdTicado: Int64;
  end;

  TTrabajadorSemanaInfo = record
    Idt: Integer;
    Nombre: string;
    Dias: array[1..7] of TDiaSemanaData;
    TotalHoras: Double;
  end;

  Tticados = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    Label1: TLabel;
    Label2: TLabel;
    DBGrid1: TDBGrid;
    qempleados: TZReadOnlyQuery;
    dsqempleados: TDataSource;
    Panel3: TPanel;
    Panel4: TPanel;
    qticados: TZQuery;
    dsqticados: TDataSource;
    Panel5: TPanel;
    buscarempleado: TEdit;
    Panel6: TPanel;
    qticadosid: TLargeintField;
    qticadoside: TSmallintField;
    qticadosfecha: TDateField;
    qticadosidt: TIntegerField;
    qticadosTRABAJADOR: TWideStringField;
    qticadoshorasm: TFloatField;
    qticadoshorasm_m: TFloatField;
    qticadoshorast: TFloatField;
    qticadoshorast_m: TFloatField;
    qticadosnum_horas: TFloatField;
    qticadosnum_horas_m: TFloatField;
    qticadosimprimir: TIntegerField;
    qticadosobservaciones: TWideStringField;
    qticadosfestivo: TIntegerField;
    Button1: TButton;
    ImageList1: TImageList;
    ticadosdb: TfrxDBDataset;
    rTicados: TfrxReport;
    frxPDFExport1: TfrxPDFExport;
    frxCSVExport1: TfrxCSVExport;
    qtotalhoras: TZQuery;
    qtotalhorastotalhoras: TFloatField;
    dstotalhoras: TDataSource;
    qtotalhorasidt: TIntegerField;
    pmodificaciones: TPanel;
    Label3: TLabel;
    fdesde: TDateTimePicker;
    fhasta: TDateTimePicker;
    Label4: TLabel;
    Label5: TLabel;
    DBText1: TDBText;
    Button2: TButton;
    lentsal: TComboBox;
    Label7: TLabel;
    Button3: TButton;
    CheckBox1: TCheckBox;
    Edit2: TEdit;
    Label9: TLabel;
    btJexcel: TButton;
    checkacumulados: TCheckBox;
    qtotales: TZQuery;
    dsqtotales: TDataSource;
    qtotalesidt: TIntegerField;
    qtotalestrabajador: TWideStringField;
    qtotalestotalhoras: TFloatField;
    Label10: TLabel;
    v_descuento: TEdit;
    Button4: TButton;
    qticadosdescuentohoras: TFloatField;
    Label11: TLabel;
    v_hora: TMaskEdit;
    qticadoshorascobrar: TFloatField;
    Label6: TLabel;
    v_horas: TEdit;
    Button5: TButton;
    qticadosentradam: TTimeField;
    qticadossalidam: TTimeField;
    qticadossalidam_m: TTimeField;
    qticadosentradat: TTimeField;
    qticadossalidat: TTimeField;
    qticadossalidat_m: TTimeField;
    qticadoshorafinmostrar: TTimeField;
    tgrupo: TDBLookupComboBox;
    qgrupostrabajadores2: TZReadOnlyQuery;
    dsqgrupostrabajadores2: TDataSource;
    qgrupostrabajadores2ide: TIntegerField;
    qgrupostrabajadores2id: TIntegerField;
    qgrupostrabajadores2descripcion: TWideStringField;
    Label212: TLabel;
    ljcentro: TDBLookupComboBox;
    Label213: TLabel;
    ljtrabajo: TDBLookupComboBox;
    Label214: TLabel;
    ljhora: TDBLookupComboBox;
    qparcelas: TZReadOnlyQuery;
    dsqparcelas: TDataSource;
    qparcelascodpar: TWideStringField;
    qparcelasempresa: TIntegerField;
    qparcelasnombre: TWideStringField;
    qtipohoras: TZReadOnlyQuery;
    dsqtipohoras: TDataSource;
    qtrabajos: TZReadOnlyQuery;
    dsqtrabajos: TDataSource;
    qtipohorascodart: TWideStringField;
    qtipohorasdescrip: TWideStringField;
    qtipohorasprecio: TFloatField;
    qtipohorasempresa: TIntegerField;
    qtrabajosid: TWideStringField;
    qtrabajosnombre: TWideStringField;
    qtrabajosempresa: TIntegerField;
    v_precio: TDBText;
    checkborrar: TCheckBox;
    qaux: TZReadOnlyQuery;
    qjornales: TZQuery;
    qjornalesid: TIntegerField;
    qjornalesempresa: TIntegerField;
    qjornalesfecha: TDateField;
    qjornalesparcela: TWideStringField;
    qjornalesidt: TIntegerField;
    qjornalestrabajador: TWideStringField;
    qjornalestypework: TWideStringField;
    qjornalesarticulo: TWideStringField;
    qjornalesqhoras: TFloatField;
    qjornalesprecio: TFloatField;
    qjornalestotal: TFloatField;
    qjornalesestado: TWideStringField;
    Button6: TButton;
    lnumtrabajadores: TLabel;
    Button7: TButton;
    qticadoshoras_reales: TFloatField;
    qticadosmostrar: TIntegerField;
    gcrpagado: TDBCheckBox;
    qticadosmodificando: TIntegerField;
    gridnormal: TDBGrid;
    gridtotales: TDBGrid;
    gridampliado: TDBGrid;
    pcModoAmpliado: TPageControl;
    tabLista: TTabSheet;
    tabMes: TTabSheet;
    pnlNavMes: TPanel;
    lblMesTitulo: TLabel;
    lblMesResumen: TLabel;
    btnMesAnt: TButton;
    btnMesSig: TButton;
    btnMesHoy: TButton;
    btnMesCargar: TButton;
    pnlDetalleDiaMes: TPanel;
    lblDetalleDiaTitulo: TLabel;
    gridDetalleDiaMes: TStringGrid;
    gridCalendarioMes: TDrawGrid;
    tabSemana: TTabSheet;
    pnlNavSemana: TPanel;
    lblSemanaTitulo: TLabel;
    lblSemanaResumen: TLabel;
    btnSemanaAnt: TButton;
    btnSemanaSig: TButton;
    btnSemanaHoy: TButton;
    gridCalendarioSemana: TDrawGrid;
    qempleadosid: TSmallintField;
    qempleadosnombre: TWideStringField;
    qempleadoside: TIntegerField;
    chktodos: TCheckBox;
    qempleadoscodart: TWideStringField;
    btactualizar: TButton;
    Button8: TButton;
    Button9: TButton;
    dsqasistencia: TDataSource;
    gridasistencia: TDBGrid;
    qempleadosnif: TWideStringField;
    SaveDialog1: TSaveDialog;
    qtotalestotalhorascompu: TFloatField;
    qticadostiempoalmuerzo: TFloatField;
    qempleadoshorascontrato: TFloatField;
    qticadossalidam_mm: TTimeField;
    qticadoshorasm_mm: TFloatField;
    qticadosentradat_mm: TTimeField;
    qticadossalidat_mm: TTimeField;
    qticadoshorast_mm: TFloatField;
    Button10: TButton;
    dbticadosdetalle: TfrxDBDataset;
    qticadosdetalle: TZQuery;
    dsqticadosdetalle: TDataSource;
    qticadosdetalleid: TLargeintField;
    qticadosdetalleide: TSmallintField;
    qticadosdetallefecha: TDateField;
    qticadosdetalleidt: TIntegerField;
    qticadosdetalleTRABAJADOR: TWideStringField;
    qticadosdetalleENTRADA_REAL: TTimeField;
    qticadosdetalleSALIDA_REAL: TTimeField;
    qticadosdetalletiempo: TFloatField;
    qticadosdetallecentro: TWideStringField;
    qjornalesorigen: TWideStringField;
    qjornalesobservaciones: TWideStringField;
    qasistir: TZQuery;
    qasistiride: TIntegerField;
    qasistiridt: TIntegerField;
    qasistiranyo: TIntegerField;
    qasistirmes: TWideStringField;
    qasistirnif: TWideStringField;
    qasistirnombre: TWideStringField;
    qasistird1: TWideStringField;
    qasistird2: TWideStringField;
    qasistird3: TWideStringField;
    qasistird4: TWideStringField;
    qasistird5: TWideStringField;
    qasistird6: TWideStringField;
    qasistird7: TWideStringField;
    qasistird8: TWideStringField;
    qasistird9: TWideStringField;
    qasistird10: TWideStringField;
    qasistird11: TWideStringField;
    qasistird12: TWideStringField;
    qasistird13: TWideStringField;
    qasistird14: TWideStringField;
    qasistird15: TWideStringField;
    qasistird16: TWideStringField;
    qasistird17: TWideStringField;
    qasistird18: TWideStringField;
    qasistird19: TWideStringField;
    qasistird20: TWideStringField;
    qasistird21: TWideStringField;
    qasistird22: TWideStringField;
    qasistird23: TWideStringField;
    qasistird24: TWideStringField;
    qasistird25: TWideStringField;
    qasistird26: TWideStringField;
    qasistird27: TWideStringField;
    qasistird28: TWideStringField;
    qasistird29: TWideStringField;
    qasistird30: TWideStringField;
    qasistird31: TWideStringField;
    qasistirfechaalta: TDateField;
    qasistirfechabaja: TDateField;
    qasistirnombre2: TWideStringField;
    procedure tgrupoChange(Sender: TObject);
    procedure buscarempleadoChange(Sender: TObject);
    procedure fdesdeChange(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure Panel5Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure gridampliadoDrawColumnCell(Sender: TObject; const Rect: TRect;
      DataCol: Integer; Column: TColumn; State: TGridDrawState);
    procedure gridnormalDrawColumnCell(Sender: TObject; const Rect: TRect;
      DataCol: Integer; Column: TColumn; State: TGridDrawState);
    procedure Button2Click(Sender: TObject);
    procedure v_horasEnter(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure CheckBox1Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure btJexcelClick(Sender: TObject);
    procedure checkacumuladosClick(Sender: TObject);
    procedure FormKeyPress(Sender: TObject; var Key: Char);
    procedure gridampliadoTitleClick(Column: TColumn);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure gridnormalTitleClick(Column: TColumn);
    procedure Button6Click(Sender: TObject);
    procedure qticadosAfterOpen(DataSet: TDataSet);
    procedure qticadosBeforePost(DataSet: TDataSet);
    procedure Button7Click(Sender: TObject);
    procedure gridampliadoCellClick(Column: TColumn);
    procedure qticadosBeforeEdit(DataSet: TDataSet);
    procedure qempleadosAfterOpen(DataSet: TDataSet);
    procedure qempleadosBeforeOpen(DataSet: TDataSet);
    procedure btactualizarClick(Sender: TObject);
    procedure gridampliadoDblClick(Sender: TObject);
    procedure Button8Click(Sender: TObject);
    procedure Button9Click(Sender: TObject);
    procedure qticadosAfterPost(DataSet: TDataSet);
    procedure Button10Click(Sender: TObject);
    procedure dsqgrupostrabajadores2DataChange(Sender: TObject; Field: TField);
    procedure DBGrid1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure DBGrid1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure pcModoAmpliadoChange(Sender: TObject);
    procedure btnMesAntClick(Sender: TObject);
    procedure btnMesSigClick(Sender: TObject);
    procedure btnMesHoyClick(Sender: TObject);
    procedure btnMesCargarClick(Sender: TObject);
    procedure gridCalendarioMesDrawCell(Sender: TObject; ACol, ARow: Longint; Rect: TRect; State: TGridDrawState);
    procedure gridCalendarioMesSelectCell(Sender: TObject; ACol, ARow: Longint; var CanSelect: Boolean);
    procedure gridCalendarioMesDblClick(Sender: TObject);
    procedure gridDetalleDiaMesDblClick(Sender: TObject);
    procedure btnSemanaAntClick(Sender: TObject);
    procedure btnSemanaSigClick(Sender: TObject);
    procedure btnSemanaHoyClick(Sender: TObject);
    procedure gridCalendarioSemanaDrawCell(Sender: TObject; ACol, ARow: Longint; Rect: TRect; State: TGridDrawState);
    procedure gridCalendarioSemanaDblClick(Sender: TObject);
  private
    { Private declarations }
    FActualizando: Boolean;
    FMesFecha: TDate;
    FSemanaFecha: TDate;
    FDiaSeleccionadoMes: TDate;
    FTicadosList: array of TTicadoInfo;
    FTrabajadoresSemana: array of TTrabajadorSemanaInfo;
    FTotalesDiaSemana: array[1..7] of Double;
    FTotalGeneralSemana: Double;
    function EsModoAmpliado: Boolean;
    function ObtenerFechaCeldaMes(ACol, ARow: Integer): TDate;
    procedure CargarDatosCalendario;
    procedure ActualizarCalendarioMes;
    procedure ActualizarCalendarioSemana;
    procedure ActualizarDetalleDiaMes;
    procedure EditarTicadoPorId(AId: Int64);
    function ObtenerFiltroTrabajadoresSQL: string;
  public
    { Public declarations }

   procedure ExportaraExcel(FileNameXLS, SheetName: String; DBGrid: TDBGrid; ProgressBarXls: TProgressBar = nil);

  end;

var
  ticados: Tticados;
  filtrotrabajadores,tlimitado:string;
  grupo:integer;
  desdeactualizar:integer;
  oldhoras:real;
  vidticados:integer;
const
  rojo=$00AAAAFF;
  amarillo=$00B9FFFF;
  verde=$00C7FBAA;
  azul=$00FFFFBB;

implementation
uses datos, fdlgticados;
{$R *.dfm}

procedure tticados.ExportaraExcel(FileNameXLS, SheetName: String; DBGrid: TDBGrid; ProgressBarXls: TProgressBar);

  procedure ProgressBarInit;
  begin
    ProgressBarXls.Max := DBGrid.DataSource.DataSet.RecordCount;
    ProgressBarXls.Position := 0;
    ProgressBarXls.Visible := True;
  end;

const
  xlWBATworksheet = -4167;
var
  Excel, WorkBook, WorkSheet: OleVariant;
  I, J: Integer;
  PBookmark: TBookmark;
begin
  // Guardar la posición en la DB y desactivar que se mueva el registro
  PBookmark := DBGrid.DataSource.DataSet.GetBookmark;
  DBGrid.DataSource.DataSet.DisableControls;
  DBGrid.DataSource.DataSet.First;

  // Comprobar si existe el component TProgressBar
  if (ProgressBarXls <> nil) then
    ProgressBarInit;

  // Crear instancia de la aplicación Excel
  Excel := CreateOleObject('Excel.Application');

  // Evitar que nos pregunte si deseamos sobreescribir el archivo
  Excel.DisplayAlerts := False;

  // Agregar libro de trabajo
  WorkBook := Excel.Workbooks.Add(xlWBATWorksheet);

  // Tomar una referencia a la hoja creada
  WorkSheet := WorkBook.WorkSheets[1];

  // Se  describe el nombre de la hoja
  WorkSheet.Name := SheetName;

  // Llenamos las celdas
  //    Toma en cuenta que las columnas y filas empiezan en 1, y que en el
  // WorkSheet.Cells[I, J], I es la fila y J es la columna.

  //   Extrae los nombres de los campos del DBGrid y los coloca en el primer registro,
  // excluyendo los campos que están ocultos
  for J := 0 to DBGrid.FieldCount -1 do
    if DBGrid.Fields[J].Visible then
    begin
      // Poner la fuente de letra en Negrita
      WorkSheet.Cells[1, J +1].Font.Bold := True;
      // Centrar la celda
//      WorkSheet.Cells[1, J +1].HorizontalAlignment := xlCenter;
      // Asignamos Valor del titulo del DBrid
      WorkSheet.Cells[1, J +1] := DBGrid.Columns[J].Title.Caption;
    end;

  // Guardar los registros
  for I := 0 to DBGrid.DataSource.DataSet.RecordCount -1 do
  begin
    // Identificamos los campos y lo grabamos según su tipo
    for J := 0 to DBGrid.FieldCount -1 do
      case DBGrid.Fields[J].DataType of
        ftAutoInc, ftBytes, ftInteger, ftSmallint, ftWord: // Auto o Numérico
          WorkSheet.Cells[I +2, J +1] := DBGrid.Fields[J].AsInteger;
        ftBCD, ftFloat, ftCurrency: // Numérico con decimales
          WorkSheet.Cells[I +2, J +1] := DBGrid.Fields[J].AsFloat;
        ftDateTime, ftDate, ftTime: // Fecha y Hora
          WorkSheet.Cells[I +2, J +1] := DBGrid.Fields[J].AsDateTime;
        else // Todo lo demas caracteres
          WorkSheet.Cells[I +2, J +1] := DBGrid.Fields[J].AsString;
      end;

    // Saltamos de registro
    DBGrid.DataSource.DataSet.Next;

    // Comprobar si existe el component TProgressBar
    if (ProgressBarXls <> nil) then
      ProgressBarXls.Position := ProgressBarXls.Position +1;
  end;

  // Comprobar si existe el component TProgressBar
  if (ProgressBarXls <> nil) then
    ProgressBarXls.Visible := False;

  // Redimensionar todas las celdas para que esten según su tamaño
  WorkSheet.Cells.Columns.AutoFit;

  // Guardar el archivo
  WorkBook.SaveAs(FileNameXLS);

  // Cierra el archivo
  WorkBook.Close(FileNameXLS);

  // Salir de Excel
  Excel.Quit;

  // posicionar el registro donde estaba
  DBGrid.DataSource.DataSet.GotoBookmark(PBookmark);
  DBGrid.DataSource.DataSet.FreeBookmark(PBookmark);
  DBGrid.DataSource.DataSet.EnableControls;
end;

procedure Tticados.btJexcelClick(Sender: TObject);
var  archivo:string;
begin
    if EsModoAmpliado or gridampliado.Visible then
    begin
        archivo:='c:\agrigest\TICADOS.xlsx';
        try
        Exportaraexcel(archivo,'TICADOS',GRIDampliado);
        finally
          showmessage('Los datos han sido exportados correctamente a C:\agrigest');
        end;
    end;
    if gridnormal.Visible then
    begin
        archivo:='c:\agrigest\TICADOS.xlsx';
        try
        Exportaraexcel(archivo,'TICADOS',GRIDnormal);
        finally
          showmessage('Los datos han sido exportados correctamente a C:\agrigest');
        end;
    end;
    if gridtotales.Visible then
    begin
        archivo:='c:\agrigest\TICADOS.xlsx';
        try
        Exportaraexcel(archivo,'TICADOS',GRIDtotales);
        finally
          showmessage('Los datos han sido exportados correctamente a C:\agrigest');
        end;
    end;

end;

procedure Tticados.buscarempleadoChange(Sender: TObject);
begin
    filtrotrabajadores:='%'+buscarempleado.Text+'%';
    qempleados.Close;
    qempleados.open;

end;

procedure Tticados.Button10Click(Sender: TObject);
begin
     qticadosdetalle.close;
     qticadosdetalle.Prepare;
     qticadosdetalle.ParamByName('FECHAINICIO').AsDate:=fdesde.Date;
     qticadosdetalle.ParamByName('FECHAFIN').AsDate:=fhasta.Date;
     qticadosdetalle.ParamByName('IDE').Asinteger:=dm.tempresaid.AsInteger;
     qticadosdetalle.Open;
        if checkbox1.Checked then
        begin
            ticadosdb.Datasource:=dsqticados;
            qticados.SortedFields:='fecha,trabajador';
            qticados.SortType:=stascending;
            rTicados.Report.Clear;
            rTicados.LoadFromFile('c:\agrigest\informes\controlhorariogrupo.fr3');
        //    rTicados.Variables.Variables['tdesde']:=QUOTEDSTR('Desde: '+datetostr(fdesde.Date));
          //  rTicados.Variables.Variables['thasta']:=QUOTEDSTR('Hasta: '+DATETOSTR(fhasta.DATE));
            rticados.Report.FileName:='Control horario ';
            rticados.ShowReport();
            rTicados.Clear;
            ticadosdb.Datasource:=dsqticados;
            qticados.SortedFields:='trabajador,fecha';
            qticados.SortType:=stascending;
            rTicados.Report.Clear;
            rTicados.LoadFromFile('c:\agrigest\informes\controlhorariodetalle.fr3');
            rTicados.Variables.Variables['tdesde']:=QUOTEDSTR('Desde: '+datetostr(fdesde.Date));
            rTicados.Variables.Variables['thasta']:=QUOTEDSTR('Hasta: '+DATETOSTR(fhasta.DATE));
            rticados.Report.FileName:='Control horario ' + qticadostrabajador.asstring;
            rticados.ShowReport();
            rTicados.Clear;
        end else
        begin
            ticadosdb.Datasource:=dsqticados;
            qticados.SortedFields:='trabajador,fecha';
            qticados.SortType:=stascending;
            rTicados.Report.Clear;
            rTicados.LoadFromFile('c:\agrigest\informes\controlhorariodetalle.fr3');
            rTicados.Variables.Variables['tdesde']:=QUOTEDSTR('Desde: '+datetostr(fdesde.Date));
            rTicados.Variables.Variables['thasta']:=QUOTEDSTR('Hasta: '+DATETOSTR(fhasta.DATE));
            rticados.Report.FileName:='Control horario ' + qticadostrabajador.asstring;
            rticados.ShowReport();
            rTicados.Clear;
        end;

end;

procedure Tticados.Button1Click(Sender: TObject);
begin
   qticados.Delete;
end;

procedure Tticados.Button2Click(Sender: TObject);
begin
    if checkacumulados.Checked then
    begin
        ticadosdb.Datasource:=dsqtotales;
        rTicados.Report.Clear;
        rTicados.LoadFromFile('c:\agrigest\informes\controlhorariototales.fr3');
        rTicados.Variables.Variables['tdesde']:=QUOTEDSTR('Desde: '+datetostr(fdesde.Date));
        rTicados.Variables.Variables['thasta']:=QUOTEDSTR('Hasta: '+DATETOSTR(fhasta.DATE));
        rticados.Report.FileName:='Control horario ' + qticadostrabajador.asstring;
        rticados.ShowReport();
        rTicados.Clear
    end else
    begin
        if checkbox1.Checked then
        begin
            ticadosdb.Datasource:=dsqticados;
            qticados.SortedFields:='fecha,trabajador';
            qticados.SortType:=stascending;
            rTicados.Report.Clear;
            rTicados.LoadFromFile('c:\agrigest\informes\controlhorariogrupo.fr3');
        //    rTicados.Variables.Variables['tdesde']:=QUOTEDSTR('Desde: '+datetostr(fdesde.Date));
          //  rTicados.Variables.Variables['thasta']:=QUOTEDSTR('Hasta: '+DATETOSTR(fhasta.DATE));
            rticados.Report.FileName:='Control horario ';
            rticados.ShowReport();
            rTicados.Clear;
            ticadosdb.Datasource:=dsqticados;
            qticados.SortedFields:='trabajador,fecha';
            qticados.SortType:=stascending;
            rTicados.Report.Clear;
            rTicados.LoadFromFile('c:\agrigest\informes\controlhorario.fr3');
            rTicados.Variables.Variables['tdesde']:=QUOTEDSTR('Desde: '+datetostr(fdesde.Date));
            rTicados.Variables.Variables['thasta']:=QUOTEDSTR('Hasta: '+DATETOSTR(fhasta.DATE));
            rticados.Report.FileName:='Control horario ' + qticadostrabajador.asstring;
            rticados.ShowReport();
            rTicados.Clear;
        end else
        begin
            ticadosdb.Datasource:=dsqticados;
            qticados.SortedFields:='trabajador,fecha';
            qticados.SortType:=stascending;
            rTicados.Report.Clear;
            rTicados.LoadFromFile('c:\agrigest\informes\controlhorario.fr3');
            rTicados.Variables.Variables['tdesde']:=QUOTEDSTR('Desde: '+datetostr(fdesde.Date));
            rTicados.Variables.Variables['thasta']:=QUOTEDSTR('Hasta: '+DATETOSTR(fhasta.DATE));
            rticados.Report.FileName:='Control horario ' + qticadostrabajador.asstring;
            rticados.ShowReport();
            rTicados.Clear;
        end;
    end;

end;

procedure Tticados.Button3Click(Sender: TObject);
var ad,entsal,aleatorio,aleatorio2,positivo:integer;
    dia,mes,anyo:word;
    tfecha:string;
begin
    qticados.First;
    desdeactualizar:=1;
    entsal:=lentsal.ItemIndex;
    if v_hora.Text<>'  :  :  ' then
    begin
        case entsal of
            0:
            begin
              qticados.First;
              while not qticados.Eof do
              begin
                 if v_hora.text<>'00:00:00' then
                 begin
                     randomize;
                     positivo:=random(2);
                     if positivo=0 then positivo:=-1;
                     randomize;
                     aleatorio:=positivo*random(10);
                     randomize;
                     aleatorio2:=random(60);
                 end;
                 qticados.Edit;
                 decodedate(qticadosfecha.AsDateTime,anyo,mes,dia);
                 tfecha:=inttostr(anyo)+'/'+inttostr(mes)+'/'+inttostr(dia);
                 qticadosentradam.Value:=strtotime(v_hora.Text);
                 qticadosentradam.Value:=qticadosentradam.AsdateTime+aleatorio/1440+aleatorio2/86400;
                 if edit2.Text <>'' then qticadosobservaciones.Value:=Edit2.Text;
                 qticados.post;
                 qticados.Next;
              end;
            end;
            1:
            begin
              qticados.First;
              while not qticados.Eof do
              begin
                 if v_hora.text<>'00:00:00' then
                 begin
                     randomize;
                     positivo:=random(2);
                     if positivo=0 then positivo:=-1;
                     randomize;
                     aleatorio:=positivo*random(10);
                     randomize;
                     aleatorio2:=random(60);
                 end;

                 qticados.Edit;
                 decodedate(qticadosfecha.AsDateTime,anyo,mes,dia);
                 tfecha:=inttostr(anyo)+'/'+inttostr(mes)+'/'+inttostr(dia);
                 qticadossalidam.Value:=strtotime(v_hora.Text);
                 qticadossalidam.Value:=qticadossalidam.AsdateTime+aleatorio/1440+aleatorio2/86400;
                 if edit2.Text <>'' then qticadosobservaciones.Value:=Edit2.Text;
                 qticados.post;
                 qticados.Next;
              end;
            end;
            2:
            begin
              qticados.First;
              while not qticados.Eof do
              begin
                 if v_hora.Text<>'00:00:00' then
                 begin
                     randomize;
                     positivo:=random(2);
                     if positivo=0 then positivo:=-1;
                     randomize;
                     aleatorio:=positivo*random(10);
                     randomize;
                     aleatorio2:=random(60);
                 end;
                 qticados.Edit;
                 decodedate(qticadosfecha.AsDateTime,anyo,mes,dia);
                 tfecha:=inttostr(anyo)+'/'+inttostr(mes)+'/'+inttostr(dia);
                 qticadosentradat.Value:=strtotime(v_hora.Text);
                 qticadosentradat.Value:=qticadosentradat.AsdateTime+aleatorio/1440+aleatorio2/86400;
                 if edit2.Text <>'' then qticadosobservaciones.Value:=Edit2.Text;
                 qticados.post;
                 qticados.Next;
              end;
            end;
            3:
            begin
              qticados.First;
              while not qticados.Eof do
              begin
                 if v_hora.Text<>'00:00:00' then
                 begin
                     randomize;
                     positivo:=random(2);
                     if positivo=0 then positivo:=-1;
                     randomize;
                     aleatorio:=positivo*random(10);
                     randomize;
                     aleatorio2:=random(60);
                 end;

                 qticados.Edit;
                 decodedate(qticadosfecha.AsDateTime,anyo,mes,dia);
                 tfecha:=inttostr(anyo)+'/'+inttostr(mes)+'/'+inttostr(dia);
                 qticadossalidat.Value:=strtotime(v_hora.Text);
                 qticadossalidat.Value:=qticadossalidat.AsdateTime+aleatorio/1440+aleatorio2/86400;
                 if edit2.Text <>'' then qticadosobservaciones.Value:=Edit2.Text;
                 qticados.post;
                 qticados.Next;
              end;
            end;
        end;
     end;
    if (v_hora.Text='  :  :  ') and (edit2.text<>'') then
    begin
      qticados.First;
      while not qticados.Eof do
      begin
         qticados.Edit;
         if edit2.Text <>'' then qticadosobservaciones.Value:=Edit2.Text;
         qticados.post;
         qticados.Next;
      end;
    end;
    qticados.Refresh;
    desdeactualizar:=0;
    qticados.First;
end;

procedure Tticados.Button4Click(Sender: TObject);
var punto:string;
formatos:tformatsettings;
begin
    GetLocaleFormatSettings(LOCALE_SYSTEM_DEFAULT, formatos);
    punto:=formatos.DecimalSeparator;
    qticados.First;
    if punto=',' then  v_descuento.text:=stringreplace(v_descuento.Text,'.',',',[rfreplaceall]);
      while not qticados.Eof do
      begin
         qticados.Edit;
         qticadosdescuentohoras.Value:=strtofloat(v_descuento.Text);
         qticados.post;
         qticados.Next;
      end;
      qticados.refresh;
      qticados.First;
end;

procedure Tticados.Button5Click(Sender: TObject);
var contador,vide,vidt:integer;
    dia,mes,anyo:word;
    tfecha:string;
    totaljornal:real;
begin
    qjornales.Open;
    qticados.First;
    qaux.SQL.Clear;
    qaux.SQL.Add('select max(id)+1 from trabajo_diario');
    qaux.Open;
    contador:=qaux.Fields[0].AsInteger;
    if qticados.RecordCount>0 then
       begin
           qticados.First;

           while not qticados.Eof do
           begin
           vide:=qticadoside.Asinteger;
           vidt:=qticadosidt.AsInteger;
           qempleados.Locate('ide,id',vararrayof([vide,vidt]),[locaseinsensitive]);
           decodedate(qticadosfecha.AsDateTime,anyo,mes,dia);
           tfecha:=floattostr(anyo)+'-'+floattostr(mes)+'-'+floattostr(dia);
              if checkborrar.Checked then
              begin
                  qaux.SQL.Clear;
                  qaux.SQL.Add('select * from trabajo_diario where idt='+qticadosidt.AsString+' and fecha='+''''+tfecha+''''+' and empresa='+qticadoside.AsString);
                  qaux.open;
                  if qaux.RecordCount>0 then
                  begin
                      qaux.SQL.Clear;
                      qaux.SQL.Add('delete from trabajo_diario where idt='+qticadosidt.AsString+' and fecha='+''''+tfecha+''''+' and empresa='+qticadoside.AsString);
                      qaux.execsql;
                  end;

              end;
              qjornales.append;
              qjornalesid.Value:=contador;
              qjornalesfecha.Value:=qticadosfecha.AsDateTime;
              qjornalesparcela.value:=ljcentro.KeyValue;
              qjornalesidt.Value:=qticadosidt.asinteger;
              qjornalestrabajador.Value:=qticadostrabajador.asstring;
              qjornalestypework.Value:=ljtrabajo.KeyValue;
              qjornalesarticulo.Value:=ljhora.KeyValue;
              qjornalesqhoras.Value:=qticadoshorascobrar.AsFloat;
              qjornalesprecio.value:=qtipohorasprecio.AsFloat;
              qjornalesobservaciones.value:=qticadosobservaciones.AsString;
              totaljornal:=qticadoshorascobrar.asfloat*qtipohorasprecio.AsFloat;
              qjornalestotal.Value:=strtofloat(FormatFloat('0.00',totaljornal));
              qjornalesestado.Value:='C';
              qjornales.Post;
              contador:=contador+1;
              qticados.Next;
           end;
       end else
           begin
             showmessage('DEBE SELECCIONAR AL MENOS UN TRABAJADOR');
           end;
      qticados.First;
end;

procedure Tticados.Button6Click(Sender: TObject);
begin
      qticados.First;
      v_horas.text:=stringreplace(v_horas.Text,' ','',[rfreplaceall]);
      if v_horas.text<>'' then
      begin
        v_horas.text:=stringreplace(v_horas.Text,'.',',',[rfreplaceall]);
        while not qticados.Eof do
        begin
           qticados.Edit;
           qticadoshorascobrar.Value:=strtofloat(v_horas.Text);
           qticados.post;
           qticados.Next;
        end;
      end;
    qticados.refresh;
    qticados.First;
end;

procedure Tticados.Button7Click(Sender: TObject);
begin
    dlgticados := Tdlgticados.Create(nil);
    try
      dlgticados.qticados.ParamByName('IDE').AsInteger:=qticadoside.AsInteger;
      dlgticados.qticados.ParamByName('IDT').AsInteger:=qticadosidt.AsInteger;
      dlgticados.qticados.ParamByName('FECHA').Asdatetime:=qticadosfecha.Asdatetime;
      dlgticados.qticados.prepare;
      dlgticados.qticados.Open;
      dlgticados.showmodal();
    finally
      dlgticados.Free;
      qticados.Refresh;
    end;
end;

procedure Tticados.Button8Click(Sender: TObject);
var minutosajuste,ajusteentrada,ajustesalida:integer;
    horaentrada,horasalida:ttime;
    hora,minutos,horaaj,minutosaj,anyo,mes,dia:word;
    dhora,dminutos,dsegundos,dmilisegundos:word;
    horasfact:real;
    tid,descuento:integer;
    vmes,vdia,vanyo,vfecha,sdescuento:string;
begin
  qticados.First;
  if dm.tempresaajuste15.AsInteger=1 then minutosajuste:=15;
  if dm.tempresaajuste30.AsInteger=1 then minutosajuste:=30;
  ajusteentrada:=dm.tempresaajusteentrada.AsInteger;
  ajustesalida:=dm.tempresaajustesalida.AsInteger;
  while not qticados.Eof do
  begin
    horasfact:=0;
    if qticadosentradam.Asstring<>'' then
    begin     //1
      horaentrada:=qticadosentradam.AsDateTime;
      if qticadossalidam.Asstring<>'' then
      begin      //2
        horasalida:=qticadossalidam.AsDateTime;
        if minutosajuste=30 then
        begin        //4
           decodetime(horaentrada,dhora,dminutos,dsegundos,dmilisegundos);
           horaaj:=dhora;
           if dminutos<=ajusteentrada then minutosaj:=0;
           if (dminutos>ajusteentrada) and (dminutos<=ajusteentrada+30) then minutosaj:=30;
           if dminutos>30+ajusteentrada then
           begin
                minutosaj:=0;
                horaaj:=horaaj+1;
           end;
           horaentrada:=encodetime(horaaj,minutosaj,0,0);
           decodetime(horasalida,dhora,dminutos,dsegundos,dmilisegundos);
           horaaj:=dhora;
           if dminutos<=ajustesalida then minutosaj:=0;
           if (dminutos>ajustesalida) and (dminutos<=ajustesalida+30) then minutosaj:=30;
           if dminutos>30+ajustesalida then
           begin
                minutosaj:=0;
                horaaj:=horaaj+1;
           end;
           horasalida:=encodetime(horaaj,minutosaj,0,0);
           horasfact:=(horasalida-horaentrada)*24;
        end; //4
        if minutosajuste=15 then
        begin        //4
           decodetime(horaentrada,dhora,dminutos,dsegundos,dmilisegundos);
           horaaj:=dhora;
           if dminutos<=ajusteentrada then minutosaj:=0;
           if (dminutos>ajusteentrada) and (dminutos<=ajusteentrada+15) then minutosaj:=15;
           if (dminutos>15+ajusteentrada) and (dminutos<=ajusteentrada+30) then minutosaj:=30;
           if (dminutos>30+ajusteentrada) and (dminutos<=ajusteentrada+45) then minutosaj:=45;
           if dminutos>45+ajusteentrada then
           begin
                minutosaj:=0;
                horaaj:=horaaj+1;
           end;
           horaentrada:=encodetime(horaaj,minutosaj,0,0);
           decodetime(horasalida,dhora,dminutos,dsegundos,dmilisegundos);
           horaaj:=dhora;
           if dminutos<=ajusteentrada then minutosaj:=0;
           if (dminutos>ajusteentrada) and (dminutos<=ajusteentrada+15) then minutosaj:=15;
           if (dminutos>15+ajusteentrada) and (dminutos<=ajusteentrada+30) then minutosaj:=30;
           if (dminutos>30+ajusteentrada) and (dminutos<=ajusteentrada+45) then minutosaj:=45;
           if dminutos>45+ajusteentrada then
           begin
                minutosaj:=0;
                horaaj:=horaaj+1;
           end;
           horasalida:=encodetime(horaaj,minutosaj,0,0);
           horasfact:=(horasalida-horaentrada)*24;
        end;
      end;     //2
    end;//1
    if qticadosentradat.Asstring<>'' then
    begin   //1
      horaentrada:=qticadosentradat.AsDateTime;
      if qticadossalidat.Asstring<>'' then
      begin    //2
        horasalida:=qticadossalidat.AsDateTime;
        if minutosajuste=30 then
        begin  //4
           decodetime(horaentrada,dhora,dminutos,dsegundos,dmilisegundos);
           horaaj:=dhora;
           if dminutos<=ajusteentrada then minutosaj:=0;
           if (dminutos>ajusteentrada) and (dminutos<=ajusteentrada+30) then minutosaj:=30;
           if dminutos>30+ajusteentrada then
           begin
                minutosaj:=0;
                horaaj:=horaaj+1;
           end;
           horaentrada:=encodetime(horaaj,minutosaj,0,0);

           decodetime(horasalida,dhora,dminutos,dsegundos,dmilisegundos);
           horaaj:=dhora;
           if dminutos<=ajustesalida then minutosaj:=0;
           if (dminutos>ajustesalida) and (dminutos<=ajustesalida+30) then minutosaj:=30;
           if dminutos>30+ajustesalida then
           begin
                minutosaj:=0;
                horaaj:=horaaj+1;
           end;
           horasalida:=encodetime(horaaj,minutosaj,0,0);
           horasfact:=horasfact+((horasalida-horaentrada)*24);
         end;         //4
        if minutosajuste=15 then
        begin  //4
           decodetime(horaentrada,dhora,dminutos,dsegundos,dmilisegundos);
           horaaj:=dhora;
           if dminutos<=ajusteentrada then minutosaj:=0;
           if (dminutos>ajusteentrada) and (dminutos<=ajusteentrada+15) then minutosaj:=15;
           if (dminutos>15+ajusteentrada) and (dminutos<=ajusteentrada+30) then minutosaj:=30;
           if (dminutos>30+ajusteentrada) and (dminutos<=ajusteentrada+45) then minutosaj:=45;
           if dminutos>45+ajusteentrada then
           begin
                minutosaj:=0;
                horaaj:=horaaj+1;
           end;
           horaentrada:=encodetime(horaaj,minutosaj,0,0);

           decodetime(horasalida,dhora,dminutos,dsegundos,dmilisegundos);
           horaaj:=dhora;
           if dminutos<=ajusteentrada then minutosaj:=0;
           if (dminutos>ajusteentrada) and (dminutos<=ajusteentrada+15) then minutosaj:=15;
           if (dminutos>15+ajusteentrada) and (dminutos<=ajusteentrada+30) then minutosaj:=30;
           if (dminutos>30+ajusteentrada) and (dminutos<=ajusteentrada+45) then minutosaj:=45;
           if dminutos>45+ajusteentrada then
           begin
                minutosaj:=0;
                horaaj:=horaaj+1;
           end;
           horasalida:=encodetime(horaaj,minutosaj,0,0);
           horasfact:=horasfact+((horasalida-horaentrada)*24);
         end;         //4

        end;  //2

      end; //1
     qticados.Edit;
     qticadoshorascobrar.asfloat:=0;
     qticadosmodificando.asinteger:=1;
     qticados.Post;
     qticados.Edit;
     qticadoshorascobrar.asfloat:=horasfact-qticadosdescuentohoras.AsFloat;
     qticadosmodificando.asinteger:=0;
     qticados.Post;
     qticados.Next;
  end;


end;

procedure Tticados.Button9Click(Sender: TObject);
var  archivo,vmes,vnombre,vnif,vhoras:string;
     tdia,tmes,tanyo:word;
     vdia,vanyo,vide,vidt:integer;
begin
  qaux.Close;
  qaux.SQL.Clear;
  qaux.SQL.Add('delete from emp_asistencia');
  qaux.execsql;

  qticados.First;
  while not qticados.Eof do
  begin
    decodedate(qticadosfecha.AsDateTime,tanyo,tmes,tdia);
    vdia:=tdia;
    vanyo:=tanyo;
    vhoras:=floattostr(qticadosnum_horas_m.AsFloat);
    case tmes of
       1:vmes:='ENERO';
       2:vmes:='FEBRERO';
       3:vmes:='MARZO';
       4:vmes:='ABRIL';
       5:vmes:='MAYO';
       6:vmes:='JUNIO';
       7:vmes:='JULIO';
       8:vmes:='AGOSTO';
       9:vmes:='SEPTIEMBRE';
      10:vmes:='OCTUBRE';
      11:vmes:='NOVIEMBRE';
      12:vmes:='DICIEMBRE';
    end;
    vide:=qticadoside.AsInteger;
    vidt:=qticadosidt.AsInteger;
    qempleados.Locate('ide,id',vararrayof([vide,vidt]),[locaseinsensitive]);
    vnif:=qempleadosnif.asstring;
    vnombre:=qempleadosnombre.AsString;
    qaux.Close;
    qaux.SQL.Clear;
    qaux.SQL.Add('select * from emp_asistencia where ide=:EMPRESA and idt=:TRABAJADOR and anyo=:ANYO and mes=:MES');
    qaux.Prepare;
    qaux.ParamByName('EMPRESA').AsInteger:=vide;
    qaux.ParamByName('TRABAJADOR').AsInteger:=vidt;
    qaux.ParamByName('ANYO').AsInteger:=vanyo;
    qaux.ParamByName('MES').Asstring:=vmes;
    qaux.Open;
    if qaux.RecordCount=0 then
    begin
      qaux.Close;
      qaux.SQL.Clear;
      qaux.SQL.Add('insert into emp_asistencia (ide,idt,nif,nombre,anyo,mes) values (:EMPRESA,:TRABAJADOR,:NIF,:NOMBRE,:ANYO,:MES)');
      qaux.Prepare;
      qaux.ParamByName('EMPRESA').AsInteger:=vide;
      qaux.ParamByName('TRABAJADOR').AsInteger:=vidt;
      qaux.ParamByName('NIF').Asstring:=vnif;
      qaux.ParamByName('NOMBRE').Asstring:=vnombre;
      qaux.ParamByName('ANYO').AsInteger:=vanyo;
      qaux.ParamByName('MES').Asstring:=vmes;
      qaux.execsql;
      qasistir.close;
      qasistir.Open;
      qasistir.Locate('ide,idt,anyo,mes',vararrayof([vide,vidt,vanyo,vmes]),[locaseinsensitive]);
    end;
       qasistir.Edit;
       case vdia of
       1:qasistird1.value:='X';
       2:qasistird2.value:='X';
       3:qasistird3.value:='X';
       4:qasistird4.value:='X';
       5:qasistird5.value:='X';
       6:qasistird6.value:='X';
       7:qasistird7.value:='X';
       8:qasistird8.value:='X';
       9:qasistird9.value:='X';
      10:qasistird10.value:='X';
      11:qasistird11.value:='X';
      12:qasistird12.value:='X';
      13:qasistird13.value:='X';
      14:qasistird14.value:='X';
      15:qasistird15.value:='X';
      16:qasistird16.value:='X';
      17:qasistird17.value:='X';
      18:qasistird18.value:='X';
      19:qasistird19.value:='X';
      20:qasistird20.value:='X';
      21:qasistird21.value:='X';
      22:qasistird22.value:='X';
      23:qasistird23.value:='X';
      24:qasistird24.value:='X';
      25:qasistird25.value:='X';
      26:qasistird26.value:='X';
      27:qasistird27.value:='X';
      28:qasistird28.value:='X';
      29:qasistird29.value:='X';
      30:qasistird30.value:='X';
      31:qasistird31.value:='X';
    end;
    qasistir.Post;
    qticados.Next;
  end;
    decodedate(fdesde.date,tanyo,tmes,tdia);
    case tmes of
       1:vmes:='ENERO';
       2:vmes:='FEBRERO';
       3:vmes:='MARZO';
       4:vmes:='ABRIL';
       5:vmes:='MAYO';
       6:vmes:='JUNIO';
       7:vmes:='JULIO';
       8:vmes:='AGOSTO';
       9:vmes:='SEPTIEMBRE';
      10:vmes:='OCTUBRE';
      11:vmes:='NOVIEMBRE';
      12:vmes:='DICIEMBRE';
    end;
    qasistir.Close;
    qasistir.SQL.Clear;
    qasistir.SQL.Add('select * from v_emp_asistencia where ide=:EMPRESA and anyo=:ANYO and mes=:MES order by anyo,nombre2');
    qasistir.Prepare;
    qasistir.ParamByName('EMPRESA').AsInteger:=vide;
    qasistir.ParamByName('MES').Asstring:=vmes;
    qasistir.ParamByName('ANYO').Asinteger:=vanyo;

    qasistir.Open;

    savedialog1.FileName:='PARTE COMUNICACION.xlsx';
    savedialog1.Execute();
    archivo:=savedialog1.FileName;
    try
    Exportaraexcel(archivo,'PARTE',GRIDASISTENCIA);
    finally
      showmessage('Los datos han sido exportados correctamente a '+archivo);
    end;
{    qasistencia.Close;
    qasistencia.SQL.Clear;
    qasistencia.SQL.Add('select * from v_emp_asistencia order by ide,idt,anyo,mes');
    qasistencia.Open;}

end;

function Tticados.ObtenerFiltroTrabajadoresSQL: string;
var
  i: Integer;
  LIds: string;
  p_empresa: Integer;
  p_empleados, p_grupo, p_activo: string;
  LBookmarkActual: TBookmark;
begin
  if DBGrid1.SelectedRows.Count > 1 then
  begin
    LIds := '';
    qempleados.DisableControls;
    try
      LBookmarkActual := qempleados.GetBookmark;
      try
        for i := 0 to DBGrid1.SelectedRows.Count - 1 do
        begin
          qempleados.GotoBookmark(DBGrid1.SelectedRows[i]);
          if qempleadosid.AsString <> '' then
          begin
            if LIds <> '' then
              LIds := LIds + ',' + qempleadosid.AsString
            else
              LIds := qempleadosid.AsString;
          end;
        end;
      finally
        if qempleados.BookmarkValid(LBookmarkActual) then
          qempleados.GotoBookmark(LBookmarkActual);
        qempleados.FreeBookmark(LBookmarkActual);
      end;
    finally
      qempleados.EnableControls;
    end;

    if LIds <> '' then
      Result := ' idt in (' + LIds + ') '
    else if (qempleados.Active) and (qempleados.RecordCount > 0) then
      Result := ' idt = ' + qempleadosid.AsString + ' '
    else
      Result := ' 1=0 ';
  end
  else if CheckBox1.Checked then
  begin
    if dm.tempresa.Active then
      p_empresa := dm.tempresaid.AsInteger
    else
    begin
      dm.tempresa.Open;
      p_empresa := dm.tempresaid.AsInteger;
    end;

    if grupo = 0 then p_grupo := '%' else p_grupo := IntToStr(grupo);
    p_empleados := '%' + buscarempleado.Text + '%';
    if chktodos.Checked then p_activo := '%' else p_activo := '1';

    Result := ' idt in (select id from trabajadores where ide=' + IntToStr(p_empresa) +
              ' and grupo like ' + QuotedStr(p_grupo) +
              ' and nombre like ' + QuotedStr(p_empleados) +
              ' and activo like ' + QuotedStr(p_activo) + ') ';
  end
  else
  begin
    if (qempleados.Active) and (qempleados.RecordCount > 0) then
      Result := ' idt = ' + qempleadosid.AsString + ' '
    else
      Result := ' 1=0 ';
  end;
end;

procedure Tticados.DBGrid1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if (Button = mbLeft) and not CheckBox1.Checked then
  begin
    btactualizarClick(Sender);
  end;
end;

procedure Tticados.DBGrid1KeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if not CheckBox1.Checked and (Key in [VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT, VK_HOME, VK_END]) then
  begin
    btactualizarClick(Sender);
  end;
end;

procedure Tticados.btactualizarClick(Sender: TObject);
var
  p_mostrar: string;
  LSQLFiltro: string;
begin
  if FActualizando then
    Exit;
  FActualizando := True;
  try
    if EsModoAmpliado or gridampliado.Visible then p_mostrar := '%' else p_mostrar := '1';
    LSQLFiltro := ObtenerFiltroTrabajadoresSQL;

    qticados.Close;
    qticados.SQL.Clear;
    qticados.SQL.Add(
      'select *,if(salidam_m>salidat_m,salidat_m,salidam_m) as salidam_mm,if(salidam_m>salidat_m,num_horas_m,horasm_m) as horasm_mm,' +
      'if(entradat<salidat_m,entradat,null) as entradat_mm,if(entradat<salidat_m,salidat_m,null) as salidat_mm,if(entradat<salidat_m,horast_m,0.00) as horast_mm ' +
      'from ticadoscompleto where mostrar like(:MOSTRAR) and fecha>=:FECHAINICIO and fecha<=:FECHAFIN and ' + LSQLFiltro +
      ' order by trabajador,fecha desc,entradam,entradat');
    qticados.Prepare;
    qticados.ParamByName('FECHAINICIO').AsDate := fdesde.Date;
    qticados.ParamByName('FECHAFIN').AsDate := fhasta.Date;
    qticados.ParamByName('MOSTRAR').AsString := p_mostrar;
    qticados.MasterSource := nil;
    qticados.Open;

    qtotalhoras.Close;
    qtotalhoras.MasterSource := nil;
    qtotalhoras.SQL.Clear;
    qtotalhoras.SQL.Add(
      'select idt,sum(num_horas_m) as totalhoras from ticadoscompleto where mostrar like(:MOSTRAR) and fecha>=:FECHAINICIO and fecha<=:FECHAFIN and ' + LSQLFiltro);
    if not CheckBox1.Checked and (DBGrid1.SelectedRows.Count <= 1) then
      qtotalhoras.SQL.Add(' group by idt order by idt');
    qtotalhoras.Prepare;
    qtotalhoras.ParamByName('FECHAINICIO').AsDate := fdesde.Date;
    qtotalhoras.ParamByName('FECHAFIN').AsDate := fhasta.Date;
    qtotalhoras.ParamByName('MOSTRAR').AsString := p_mostrar;
    qtotalhoras.Open;

    qtotales.Close;
    qtotales.MasterSource := nil;
    qtotales.SQL.Clear;
    if CheckBox1.Checked or (DBGrid1.SelectedRows.Count > 1) then
      qtotales.SQL.Add(
        'select idt,trabajador,sum(num_horas_m) as totalhoras,sum(horascobrar) as totalhorascompu ' +
        'from ticadoscompleto where mostrar like(:MOSTRAR) and fecha>=:FECHAINICIO and fecha<=:FECHAFIN and ' + LSQLFiltro +
        ' group by trabajador order by trabajador')
    else
      qtotales.SQL.Add(
        'select idt,trabajador,sum(num_horas_m) as totalhoras,sum(horascobrar) as totalhorascompu ' +
        'from ticadoscompleto where mostrar like(:MOSTRAR) and fecha>=:FECHAINICIO and fecha<=:FECHAFIN and ' + LSQLFiltro +
        ' group by idt order by trabajador');
    qtotales.Prepare;
    qtotales.ParamByName('FECHAINICIO').AsDate := fdesde.Date;
    qtotales.ParamByName('FECHAFIN').AsDate := fhasta.Date;
    qtotales.ParamByName('MOSTRAR').AsString := p_mostrar;
    qtotales.Open;

    if EsModoAmpliado then
      CargarDatosCalendario;
  finally
    FActualizando := False;
  end;
end;

procedure Tticados.CheckBox1Click(Sender: TObject);
begin
    btactualizar.Click;
end;

procedure Tticados.dsqgrupostrabajadores2DataChange(Sender: TObject;
  Field: TField);
begin
  grupo:=qgrupostrabajadores2id.asinteger;
  qempleados.Close;
  qempleados.Open;
end;

procedure Tticados.checkacumuladosClick(Sender: TObject);
begin
    if checkacumulados.Checked then
    begin
        gridtotales.Visible:=true;
        gridnormal.Visible:=false;
        gridampliado.Visible:=false;
        if pcModoAmpliado <> nil then pcModoAmpliado.Visible:=false;
        gridtotales.Columns[2].Title.caption:='Horas desde el '+datetostr(fdesde.Date)+' hasta el '+datetostr(fhasta.Date);
    end else
    begin
        gridtotales.Visible:=false;
        gridnormal.Visible:=true;
        gridampliado.Visible:=false;
        if pcModoAmpliado <> nil then pcModoAmpliado.Visible:=false;
    end;
    btactualizar.Click;
end;

procedure Tticados.gridnormalDrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
begin
    if qticadosfestivo.Asinteger=1 then
    begin
        gridnormal.Canvas.brush.Color := rojo;
    end;

    gridnormal.DefaultDrawColumnCell(Rect, DataCol, Column, State);
end;

procedure Tticados.gridnormalTitleClick(Column: TColumn);
var
  st:ZAbstractRODataset.TSortType;
begin
  st:=qticados.SortType;
  qticados.SortedFields:=Column.FieldName;
  If st = stAscending then qticados.SortType:=stDescending else qticados.SortType:=stAscending;
  dsqticados.DataSet.First;
end;

procedure Tticados.v_horasEnter(Sender: TObject);
begin
   v_horas.Text:='';
end;

procedure Tticados.fdesdeChange(Sender: TObject);
begin
  btactualizar.Click;
end;

procedure Tticados.FormClose(Sender: TObject; var Action: TCloseAction);
begin
   qticados.Close;
   qtotalhoras.Close;
   qempleados.Close;
end;

procedure Tticados.FormKeyPress(Sender: TObject; var Key: Char);
var formatos:tformatsettings;
punto:string;
begin
    GetLocaleFormatSettings(LOCALE_SYSTEM_DEFAULT, formatos);
    punto:=formatos.DecimalSeparator;
    if punto=',' then
    begin
        key:=upcase(key);
        if (key='.') and (activecontrol is tdbedit) then
        begin
           if  (activecontrol as tdbedit).Field.DataType in [ftfloat,ftCurrency,ftbcd,ftfmtbcd] then key:=','
        end;
        if (key='.') and (activecontrol is tdbgrid) then
        begin
            key:=',';
        end;
    end;
    if (activecontrol is tdbgrid) then
    begin
        if Key = #13 then Key :=#9;
    end;

    if (key=#13) then
    begin
        Perform(WM_NextDLGCtl,0,0);
        key:=#0;
    end;
end;

procedure Tticados.FormShow(Sender: TObject);
begin
   DM.tempresa.Open;
   fdesde.Date:=date()-1;
   fhasta.Date:=date()-1;
   gridampliado.Visible:=false;
   if pcModoAmpliado <> nil then
   begin
     pcModoAmpliado.Visible:=false;
     pcModoAmpliado.ActivePage:=tabLista;
   end;
   panel6.Visible:=false;
   pmodificaciones.Visible:=false;
   gridnormal.Visible:=true;
   desdeactualizar:=0;
   FMesFecha := Date;
   FSemanaFecha := Date;
   FDiaSeleccionadoMes := Date;
   gcrpagado.Parent := tabLista;
   qgrupostrabajadores2.Prepare;
   qgrupostrabajadores2.ParamByName('IDEMPRESA').AsInteger:=dm.tempresaid.AsInteger;
   qgrupostrabajadores2.open;
   tgrupo.KeyValue:=qgrupostrabajadores2id.AsString;
   qparcelas.Open;
   qtipohoras.Open;
   qtrabajos.Open;
end;

procedure Tticados.gridampliadoCellClick(Column: TColumn);
begin
    if column.Field.FieldName ='mostrar' then
    begin
        if qticadosmostrar.asinteger=1 then
         begin
           qticados.Edit;
           qticadosmostrar.value:=0;
           qticados.Post;
//           qticados.Refresh;
           gridampliado.selectedIndex:=18;
         end else
               begin
                 qticados.edit;
                 qticadosmostrar.Value:=1;
                 qticados.Post;
//                 qticados.Refresh;
                 gridampliado.SelectedIndex:=18;
               end;
    end;
    qtotalhoras.close;
    qtotalhoras.Open;
end;

procedure Tticados.gridampliadoDblClick(Sender: TObject);
var vidticados:integer;
begin
    vidticados:=qticadosid.AsInteger;
    dlgticados := Tdlgticados.Create(nil);
    try
      dlgticados.qticados.ParamByName('IDE').AsInteger:=qticadoside.AsInteger;
      dlgticados.qticados.ParamByName('IDT').AsInteger:=qticadosidt.AsInteger;
      dlgticados.qticados.ParamByName('FECHA').Asdatetime:=qticadosfecha.Asdatetime;
      dlgticados.qticados.prepare;
      dlgticados.qticados.Open;
      dlgticados.idticado:=vidticados;
      dlgticados.showmodal();
    finally
      dlgticados.Free;
      qticados.Refresh;
      qticados.Locate('id',vidticados,[locaseinsensitive]);
    end;
end;

procedure Tticados.gridampliadoDrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
const IsChecked : array[Boolean] of Integer = (DFCS_BUTTONCHECK, DFCS_BUTTONCHECK or DFCS_CHECKED);
var
    DrawState: Integer;
    DrawRect: TRect;
begin
if (gdFocused in State) then
begin
    if qticadosfestivo.Asinteger=1 then
    begin
        Gridampliado.Canvas.brush.Color := rojo;
    end;
    gridampliado.DefaultDrawColumnCell(Rect, DataCol, Column, State);

    if (Column.Field.FieldName = 'mostrar') then
     begin
       if gcrpagado.Parent <> tabLista then
         gcrpagado.Parent := tabLista;
       gcrpagado.Left := Rect.Left + gridampliado.Left + 2;
       gcrpagado.Top := Rect.Top + gridampliado.top + 2;
       gcrpagado.Width := Rect.Right - Rect.Left;
       gcrpagado.Height := Rect.Bottom - Rect.Top;
       gcrpagado.Visible := True;
     end;
end else
     begin
        if qticadosfestivo.Asinteger=1 then
        begin
            Gridampliado.Canvas.brush.Color := rojo;
        end;
        gridampliado.DefaultDrawColumnCell(Rect, DataCol, Column, State);

       if (Column.Field.FieldName = 'mostrar') then
       begin
         DrawRect:=Rect;
         InflateRect(DrawRect,-1,-1);
         if column.Field.Asinteger=0  then DrawState := ischecked[false];
         if column.Field.Asinteger=1  then DrawState := ischecked[true];
         //DrawState := ISChecked[Column.Field.Asboolean];
         gridampliado.Canvas.FillRect(Rect);
         DrawFrameControl(gridampliado.Canvas.Handle, DrawRect,
         DFC_BUTTON, DrawState);
       end;
    end;


end;

procedure Tticados.gridampliadoTitleClick(Column: TColumn);
var
  st:ZAbstractRODataset.TSortType;
begin
  st:=qticados.SortType;
  qticados.SortedFields:=Column.FieldName;
  If st = stAscending then qticados.SortType:=stDescending else qticados.SortType:=stAscending;
  dsqticados.DataSet.First;
end;

procedure Tticados.Panel5Click(Sender: TObject);
var idt:integer;
begin
   idt:=qempleadosid.AsInteger;


   if gridnormal.visible then
   begin
      gridampliado.Visible:=true;
      if pcModoAmpliado <> nil then
        pcModoAmpliado.Visible:=true;
      panel6.Visible:=true;
      gridnormal.Visible:=false;
      pmodificaciones.visible:=true;
      button10.Visible:=true;
      if FMesFecha = 0 then FMesFecha := fdesde.Date;
      if FSemanaFecha = 0 then FSemanaFecha := fdesde.Date;

   end else
   begin
      gridampliado.Visible:=false;
      if pcModoAmpliado <> nil then
        pcModoAmpliado.Visible:=false;
      panel6.Visible:=false;
      gridnormal.Visible:=true;
      pmodificaciones.visible:=false;
      button10.Visible:=false;
   end;
   btactualizar.Click;
   qempleados.Locate('id',idt,[locaseinsensitive]);

end;

procedure Tticados.qempleadosAfterOpen(DataSet: TDataSet);
begin
  btactualizarClick(nil);
end;

procedure Tticados.qempleadosBeforeOpen(DataSet: TDataSet);
var p_empresa:integer;
    p_empleados,p_grupo,p_activo:string;
begin
      if dm.tempresa.Active then p_empresa:=dm.tempresaid.AsInteger
      else
        begin
          dm.tempresa.Open;
          p_empresa:=dm.tempresaid.AsInteger;
        end;
      if grupo=0 then p_grupo:='%' else p_grupo:=inttostr(grupo);
      p_empleados:='%'+buscarempleado.Text+'%';
      if chktodos.Checked then p_activo:='%' else p_activo:='1';
      qempleados.Prepare;
      qempleados.parambyname('EMPRESA').AsInteger:=p_empresa;
      qempleados.parambyname('GRUPO').Asstring:=p_grupo;
      qempleados.parambyname('EMPLEADO').Asstring:=p_empleados;
      qempleados.parambyname('ACTIVO').Asstring:=p_activo;
end;

procedure Tticados.qticadosAfterOpen(DataSet: TDataSet);
var
  p_mostrar: string;
begin
  if CheckBox1.Checked then
  begin
    if EsModoAmpliado or gridampliado.Visible then p_mostrar := '%' else p_mostrar := '1';
    qaux.Close;
    qaux.SQL.Clear;
    qaux.SQL.Add('select count(distinct(idt)) from ticadoscompleto where mostrar like(:MOSTRAR) and fecha>=:FECHAINICIO and fecha<=:FECHAFIN and ' + ObtenerFiltroTrabajadoresSQL);
    qaux.Prepare;
    qaux.ParamByName('FECHAINICIO').AsDate := fdesde.Date;
    qaux.ParamByName('FECHAFIN').AsDate := fhasta.Date;
    qaux.ParamByName('MOSTRAR').AsString := p_mostrar;
    qaux.Open;
    lnumtrabajadores.Caption := 'Trabajadores seleccionados: ' + qaux.Fields[0].AsString;
    qaux.Close;
  end
  else if DBGrid1.SelectedRows.Count > 1 then
  begin
    lnumtrabajadores.Caption := 'Trabajadores seleccionados: ' + IntToStr(DBGrid1.SelectedRows.Count);
  end
  else if (qempleados.Active) and (qempleados.RecordCount > 0) then
  begin
    lnumtrabajadores.Caption := 'Trabajadores seleccionados: 1';
  end
  else
    lnumtrabajadores.Caption := 'Trabajadores seleccionados: 0';
end;

procedure Tticados.qticadosAfterPost(DataSet: TDataSet);
begin
   qticados.Refresh;
   qticados.Locate('id',vidticados,[locaseinsensitive]);
end;

procedure Tticados.qticadosBeforeEdit(DataSet: TDataSet);
begin
    oldhoras:=qticadoshorascobrar.AsFloat;
end;

procedure Tticados.qticadosBeforePost(DataSet: TDataSet);
var hora:string;
begin
{    if qticadossalidat.AsString<>'' then
    begin
        hora:=qticadossalidat.asstring;
        qticadoshorafinmostrar.Value:=strtotime(hora);
    end;
    if (qticadossalidam.AsString<>'') and (qticadossalidat.AsString='') then
    begin
        hora:=qticadossalidam.asstring;
       qticadoshorafinmostrar.Value:=strtotime(hora);
    end; }
    if (qticadoshorascobrar.AsFloat<>oldhoras) and (qticadosmodificando.asinteger=0) then
    begin
       qticadosmodificando.value:=1;
    end;
    vidticados:=qticadosid.AsInteger;

end;

procedure Tticados.tgrupoChange(Sender: TObject);
begin
  grupo:=qgrupostrabajadores2id.asinteger;
  qempleados.Close;
  qempleados.Open;
end;

function Tticados.EsModoAmpliado: Boolean;
begin
  Result := (pcModoAmpliado <> nil) and pcModoAmpliado.Visible;
end;

function Tticados.ObtenerFechaCeldaMes(ACol, ARow: Integer): TDate;
var
  LPrimerDiaMes: TDate;
  LDiaSemanaInicio: Integer;
  LDiaOffset: Integer;
begin
  if FMesFecha = 0 then
    FMesFecha := Date;
  LPrimerDiaMes := StartOfTheMonth(FMesFecha);
  LDiaSemanaInicio := DayOfTheWeek(LPrimerDiaMes); // 1=Lunes .. 7=Domingo
  LDiaOffset := (ARow - 1) * 7 + ACol - (LDiaSemanaInicio - 1);
  Result := LPrimerDiaMes + LDiaOffset;
end;

procedure Tticados.CargarDatosCalendario;
var
  i: Integer;
  LBM: TBookmark;
  LInfo: TTicadoInfo;
  LIdxTrabajador: Integer;
  LDiaSemana: Integer;
  LFechaTicado: TDate;
  LSemInicio, LSemFin: TDate;

  function BuscarOAgregarTrabajador(AIdt: Integer; const ANombre: string): Integer;
  var
    k: Integer;
  begin
    for k := 0 to High(FTrabajadoresSemana) do
    begin
      if FTrabajadoresSemana[k].Idt = AIdt then
      begin
        Result := k;
        Exit;
      end;
    end;
    SetLength(FTrabajadoresSemana, Length(FTrabajadoresSemana) + 1);
    Result := High(FTrabajadoresSemana);
    FTrabajadoresSemana[Result].Idt := AIdt;
    FTrabajadoresSemana[Result].Nombre := ANombre;
    FTrabajadoresSemana[Result].TotalHoras := 0;
  end;

begin
  SetLength(FTicadosList, 0);
  SetLength(FTrabajadoresSemana, 0);
  for i := 1 to 7 do
    FTotalesDiaSemana[i] := 0;
  FTotalGeneralSemana := 0;

  if FSemanaFecha = 0 then
    FSemanaFecha := Date;
  LSemInicio := StartOfTheWeek(FSemanaFecha);
  LSemFin := EndOfTheWeek(FSemanaFecha);

  if not qticados.Active or (qticados.RecordCount = 0) then
  begin
    ActualizarCalendarioMes;
    ActualizarCalendarioSemana;
    Exit;
  end;

  qticados.DisableControls;
  LBM := qticados.GetBookmark;
  try
    qticados.First;
    while not qticados.Eof do
    begin
      SetLength(FTicadosList, Length(FTicadosList) + 1);
      LInfo.Id := qticadosid.AsLargeInt;
      LInfo.Ide := qticadoside.AsInteger;
      LInfo.Idt := qticadosidt.AsInteger;
      LInfo.Fecha := qticadosfecha.AsDateTime;
      LInfo.Trabajador := qticadosTRABAJADOR.AsString;
      if not qticadosentradam.IsNull then
        LInfo.EntradaM := FormatDateTime('hh:nn', qticadosentradam.AsDateTime)
      else
        LInfo.EntradaM := '';
      if not qticadossalidam_m.IsNull then
        LInfo.SalidaM := FormatDateTime('hh:nn', qticadossalidam_m.AsDateTime)
      else
        LInfo.SalidaM := '';
      LInfo.HorasM := qticadoshorasm_mm.AsFloat;

      if not qticadosentradat_mm.IsNull then
        LInfo.EntradaT := FormatDateTime('hh:nn', qticadosentradat_mm.AsDateTime)
      else
        LInfo.EntradaT := '';
      if not qticadossalidat_mm.IsNull then
        LInfo.SalidaT := FormatDateTime('hh:nn', qticadossalidat_mm.AsDateTime)
      else
        LInfo.SalidaT := '';
      LInfo.HorasT := qticadoshorast_mm.AsFloat;

      LInfo.NumHoras := qticadosnum_horas_m.AsFloat;
      if (LInfo.NumHoras = 0) and not qticadosnum_horas.IsNull then
        LInfo.NumHoras := qticadosnum_horas.AsFloat;

      LInfo.Descuento := qticadosdescuentohoras.AsFloat;
      LInfo.HorasCobrar := qticadoshorascobrar.AsFloat;
      LInfo.Festivo := qticadosfestivo.AsInteger;
      LInfo.Observaciones := qticadosobservaciones.AsString;

      FTicadosList[High(FTicadosList)] := LInfo;

      // Procesar para la matriz semanal si la fecha cae dentro de la semana activa
      LFechaTicado := Trunc(LInfo.Fecha);
      if (LFechaTicado >= Trunc(LSemInicio)) and (LFechaTicado <= Trunc(LSemFin)) then
      begin
        LDiaSemana := DayOfTheWeek(LFechaTicado); // 1..7
        LIdxTrabajador := BuscarOAgregarTrabajador(LInfo.Idt, LInfo.Trabajador);
        with FTrabajadoresSemana[LIdxTrabajador] do
        begin
          Dias[LDiaSemana].Horas := Dias[LDiaSemana].Horas + LInfo.NumHoras;
          if LInfo.EntradaM <> '' then
            Dias[LDiaSemana].EntradaM := LInfo.EntradaM;
          if LInfo.SalidaM <> '' then
            Dias[LDiaSemana].SalidaM := LInfo.SalidaM;
          if LInfo.EntradaT <> '' then
            Dias[LDiaSemana].EntradaT := LInfo.EntradaT;
          if LInfo.SalidaT <> '' then
            Dias[LDiaSemana].SalidaT := LInfo.SalidaT;
          if LInfo.Festivo = 1 then
            Dias[LDiaSemana].Festivo := 1;
          Dias[LDiaSemana].TieneDatos := True;
          Dias[LDiaSemana].IdTicado := LInfo.Id;
          TotalHoras := TotalHoras + LInfo.NumHoras;
        end;
        FTotalesDiaSemana[LDiaSemana] := FTotalesDiaSemana[LDiaSemana] + LInfo.NumHoras;
        FTotalGeneralSemana := FTotalGeneralSemana + LInfo.NumHoras;
      end;

      qticados.Next;
    end;
  finally
    if qticados.BookmarkValid(LBM) then
      qticados.GotoBookmark(LBM);
    qticados.FreeBookmark(LBM);
    qticados.EnableControls;
  end;

  ActualizarCalendarioMes;
  ActualizarCalendarioSemana;
end;

procedure Tticados.ActualizarCalendarioMes;
var
  LPrimerDia, LUltimoDia: TDate;
  LTotalMes: Double;
  i: Integer;
begin
  if FMesFecha = 0 then
    FMesFecha := Date;

  LPrimerDia := StartOfTheMonth(FMesFecha);
  LUltimoDia := EndOfTheMonth(FMesFecha);

  lblMesTitulo.Caption := FormatDateTime('mmmm yyyy', FMesFecha);
  if Length(lblMesTitulo.Caption) > 0 then
    lblMesTitulo.Caption := UpperCase(Copy(lblMesTitulo.Caption, 1, 1)) + Copy(lblMesTitulo.Caption, 2, Length(lblMesTitulo.Caption));

  LTotalMes := 0;
  for i := 0 to High(FTicadosList) do
  begin
    if (FTicadosList[i].Fecha >= LPrimerDia) and (FTicadosList[i].Fecha <= LUltimoDia) then
      LTotalMes := LTotalMes + FTicadosList[i].NumHoras;
  end;
  lblMesResumen.Caption := 'Total Horas Mes: ' + FormatFloat('0.00', LTotalMes) + ' h';

  if FDiaSeleccionadoMes = 0 then
    FDiaSeleccionadoMes := Date;

  gridCalendarioMes.Invalidate;
  ActualizarDetalleDiaMes;
end;

procedure Tticados.ActualizarDetalleDiaMes;
var
  i, LRow: Integer;
  LCount: Integer;
  LTotalDia: Double;
begin
  gridDetalleDiaMes.RowCount := 2;
  gridDetalleDiaMes.ColCount := 7;
  gridDetalleDiaMes.FixedRows := 1;
  gridDetalleDiaMes.FixedCols := 0;

  gridDetalleDiaMes.Cells[0, 0] := 'ID';
  gridDetalleDiaMes.Cells[1, 0] := 'Trabajador';
  gridDetalleDiaMes.Cells[2, 0] := 'Mañana';
  gridDetalleDiaMes.Cells[3, 0] := 'Tarde';
  gridDetalleDiaMes.Cells[4, 0] := 'Horas Tot.';
  gridDetalleDiaMes.Cells[5, 0] := 'Festivo';
  gridDetalleDiaMes.Cells[6, 0] := 'Observaciones';

  gridDetalleDiaMes.ColWidths[0] := 45;
  gridDetalleDiaMes.ColWidths[1] := 180;
  gridDetalleDiaMes.ColWidths[2] := 100;
  gridDetalleDiaMes.ColWidths[3] := 100;
  gridDetalleDiaMes.ColWidths[4] := 75;
  gridDetalleDiaMes.ColWidths[5] := 55;
  gridDetalleDiaMes.ColWidths[6] := 250;

  LRow := 1;
  LCount := 0;
  LTotalDia := 0;

  for i := 0 to High(FTicadosList) do
  begin
    if Trunc(FTicadosList[i].Fecha) = Trunc(FDiaSeleccionadoMes) then
    begin
      if LRow >= gridDetalleDiaMes.RowCount then
        gridDetalleDiaMes.RowCount := LRow + 1;

      gridDetalleDiaMes.Cells[0, LRow] := IntToStr(FTicadosList[i].Id);
      gridDetalleDiaMes.Cells[1, LRow] := FTicadosList[i].Trabajador;
      if (FTicadosList[i].EntradaM <> '') or (FTicadosList[i].SalidaM <> '') then
        gridDetalleDiaMes.Cells[2, LRow] := FTicadosList[i].EntradaM + ' - ' + FTicadosList[i].SalidaM
      else
        gridDetalleDiaMes.Cells[2, LRow] := '-';

      if (FTicadosList[i].EntradaT <> '') or (FTicadosList[i].SalidaT <> '') then
        gridDetalleDiaMes.Cells[3, LRow] := FTicadosList[i].EntradaT + ' - ' + FTicadosList[i].SalidaT
      else
        gridDetalleDiaMes.Cells[3, LRow] := '-';

      gridDetalleDiaMes.Cells[4, LRow] := FormatFloat('0.00', FTicadosList[i].NumHoras) + ' h';
      if FTicadosList[i].Festivo = 1 then
        gridDetalleDiaMes.Cells[5, LRow] := 'SÍ'
      else
        gridDetalleDiaMes.Cells[5, LRow] := 'NO';
      gridDetalleDiaMes.Cells[6, LRow] := FTicadosList[i].Observaciones;

      Inc(LCount);
      LTotalDia := LTotalDia + FTicadosList[i].NumHoras;
      Inc(LRow);
    end;
  end;

  if LCount = 0 then
  begin
    gridDetalleDiaMes.RowCount := 2;
    for i := 0 to 6 do
      gridDetalleDiaMes.Cells[i, 1] := '';
    gridDetalleDiaMes.Cells[1, 1] := '(Sin registros para este día)';
  end;

  lblDetalleDiaTitulo.Caption := ' Detalle del ' + FormatDateTime('dddd, dd "de" mmmm "de" yyyy', FDiaSeleccionadoMes) +
    '  -  Total: ' + FormatFloat('0.00', LTotalDia) + ' h (' + IntToStr(LCount) + ' trabajadores)  [Doble clic para editar]';
end;

procedure Tticados.ActualizarCalendarioSemana;
var
  LSemInicio, LSemFin: TDate;
  i: Integer;
  LTotalFilas: Integer;
begin
  if FSemanaFecha = 0 then
    FSemanaFecha := Date;

  LSemInicio := StartOfTheWeek(FSemanaFecha);
  LSemFin := EndOfTheWeek(FSemanaFecha);

  lblSemanaTitulo.Caption := 'Semana del ' + FormatDateTime('dd/mm/yyyy', LSemInicio) + ' al ' + FormatDateTime('dd/mm/yyyy', LSemFin);
  lblSemanaResumen.Caption := 'Total Horas Semana: ' + FormatFloat('0.00', FTotalGeneralSemana) + ' h (' + IntToStr(Length(FTrabajadoresSemana)) + ' trab.)';

  gridCalendarioSemana.ColCount := 9;
  gridCalendarioSemana.FixedCols := 1;
  gridCalendarioSemana.FixedRows := 1;

  gridCalendarioSemana.ColWidths[0] := 190; // Trabajador
  for i := 1 to 7 do
    gridCalendarioSemana.ColWidths[i] := 115; // Lunes..Domingo
  gridCalendarioSemana.ColWidths[8] := 95;  // Total Semana

  LTotalFilas := Length(FTrabajadoresSemana);
  if LTotalFilas > 0 then
    gridCalendarioSemana.RowCount := LTotalFilas + 2 // +1 header, +1 footer
  else
    gridCalendarioSemana.RowCount := 2;

  gridCalendarioSemana.Invalidate;
end;

procedure Tticados.EditarTicadoPorId(AId: Int64);
var
  vIde, vIdt: Integer;
  vFecha: TDateTime;
begin
  if AId <= 0 then
    Exit;

  if not qticados.Locate('id', AId, []) then
    Exit;

  vIde := qticadoside.AsInteger;
  vIdt := qticadosidt.AsInteger;
  vFecha := qticadosfecha.AsDateTime;

  dlgticados := Tdlgticados.Create(nil);
  try
    dlgticados.qticados.ParamByName('IDE').AsInteger := vIde;
    dlgticados.qticados.ParamByName('IDT').AsInteger := vIdt;
    dlgticados.qticados.ParamByName('FECHA').AsDateTime := vFecha;
    dlgticados.qticados.Prepare;
    dlgticados.qticados.Open;
    dlgticados.idticado := AId;
    dlgticados.ShowModal;
  finally
    dlgticados.Free;
    btactualizarClick(nil);
  end;
end;

procedure Tticados.pcModoAmpliadoChange(Sender: TObject);
begin
  if pcModoAmpliado.ActivePage = tabMes then
  begin
    if FMesFecha = 0 then
      FMesFecha := fdesde.Date;
    ActualizarCalendarioMes;
  end
  else if pcModoAmpliado.ActivePage = tabSemana then
  begin
    if FSemanaFecha = 0 then
      FSemanaFecha := fdesde.Date;
    ActualizarCalendarioSemana;
  end;
end;

procedure Tticados.btnMesAntClick(Sender: TObject);
begin
  FMesFecha := IncMonth(FMesFecha, -1);
  fdesde.Date := StartOfTheMonth(FMesFecha);
  fhasta.Date := EndOfTheMonth(FMesFecha);
  btactualizarClick(nil);
end;

procedure Tticados.btnMesSigClick(Sender: TObject);
begin
  FMesFecha := IncMonth(FMesFecha, 1);
  fdesde.Date := StartOfTheMonth(FMesFecha);
  fhasta.Date := EndOfTheMonth(FMesFecha);
  btactualizarClick(nil);
end;

procedure Tticados.btnMesHoyClick(Sender: TObject);
begin
  FMesFecha := Date;
  fdesde.Date := StartOfTheMonth(FMesFecha);
  fhasta.Date := EndOfTheMonth(FMesFecha);
  btactualizarClick(nil);
end;

procedure Tticados.btnMesCargarClick(Sender: TObject);
begin
  fdesde.Date := StartOfTheMonth(FMesFecha);
  fhasta.Date := EndOfTheMonth(FMesFecha);
  btactualizarClick(nil);
end;

procedure Tticados.btnSemanaAntClick(Sender: TObject);
begin
  FSemanaFecha := IncWeek(FSemanaFecha, -1);
  fdesde.Date := StartOfTheWeek(FSemanaFecha);
  fhasta.Date := EndOfTheWeek(FSemanaFecha);
  btactualizarClick(nil);
end;

procedure Tticados.btnSemanaSigClick(Sender: TObject);
begin
  FSemanaFecha := IncWeek(FSemanaFecha, 1);
  fdesde.Date := StartOfTheWeek(FSemanaFecha);
  fhasta.Date := EndOfTheWeek(FSemanaFecha);
  btactualizarClick(nil);
end;

procedure Tticados.btnSemanaHoyClick(Sender: TObject);
begin
  FSemanaFecha := Date;
  fdesde.Date := StartOfTheWeek(FSemanaFecha);
  fhasta.Date := EndOfTheWeek(FSemanaFecha);
  btactualizarClick(nil);
end;

procedure Tticados.gridCalendarioMesDrawCell(Sender: TObject; ACol, ARow: Longint;
  Rect: TRect; State: TGridDrawState);
const
  DiasSemanaNombres: array[0..6] of string = ('Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo');
var
  LDia: TDate;
  LEsMesActual: Boolean;
  LNumTrab: Integer;
  LHorasDia: Double;
  LEsFestivo: Boolean;
  LBgColor, LTextColor: TColor;
  LDayStr: string;
  i: Integer;
begin
  if ARow = 0 then
  begin
    gridCalendarioMes.Canvas.Brush.Color := $004A3C28;
    gridCalendarioMes.Canvas.FillRect(Rect);
    gridCalendarioMes.Canvas.Font.Style := [fsBold];
    gridCalendarioMes.Canvas.Font.Color := clWhite;
    gridCalendarioMes.Canvas.Font.Size := 9;
    LDayStr := DiasSemanaNombres[ACol];
    gridCalendarioMes.Canvas.TextRect(Rect, Rect.Left + (Rect.Right - Rect.Left - gridCalendarioMes.Canvas.TextWidth(LDayStr)) div 2,
      Rect.Top + (Rect.Bottom - Rect.Top - gridCalendarioMes.Canvas.TextHeight(LDayStr)) div 2, LDayStr);
    Exit;
  end;

  LDia := ObtenerFechaCeldaMes(ACol, ARow);
  LEsMesActual := (MonthOf(LDia) = MonthOf(FMesFecha)) and (YearOf(LDia) = YearOf(FMesFecha));

  LNumTrab := 0;
  LHorasDia := 0;
  LEsFestivo := False;
  for i := 0 to High(FTicadosList) do
  begin
    if Trunc(FTicadosList[i].Fecha) = Trunc(LDia) then
    begin
      Inc(LNumTrab);
      LHorasDia := LHorasDia + FTicadosList[i].NumHoras;
      if FTicadosList[i].Festivo = 1 then
        LEsFestivo := True;
    end;
  end;

  if not LEsMesActual then
  begin
    LBgColor := $00F7F7F7;
    LTextColor := $00A5A5A5;
  end
  else if Trunc(LDia) = Trunc(Date) then
  begin
    LBgColor := $00FFF5E6;
    LTextColor := $00994C00;
  end
  else if LEsFestivo then
  begin
    LBgColor := $00E6E6FF;
    LTextColor := $002020B0;
  end
  else if Trunc(LDia) = Trunc(FDiaSeleccionadoMes) then
  begin
    LBgColor := $00E8F0FE;
    LTextColor := clBlack;
  end
  else
  begin
    LBgColor := clWhite;
    LTextColor := clBlack;
  end;

  gridCalendarioMes.Canvas.Brush.Color := LBgColor;
  gridCalendarioMes.Canvas.FillRect(Rect);

  if Trunc(LDia) = Trunc(Date) then
    gridCalendarioMes.Canvas.Pen.Color := $00F5A623
  else if Trunc(LDia) = Trunc(FDiaSeleccionadoMes) then
    gridCalendarioMes.Canvas.Pen.Color := $004A90E2
  else
    gridCalendarioMes.Canvas.Pen.Color := $00E0E0E0;

  gridCalendarioMes.Canvas.Brush.Style := bsClear;
  gridCalendarioMes.Canvas.Rectangle(Rect.Left, Rect.Top, Rect.Right, Rect.Bottom);

  gridCalendarioMes.Canvas.Font.Style := [fsBold];
  gridCalendarioMes.Canvas.Font.Color := LTextColor;
  gridCalendarioMes.Canvas.Font.Size := 9;
  LDayStr := IntToStr(DayOf(LDia));
  if Trunc(LDia) = Trunc(Date) then
    LDayStr := LDayStr + ' (Hoy)';
  gridCalendarioMes.Canvas.TextOut(Rect.Left + 5, Rect.Top + 3, LDayStr);

  if LEsFestivo and LEsMesActual then
  begin
    gridCalendarioMes.Canvas.Font.Style := [fsBold];
    gridCalendarioMes.Canvas.Font.Color := clRed;
    gridCalendarioMes.Canvas.Font.Size := 7;
    gridCalendarioMes.Canvas.TextOut(Rect.Right - 55, Rect.Top + 3, '★ Festivo');
  end;

  if (LNumTrab > 0) and LEsMesActual then
  begin
    gridCalendarioMes.Canvas.Font.Style := [];
    gridCalendarioMes.Canvas.Font.Size := 8;
    gridCalendarioMes.Canvas.Font.Color := $00444444;
    gridCalendarioMes.Canvas.TextOut(Rect.Left + 5, Rect.Top + 17, IntToStr(LNumTrab) + ' trab.');

    gridCalendarioMes.Canvas.Font.Style := [fsBold];
    gridCalendarioMes.Canvas.Font.Color := $00993300;
    gridCalendarioMes.Canvas.TextOut(Rect.Left + 5, Rect.Top + 29, FormatFloat('0.00', LHorasDia) + ' h');
  end;
end;

procedure Tticados.gridCalendarioMesSelectCell(Sender: TObject; ACol, ARow: Longint; var CanSelect: Boolean);
begin
  CanSelect := True;
  if ARow >= 1 then
  begin
    FDiaSeleccionadoMes := ObtenerFechaCeldaMes(ACol, ARow);
    ActualizarDetalleDiaMes;
  end;
end;

procedure Tticados.gridCalendarioMesDblClick(Sender: TObject);
var
  LCol, LRow: Integer;
  LDia: TDate;
  i: Integer;
  LCount: Integer;
  LLastId: Int64;
begin
  LCol := gridCalendarioMes.Col;
  LRow := gridCalendarioMes.Row;
  if LRow >= 1 then
  begin
    LDia := ObtenerFechaCeldaMes(LCol, LRow);
    FDiaSeleccionadoMes := LDia;
    ActualizarDetalleDiaMes;

    LCount := 0;
    LLastId := 0;
    for i := 0 to High(FTicadosList) do
    begin
      if Trunc(FTicadosList[i].Fecha) = Trunc(LDia) then
      begin
        Inc(LCount);
        LLastId := FTicadosList[i].Id;
      end;
    end;
    if LCount = 1 then
      EditarTicadoPorId(LLastId);
  end;
end;

procedure Tticados.gridDetalleDiaMesDblClick(Sender: TObject);
var
  LId: Int64;
  LRow: Integer;
begin
  LRow := gridDetalleDiaMes.Row;
  if (LRow >= 1) and (gridDetalleDiaMes.Cells[0, LRow] <> '') then
  begin
    LId := StrToInt64Def(gridDetalleDiaMes.Cells[0, LRow], 0);
    if LId > 0 then
      EditarTicadoPorId(LId);
  end;
end;

procedure Tticados.gridCalendarioSemanaDrawCell(Sender: TObject; ACol, ARow: Longint;
  Rect: TRect; State: TGridDrawState);
const
  DiasAbrev: array[0..6] of string = ('Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb', 'Dom');
var
  LSemInicio, LDia: TDate;
  LText: string;
  LBgColor: TColor;
  LIdx: Integer;
begin
  if FSemanaFecha = 0 then
    FSemanaFecha := Date;
  LSemInicio := StartOfTheWeek(FSemanaFecha);

  // 1. Fila de Cabecera (ARow = 0)
  if ARow = 0 then
  begin
    gridCalendarioSemana.Canvas.Brush.Color := $004A3C28;
    gridCalendarioSemana.Canvas.FillRect(Rect);
    gridCalendarioSemana.Canvas.Font.Style := [fsBold];
    gridCalendarioSemana.Canvas.Font.Color := clWhite;
    gridCalendarioSemana.Canvas.Font.Size := 9;

    if ACol = 0 then
      LText := '  Trabajador / Cuadrilla'
    else if (ACol >= 1) and (ACol <= 7) then
    begin
      LDia := LSemInicio + (ACol - 1);
      LText := DiasAbrev[ACol - 1] + ' ' + FormatDateTime('dd/mm', LDia);
      if Trunc(LDia) = Trunc(Date) then
        LText := LText + ' *';
    end
    else
      LText := 'Total H.';

    if ACol = 0 then
      gridCalendarioSemana.Canvas.TextRect(Rect, Rect.Left + 4, Rect.Top + (Rect.Bottom - Rect.Top - gridCalendarioSemana.Canvas.TextHeight(LText)) div 2, LText)
    else
      gridCalendarioSemana.Canvas.TextRect(Rect, Rect.Left + (Rect.Right - Rect.Left - gridCalendarioSemana.Canvas.TextWidth(LText)) div 2,
        Rect.Top + (Rect.Bottom - Rect.Top - gridCalendarioSemana.Canvas.TextHeight(LText)) div 2, LText);
    Exit;
  end;

  // 2. Fila de Totales Generales (Pie de tabla)
  if (Length(FTrabajadoresSemana) > 0) and (ARow = Length(FTrabajadoresSemana) + 1) then
  begin
    gridCalendarioSemana.Canvas.Brush.Color := $00E6E1DC;
    gridCalendarioSemana.Canvas.FillRect(Rect);
    gridCalendarioSemana.Canvas.Font.Style := [fsBold];
    gridCalendarioSemana.Canvas.Font.Color := clBlack;
    gridCalendarioSemana.Canvas.Font.Size := 9;

    if ACol = 0 then
    begin
      LText := '  TOTALES DÍA:';
      gridCalendarioSemana.Canvas.TextRect(Rect, Rect.Left + 4, Rect.Top + (Rect.Bottom - Rect.Top - gridCalendarioSemana.Canvas.TextHeight(LText)) div 2, LText);
    end
    else if (ACol >= 1) and (ACol <= 7) then
    begin
      LText := FormatFloat('0.00', FTotalesDiaSemana[ACol]) + ' h';
      gridCalendarioSemana.Canvas.Font.Color := $00803000;
      gridCalendarioSemana.Canvas.TextRect(Rect, Rect.Left + (Rect.Right - Rect.Left - gridCalendarioSemana.Canvas.TextWidth(LText)) div 2,
        Rect.Top + (Rect.Bottom - Rect.Top - gridCalendarioSemana.Canvas.TextHeight(LText)) div 2, LText);
    end
    else
    begin
      LText := FormatFloat('0.00', FTotalGeneralSemana) + ' h';
      gridCalendarioSemana.Canvas.Font.Color := $00990000;
      gridCalendarioSemana.Canvas.TextRect(Rect, Rect.Left + (Rect.Right - Rect.Left - gridCalendarioSemana.Canvas.TextWidth(LText)) div 2,
        Rect.Top + (Rect.Bottom - Rect.Top - gridCalendarioSemana.Canvas.TextHeight(LText)) div 2, LText);
    end;
    Exit;
  end;

  // 3. Filas de Datos de Trabajadores
  LIdx := ARow - 1;
  if (LIdx < 0) or (LIdx > High(FTrabajadoresSemana)) then
  begin
    gridCalendarioSemana.Canvas.Brush.Color := clWhite;
    gridCalendarioSemana.Canvas.FillRect(Rect);
    if (ACol = 0) and (Length(FTrabajadoresSemana) = 0) then
    begin
      gridCalendarioSemana.Canvas.Font.Color := clGray;
      gridCalendarioSemana.Canvas.Font.Style := [fsItalic];
      gridCalendarioSemana.Canvas.TextOut(Rect.Left + 8, Rect.Top + 6, '(Sin registros para esta semana)');
    end;
    Exit;
  end;

  LBgColor := clWhite;
  if (ACol >= 1) and (ACol <= 7) and (FTrabajadoresSemana[LIdx].Dias[ACol].Festivo = 1) then
    LBgColor := $00E8E8FF
  else if ACol = 8 then
    LBgColor := $00F4F7F9;

  gridCalendarioSemana.Canvas.Brush.Color := LBgColor;
  gridCalendarioSemana.Canvas.FillRect(Rect);
  gridCalendarioSemana.Canvas.Brush.Style := bsClear;

  gridCalendarioSemana.Canvas.Pen.Color := $00EBEBEB;
  gridCalendarioSemana.Canvas.Rectangle(Rect.Left, Rect.Top, Rect.Right, Rect.Bottom);

  if ACol = 0 then
  begin
    gridCalendarioSemana.Canvas.Font.Style := [fsBold];
    gridCalendarioSemana.Canvas.Font.Color := clBlack;
    gridCalendarioSemana.Canvas.Font.Size := 8;
    LText := FTrabajadoresSemana[LIdx].Nombre;
    gridCalendarioSemana.Canvas.TextRect(Rect, Rect.Left + 6, Rect.Top + (Rect.Bottom - Rect.Top - gridCalendarioSemana.Canvas.TextHeight(LText)) div 2, LText);
  end
  else if (ACol >= 1) and (ACol <= 7) then
  begin
    with FTrabajadoresSemana[LIdx].Dias[ACol] do
    begin
      if TieneDatos then
      begin
        gridCalendarioSemana.Canvas.Font.Style := [fsBold];
        gridCalendarioSemana.Canvas.Font.Size := 9;
        gridCalendarioSemana.Canvas.Font.Color := $00993300;
        LText := FormatFloat('0.00', Horas) + ' h';
        gridCalendarioSemana.Canvas.TextOut(Rect.Left + (Rect.Right - Rect.Left - gridCalendarioSemana.Canvas.TextWidth(LText)) div 2,
          Rect.Top + 4, LText);

        gridCalendarioSemana.Canvas.Font.Style := [];
        gridCalendarioSemana.Canvas.Font.Size := 7;
        gridCalendarioSemana.Canvas.Font.Color := $00444444;
        if (EntradaM <> '') or (SalidaM <> '') then
          gridCalendarioSemana.Canvas.TextOut(Rect.Left + 4, Rect.Top + 20, 'M: ' + EntradaM + '-' + SalidaM);

        if (EntradaT <> '') or (SalidaT <> '') then
          gridCalendarioSemana.Canvas.TextOut(Rect.Left + 4, Rect.Top + 34, 'T: ' + EntradaT + '-' + SalidaT);
      end
      else
      begin
        gridCalendarioSemana.Canvas.Font.Style := [];
        gridCalendarioSemana.Canvas.Font.Size := 8;
        gridCalendarioSemana.Canvas.Font.Color := $00B0B0B0;
        LText := '-';
        gridCalendarioSemana.Canvas.TextOut(Rect.Left + (Rect.Right - Rect.Left - gridCalendarioSemana.Canvas.TextWidth(LText)) div 2,
          Rect.Top + (Rect.Bottom - Rect.Top - gridCalendarioSemana.Canvas.TextHeight(LText)) div 2, LText);
      end;
    end;
  end
  else if ACol = 8 then
  begin
    gridCalendarioSemana.Canvas.Font.Style := [fsBold];
    gridCalendarioSemana.Canvas.Font.Size := 9;
    gridCalendarioSemana.Canvas.Font.Color := $00880000;
    LText := FormatFloat('0.00', FTrabajadoresSemana[LIdx].TotalHoras) + ' h';
    gridCalendarioSemana.Canvas.TextOut(Rect.Left + (Rect.Right - Rect.Left - gridCalendarioSemana.Canvas.TextWidth(LText)) div 2,
      Rect.Top + (Rect.Bottom - Rect.Top - gridCalendarioSemana.Canvas.TextHeight(LText)) div 2, LText);
  end;
end;

procedure Tticados.gridCalendarioSemanaDblClick(Sender: TObject);
var
  LCol, LRow: Integer;
  LIdTicado: Int64;
begin
  LCol := gridCalendarioSemana.Col;
  LRow := gridCalendarioSemana.Row;

  if (LRow >= 1) and (LRow <= Length(FTrabajadoresSemana)) and (LCol >= 1) and (LCol <= 7) then
  begin
    LIdTicado := FTrabajadoresSemana[LRow - 1].Dias[LCol].IdTicado;
    if LIdTicado > 0 then
      EditarTicadoPorId(LIdTicado);
  end;
end;

end.
