unit frm_Articulos;

interface

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

type
  TfrmArticulos = class(TfrmBaseList)
    btnReemplazar: TSpeedButton;
    btnHistorico: TSpeedButton;
    procedure FormShow(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnRefreshClick(Sender: TObject); override;
    procedure btnNewClick(Sender: TObject); override;
    procedure btnEditClick(Sender: TObject); override;
    procedure btnDeleteClick(Sender: TObject); override;
    procedure btnReemplazarClick(Sender: TObject);
    procedure btnHistoricoClick(Sender: TObject);
  private
    FFamiliaIds: TStringList;
    FIvaIds: TStringList;
    FIvaNames: TStringList;
    FIvaRates: TStringList;
    grpFamilias: TGroupBox;
    cbFamiliaFilter: TComboBox;
    procedure FamiliaFilterChange(Sender: TObject);
    procedure dbGridMainCellClick(Column: TColumn);
    procedure dbGridMainKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure dbGridMainKeyPress(Sender: TObject; var Key: Char);
    procedure FamiliaDescChange(Sender: TField);
    procedure IvaDescChange(Sender: TField);
    procedure Pvp1IvaGetText(Sender: TField; var Text: string; DisplayText: Boolean);
    procedure Pvp1IvaSetText(Sender: TField; const Text: string);
  protected
    procedure ApplyAllFilters; override;
  public
    { Public declarations }
  end;

var
  frmArticulos: TfrmArticulos;

implementation

uses
  dmg_Main, frm_ArticulosEditor, frm_SelectProduct, frm_VentasPreciosHistorico;

{$R *.dfm}

procedure TfrmArticulos.FormShow(Sender: TObject);
begin
  AlphaFilterField := 'descripcion';
  StatusFilterField := 'activo';
  StatusValues.Add('Activo');
  StatusValues.Add('Inactivo');
  DateFilterField := 'created_at';

  // Inicializar lista de IDs de familia
  FFamiliaIds := TStringList.Create;

  // Inicializar lista de IVAs
  FIvaIds := TStringList.Create;
  FIvaNames := TStringList.Create;
  FIvaRates := TStringList.Create;

  // Cargar los tipos de IVA de la base de datos
  dmgMain.qryExec.Close;
  dmgMain.qryExec.SQL.Text := 'SELECT id, descripcion, tipo FROM ge_tipos_iva WHERE activo = 1 ORDER BY tipo';
  dmgMain.qryExec.Open;
  while not dmgMain.qryExec.Eof do
  begin
    FIvaNames.Add(dmgMain.qryExec.FieldByName('descripcion').AsString);
    FIvaIds.Add(dmgMain.qryExec.FieldByName('id').AsString);
    FIvaRates.Add(dmgMain.qryExec.FieldByName('tipo').AsString);
    dmgMain.qryExec.Next;
  end;
  dmgMain.qryExec.Close;

  // Crear filtro de familia dinámicamente en el panel izquierdo
  grpFamilias := TGroupBox.Create(Self);
  grpFamilias.Parent := pnlLeftFilter;
  grpFamilias.Align := alTop;
  grpFamilias.Caption := 'Familia';
  grpFamilias.Height := 55;
  grpFamilias.Padding.Left := 5;
  grpFamilias.Padding.Right := 5;
  grpFamilias.Padding.Top := 3;
  grpFamilias.Padding.Bottom := 5;
  grpFamilias.Top := 0; // Colocar al principio del panel
  grpFamilias.Visible := True;

  cbFamiliaFilter := TComboBox.Create(Self);
  cbFamiliaFilter.Parent := grpFamilias;
  cbFamiliaFilter.Align := alClient;
  cbFamiliaFilter.Style := csDropDownList;
  cbFamiliaFilter.OnChange := FamiliaFilterChange;

  // Cargar las familias de la base de datos
  cbFamiliaFilter.Items.Clear;
  cbFamiliaFilter.Items.Add('[Todas]');

  dmgMain.qryExec.Close;
  dmgMain.qryExec.SQL.Text := 'SELECT id, descripcion FROM ge_familias WHERE activo = 1 ORDER BY descripcion';
  dmgMain.qryExec.Open;
  while not dmgMain.qryExec.Eof do
  begin
    cbFamiliaFilter.Items.Add(dmgMain.qryExec.FieldByName('descripcion').AsString);
    FFamiliaIds.Add(dmgMain.qryExec.FieldByName('id').AsString);
    dmgMain.qryExec.Next;
  end;
  dmgMain.qryExec.Close;
  cbFamiliaFilter.ItemIndex := 0;

  inherited;
  
  frmArticulos := Self;
  OnDestroy := FormDestroy;
  pnlSearch.Visible := True;
  lblSearch.Caption := 'Buscar Artículo:';

  // Seleccionar 'Activo' por defecto en el filtro de estado para mostrar solo artículos activos al iniciar
  for var I := 0 to grpStatuses.ControlCount - 1 do
  begin
    if grpStatuses.Controls[I] is TComboBox then
    begin
      TComboBox(grpStatuses.Controls[I]).ItemIndex := 1; // 0=TODOS, 1=Activo, 2=Inactivo
      ApplyAllFilters;
      Break;
    end;
  end;

  dbGridMain.Options := dbGridMain.Options + [dgEditing] - [dgRowSelect];
  dbGridMain.OnCellClick := dbGridMainCellClick;
  dbGridMain.OnKeyDown := dbGridMainKeyDown;
  dbGridMain.OnKeyPress := dbGridMainKeyPress;
end;

procedure TfrmArticulos.dbGridMainKeyPress(Sender: TObject; var Key: Char);
begin
  // Si se presiona el punto en un campo numérico/precio, convertirlo al separador decimal del sistema (coma)
  if (Key = '.') and (dbGridMain.SelectedField <> nil) and 
     (dbGridMain.SelectedField.DataType in [ftFloat, ftCurrency, ftBCD, ftFMTBcd, ftSingle, ftExtended]) then
  begin
    Key := FormatSettings.DecimalSeparator;
  end;
end;

procedure TfrmArticulos.FormDestroy(Sender: TObject);
begin
  if Assigned(FFamiliaIds) then
    FreeAndNil(FFamiliaIds);

  if Assigned(FIvaIds) then
    FreeAndNil(FIvaIds);

  if Assigned(FIvaNames) then
    FreeAndNil(FIvaNames);

  if Assigned(FIvaRates) then
    FreeAndNil(FIvaRates);

  if frmArticulos = Self then
    frmArticulos := nil;
end;

procedure TfrmArticulos.FamiliaFilterChange(Sender: TObject);
begin
  ApplyAllFilters;
end;

procedure TfrmArticulos.ApplyAllFilters;
var
  LFamilyFilter: string;
begin
  inherited ApplyAllFilters;

  if Assigned(cbFamiliaFilter) and (cbFamiliaFilter.ItemIndex > 0) and Assigned(FFamiliaIds) then
  begin
    LFamilyFilter := 'id_familia = ' + QuotedStr(FFamiliaIds[cbFamiliaFilter.ItemIndex - 1]);
    if FQryMain.Filter <> '' then
      FQryMain.Filter := '(' + FQryMain.Filter + ') AND (' + LFamilyFilter + ')'
    else
      FQryMain.Filter := LFamilyFilter;
    FQryMain.Filtered := True;
  end;

  lblRecordCount.Caption := Format('Registros: %d', [FQryMain.RecordCount]);
end;

procedure TfrmArticulos.dbGridMainCellClick(Column: TColumn);
var
  LWasActive: Boolean;
begin
  if (Column.Field <> nil) and SameText(Column.FieldName, 'activo') then
  begin
    LWasActive := (Column.Field.AsInteger <> 0);
    if not (FQryMain.State in [dsEdit]) then
      FQryMain.Edit;
    if LWasActive then
      Column.Field.AsInteger := 0
    else
      Column.Field.AsInteger := 1;
    FQryMain.Post;
    
    if LWasActive then
      dbGridMain.SelectedIndex := 1; // Mover foco a columna 'descripcion'
  end;
end;

procedure TfrmArticulos.dbGridMainKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
var
  LWasActive: Boolean;
begin
  if (Key = VK_SPACE) and (dbGridMain.SelectedField <> nil) and SameText(dbGridMain.SelectedField.FieldName, 'activo') then
  begin
    LWasActive := (dbGridMain.SelectedField.AsInteger <> 0);
    if not (FQryMain.State in [dsEdit]) then
      FQryMain.Edit;
    if LWasActive then
      dbGridMain.SelectedField.AsInteger := 0
    else
      dbGridMain.SelectedField.AsInteger := 1;
    FQryMain.Post;
    Key := 0; // Consumir tecla
    
    if LWasActive then
      dbGridMain.SelectedIndex := 1; // Mover foco a columna 'descripcion'
  end;
end;

procedure TfrmArticulos.FamiliaDescChange(Sender: TField);
var
  LIndex: Integer;
begin
  if Sender.DataSet.State in [dsEdit, dsInsert] then
  begin
    if Sender.AsString = '' then
      Sender.DataSet.FieldByName('id_familia').Clear
    else
    begin
      LIndex := cbFamiliaFilter.Items.IndexOf(Sender.AsString);
      if LIndex > 0 then
        Sender.DataSet.FieldByName('id_familia').AsString := FFamiliaIds[LIndex - 1]
      else
        Sender.DataSet.FieldByName('id_familia').Clear;
    end;
  end;
end;

procedure TfrmArticulos.IvaDescChange(Sender: TField);
var
  LIndex: Integer;
begin
  if Sender.DataSet.State in [dsEdit, dsInsert] then
  begin
    if Sender.AsString = '' then
      Sender.DataSet.FieldByName('id_tipo_iva').Clear
    else
    begin
      LIndex := FIvaNames.IndexOf(Sender.AsString);
      if LIndex >= 0 then
        Sender.DataSet.FieldByName('id_tipo_iva').AsString := FIvaIds[LIndex];
    end;
  end;
end;

procedure TfrmArticulos.Pvp1IvaGetText(Sender: TField; var Text: string; DisplayText: Boolean);
var
  LSinIva, LIvaRate, LConIva: Double;
begin
  if Sender.IsNull then
  begin
    Text := '';
    Exit;
  end;

  LSinIva := Sender.AsFloat;
  LIvaRate := Sender.DataSet.FieldByName('tipo_iva_pct').AsFloat;
  LConIva := LSinIva * (1 + (LIvaRate / 100));

  if DisplayText then
    Text := FormatFloat('#,##0.00', LConIva)
  else
    Text := FloatToStr(LConIva);
end;

procedure TfrmArticulos.Pvp1IvaSetText(Sender: TField; const Text: string);
var
  LText, LCleanText: string;
  LConIva, LIvaRate, LSinIva: Double;
  LFS: TFormatSettings;
begin
  LText := Trim(Text);
  if LText = '' then
  begin
    Sender.Clear;
    Exit;
  end;

  LCleanText := StringReplace(LText, ' ', '', [rfReplaceAll]);
  
  // Si contiene tanto punto como coma, asumimos que el punto es separador de millar y la coma es el decimal (ej: 1.250,50)
  if (Pos('.', LCleanText) > 0) and (Pos(',', LCleanText) > 0) then
  begin
    LCleanText := StringReplace(LCleanText, '.', '', [rfReplaceAll]);
    LCleanText := StringReplace(LCleanText, ',', '.', [rfReplaceAll]);
  end
  else
  begin
    // Si solo tiene punto o solo tiene coma, tratar ese símbolo como separador decimal
    LCleanText := StringReplace(LCleanText, ',', '.', [rfReplaceAll]);
  end;

  LFS := TFormatSettings.Create;
  LFS.DecimalSeparator := '.';
  LConIva := StrToFloatDef(LCleanText, 0, LFS);
  
  LIvaRate := Sender.DataSet.FieldByName('tipo_iva_pct').AsFloat;

  if LIvaRate <> -100 then
    LSinIva := LConIva / (1 + (LIvaRate / 100))
  else
    LSinIva := 0;

  Sender.AsFloat := LSinIva;
end;

procedure TfrmArticulos.btnRefreshClick(Sender: TObject);
var
  LSql: string;
begin
  FQryMain.Close;
  LSql :=
    'SELECT a.id, a.descripcion, a.pvp1, a.activo, a.created_at, a.id_familia, a.dias_vida, a.id_tipo_iva, a.id_maestro, ' +
    'f.descripcion as familia_desc, t.descripcion as iva_desc, COALESCE(t.tipo, 0) as tipo_iva_pct, ' +
    'am.descripcion as maestro_desc ' +
    'FROM ge_articulos a ' +
    'LEFT JOIN ge_familias f ON a.id_familia = f.id ' +
    'LEFT JOIN ge_tipos_iva t ON a.id_tipo_iva = t.id ' +
    'LEFT JOIN ge_articulos am ON a.id_maestro = am.id ';
    
  if Trim(edtSearch.Text) <> '' then
  begin
    LSql := LSql + 'WHERE (a.descripcion LIKE :search OR CAST(a.id AS CHAR) LIKE :search) ';
  end;
  LSql := LSql + 'ORDER BY a.descripcion';
  
  FQryMain.SQL.Text := LSql;
  
  if Trim(edtSearch.Text) <> '' then
  begin
    FQryMain.ParamByName('search').DataType := ftWideString;
    FQryMain.ParamByName('search').AsWideString := '%' + Trim(edtSearch.Text) + '%';
  end;
    
  FQryMain.Open;
  
  // Configurar FireDAC para permitir edición de ge_articulos
  FQryMain.UpdateOptions.UpdateTableName := 'ge_articulos';
  FQryMain.UpdateOptions.KeyFields := 'id';
  FQryMain.UpdateOptions.ReadOnly := False;
  
  if FQryMain.FindField('familia_desc') <> nil then
  begin
    FQryMain.FieldByName('familia_desc').ProviderFlags := [];
    FQryMain.FieldByName('familia_desc').ReadOnly := False;
    FQryMain.FieldByName('familia_desc').OnChange := FamiliaDescChange;
  end;

  if FQryMain.FindField('iva_desc') <> nil then
  begin
    FQryMain.FieldByName('iva_desc').ProviderFlags := [];
    FQryMain.FieldByName('iva_desc').ReadOnly := False;
    FQryMain.FieldByName('iva_desc').OnChange := IvaDescChange;
  end;

  if FQryMain.FindField('tipo_iva_pct') <> nil then
  begin
    FQryMain.FieldByName('tipo_iva_pct').ProviderFlags := [];
    FQryMain.FieldByName('tipo_iva_pct').ReadOnly := True;
  end;
  
  if FQryMain.FindField('pvp1') <> nil then
  begin
    FQryMain.FieldByName('pvp1').ReadOnly := False;
    FQryMain.FieldByName('pvp1').OnGetText := Pvp1IvaGetText;
    FQryMain.FieldByName('pvp1').OnSetText := Pvp1IvaSetText;
  end;

  if FQryMain.FindField('activo') <> nil then
    FQryMain.FieldByName('activo').ReadOnly := False;
    
  if FQryMain.FindField('id_familia') <> nil then
    FQryMain.FieldByName('id_familia').ReadOnly := False;

  if FQryMain.FindField('id_tipo_iva') <> nil then
    FQryMain.FieldByName('id_tipo_iva').ReadOnly := False;

  if FQryMain.FindField('dias_vida') <> nil then
    FQryMain.FieldByName('dias_vida').ReadOnly := False;

  if FQryMain.FindField('maestro_desc') <> nil then
  begin
    FQryMain.FieldByName('maestro_desc').ProviderFlags := [];
    FQryMain.FieldByName('maestro_desc').ReadOnly := True;
  end;
  
  // Configurar títulos y anchos de columnas de la rejilla
  dbGridMain.Columns.Clear;
  with dbGridMain.Columns.Add do
  begin
    FieldName := 'id';
    Title.Caption := 'ID';
    Width := 60;
    Alignment := taRightJustify;
    ReadOnly := True;
  end;
  with dbGridMain.Columns.Add do
  begin
    FieldName := 'descripcion';
    Title.Caption := 'Descripción';
    Width := 250;
    ReadOnly := True;
  end;
  with dbGridMain.Columns.Add do
  begin
    FieldName := 'familia_desc';
    Title.Caption := 'Familia';
    Width := 130;
    ReadOnly := False;
    
    // Rellenar PickList con las familias cargadas
    PickList.Clear;
    PickList.Add(''); // Opción vacía para desasignar la familia
    for var I := 0 to cbFamiliaFilter.Items.Count - 1 do
    begin
      if I > 0 then // Omitir '[Todas]'
        PickList.Add(cbFamiliaFilter.Items[I]);
    end;
  end;
  with dbGridMain.Columns.Add do
  begin
    FieldName := 'maestro_desc';
    Title.Caption := 'Art. Maestro';
    Width := 160;
    ReadOnly := True;
  end;
  with dbGridMain.Columns.Add do
  begin
    FieldName := 'dias_vida';
    Title.Caption := 'Días de Vida';
    Width := 85;
    ReadOnly := False;
  end;
  with dbGridMain.Columns.Add do
  begin
    FieldName := 'iva_desc';
    Title.Caption := 'IVA';
    Width := 110;
    ReadOnly := False;
    
    // Rellenar PickList con los IVAs cargados
    PickList.Clear;
    PickList.Add('');
    for var I := 0 to FIvaNames.Count - 1 do
      PickList.Add(FIvaNames[I]);
  end;
  with dbGridMain.Columns.Add do
  begin
    FieldName := 'pvp1';
    Title.Caption := 'PVP 1 (IVA inc.)';
    Width := 105;
    Alignment := taRightJustify;
    ReadOnly := False;
  end;
  with dbGridMain.Columns.Add do
  begin
    FieldName := 'activo';
    Title.Caption := 'Activo';
    Width := 65;
    ReadOnly := False;
  end;
end;

procedure TfrmArticulos.btnEditClick(Sender: TObject);
begin
  if FQryMain.IsEmpty then Exit;
  
  if not Assigned(frmArticulosEditor) then
    Application.CreateForm(TfrmArticulosEditor, frmArticulosEditor);
  
  frmArticulosEditor.ParentForm := Self;
  frmArticulosEditor.ArticuloId := FQryMain.FieldByName('id').AsString;
  if frmArticulosEditor.ShowModal = mrOk then
    btnRefreshClick(nil);
end;

procedure TfrmArticulos.btnNewClick(Sender: TObject);
begin
  if not Assigned(frmArticulosEditor) then
    Application.CreateForm(TfrmArticulosEditor, frmArticulosEditor);
  
  frmArticulosEditor.ParentForm := Self;
  frmArticulosEditor.ArticuloId := '';
  if frmArticulosEditor.ShowModal = mrOk then
    btnRefreshClick(nil);
end;

procedure TfrmArticulos.btnDeleteClick(Sender: TObject);
begin
  if FQryMain.IsEmpty then Exit;
  
  if MessageDlg('¿Está seguro de que desea eliminar este artículo?', mtConfirmation, [mbYes, mbNo], 0) = mrYes then
  begin
    try
      dmgMain.qryExec.Close;
      dmgMain.qryExec.SQL.Text := 'DELETE FROM ge_articulos WHERE id = :id';
      dmgMain.qryExec.ParamByName('id').AsString := FQryMain.FieldByName('id').AsString;
      dmgMain.qryExec.ExecSQL;
      btnRefreshClick(nil);
    except
      on E: Exception do
        ShowMessage('Error al eliminar el artículo: ' + E.Message);
    end;
  end;
end;

procedure TfrmArticulos.btnReemplazarClick(Sender: TObject);
var
  LOldId, LOldDesc, LNewId, LNewCode, LNewDesc: string;
begin
  if FQryMain.IsEmpty then Exit;

  LOldId := FQryMain.FieldByName('id').AsString;
  LOldDesc := FQryMain.FieldByName('descripcion').AsString;

  if not Assigned(frmSelectProduct) then
    Application.CreateForm(TfrmSelectProduct, frmSelectProduct);

  frmSelectProduct.MultiSelect := False;

  if frmSelectProduct.ShowModal = mrOk then
  begin
    LNewId := frmSelectProduct.SelectedId;
    LNewCode := frmSelectProduct.SelectedCode;
    LNewDesc := frmSelectProduct.SelectedDesc;

    if LOldId = LNewId then
    begin
      ShowMessage('El artículo seleccionado para reemplazar es el mismo. Operación cancelada.');
      Exit;
    end;

    if MessageDlg(Format('¿Está seguro de que desea reemplazar todas las referencias del artículo "%s" por "%s" en todos los documentos de venta?' + #13#10 + 'Esta acción modificará Presupuestos, Pedidos, Albaranes y Facturas.', [LOldDesc, LNewDesc]), mtConfirmation, [mbYes, mbNo], 0) = mrYes then
    begin
      dmgMain.dbConn.StartTransaction;
      try
        // 1. Presupuestos Lineas
        dmgMain.qryExec.Close;
        dmgMain.qryExec.SQL.Text := 'UPDATE ge_presupuestos_lineas SET articulo_id = :new_id WHERE articulo_id = :old_id';
        dmgMain.qryExec.ParamByName('new_id').AsString := LNewId;
        dmgMain.qryExec.ParamByName('old_id').AsString := LOldId;
        dmgMain.qryExec.ExecSQL;

        // 2. Pedidos Lineas
        dmgMain.qryExec.Close;
        dmgMain.qryExec.SQL.Text := 'UPDATE ge_pedidos_lineas SET id_articulo = :new_id WHERE id_articulo = :old_id';
        dmgMain.qryExec.ParamByName('new_id').AsString := LNewId;
        dmgMain.qryExec.ParamByName('old_id').AsString := LOldId;
        dmgMain.qryExec.ExecSQL;

        // 3. Albaranes Lineas
        dmgMain.qryExec.Close;
        dmgMain.qryExec.SQL.Text := 'UPDATE ge_albaranes_lineas SET articulo_id = :new_id, articulo_codigo = :new_code WHERE articulo_id = :old_id';
        dmgMain.qryExec.ParamByName('new_id').AsString := LNewId;
        dmgMain.qryExec.ParamByName('new_code').AsString := LNewCode;
        dmgMain.qryExec.ParamByName('old_id').AsString := LOldId;
        dmgMain.qryExec.ExecSQL;

        // 4. Facturas Lineas
        dmgMain.qryExec.Close;
        dmgMain.qryExec.SQL.Text := 'UPDATE ge_facturas_lineas SET articulo_id = :new_id, articulo_codigo = :new_code WHERE articulo_id = :old_id';
        dmgMain.qryExec.ParamByName('new_id').AsString := LNewId;
        dmgMain.qryExec.ParamByName('new_code').AsString := LNewCode;
        dmgMain.qryExec.ParamByName('old_id').AsString := LOldId;
        dmgMain.qryExec.ExecSQL;

        dmgMain.dbConn.Commit;
        ShowMessage('Reemplazo en documentos de venta realizado con éxito.');

        // Preguntar si quiere desactivar el original
        if MessageDlg(Format('¿Desea desactivar el artículo original "%s" en la base de datos?', [LOldDesc]), mtConfirmation, [mbYes, mbNo], 0) = mrYes then
        begin
          try
            dmgMain.qryExec.Close;
            dmgMain.qryExec.SQL.Text := 'UPDATE ge_articulos SET activo = 0, id_user_update = :user, update_at = CURRENT_TIMESTAMP WHERE id = :id';
            dmgMain.qryExec.ParamByName('id').AsString := LOldId;
            dmgMain.qryExec.ParamByName('user').AsString := dmgMain.CurrentUserId;
            dmgMain.qryExec.ExecSQL;
            ShowMessage('Artículo original desactivado con éxito.');
          except
            on E: Exception do
              MessageDlg('No se ha podido desactivar el artículo original: ' + E.Message, mtWarning, [mbOk], 0);
          end;
        end;

        btnRefreshClick(nil);
        dbGridMain.SelectedIndex := 1;
      except
        on E: Exception do
        begin
          dmgMain.dbConn.Rollback;
          ShowMessage('Error al realizar el reemplazo: ' + E.Message);
        end;
      end;
    end;
  end;
end;

procedure TfrmArticulos.btnHistoricoClick(Sender: TObject);
var
  LArticuloId: Integer;
  LDesc: string;
begin
  if FQryMain.Active and not FQryMain.IsEmpty then
  begin
    LArticuloId := FQryMain.FieldByName('id').AsInteger;
    LDesc := FQryMain.FieldByName('descripcion').AsString;
    TfrmVentasPreciosHistorico.MostrarHistorico(
      Self,
      '',
      LArticuloId,
      0,
      0,
      'Histórico de Precios: ' + LDesc
    );
  end
  else
    ShowMessage('Seleccione un artículo para consultar su histórico de precios.');
end;

end.
