unit frm_TrabajadorContratoModal;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls,
  Vcl.ComCtrls, Data.DB, FireDAC.Comp.Client, FireDAC.Stan.Param, FireDAC.Stan.Intf,
  System.DateUtils, uAppTheme;

type
  TfrmTrabajadorContratoModal = class(TForm)
    pnlTop: TPanel;
    lblTitulo: TLabel;
    lblSubtitulo: TLabel;
    pnlBody: TPanel;
    lblEmpresa: TLabel;
    cmbEmpresa: TComboBox;
    lblTipoContrato: TLabel;
    cmbTipoContrato: TComboBox;
    lblFechaAlta: TLabel;
    dtpFechaAlta: TDateTimePicker;
    lblFechaIncorporacion: TLabel;
    dtpFechaIncorporacion: TDateTimePicker;
    lblFechaFinPrevisto: TLabel;
    dtpFechaFinPrevisto: TDateTimePicker;
    lblFechaDesconexion: TLabel;
    dtpFechaDesconexion: TDateTimePicker;
    lblFechaBaja: TLabel;
    dtpFechaBaja: TDateTimePicker;
    lblMotivoAlta: TLabel;
    edtMotivoAlta: TEdit;
    lblMotivoBaja: TLabel;
    edtMotivoBaja: TEdit;
    lblObservaciones: TLabel;
    edtObservaciones: TEdit;
    pnlEstado: TPanel;
    lblEstadoInfo: TLabel;
    lblEstado: TLabel;
    pnlBottom: TPanel;
    btnGuardar: TButton;
    btnCancelar: TButton;

    procedure FormCreate(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure FechaControlChanged(Sender: TObject);
    procedure btnGuardarClick(Sender: TObject);
  private
    FTrabajadorId: string;
    FContratoId: Integer;
    procedure CargarEmpresas;
    procedure CargarContratoExistente;
    procedure ActualizarEstadoVisual;
  public
    class function Execute(const ATrabajadorId: string; AContratoId: Integer = 0): Boolean;
  end;

var
  frmTrabajadorContratoModal: TfrmTrabajadorContratoModal;

implementation

uses
  dmg_Main, uDbErrorHandler;

{$R *.dfm}

class function TfrmTrabajadorContratoModal.Execute(const ATrabajadorId: string;
  AContratoId: Integer = 0): Boolean;
var
  LFrm: TfrmTrabajadorContratoModal;
begin
  Result := False;
  LFrm := TfrmTrabajadorContratoModal.Create(Application);
  try
    LFrm.FTrabajadorId := ATrabajadorId;
    LFrm.FContratoId := AContratoId;
    if LFrm.ShowModal = mrOk then
      Result := True;
  finally
    LFrm.Free;
  end;
end;

procedure TfrmTrabajadorContratoModal.FormCreate(Sender: TObject);
begin
  FTrabajadorId := '';
  FContratoId := 0;
  dtpFechaAlta.Date := Date;
  dtpFechaIncorporacion.Date := Date;
  dtpFechaIncorporacion.Checked := False;
  dtpFechaFinPrevisto.Date := Date;
  dtpFechaFinPrevisto.Checked := False;
  dtpFechaDesconexion.Date := Date;
  dtpFechaDesconexion.Checked := False;
  dtpFechaBaja.Date := Date;
  dtpFechaBaja.Checked := False;
end;

procedure TfrmTrabajadorContratoModal.FormShow(Sender: TObject);
begin
  TAppTheme.ApplyToForm(Self);
  CargarEmpresas;

  if FContratoId > 0 then
  begin
    Caption := 'Modificar Periodo de Contratación (ID: ' + IntToStr(FContratoId) + ')';
    lblTitulo.Caption := 'Modificar Periodo de Contratación (ID: ' + IntToStr(FContratoId) + ')';
    lblSubtitulo.Caption := 'Edite los parámetros del contrato. El empleado se activará o desactivará según las fechas.';
    CargarContratoExistente;
  end
  else
  begin
    Caption := 'Nuevo Periodo de Contratación';
    lblTitulo.Caption := 'Nuevo Periodo de Contratación';
    lblSubtitulo.Caption := 'Indique los parámetros del nuevo contrato.';
    dtpFechaAlta.Date := Date;
    dtpFechaAlta.Checked := True;
    dtpFechaIncorporacion.Date := Date;
    dtpFechaIncorporacion.Checked := False;
    dtpFechaFinPrevisto.Date := Date;
    dtpFechaFinPrevisto.Checked := False;
    dtpFechaDesconexion.Date := Date;
    dtpFechaDesconexion.Checked := False;
    dtpFechaBaja.Date := Date;
    dtpFechaBaja.Checked := False;
    cmbTipoContrato.Text := 'Fijo Discontinuo / Campaña';
    edtMotivoAlta.Text := 'Campaña / Nueva Incorporación';
    edtMotivoBaja.Text := '';
    edtObservaciones.Text := '';
    ActualizarEstadoVisual;
  end;
end;

procedure TfrmTrabajadorContratoModal.CargarEmpresas;
var
  Qry: TFDQuery;
begin
  cmbEmpresa.Items.Clear;
  Qry := TFDQuery.Create(nil);
  try
    Qry.Connection := dmgMain.dbConn;
    Qry.SQL.Text := 'SELECT id, nombre FROM ge_empresas ORDER BY id';
    Qry.Open;
    while not Qry.Eof do
    begin
      cmbEmpresa.Items.AddObject(Qry.FieldByName('nombre').AsString, TObject(IntPtr(Qry.FieldByName('id').AsInteger)));
      Qry.Next;
    end;
  finally
    Qry.Free;
  end;

  if cmbEmpresa.Items.Count > 0 then
    cmbEmpresa.ItemIndex := 0;
end;

procedure TfrmTrabajadorContratoModal.CargarContratoExistente;
var
  Qry: TFDQuery;
  I, LEmpId: Integer;
begin
  if FContratoId <= 0 then Exit;

  Qry := TFDQuery.Create(nil);
  try
    Qry.Connection := dmgMain.dbConn;
    Qry.SQL.Text := 'SELECT * FROM ge_trabajadores_contratos WHERE id = :id';
    Qry.ParamByName('id').AsInteger := FContratoId;
    Qry.Open;

    if not Qry.IsEmpty then
    begin
      LEmpId := Qry.FieldByName('id_empresa').AsInteger;
      for I := 0 to cmbEmpresa.Items.Count - 1 do
      begin
        if Integer(IntPtr(cmbEmpresa.Items.Objects[I])) = LEmpId then
        begin
          cmbEmpresa.ItemIndex := I;
          Break;
        end;
      end;

      cmbTipoContrato.Text := Qry.FieldByName('tipo_contrato').AsString;

      if not Qry.FieldByName('fecha_alta').IsNull then
      begin
        dtpFechaAlta.Date := Qry.FieldByName('fecha_alta').AsDateTime;
        dtpFechaAlta.Checked := True;
      end;

      if not Qry.FieldByName('fecha_incorporacion').IsNull then
      begin
        dtpFechaIncorporacion.Date := Qry.FieldByName('fecha_incorporacion').AsDateTime;
        dtpFechaIncorporacion.Checked := True;
      end
      else
        dtpFechaIncorporacion.Checked := False;

      if not Qry.FieldByName('fecha_desconexion').IsNull then
      begin
        dtpFechaDesconexion.Date := Qry.FieldByName('fecha_desconexion').AsDateTime;
        dtpFechaDesconexion.Checked := True;
      end
      else
        dtpFechaDesconexion.Checked := False;

      if not Qry.FieldByName('fecha_baja').IsNull then
      begin
        dtpFechaBaja.Date := Qry.FieldByName('fecha_baja').AsDateTime;
        dtpFechaBaja.Checked := True;
      end
      else
        dtpFechaBaja.Checked := False;

      if not Qry.FieldByName('fecha_fin_contrato').IsNull then
      begin
        dtpFechaFinPrevisto.Date := Qry.FieldByName('fecha_fin_contrato').AsDateTime;
        dtpFechaFinPrevisto.Checked := True;
      end
      else
        dtpFechaFinPrevisto.Checked := False;

      edtMotivoAlta.Text := Qry.FieldByName('motivo_alta').AsString;
      edtMotivoBaja.Text := Qry.FieldByName('motivo_baja').AsString;
      edtObservaciones.Text := Qry.FieldByName('observaciones').AsString;
    end;
  finally
    Qry.Free;
  end;

  ActualizarEstadoVisual;
end;

procedure TfrmTrabajadorContratoModal.FechaControlChanged(Sender: TObject);
begin
  ActualizarEstadoVisual;
end;

procedure TfrmTrabajadorContratoModal.ActualizarEstadoVisual;
var
  LTieneBajaODesconexion: Boolean;
begin
  // Control: si la fecha de baja o de desconexión tienen valor se debe desactivar el empleado
  // y si están las dos vacías debe estar activado
  LTieneBajaODesconexion := dtpFechaBaja.Checked or dtpFechaDesconexion.Checked;
  if LTieneBajaODesconexion then
  begin
    lblEstado.Caption := #9679 + ' INACTIVO - Empleado DESACTIVADO (Fecha de Baja o Desconexi'#243'n indicada)';
    lblEstado.Font.Color := clRed;
  end
  else
  begin
    lblEstado.Caption := #9679 + ' ACTIVO - Empleado ACTIVADO (Sin fecha de baja ni desconexi'#243'n)';
    lblEstado.Font.Color := TColor($008000); // Verde
  end;
end;

procedure TfrmTrabajadorContratoModal.btnGuardarClick(Sender: TObject);
var
  Qry: TFDQuery;
  LEmpId, LActivo: Integer;
  LTieneBajaODesconexion: Boolean;
  LFechaBajaFinal: TDateTime;
  LTieneFechaBajaFinal: Boolean;
begin
  if cmbEmpresa.ItemIndex < 0 then
  begin
    ShowMessage('Debe seleccionar una empresa.');
    cmbEmpresa.SetFocus;
    Exit;
  end;

  LEmpId := Integer(IntPtr(cmbEmpresa.Items.Objects[cmbEmpresa.ItemIndex]));

  // Validaciones
  if dtpFechaBaja.Checked and (dtpFechaBaja.Date < dtpFechaAlta.Date) then
  begin
    ShowMessage('La fecha de baja no puede ser anterior a la fecha de alta.');
    dtpFechaBaja.SetFocus;
    Exit;
  end;

  if dtpFechaDesconexion.Checked and (dtpFechaDesconexion.Date < dtpFechaAlta.Date) then
  begin
    ShowMessage('La fecha de desconexión no puede ser anterior a la fecha de alta.');
    dtpFechaDesconexion.SetFocus;
    Exit;
  end;

  // REGLA:
  // "si la fecha de baja o de desconexion tienen valor se debe desactivar el empleado y si estan las dos vacias debe estar activado"
  LTieneBajaODesconexion := dtpFechaBaja.Checked or dtpFechaDesconexion.Checked;
  if LTieneBajaODesconexion then
    LActivo := 0
  else
    LActivo := 1;

  LTieneFechaBajaFinal := False;
  LFechaBajaFinal := 0;
  if dtpFechaBaja.Checked then
  begin
    LFechaBajaFinal := dtpFechaBaja.Date;
    LTieneFechaBajaFinal := True;
  end
  else if dtpFechaDesconexion.Checked then
  begin
    LFechaBajaFinal := dtpFechaDesconexion.Date;
    LTieneFechaBajaFinal := True;
  end;

  Qry := TFDQuery.Create(nil);
  try
    Qry.Connection := dmgMain.dbConn;

    if FContratoId > 0 then
    begin
      // 1. MODIFICAR CONTRATO EXISTENTE
      Qry.SQL.Text :=
        'UPDATE ge_trabajadores_contratos SET ' +
        '  id_empresa = :emp, ' +
        '  fecha_alta = :alta, ' +
        '  fecha_incorporacion = :inc, ' +
        '  fecha_desconexion = :descon, ' +
        '  fecha_baja = :baja, ' +
        '  fecha_fin_contrato = :fin, ' +
        '  tipo_contrato = :tipo, ' +
        '  motivo_alta = :motivo_alta, ' +
        '  motivo_baja = :motivo_baja, ' +
        '  activo = :activo, ' +
        '  observaciones = :obs, ' +
        '  id_user_update = :user, ' +
        '  updated_at = CURRENT_TIMESTAMP ' +
        'WHERE id = :id AND id_trabajador = :trab';
      Qry.ParamByName('id').AsInteger := FContratoId;
    end
    else
    begin
      // 2. INSERTAR NUEVO CONTRATO
      Qry.SQL.Text :=
        'INSERT INTO ge_trabajadores_contratos ( ' +
        '  id_empresa, id_trabajador, fecha_alta, fecha_incorporacion, fecha_desconexion, ' +
        '  fecha_baja, fecha_fin_contrato, tipo_contrato, motivo_alta, motivo_baja, ' +
        '  activo, observaciones, id_user_creator, id_user_update ' +
        ') VALUES ( ' +
        '  :emp, :trab, :alta, :inc, :descon, :baja, :fin, :tipo, :motivo_alta, :motivo_baja, ' +
        '  :activo, :obs, :user, :user ' +
        ')';
    end;

    Qry.ParamByName('emp').AsInteger := LEmpId;
    Qry.ParamByName('trab').AsString := FTrabajadorId;
    Qry.ParamByName('alta').AsDate := dtpFechaAlta.Date;

    Qry.ParamByName('inc').DataType := ftDate;
    if dtpFechaIncorporacion.Checked then
      Qry.ParamByName('inc').AsDate := dtpFechaIncorporacion.Date
    else
      Qry.ParamByName('inc').Clear;

    Qry.ParamByName('descon').DataType := ftDate;
    if dtpFechaDesconexion.Checked then
      Qry.ParamByName('descon').AsDate := dtpFechaDesconexion.Date
    else
      Qry.ParamByName('descon').Clear;

    Qry.ParamByName('baja').DataType := ftDate;
    if dtpFechaBaja.Checked then
      Qry.ParamByName('baja').AsDate := dtpFechaBaja.Date
    else
      Qry.ParamByName('baja').Clear;

    Qry.ParamByName('fin').DataType := ftDate;
    if dtpFechaFinPrevisto.Checked then
      Qry.ParamByName('fin').AsDate := dtpFechaFinPrevisto.Date
    else
      Qry.ParamByName('fin').Clear;

    Qry.ParamByName('tipo').AsString := Trim(cmbTipoContrato.Text);
    Qry.ParamByName('motivo_alta').AsString := Trim(edtMotivoAlta.Text);
    Qry.ParamByName('motivo_baja').AsString := Trim(edtMotivoBaja.Text);
    Qry.ParamByName('activo').AsInteger := LActivo;
    Qry.ParamByName('obs').AsString := Trim(edtObservaciones.Text);
    Qry.ParamByName('user').AsString := dmgMain.CurrentUserId;
    Qry.ExecSQL;

    // SINCRONIZAR CON ge_trabajadores_empresas y ge_trabajadores manteniendo la empresa del contrato
    if LActivo = 1 then
    begin
      // ACTIVAR EMPLEADO EN LA EMPRESA DEL CONTRATO
      Qry.SQL.Text :=
        'INSERT INTO ge_trabajadores_empresas ( ' +
        '  id_trabajador, id_empresa, codigo, activo, fecha_alta, fecha_baja, id_user_creator, id_user_update ' +
        ') VALUES ( ' +
        '  :trab, :emp, COALESCE((SELECT codigo FROM ge_trabajadores WHERE id = :trab2), 0), 1, :alta, NULL, :user, :user ' +
        ') ON DUPLICATE KEY UPDATE ' +
        '  activo = 1, fecha_alta = VALUES(fecha_alta), fecha_baja = NULL, id_user_update = VALUES(id_user_update), updated_at = CURRENT_TIMESTAMP';
      Qry.ParamByName('trab').AsString := FTrabajadorId;
      Qry.ParamByName('trab2').AsString := FTrabajadorId;
      Qry.ParamByName('emp').AsInteger := LEmpId;
      Qry.ParamByName('alta').AsDate := dtpFechaAlta.Date;
      Qry.ParamByName('user').AsString := dmgMain.CurrentUserId;
      Qry.ExecSQL;

      // Desactivar en cualquier otra empresa
      Qry.SQL.Text := 'UPDATE ge_trabajadores_empresas SET activo = 0 WHERE id_trabajador = :trab AND id_empresa <> :emp';
      Qry.ParamByName('trab').AsString := FTrabajadorId;
      Qry.ParamByName('emp').AsInteger := LEmpId;
      Qry.ExecSQL;

      Qry.SQL.Text :=
        'UPDATE ge_trabajadores SET ' +
        '  fecha_alta = :alta, fecha_baja = NULL, activo = 1, ' +
        '  id_user_update = :user, updated_at = CURRENT_TIMESTAMP ' +
        'WHERE id = :trab';
      Qry.ParamByName('alta').AsDate := dtpFechaAlta.Date;
      Qry.ParamByName('user').AsString := dmgMain.CurrentUserId;
      Qry.ParamByName('trab').AsString := FTrabajadorId;
      Qry.ExecSQL;
    end
    else
    begin
      // DESACTIVAR EMPLEADO EN LA EMPRESA DEL CONTRATO
      Qry.SQL.Text :=
        'INSERT INTO ge_trabajadores_empresas ( ' +
        '  id_trabajador, id_empresa, codigo, activo, fecha_alta, fecha_baja, id_user_creator, id_user_update ' +
        ') VALUES ( ' +
        '  :trab, :emp, COALESCE((SELECT codigo FROM ge_trabajadores WHERE id = :trab2), 0), 0, :alta, :baja, :user, :user ' +
        ') ON DUPLICATE KEY UPDATE ' +
        '  activo = 0, fecha_baja = VALUES(fecha_baja), id_user_update = VALUES(id_user_update), updated_at = CURRENT_TIMESTAMP';
      Qry.ParamByName('trab').AsString := FTrabajadorId;
      Qry.ParamByName('trab2').AsString := FTrabajadorId;
      Qry.ParamByName('emp').AsInteger := LEmpId;
      Qry.ParamByName('alta').AsDate := dtpFechaAlta.Date;
      Qry.ParamByName('baja').DataType := ftDate;
      if LTieneFechaBajaFinal then
        Qry.ParamByName('baja').AsDate := LFechaBajaFinal
      else
        Qry.ParamByName('baja').Clear;
      Qry.ParamByName('user').AsString := dmgMain.CurrentUserId;
      Qry.ExecSQL;

      // Desactivar en cualquier otra empresa
      Qry.SQL.Text := 'UPDATE ge_trabajadores_empresas SET activo = 0 WHERE id_trabajador = :trab AND id_empresa <> :emp';
      Qry.ParamByName('trab').AsString := FTrabajadorId;
      Qry.ParamByName('emp').AsInteger := LEmpId;
      Qry.ExecSQL;

      Qry.SQL.Text :=
        'UPDATE ge_trabajadores SET ' +
        '  fecha_baja = :baja, activo = 0, ' +
        '  id_user_update = :user, updated_at = CURRENT_TIMESTAMP ' +
        'WHERE id = :trab';
      Qry.ParamByName('baja').DataType := ftDate;
      if LTieneFechaBajaFinal then
        Qry.ParamByName('baja').AsDate := LFechaBajaFinal
      else
        Qry.ParamByName('baja').Clear;
      Qry.ParamByName('user').AsString := dmgMain.CurrentUserId;
      Qry.ParamByName('trab').AsString := FTrabajadorId;
      Qry.ExecSQL;
    end;

  finally
    Qry.Free;
  end;

  ModalResult := mrOk;
end;

end.
