{
===============================================================================
  Copyright (©) 2001. Rodax Software.
===============================================================================
  Los contenidos de este fichero son propiedad de Rodax Software titular del
  copyright. Este fichero sólo podrá ser copiado, distribuido y utilizado,
  en su totalidad o en parte, con el permiso escrito de Rodax Software, o de
  acuerdo con los términos y condiciones establecidas en el acuerdo/contrato
  bajo el que se suministra.
  -----------------------------------------------------------------------------
  Web:  www.rodax-software.com
===============================================================================
  Fecha primera versión: 01-10-2001
  Versión actual: 1.2.5
  Fecha versión actual: 05-09-2005
===============================================================================
  Modificaciones:

    Fecha         Comentarios
    ---------------------------------------------------------------------------
    16-10-2001    Se ha utilizado una tabla de memoria para tratar la lista
                  de detalles del presupuesto.

    17-10-2001    Cuando se inserta un concepto se inserta por debajo del con-
                  cepto actual. Con la tecla 'Insert' se inserta por encima.

    17-10-2001    Se ha añadido 'cliente final'.

    21-10-2001    En el modo Consultar/Eliminar se quedaban activados algunos
                  botones con lupa.

    27-10-2001    Se ha arreglado un fallo que al añadir un concepto estando
                  en la última fila lo hacia por encima del registro, no por
                  debajo.

    29-10-2001    Cuando se elimina un concepto con <CTRL+Supr> hay que
                  volver a recalcular el importe total del presupuesto.

    30-10-2001    El tamaño de la letra de los campos 'Portada' y 'Memoria' se
                  ha ampliado a 10 puntos.

    27-11-2001    Se recupera la columna 'Unid. medida' del artículo.

    15-01-2002    Se añaden 'capitulos opcionales'.

    07-02-2002    Desactivada la opción de 'CancelOnExit' del grid.

    24-02-2002    Cuando se recupera los datos de un artículo, si las columnas
                  Cantidad, Precio, Unid. medida, Total ya están rellenas en
                  el grid, no se pisa con los valores del material.

    24-02-2002    En la ventana modal de artículos seleccionar, si es posible,
                  la fila con el último material seleccionado.

    02-03-2002    En el contenido se pueden añadir muchos materiales a la vez.

    07-04-2002    Se ha adaptado para la transacción única.

    09-04-2002    En las funciones 'CancelarAnadir', 'CancelarModificar',
                  'CancelarEliminar', 'AnadirDatos', 'ModificarDatos', y
                  'EliminarDatos' cerrar todas las tablas que se usen.

    09-04-2002    En el evento 'bCancelarClick' llamar a la función
                  'TratarCambios' en vez de 'DescartarOperacion'.

    05-05-2002    En el procedimiento 'SetCodigoArticulo' no se daba un mensaje
                  de error cuando el artículo no existía.

    11-05-2002    P215. Copia de presupuestos.

    21-08-2002    P237. Revisar los botones de 'Eliminar' y 'Eliminar todo'
                  para que al pulsar 'Esc' cancele la operación y no la
                  ejecute como ahora.

    21-08-2002    P238. Revisar el grid de los detalles para que se pueda
                  borrar un código de artículo cuando ya se ha introducido.

    14-09-2002    P242. Sacar una ventana modal para editar el
                  texto de un concepto.

    24-09-2002    Se producía una excepción si el cursor estaba en el código
                  del presupuesto, se pulsaba la tecla 'Esc' y se elegía 'No'.
                  El frame estaba oculto pero saltaba el evento OnExit del
                  campo de código de factura.

    04-12-2002    Se producía una excepción al recalcular el total del presu-
                  puesto cuando había muchos conceptos.

    21-12-2002    Se ha eliminado un error con el campo 'PROVINCIA'. Al estar
                  situado en ese campo y dar Esc para salir se puede producir
                  una excepción.

    08-03-2003    Se han puesto componentes con calendario.

    08-03-2004    p272. Adaptación a multiempresa.

    19-07-2004    p278. Error al copiar un presupuesto. No estaba bien adaptado
                  a multiempresa.

    18-03-2005    p587. Adaptación a Bonificaciones

    05-09-2005    Cambio de dxGrid a cxGrid.
===============================================================================
}

unit PresupuestoCliente;

interface

uses
  Windows, RdxBarras, RdxBotones, StdCtrls, RdxComboBox, RdxCampos,
  RdxMemo, RdxTitulos, Controls, ExtCtrls, RdxPaneles, Forms, Classes,
  RdxFramePresupuestos, ComCtrls, RdxPageControl, Grids, DBGrids, RXDBCtrl,
  Db, RdxRichEdit, Graphics, RxMemDS,IBCustomDataSet, Configuracion, dxCntner,
  dxEditor, dxExEdtr, dxEdLib, dxDBELib, dxTL, dxDBCtrl, dxDBGrid,
  Colores, cxControls, cxContainer, cxEdit, cxTextEdit, cxMaskEdit,
  cxDropDownEdit, cxCalendar, cxDBEdit, cxButtonEdit, cxCheckBox,
  cxGridLevel, cxGridCustomTableView, cxGridTableView, cxGridDBTableView,
  cxClasses, cxGridCustomView, cxGrid, cxGraphics;

type
  TfrPresupuestoCliente = class(TRdxFramePresupuestos)
    pnlScroll: TRdxScrollPanel;
    brSalir: TRdxBarraInferior;
    bSalir: TRdxBoton;
    brGuardar: TRdxBarraInferior;
    bGuardar: TRdxBoton;
    bCancelar: TRdxBoton;
    pnlPresupuesto: TRdxPanel;
    eFechaEmision: TLabel;
    eEstadoPresupuesto: TLabel;
    eRealizadoPor: TLabel;
    eCodPedido: TLabel;
    eFechaAlta: TLabel;
    eCodigo: TLabel;
    cPresupuesto: TRdxCabecera;
    Situacion: TRdxDBComboBox;
    Usuario: TRdxDBEdit;
    CodigoPedido: TRdxDBEdit;
    pnlPaginas: TRdxPanel;
    Paginas: TRdxPagesControl;
    pagCliente: TTabSheet;
    pagContenido: TTabSheet;
    pagPortada: TTabSheet;
    pnlCliente: TRdxPanel;
    eCodigoCliente: TLabel;
    eNIFCIF: TLabel;
    eNombre: TLabel;
    eDireccion: TLabel;
    eNumero: TLabel;
    ePiso: TLabel;
    ePoblacion: TLabel;
    eCodigoPostal: TLabel;
    eProvincia: TLabel;
    ePersona: TLabel;
    eTelefono1: TLabel;
    eFax: TLabel;
    NIF: TRdxDBEdit;
    Nombre: TRdxDBEdit;
    Calle: TRdxDBEdit;
    Numero: TRdxDBEdit;
    Piso: TRdxDBEdit;
    Poblacion: TRdxDBEdit;
    CodigoPostal: TRdxDBEdit;
    Provincia: TRdxDBEdit;
    PersonaContacto: TRdxDBEdit;
    Telefono: TRdxDBEdit;
    Fax: TRdxDBEdit;
    ImporteTotal: TRdxDBEdit;
    eImporteEuros: TLabel;
    pnlGridArticulos: TPanel;
    pnlBarraGrid: TRdxPanel;
    bAnadirCon: TRdxBoton;
    bEliminar: TRdxBoton;
    bEliminarTodo: TRdxBoton;
    dsPresupuesto: TDataSource;
    dsDetallesPresupuesto: TDataSource;
    pagDescripcion: TTabSheet;
    RdxPanel2: TRdxPanel;
    Label1: TLabel;
    Image1: TImage;
    RdxPanel3: TRdxPanel;
    RdxPanel4: TRdxPanel;
    Label2: TLabel;
    Image2: TImage;
    RdxPanel5: TRdxPanel;
    bAnadirCap: TRdxBoton;
    pagNotas: TTabSheet;
    RdxPanel6: TRdxPanel;
    Label3: TLabel;
    RdxPanel7: TRdxPanel;
    RdxPanel1: TRdxPanel;
    RdxCabecera1: TRdxCabecera;
    Label4: TLabel;
    Label5: TLabel;
    NombreClienteFinal: TRdxDBEdit;
    Notas: TRdxDBRichEdit;
    Memoria: TRdxDBRichEdit;
    Portada: TRdxDBRichEdit;
    bAnadirOp: TRdxBoton;
    pnlTitulo: TRdxPanelTituloOperacion;
    FechaAlta: TcxDBDateEdit;
    FechaDecision: TcxDBDateEdit;
    Codigo: TcxDBButtonEdit;
    CodCliente: TcxDBButtonEdit;
    CodClienteFinal: TcxDBButtonEdit;
    RdxPanel8: TRdxPanel;
    Label6: TLabel;
    DesBonificacion: TRdxDBEdit;
    Label7: TLabel;
    cxBonificacion: TcxCheckBox;
    ImpBonificacion: TRdxDBEdit;
    gridDetalles: TcxGrid;
    gridDetallesView: TcxGridDBTableView;
    gridDetallesLevel1: TcxGridLevel;
    procedure bSalirClick(Sender: TObject);
    procedure bGuardarClick(Sender: TObject);
    procedure bCancelarClick(Sender: TObject);
    procedure ProvinciaButtonClick(Sender: TObject);
    procedure PoblacionButtonClick(Sender: TObject);
    procedure bAnadirConClick(Sender: TObject);
    procedure bEliminarClick(Sender: TObject);
    procedure bEliminarTodoClick(Sender: TObject);
    procedure bAnadirCapClick(Sender: TObject);
    procedure bAnadirOpClick(Sender: TObject);
    procedure gridDetalles2Editing(Sender: TObject; Node: TdxTreeListNode;
      var Allow: Boolean);
    procedure gridDetalles2CustomDrawCell(Sender: TObject; ACanvas: TCanvas;
      ARect: TRect; ANode: TdxTreeListNode; AColumn: TdxTreeListColumn;
      ASelected, AFocused, ANewItemRow: Boolean; var AText: String;
      var AColor: TColor; AFont: TFont; var AAlignment: TAlignment;
      var ADone: Boolean);
    procedure RdxFramePresupuestosShow(Sender: TObject);
    procedure CodigoPropertiesButtonClick(Sender: TObject;
      AButtonIndex: Integer);
    procedure CodigoPropertiesValidate(Sender: TObject;
      var DisplayValue: Variant; var ErrorText: TCaption;
      var Error: Boolean);
    procedure CodClientePropertiesButtonClick(Sender: TObject;
      AButtonIndex: Integer);
    procedure CodClientePropertiesValidate(Sender: TObject;
      var DisplayValue: Variant; var ErrorText: TCaption;
      var Error: Boolean);
    procedure CodClienteFinalPropertiesButtonClick(Sender: TObject;
      AButtonIndex: Integer);
    procedure CodClienteFinalPropertiesValidate(Sender: TObject;
      var DisplayValue: Variant; var ErrorText: TCaption;
      var Error: Boolean);
    procedure cxBonificacionPropertiesChange(Sender: TObject);
    procedure gridDetallesViewEditing(Sender: TcxCustomGridTableView;
      AItem: TcxCustomGridTableItem; var AAllow: Boolean);
    procedure gridDetallesViewCustomDrawCell(
      Sender: TcxCustomGridTableView; ACanvas: TcxCanvas;
      AViewInfo: TcxGridTableDataCellViewInfo; var ADone: Boolean);
    procedure GridBotonCodigoArticuloClick(Sender: TObject; AButtonIndex: Integer);
  private
    FCodigoProvincia : Variant;
    FCodigoPoblacion : Variant;
    FCodigoCliente : Variant;
    FCodigoClienteFinal : Variant;
    FCodigoArticulo : Variant;
    FCodigoClienteAux : Variant;
    FTablaDetallesMem : TRxMemoryData;
    procedure CalcularTotalDetalle;
    procedure CalcularTotalPresupuesto;
    procedure ActivarEventosCampos;
    procedure BorrarDetalles;
    procedure BorrarDetallesIB;
    procedure SalvarDetalles;
    procedure CargarDetalles;
    procedure DetalleAfterDelete (DataSet: TDataSet);
    procedure DetalleAfterInsert (DataSet: TDataSet);    
    procedure CopiarDatosPresupuesto;
    procedure CopiarConceptosPresupuesto;
  protected
    procedure ActivarModoAnadir; override;
    procedure ActivarModoModificar; override;
    procedure ActivarModoConsultar; override;
    procedure ActivarModoEliminar; override;
    function AnadirDatos : Boolean; override;
    function ModificarDatos : Boolean; override;
    function EliminarDatos : Boolean; override;
    function CancelarAnadir : Boolean; override;
    function CancelarModificar : Boolean; override;
    function CancelarEliminar : Boolean; override;
    function ComprobarDatos : Boolean; override;
    procedure VerModal; override;
    procedure SetCodigoProvincia (Value : Variant); virtual;
    procedure SetCodigoPoblacion (Value : Variant); virtual;
    procedure SetCodigoCliente (Value : Variant);
    procedure SetCodigoClienteFinal (Value : Variant);
    procedure SetCodigoArticulo (Value : Variant);
    procedure FreeContenido; override;
    procedure BuscarPresupuesto; override;
  public
    property CodigoProvincia : Variant read FCodigoProvincia write SetCodigoProvincia;
    property CodigoPoblacion : Variant read FCodigoPoblacion write SetCodigoPoblacion;
    property CodigoCliente : Variant read FCodigoCliente write SetCodigoCliente;
    property CodigoClienteFinal : Variant read FCodigoClienteFinal write SetCodigoClienteFinal;
    property CodigoArticulo : Variant read FCodigoArticulo write SetCodigoArticulo;
    constructor Create (AOwner : TComponent); override;
    destructor Destroy; override;
  published
    property TablaPresupuestos;
    property TablaDetallesPresupuestos;
    property TablaDetallesMem : TRxMemoryData read FTablaDetallesMem write FTablaDetallesMem;
    property CodigoPresupuesto;
    property CodigoPresupuestoOrigen;
    procedure ProvinciaSetText(Sender: TField; const Text: String);
    procedure GridBotonDescripcionClick(Sender: TObject);
    procedure CodigoArticuloDetalleSetText(Sender: TField; const Text: String);
    procedure PlusDetalleSetText(Sender: TField; const Text: String);
    procedure CantidadDetalleSetText(Sender: TField; const Text: String);
    procedure PrecioDetalleSetText(Sender: TField; const Text: String);
    procedure PrecioMinutoDetalleSetText(Sender: TField; const Text: String);
    procedure MinutosDetalleSetText(Sender: TField; const Text: String);
    procedure ImpBonificacionSetText(Sender: TField; const Text: String);
  end;

var
  frPresupuestoCliente: TfrPresupuestoCliente;

implementation

{$R *.DFM}

uses
  PresupuestosClientes, BaseDatos, TablaPresupuestos, IBDatabase,
  Mensajes, Clientes, RdxFrameProvincias, RdxFramePoblaciones,
  TablaProvincias, Provincias, Poblaciones, TablaClientes, RdxFrameClientes,
  IB, Articulos, RdxFrameArticulos, TablaArticulos, RdxEmpresaActiva,
  Tipos, StrFunc, Sysutils, TablaPoblaciones, Excepciones, NumFunc,
  IBErrorCodes, dxDBTLCL, IBSQL, EditorDescripcion, Literales,
  TablaAlmacenes, Constantes, cxGridDBDataDefinitions;

var
  NuevoConcepto : Integer;

{ TfrPresupuestoCliente }

procedure TfrPresupuestoCliente.ActivarModoAnadir;
var
  CodNuevo : Variant;
begin
  dsPresupuesto.AutoEdit := True;
  dsDetallesPresupuesto.AutoEdit := True;
  Codigo.Properties.Buttons[0].Visible := False;
  Codigo.Properties.ReadOnly := False;
  Codigo.Properties.OnValidate := CodigoPropertiesValidate;
  CodCliente.Properties.Buttons[0].Visible := True;
  CodCliente.Properties.OnValidate := CodClientePropertiesValidate;
  CodClienteFinal.Properties.Buttons[0].Visible := True;
  CodClienteFinal.Properties.OnValidate := CodClienteFinalPropertiesValidate;
  Poblacion.VerBoton := True;
  Provincia.VerBoton := True;
  cxBonificacion.Properties.ReadOnly := False;
  ActivarEdicionGridDetalles(gridDetallesView);


  (gridDetallesView.GetColumnByFieldName('CODIGOARTICULO').Properties as TcxButtonEditProperties).OnButtonClick := GridBotonCodigoArticuloClick;

{  (gridDetalles.ColumnByFieldName('DESCRIPCION')
    as TdxDBTreeListButtonColumn).OnEditButtonClick := GridBotonDescripcionClick;}

  pnlBarraGrid.Visible := True;

  try
    { Inicializar la tabla de presupuestos }
    TablaPresupuestos.DisableControls;
    TablaPresupuestos.Close;
    CodNuevo := dmTablaPresupuestos.darNuevoCodigo;
    with TablaPresupuestos do
    begin
      CachedUpdates := True;
      Prepare;
      Open;
      EnableControls;
      Insert;
      FieldByName('CODIGOEMPRESA').AsInteger := EmpresaActiva.Codigo;
      FieldByName('PROVINCIA').OnSetText := ProvinciaSetText;
    end;

    Codigo.DataBinding.Field.asString := CodNuevo;
    FechaAlta.DataBinding.Field.AsString := DateToStr(Date);
    Situacion.Field.AsString := Situacion.Items.Strings[0];
    Usuario.Field.AsString := dmBaseDatos.Usuario;
    Notas.Field.AsString := msgPreNotaPorDefecto;

    { Inicializar la tabla de detalles }
    with TablaDetallesPresupuestos do
    begin
      Close;
      ParamByName('CODIGOEMPRESA').AsInteger := EmpresaActiva.Codigo;
      Params.ByName('CODIGOPRESUPUESTO').AsString := CodNuevo;
      Prepare;
      Open;
    end;

    with TablaDetallesMem do
    begin
      Close;
      Open;
      ActivarEventosCampos;
    end;

    dmTablaPresupuestos.InicializarTablaPresupuestos(@TablaPresupuestos);
    dmTablaPresupuestos.InicializarTablaDetalles(@TablaDetallesMem);

    if not EsCadenaVacia(CodigoPresupuestoOrigen) then
      CopiarDatosPresupuesto;

    Visible := True;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

procedure TfrPresupuestoCliente.ActivarModoConsultar;
begin
  dsPresupuesto.AutoEdit := False;
  dsDetallesPresupuesto.AutoEdit := False;
  Codigo.Properties.Buttons[0].Visible := True;
  Codigo.Properties.OnValidate := nil;
  CodCliente.Properties.Buttons[0].Visible := False;
  CodCliente.Properties.OnValidate := nil;
  CodClienteFinal.Properties.Buttons[0].Visible := False;
  CodClienteFinal.Properties.OnValidate := nil;
  Poblacion.VerBoton := False;
  Provincia.VerBoton := False;

  DesactivarEdicionGridDetalles(gridDetallesView);

  (gridDetallesView.GetColumnByFieldName('CODIGOARTICULO').Properties as TcxButtonEditProperties).OnButtonClick := NIL;

{ (gridDetalles.ColumnByFieldName('DESCRIPCION')
    as TdxDBTreeListButtonColumn).OnEditButtonClick := NIL;}

  pnlBarraGrid.Visible := False;
  try
    TablaPresupuestos.Prepare;
    TablaPresupuestos.Open;

    if TablaPresupuestos.RecordCount = 0 then
    begin
      VerMensajeFmt(msgPreNoExistePre, [CodigoPresupuesto]);
      CloseFrame;
      Exit;
    end;

    TablaPresupuestos.Cancel;

    with TablaDetallesPresupuestos do
    begin
      Close;
      ParamByName('CODIGOEMPRESA').AsInteger := EmpresaActiva.Codigo;
      Params.ByName('CODIGOPRESUPUESTO').AsString := CodigoPresupuesto;
      Prepare;
      Open;
      Cancel;
    end;

    with TablaDetallesMem do
    begin
      Close;
      Open;
      Cancel;
      CargarDetalles;
    end;

    dmTablaPresupuestos.InicializarTablaPresupuestos(@TablaPresupuestos);
    dmTablaPresupuestos.InicializarTablaDetalles(@TablaDetallesMem);

    //Establecemos si hay o no bonificación
    if not VarIsNull(TablaPresupuestos.FieldByName('DESBONIFICACION').AsVariant) then
       cxBonificacion.Checked := True;
    cxBonificacion.Properties.ReadOnly := True;

    Visible := True;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

procedure TfrPresupuestoCliente.ActivarModoEliminar;
begin
  dsPresupuesto.AutoEdit := False;
  dsDetallesPresupuesto.AutoEdit := False;
  Codigo.Properties.Buttons[0].Visible := True;
  Codigo.Properties.OnValidate := nil;
  CodCliente.Properties.Buttons[0].Visible := False;
  CodCliente.Properties.OnValidate := nil;
  CodClienteFinal.Properties.Buttons[0].Visible := False;
  CodClienteFinal.Properties.OnValidate := nil;
  Poblacion.VerBoton := False;
  Provincia.VerBoton := False;

  DesactivarEdicionGridDetalles(gridDetallesView);

  (gridDetallesView.GetColumnByFieldName('CODIGOARTICULO').Properties as TcxButtonEditProperties).OnButtonClick := NIL;

{ // Para poder consultar el texto del concepto:
  (gridDetalles.ColumnByFieldName('DESCRIPCION')
    as TdxDBTreeListButtonColumn).OnEditButtonClick := NIL;}

  pnlBarraGrid.Visible := False;
  try
    TablaPresupuestos.Prepare;
    TablaPresupuestos.Open;

    if TablaPresupuestos.RecordCount = 0 then
    begin
      VerMensajeFmt(msgPreNoExistePre, [CodigoPresupuesto]);
      CancelarEliminar;
      CloseFrame;
      Exit;
    end;

    TablaPresupuestos.Cancel;

    with TablaDetallesPresupuestos do
    begin
      Close;
      ParamByName('CODIGOEMPRESA').AsInteger := EmpresaActiva.Codigo;
      Params.ByName('CODIGOPRESUPUESTO').AsString := CodigoPresupuesto;
      Prepare;
      Open;
      Cancel;
    end;

    with TablaDetallesMem do
    begin
      Close;
      Open;
      Cancel;
      CargarDetalles;
    end;

    dmTablaPresupuestos.InicializarTablaPresupuestos(@TablaPresupuestos);
    dmTablaPresupuestos.InicializarTablaDetalles(@TablaDetallesMem);

    //Establecemos si hay o no bonificación
    if not VarIsNull(TablaPresupuestos.FieldByName('DESBONIFICACION').AsVariant) then
       cxBonificacion.Checked := True;
    cxBonificacion.Properties.ReadOnly := True;

    Visible := True;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

procedure TfrPresupuestoCliente.ActivarModoModificar;
begin
  dsPresupuesto.AutoEdit := True;
  dsDetallesPresupuesto.AutoEdit := True;
  Codigo.Properties.Buttons[0].Visible := True;
  Codigo.Properties.ReadOnly := True;
  Codigo.Properties.OnValidate := nil;
  CodCliente.Properties.Buttons[0].Visible := True;
  CodCliente.Properties.OnValidate := CodClientePropertiesValidate;
  CodClienteFinal.Properties.Buttons[0].Visible := True;
  CodClienteFinal.Properties.OnValidate := CodClienteFinalPropertiesValidate;
  Poblacion.VerBoton := True;
  Provincia.VerBoton := True;

  ActivarEdicionGridDetalles(gridDetallesView);

  (gridDetallesView.GetColumnByFieldName('CODIGOARTICULO').Properties as TcxButtonEditProperties).OnButtonClick := GridBotonCodigoArticuloClick;

{ (gridDetalles.ColumnByFieldName('DESCRIPCION')
    as TdxDBTreeListButtonColumn).OnEditButtonClick := GridBotonDescripcionClick;}

  pnlBarraGrid.Visible := True;
  try
    TablaPresupuestos.Prepare;
    TablaPresupuestos.Open;
    TablaPresupuestos.FieldByName('PROVINCIA').OnSetText := ProvinciaSetText;

    if TablaPresupuestos.RecordCount = 0 then
    begin
      VerMensajeFmt(msgPreNoExistePre, [CodigoPresupuesto]);
      CancelarModificar;
      CloseFrame;
      Exit;
    end;

    TablaPresupuestos.Edit;
    TablaPresupuestos.Post;
    TablaPresupuestos.Edit;

    with TablaDetallesPresupuestos do
    begin
      Close;
      ParamByName('CODIGOEMPRESA').AsInteger := EmpresaActiva.Codigo;
      Params.ByName('CODIGOPRESUPUESTO').AsString := CodigoPresupuesto;
      Prepare;
      Open;
    end;

    with TablaDetallesMem do
    begin
      Close;
      Open;
      CargarDetalles;
      ActivarEventosCampos;
      CalcularTotalPresupuesto;
    end;

    dmTablaPresupuestos.InicializarTablaPresupuestos(@TablaPresupuestos);
    dmTablaPresupuestos.InicializarTablaDetalles(@TablaDetallesMem);

    //Establecemos si hay o no bonificación
    if not VarIsNull(TablaPresupuestos.FieldByName('DESBONIFICACION').AsVariant) then
       cxBonificacion.Checked := True;
    cxBonificacion.Properties.ReadOnly := False;

    Visible := True;
  except
    on E : EIBError do
    begin
      case E.IBErrorCode of
        isc_lock_conflict : begin
                              VerMensajeFmt(msgPreBloqueado, [CodigoPresupuesto]);
                              CancelarModificar;
                              CloseFrame;
                              Exit;
                            end
        else
          TratarExcepcion(E);
      end;
    end;
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

function TfrPresupuestoCliente.AnadirDatos: Boolean;
begin
  Result := False;
  try
    CalcularTotalPresupuesto;
    TablaPresupuestos.Post;
    TablaPresupuestos.ApplyUpdates;

    BorrarDetallesIB;
    SalvarDetalles;

    dmTablaPresupuestos.IncrementarCodigo;
    FCodigoPresupuesto := TablaPresupuestos.FieldByName('CODIGO').AsString;
    Commit;
    TablaPresupuestos.CachedUpdates := False;
    TablaPresupuestos.Close;
    TablaDetallesPresupuestos.Close;
    TablaDetallesMem.Close;
    Result := True;
  except
    on E : EIBError do begin
      if E.IBErrorCode = isc_unique_key_violation then begin
        VerMensajeFmt(msgPreCodPreRepetido, [Codigo.DataBinding.Field.AsString]);
        TablaPresupuestos.Edit;
      end
      else
        TratarExcepcion(E);
    end;
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

procedure TfrPresupuestoCliente.BuscarPresupuesto;
begin
  if Transaccion = NIL then
    Exit;
  try
    TablaPresupuestos.DisableControls;
    TablaDetallesPresupuestos.DisableControls;
    TablaDetallesMem.DisableControls;

    TablaPresupuestos.Close;
    TablaDetallesPresupuestos.Close;

    // Buscar la fila a tratar si es necesario
    if not EsCadenaVacia(FCodigoPresupuesto) then
    begin
      TablaPresupuestos.ParamByName('CODIGOEMPRESA').AsInteger := EmpresaActiva.Codigo;
      TablaPresupuestos.Params.ByName('CODIGO').AsString := FCodigoPresupuesto;

      TablaDetallesPresupuestos.ParamByName('CODIGOEMPRESA').AsInteger := EmpresaActiva.Codigo;
      TablaDetallesPresupuestos.Params.ByName('CODIGOPRESUPUESTO').AsString := FCodigoPresupuesto;
    end;

    TablaPresupuestos.Prepare;
    TablaPresupuestos.Open;

    TablaDetallesPresupuestos.Prepare;
    TablaDetallesPresupuestos.Open;

    TablaDetallesMem.Close;
    TablaDetallesMem.Open;

    BorrarDetalles;
    CargarDetalles;

    dmTablaPresupuestos.InicializarTablaPresupuestos(@TablaPresupuestos);
    dmTablaPresupuestos.InicializarTablaDetalles(@TablaDetallesMem);

    TablaPresupuestos.EnableControls;
    TablaDetallesPresupuestos.EnableControls;
    TablaDetallesMem.EnableControls;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

procedure TfrPresupuestoCliente.CalcularTotalDetalle;
var
  auxCantidad,
  auxPrecio,
  auxMinutos,
  auxPlus,
  auxTotal,
  TotalAnt,
  TotalPre : double;
begin
  with TablaDetallesMem do
  begin
    auxCantidad := FieldByName('CANTIDAD').AsFloat;
    auxPrecio := FieldByName('PRECIOUNIDAD').AsFloat;
    auxMinutos := FieldByName('MINUTOS').AsFloat * FieldByName('PRECIOMINUTO').AsFloat;
    auxPlus := FieldByName('PLUS').AsFloat;
    auxTotal := (auxCantidad * auxPrecio) + auxMinutos;
    auxTotal := auxTotal + (auxTotal * (auxPlus / 100));
    if auxCantidad > 0 then
      FieldByName('PRECIO').AsFloat := auxTotal / auxCantidad
    else
      FieldByName('PRECIO').AsFloat := 0;
    TotalAnt := FieldByName('TOTAL').AsFloat;
    FieldByName('TOTAL').AsFloat := auxTotal;
  end;
  TotalPre := TablaPresupuestos.FieldByName('IMPORTETOTAL').AsFloat;
  TotalPre := TotalPre - TotalAnt;
  TotalPre := TotalPre + auxTotal;
  TablaPresupuestos.FieldByName('IMPORTETOTAL').AsFloat := TotalPre;
end;

procedure TfrPresupuestoCliente.CalcularTotalPresupuesto;
var
  ImporteTotal : Double;
  FDetallesBookmark : string;
begin
  ImporteTotal := 0;
  with TablaDetallesMem do
  begin
    DisableControls;
    FDetallesBookmark := Bookmark;
    try
      First;
      while not EOF do begin
        ImporteTotal := ImporteTotal + FieldByName('TOTAL').AsFloat;
        Next;
      end;

      //Restamos la bonificacion si la tuviera
      if cxBonificacion.Checked then
         ImporteTotal := ImporteTotal - TablaPresupuestos.FieldByName('IMPBONIFICACION').AsFloat;

    finally
      TablaPresupuestos.FieldByName('IMPORTETOTAL').AsFloat := ImporteTotal;
      if RecordCount > 0  then
        Bookmark := FDetallesBookmark;
      EnableControls;
    end;
  end;
end;

function TfrPresupuestoCliente.CancelarAnadir: Boolean;
begin
  Result := False;
  try
    TablaDetallesMem.Close;
    TablaPresupuestos.CancelUpdates;
    RollBack;
    TablaPresupuestos.CachedUpdates := False;
    TablaPresupuestos.Close;
    TablaDetallesPresupuestos.Close;
    Result := True;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

function TfrPresupuestoCliente.CancelarEliminar: Boolean;
begin
  Result := False;
  try
    TablaDetallesMem.Close;
    RollBack;
    TablaPresupuestos.Close;
    TablaDetallesPresupuestos.Close;
    Result := True;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

function TfrPresupuestoCliente.CancelarModificar: Boolean;
begin
  Result := False;
  try
    TablaDetallesMem.Close;
    RollBack;
    TablaPresupuestos.Close;
    TablaDetallesPresupuestos.Close;
    Result := True;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

function TfrPresupuestoCliente.ComprobarDatos: Boolean;
var
  AuxNumDetalles : integer;
begin
  Result := False;

  if not (Modo in [Anadir, Modificar, Eliminar]) then
  begin
    Result := True;
    exit;
  end;

  if Modo = Eliminar then
  begin
    if dmTablaAlmacenes.ExistePresupuestoEnObra(CodigoPresupuesto) then
    begin
      VerMensaje(msgPreNoEliminarEnObra);
      Exit;
    end;
  end;

  if EsCadenaVacia(FechaAlta.DataBinding.Field.AsString) then
  begin
    VerMensaje(msgPreFaltaFecAlta);
    FechaAlta.SetFocus;
    Exit;
  end;

  if ((UpperCase(Situacion.Field.AsString) = CTE_ACEPTADO) or
      (UpperCase(Situacion.Field.AsString) = CTE_ANULADO)) and
     EsCadenaVacia(FechaDecision.DataBinding.Field.AsString) then
  begin
    VerMensaje(msgPreFaltaFecDecision);
    FechaDecision.SetFocus;
    Exit;
  end;

  if (UpperCase(Situacion.Field.AsString) = CTE_PENDIENTE) and
     not EsCadenaVacia(FechaDecision.DataBinding.Field.AsString) then
  begin
    VerMensaje(msgPreSobraFecDecision);
    FechaDecision.SetFocus;
    Exit;
  end;

  if EsCadenaVacia(Nombre.Field.AsString) then
  begin
    VerMensaje(msgPreFaltaNombreCli);
    Paginas.ActivePageIndex := 0;
    Nombre.SetFocus;
    Exit;
  end;

  if TablaDetallesMem.IsEmpty then
  begin
    VerMensaje(msgPreFaltaArticulos);
    Paginas.ActivePageIndex := 1;
    gridDetalles.SetFocus;
    Exit
  end;

  if cxBonificacion.Checked then
  begin
    if VarIsNull(TablaPresupuestos.FieldByName('DESBONIFICACION').AsVariant) then
    begin
      VerMensaje(msgPreFaltasDatosBoni);
      Paginas.ActivePageIndex := 1;
      DesBonificacion.SetFocus;
      Exit
    end;

    if VarIsNull(TablaPresupuestos.FieldByName('IMPBONIFICACION').AsVariant) then
    begin
      VerMensaje(msgPreFaltasDatosBoni);
      Paginas.ActivePageIndex := 1;
      ImpBonificacion.SetFocus;
      Exit
    end;
  end;

  Result := True;
end;

constructor TfrPresupuestoCliente.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FCodigoProvincia := NULL;
  FCodigoPoblacion := NULL;
  FCodigoCliente := NULL;
  FCodigoArticulo := NULL;

  Entidad := entPresupuestoCliente;
  ConfigurarFrame(Self, Self.Entidad);

  BaseDatos := dmBaseDatos.BD;

  Transaccion := dmBaseDatos.Transaccion;

  TablaPresupuestos := TIBDataSet.Create(Self);
  TablaDetallesPresupuestos := TIBDataSet.Create(Self);
  TablaDetallesMem := TRxMemoryData.Create(Self);

  dsPresupuesto.DataSet := TablaPresupuestos;
  dsDetallesPresupuesto.DataSet := TablaDetallesMem;

  with TablaPresupuestos do
  begin
    Database := BaseDatos;
    Transaction := Transaccion;
    SelectSQL.Assign(dmTablaPresupuestos.sqlConsultarPresupuesto);
    InsertSQL.Assign(dmTablaPresupuestos.sqlInsertarPresupuesto);
    ModifySQL.Assign(dmTablaPresupuestos.sqlModificarPresupuesto);
    DeleteSQL.Assign(dmTablaPresupuestos.sqlEliminarPresupuesto);
  end;

  with TablaDetallesPresupuestos do
  begin
    Database := BaseDatos;
    Transaction := Transaccion;
    SelectSQL.Assign(dmTablaPresupuestos.sqlConsultarGridDetalles);
    InsertSQL.Assign(dmTablaPresupuestos.sqlInsertarDetalles);
    ModifySQL.Assign(dmTablaPresupuestos.sqlModificarDetalles);
    DeleteSQL.Assign(dmTablaPresupuestos.sqlEliminarDetalles);
  end;

  try
    TablaDetallesMem.CopyStructure(TablaDetallesPresupuestos);
    TablaDetallesMem.FieldByName('CODIGOEMPRESA').Required := False;
    TablaDetallesMem.FieldByName('CODIGOPRESUPUESTO').Required := False;
    TablaDetallesMem.FieldByName('NUMCONCEPTO').Required := False;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;

  dmTablaPresupuestos.InicializarGridDetalles(gridDetallesView);
  Situacion.Items := dmTablaPresupuestos.darSituaciones;
  Paginas.ActivePage := pagCliente;
end;

destructor TfrPresupuestoCliente.Destroy;
begin
  gridDetallesView.DataController.DataSource := NIL;

  TablaDetallesMem.Close;
  TablaDetallesMem.Free;

  TablaPresupuestos.Close;
  TablaPresupuestos.UnPrepare;
  TablaPresupuestos.Free;

  TablaDetallesPresupuestos.Close;
  TablaDetallesPresupuestos.Unprepare;
  TablaDetallesPresupuestos.Free;

  inherited;
end;

function TfrPresupuestoCliente.EliminarDatos: Boolean;
begin
  Result := False;
  try
    TablaPresupuestos.Delete;
    Commit;
    BorrarDetalles;
    TablaPresupuestos.Close;
    TablaDetallesPresupuestos.Close;
    TablaDetallesMem.Close;
    Result := True;
  except
    on E : EIBError do
    begin
      case E.IBErrorCode of
        isc_lock_conflict : VerMensajeFmt(msgPreBloqueado, [Codigo.DataBinding.Field.AsString]);
        else
          TratarExcepcion(E);
      end;
    end;
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

procedure TfrPresupuestoCliente.FreeContenido;
var
  Contador : integer;
  ListaCodigos : TStringList;
begin
  if (ContenidoModal is TRdxFramePresupuestos) then begin
    CodigoPresupuesto := (ContenidoModal as TRdxFramePresupuestos).CodigoPresupuesto;
    ActivarModo;
  end;
  if (ContenidoModal is TRdxFrameArticulos) then
  begin
    ListaCodigos := (ContenidoModal as TRdxFrameArticulos).ListaArticulos;
    for Contador := 0 to ListaCodigos.Count - 1 do
    begin
      CodigoArticulo := ListaCodigos.Strings[Contador];
      bAnadirConClick(Self);
    end;
    TablaDetallesMem.Delete;
  end;

  if (ContenidoModal is TfrEditorDescripcion) then
  begin
    TablaDetallesMem.FieldByName('DESCRIPCION').AsString := (ContenidoModal as TfrEditorDescripcion).Texto;
    TablaDetallesMem.Post;
    TablaDetallesMem.Edit;
  end;

  if (ContenidoModal is TRdxFrameClientes) then
    FCodigoClienteAux := (ContenidoModal as TRdxFrameClientes).CodigoCliente;
  if (ContenidoModal is TRdxFrameProvincias) then
    CodigoProvincia := (ContenidoModal as TRdxFrameProvincias).CodigoProvincia;
  if (ContenidoModal is TRdxFramePoblaciones) then begin
    CodigoProvincia := (ContenidoModal as TRdxFramePoblaciones).CodigoProvincia;
    CodigoPoblacion := (ContenidoModal as TRdxFramePoblaciones).CodigoPoblacion;
  end;
  inherited FreeContenido;
end;

function TfrPresupuestoCliente.ModificarDatos: Boolean;
begin
  Result := False;
  try
    CalcularTotalPresupuesto;
    TablaPresupuestos.Post;
    BorrarDetallesIB;
    SalvarDetalles;
    Commit;
    TablaPresupuestos.Close;
    TablaDetallesPresupuestos.Close;
    TablaDetallesMem.Close;
    Result := True;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

procedure TfrPresupuestoCliente.SetCodigoArticulo(Value: Variant);
var
  DatosArticulo : TDatosArticulo;
begin
  if VarIsNull(Value) then
    exit;
  DatosArticulo := TDatosArticulo.Create;
  DatosArticulo.Codigo := Value;
  try
    if dmTablaArticulos.darDatosArticulo(DatosArticulo) then
    begin
      with TablaDetallesMem do
      begin
        Edit;
	      FieldByName('TIPO').AsString := 'CON';
        FieldByName('CODIGOARTICULO').AsString := DatosArticulo.Codigo;
        FieldByName('DESCRIPCION').AsString := DatosArticulo.Descripcion;

        if EsCadenaVacia(FieldByName('CANTIDAD').AsString) then
          FieldByName('CANTIDAD').AsString := '1';

        if EsCadenaVacia(FieldByName('UNIDADESMEDIDA').AsString) then
          FieldByName('UNIDADESMEDIDA').AsString := DatosArticulo.Unidadesmedida;

        if EsCadenaVacia(FieldByName('PRECIOUNIDAD').AsString) then
          FieldByName('PRECIOUNIDAD').AsString := DatosArticulo.Precio;

        if EsCadenaVacia(FieldByName('PRECIO').AsString) then
          FieldByName('PRECIO').AsString := DatosArticulo.Precio;

        if EsCadenaVacia(FieldByName('TOTAL').AsString) then
          FieldByName('TOTAL').AsString := DatosArticulo.Precio;
        Post;
      end;
      FCodigoArticulo := Value;
      CalcularTotalPresupuesto;
    end
    else
      raise Exception.CreateFmt(msgArtCodArtNoExiste, [Value]);
  finally
    DatosArticulo.Free;
  end;
end;

procedure TfrPresupuestoCliente.SetCodigoCliente(Value: Variant);
var
  DatosCliente : TDatosCliente;
begin
  if VarIsNull(Value) then
    exit;

  FCodigoCliente := Value;
  DatosCliente := TDatosCliente.Create;
  try
    DatosCliente.Codigo := FCodigoCliente;
    dmTablaClientes.darDatosCliente(DatosCliente);
    CodCliente.DataBinding.Field.AsString := DatosCliente.Codigo;
    NIF.Field.AsString := DatosCliente.Nifcif;
    Nombre.Field.AsString := DatosCliente.Nombre;
    PersonaContacto.Field.AsString := DatosCliente.PersonaContacto;
    Telefono.Field.AsString := DatosCliente.Telefono1;
    Fax.Field.AsString := DatosCliente.Fax;
    Calle.Field.AsString := DatosCliente.Calle;
    Numero.Field.AsString := DatosCliente.Numero;
    Piso.Field.AsString := DatosCliente.Piso;
    CodigoPostal.Field.AsString := DatosCliente.CodigoPostal;
    Poblacion.Field.AsString := DatosCliente.Poblacion;
    Provincia.Field.AsString := DatosCliente.Provincia;
    FCodigoProvincia := dmTablaProvincias.darCodigoProvincia(DatosCliente.Provincia);
    CalcularTotalPresupuesto;
  finally
    DatosCliente.Free;
  end;
end;

procedure TfrPresupuestoCliente.SetCodigoPoblacion(Value: Variant);
begin
  if (not VarIsNull(FCodigoPoblacion)) and (FCodigoPoblacion = Value) then
    exit;

  if (not VarIsNull(Value)) then
  begin
    FCodigoPoblacion := Value;
    Poblacion.Field.AsString := dmTablaPoblaciones.darNombrePoblacion(FCodigoProvincia, FCodigoPoblacion);
  end;
end;

procedure TfrPresupuestoCliente.SetCodigoProvincia(Value: Variant);
begin
  if (not VarIsNull(FCodigoProvincia)) and (FCodigoProvincia = Value) then
    exit;

  if (not VarIsNull(Value)) then
  begin
    FCodigoProvincia := Value;
    Provincia.Field.AsString := dmTablaProvincias.darNombreProvincia(FCodigoProvincia);
  end;
end;

procedure TfrPresupuestoCliente.VerModal;
begin
  if (ContenidoModal is TRdxFramePoblaciones) then
    (ContenidoModal as TRdxFramePoblaciones).CodigoProvincia := CodigoProvincia;
  if (ContenidoModal is TRdxFrameArticulos) then
    (ContenidoModal as TRdxFrameArticulos).CodigoArticulo := CodigoArticulo;
  if (ContenidoModal is TfrEditorDescripcion) then
    (ContenidoModal as TfrEditorDescripcion).Texto := TablaDetallesMem.FieldByName('DESCRIPCION').AsString;
  inherited;
end;

procedure TfrPresupuestoCliente.bSalirClick(Sender: TObject);
begin
  try
    Rollback;
    CloseFrame;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

procedure TfrPresupuestoCliente.bGuardarClick(Sender: TObject);
begin
  if (RealizarOperacion) then
    CloseFrame;
end;

procedure TfrPresupuestoCliente.bCancelarClick(Sender: TObject);
begin
  if (TratarCambios = IDOK) then
    CloseFrame;
end;


procedure TfrPresupuestoCliente.CodigoArticuloDetalleSetText(
  Sender: TField; const Text: String);
var
  Codigo : String;
begin
  if (EsCadenaVacia(Text)) then
  begin
     Sender.AsString := '';
     exit;
  end;

  Codigo := Trim(Text);
  if (dmTablaArticulos.validarCodigo(Codigo)) then
    Codigo := dmTablaArticulos.formatearCodigo(Codigo)
  else
    raise Exception.CreateFmt(msgArtCodArtIncorrecto, [Codigo]);
  Sender.AsString := Codigo;
  CodigoArticulo := Codigo;
end;

procedure TfrPresupuestoCliente.PlusDetalleSetText(Sender: TField;
  const Text: String);
begin
  if EsCadenaVacia(Text) then
    Sender.AsString := '0'
  else begin
    validarDto(Text);
    Sender.AsString := Text;
  end;
  CalcularTotalDetalle;
end;

procedure TfrPresupuestoCliente.CantidadDetalleSetText(Sender: TField;
  const Text: String);
begin
  if EsCadenaVacia(Text) then
    Sender.AsString := '1'
  else
    Sender.AsString := Text;
  CalcularTotalDetalle;
end;

procedure TfrPresupuestoCliente.PrecioDetalleSetText(Sender: TField;
  const Text: String);
begin
  if EsCadenaVacia(Text) then
    Sender.AsString := '0'
  else
    Sender.AsString := Text;
  CalcularTotalDetalle;
end;

procedure TfrPresupuestoCliente.ProvinciaButtonClick(Sender: TObject);
begin
  CaptionModal := 'Lista de provincias';
  WidthModal := 280;
  HeightModal := 460;
  ContenidoModal := TfrProvincias.Create(Self);
end;

procedure TfrPresupuestoCliente.PoblacionButtonClick(Sender: TObject);
begin
  if (VarIsNull(CodigoProvincia)) then begin
    VerMensaje(msgSinProvincia);
    Paginas.ActivePageIndex := 0;
    Provincia.SetFocus;
    Exit;
  end;
  CaptionModal := Format(msgListaPoblaciones, [dmTablaProvincias.darNombreProvincia(CodigoProvincia)]);
  WidthModal := 280;
  HeightModal := 460;
  ContenidoModal := TfrPoblaciones.Create(Self);
end;

procedure TfrPresupuestoCliente.bAnadirConClick(Sender: TObject);
begin
  try
    with TablaDetallesMem do
    begin
      DisableControls;
      Next;
      if EOF then
        Append
      else
        Insert;
      EnableControls;
    end;
    Paginas.ActivePage := pagContenido;
    gridDetalles.SetFocus;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

procedure TfrPresupuestoCliente.bEliminarClick(Sender: TObject);
var
  i, j: Integer;
  s: string;
begin
  if gridDetallesView.Controller.SelectedRowCount > 1 then
    s := msgDeseaBorrarConceptos
  else
    s := msgDeseaBorrar;

  if (VerMensajePregunta(s) <> IDYES) then
    Exit;
  if TablaDetallesMem.RecordCount = 0 then begin
    { Hacemos un cancel de la tabla por si el registro actual estuviera
      recien creado }
    TablaDetallesMem.Cancel;
    Exit
  end;

  try
    gridDetallesView.DataController.DeleteSelection;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

procedure TfrPresupuestoCliente.bEliminarTodoClick(Sender: TObject);
begin
  if (VerMensajePregunta(msgDeseaBorrarTodo) <> IDYES) then
    Exit;
  BorrarDetalles;
  CalcularTotalPresupuesto;
end;

procedure TfrPresupuestoCliente.MinutosDetalleSetText(Sender: TField;
  const Text: String);
begin
  if EsCadenaVacia(Text) then
    Sender.AsString := '0'
  else
    Sender.AsString := Text;
  CalcularTotalDetalle;
end;

procedure TfrPresupuestoCliente.PrecioMinutoDetalleSetText(Sender: TField;
  const Text: String);
begin
  if EsCadenaVacia(Text) then
    Sender.AsString := '0'
  else
    Sender.AsString := Text;
  CalcularTotalDetalle;
end;

procedure TfrPresupuestoCliente.bAnadirCapClick(Sender: TObject);
begin
  try
    with TablaDetallesMem do
    begin
      DisableControls;
      Next;
      if EOF then
        Append
      else
        Insert;
      Edit;
      FieldByName('TIPO').AsString := 'TIT';
      FieldByName('DESCRIPCION').AsString := 'Nombre del capítulo';
      Post;
      EnableControls;
    end;
    Paginas.ActivePage := pagContenido;
    gridDetalles.SetFocus;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

procedure TfrPresupuestoCliente.ActivarEventosCampos;
begin
  with TablaDetallesMem do
  begin
    FieldByName('CODIGOARTICULO').OnSetText := CodigoArticuloDetalleSetText;
    FieldByName('PLUS').OnSetText := PlusDetalleSetText;
    FieldByName('CANTIDAD').OnSetText := CantidadDetalleSetText;
    FieldByName('PRECIOUNIDAD').OnSetText := PrecioDetalleSetText;
    FieldByName('PRECIOMINUTO').OnSetText := PrecioMinutoDetalleSetText;
    FieldByName('MINUTOS').OnSetText := MinutosDetalleSetText;
    AfterDelete := DetalleAfterDelete;
    AfterInsert := DetalleAfterInsert;
  end;
end;

procedure TfrPresupuestoCliente.BorrarDetalles;
begin
  with TablaDetallesMem do
  begin
    DisableControls;
    EmptyTable;
    EnableControls;
  end;
end;

procedure TfrPresupuestoCliente.SalvarDetalles;
var
  NumeroCampo : Integer;
  NumConcepto : Integer;
begin
  try
    with TablaDetallesMem do
    begin
      if IsEmpty then
        Exit;
      NumConcepto := 0;
      DisableControls;
      First;
      while not EOF do
      begin
        TablaDetallesPresupuestos.Append;
        for NumeroCampo := 0 to FieldCount-1 do
        begin
          if Fields[NumeroCampo].FieldName = 'CODIGOEMPRESA' then
            TablaDetallesPresupuestos.Fields[NumeroCampo].AsInteger := EmpresaActiva.Codigo
          else begin
            if Fields[NumeroCampo].FieldName = 'CODIGOPRESUPUESTO' then
              TablaDetallesPresupuestos.Fields[NumeroCampo].AsString := Codigo.DataBinding.Field.AsString
            else
              if Fields[NumeroCampo].FieldName = 'NUMCONCEPTO' then
                TablaDetallesPresupuestos.Fields[NumeroCampo].AsInteger := NumConcepto
              else
                if (Fields[NumeroCampo].FieldName = 'TIPO') and EsCadenaVacia(Fields[NumeroCampo].AsString) then
                  TablaDetallesPresupuestos.Fields[NumeroCampo].AsString := 'CON'
                else
                  TablaDetallesPresupuestos.Fields[NumeroCampo].AsString := Fields[NumeroCampo].AsString;
          end;
        end;
        TablaDetallesPresupuestos.Post;
        Next;
        NumConcepto := NumConcepto + 1;
      end;
      EnableControls;
    end;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

procedure TfrPresupuestoCliente.CargarDetalles;
var
  NumeroCampo : Integer;
begin
  with TablaDetallesMem do
  begin
    if TablaDetallesPresupuestos.IsEmpty then
      Exit;
    DisableControls;
    TablaDetallesPresupuestos.First;
    while not TablaDetallesPresupuestos.EOF do
    begin
      Append;
      if not (State in dsEditModes) then
        Edit;
      for NumeroCampo := 0 to TablaDetallesPresupuestos.FieldCount-1 do
        Fields[NumeroCampo].AsString := TablaDetallesPresupuestos.Fields[NumeroCampo].AsString;
      Post;
      TablaDetallesPresupuestos.Next;
    end;
    First;
    EnableControls;
  end;
end;

procedure TfrPresupuestoCliente.BorrarDetallesIB;
begin
  with TablaDetallesPresupuestos do
  begin
    if IsEmpty then
      Exit;
    DisableControls;
    Last;
    while not BOF do
    begin
      Delete;
      Prior;
    end;
    if not IsEmpty then
      Delete;
    EnableControls;
  end;
end;

procedure TfrPresupuestoCliente.SetCodigoClienteFinal(Value: Variant);
var
  DatosCliente : TDatosCliente;
begin
  if VarIsNull(Value) then
    exit;

  FCodigoClienteFinal := Value;
  DatosCliente := TDatosCliente.Create;
  try
    DatosCliente.Codigo := FCodigoClienteFinal;
    dmTablaClientes.darDatosCliente(DatosCliente);
    CodClienteFinal.DataBinding.Field.AsString := DatosCliente.Codigo;
    NombreClienteFinal.Field.AsString := DatosCliente.Nombre;
  finally
    DatosCliente.Free;
  end;
end;

procedure TfrPresupuestoCliente.DetalleAfterDelete(DataSet: TDataSet);
begin
  CalcularTotalPresupuesto;
end;

procedure TfrPresupuestoCliente.bAnadirOpClick(Sender: TObject);
begin
  try
    with TablaDetallesMem do
    begin
      DisableControls;
      Next;
      if EOF then
        Append
      else
        Insert;
      Edit;
      FieldByName('TIPO').AsString := 'OPC';
      FieldByName('DESCRIPCION').AsString := 'Nombre del capítulo opcional';
      Post;
      EnableControls;
    end;
    Paginas.ActivePage := pagContenido;
    gridDetalles.SetFocus;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

procedure TfrPresupuestoCliente.gridDetalles2Editing(Sender: TObject;
  Node: TdxTreeListNode; var Allow: Boolean);
var
  IndiceCol : Integer;
begin
{  IndiceCol := (Sender as TdxDBGrid).ColumnByFieldName('TIPO').Index;
  if ((Node.Strings[IndiceCol] = 'CON') or EsCadenaVacia(Node.Strings[IndiceCol]))
  then begin
    Allow := True;
    Exit;
  end
  else
  begin
    if (gridDetalles.FocusedField.FieldName <> 'DESCRIPCION') then
      Allow := False;
  end;}
end;

procedure TfrPresupuestoCliente.gridDetalles2CustomDrawCell(Sender: TObject;
  ACanvas: TCanvas; ARect: TRect; ANode: TdxTreeListNode;
  AColumn: TdxTreeListColumn; ASelected, AFocused, ANewItemRow: Boolean;
  var AText: String; var AColor: TColor; AFont: TFont;
  var AAlignment: TAlignment; var ADone: Boolean);
var
  IndiceCol : Integer;
begin
  IndiceCol := (Sender as TdxDBGrid).ColumnByFieldName('TIPO').Index;
  if ((ANode.Strings[IndiceCol] = 'CON') or EsCadenaVacia(ANode.Strings[IndiceCol])) then
    Exit;
  if ANode.Strings[IndiceCol] <> 'CON' then
  begin
    AFont.Style := AFont.Style + [fsBold];
    if ANode.Strings[IndiceCol] = 'OPC' then
      AFont.Style := AFont.Style + [fsItalic];
    if (not ASelected) and (not Focused) then
      AColor := rdxLightGreen;
  end;

end;

procedure TfrPresupuestoCliente.CopiarDatosPresupuesto;
var
  DatosPre : TDatosPresupuesto;
begin
  DatosPre := TDatosPresupuesto.Create;
  DatosPre.Codigo := CodigoPresupuestoOrigen;
  DatosPre.CodigoEmpresa := EmpresaActiva.Codigo;  
  try
    if dmTablaPresupuestos.DarDatosPresupuesto(DatosPre) then
    begin
      CodCliente.DataBinding.Field.AsString := DatosPre.CodigoCliente;
      NIF.Field.AsString := DatosPre.NIFCIF;
      Nombre.Field.AsString := DatosPre.Nombre;
      Calle.Field.AsString := DatosPre.Calle;
      Numero.Field.AsString := DatosPre.Numero;
      Piso.Field.AsString := DatosPre.Piso;
      CodigoPostal.Field.AsString := DatosPre.CodigoPostal;
      Poblacion.Field.AsString := DatosPre.Poblacion;
      Provincia.Field.AsString := DatosPre.Provincia;
      FCodigoProvincia := dmTablaProvincias.darCodigoProvincia(DatosPre.Provincia);
      PersonaContacto.Field.AsString := DatosPre.PersonaContacto;
      Telefono.Field.AsString := DatosPre.Telefono;
      Fax.Field.AsString := DatosPre.Fax;
      CodClienteFinal.DataBinding.Field.AsString := DatosPre.CodigoClienteFinal;
      NombreClienteFinal.Field.AsString := DatosPre.NombreClienteFinal;
      Portada.Field.AsString := DatosPre.Portada;
      Memoria.Field.AsString := DatosPre.Descripcion;
      Notas.Field.AsString := DatosPre.Notas;

      CopiarConceptosPresupuesto;
      CalcularTotalPresupuesto;
    end
  finally
    DatosPre.Free;
  end;
end;

procedure TfrPresupuestoCliente.CopiarConceptosPresupuesto;
var
  oSQL : TIBSQL;
begin
  oSQL := TIBSQL.Create(Self);
  with oSQL do
  begin
    Database := dmBaseDatos.BD;
    Transaction := dmBaseDatos.Transaccion;
    SQL.Add('select * ');
    SQL.Add('from DETALLESPRESUPUESTOSCLIENTE ');
    SQL.Add('where CODIGOPRESUPUESTO = :CODIGOPRESUPUESTO and ');
    SQL.Add('CODIGOEMPRESA = :CODIGOEMPRESA ');
    SQL.Add('order by NUMCONCEPTO');
  end;

  try
    with TablaDetallesMem do
    begin
      oSQL.ParamByName('CODIGOEMPRESA').AsInteger := EmpresaActiva.Codigo;
      oSQL.ParamByName('CODIGOPRESUPUESTO').AsString := CodigoPresupuestoOrigen;
      oSQL.Prepare;
      oSQL.ExecQuery;

      DisableControls;
      while ((not oSQL.EOF)) do // and (oSQL.RowsAffected > 0)) do
      begin
        Append;
        if not (State in dsEditModes) then
          Edit;
        FieldByName('CODIGOPRESUPUESTO').AsString := Codigo.DataBinding.Field.AsString;
        FieldByName('NUMCONCEPTO').AsInteger := oSQL.FieldByName('NUMCONCEPTO').AsInteger;
        FieldByName('TIPO').AsString := oSQL.FieldByName('TIPO').AsString;
        FieldByName('CODIGOARTICULO').AsString := oSQL.FieldByName('CODIGOARTICULO').AsString;
        FieldByName('DESCRIPCION').AsString := oSQL.FieldByName('DESCRIPCION').AsString;
        FieldByName('CANTIDAD').AsString := oSQL.FieldByName('CANTIDAD').AsString;
        FieldByName('UNIDADESMEDIDA').AsString := oSQL.FieldByName('UNIDADESMEDIDA').AsString;
        FieldByName('PRECIOUNIDAD').AsString := oSQL.FieldByName('PRECIOUNIDAD').AsString;
        FieldByName('PRECIO').AsString := oSQL.FieldByName('PRECIO').AsString;
        FieldByName('MINUTOS').AsString := oSQL.FieldByName('MINUTOS').AsString;
        FieldByName('PRECIOMINUTO').AsString := oSQL.FieldByName('PRECIOMINUTO').AsString;
        FieldByName('PLUS').AsString := oSQL.FieldByName('PLUS').AsString;
        FieldByName('TOTAL').AsString := oSQL.FieldByName('TOTAL').AsString;
        Post;
        oSQL.Next;
      end;
      First;
      EnableControls;
    end;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
  oSQL.Close;
  oSQL.Transaction := NIL;
  oSQL.Free;
end;

procedure TfrPresupuestoCliente.GridBotonDescripcionClick(Sender: TObject);
begin
  TablaDetallesMem.Edit;
  WidthModal := 420;
  HeightModal := 435;
  ModoModal := Modo;
  ContenidoModal := TfrEditorDescripcion.Create(Self);
end;

procedure TfrPresupuestoCliente.ProvinciaSetText(Sender: TField;
  const Text: String);
begin
  FCodigoProvincia := dmTablaProvincias.darCodigoProvincia(Text);
  Sender.AsString := Text;
end;

procedure TfrPresupuestoCliente.RdxFramePresupuestosShow(Sender: TObject);
begin
  FechaAlta.SetFocus;
end;

procedure TfrPresupuestoCliente.CodigoPropertiesButtonClick(
  Sender: TObject; AButtonIndex: Integer);
begin
  if (TratarCambios = IDCANCEL) then
    exit;
  { Esto es porque en modo 'Modificar' hacemos un cambio y pulsamos
    este botón se cierra la tabla y si en el frame hijo (el del grid) damos
    a cancelar, FCodigoPresupuesto es NULL y da error al activar modo porque
    no se inicializa los parámetros de la sql. Lo hace BuscarPresupuesto. }
  if not TablaPresupuestos.Active then
    BuscarPresupuesto;
  ContenidoModal := TfrPresupuestosClientes.Create(Self);
end;

procedure TfrPresupuestoCliente.CodigoPropertiesValidate(Sender: TObject;
  var DisplayValue: Variant; var ErrorText: TCaption; var Error: Boolean);
begin
  inherited;
  if (Modo <> Anadir) or (Visible = false) then
    exit;

  if EsCadenaVacia(DisplayValue) then
    Codigo.DataBinding.Field.AsString := dmTablaPresupuestos.darNuevoCodigo;

  if (dmTablaPresupuestos.validarCodigo(DisplayValue)) then
  begin
    Codigo.DataBinding.Field.asString := dmTablaPresupuestos.formatearCodigo(DisplayValue);
    if (dmTablaPresupuestos.ExisteCodigo(EmpresaActiva.Codigo, DisplayValue)) then begin
      VerMensajeFmt(msgPreCodPreRepetido, [DisplayValue]);
      Codigo.SetFocus;
    end
  end
  else begin
    VerMensajeFmt(msgPreCodPreIncorrecto, [Codigo.Text]);
    Codigo.SetFocus;
  end;
end;

procedure TfrPresupuestoCliente.CodClientePropertiesButtonClick(
  Sender: TObject; AButtonIndex: Integer);
begin
  ContenidoModal := TfrClientes.Create(Self);
  CodigoCliente := FCodigoClienteAux;
end;

procedure TfrPresupuestoCliente.CodClientePropertiesValidate(
  Sender: TObject; var DisplayValue: Variant; var ErrorText: TCaption;
  var Error: Boolean);
begin
  if not (Modo in [Anadir, Modificar]) then
    Exit;

  if EsCadenaVacia(DisplayValue) then
    Exit;

  if (dmTablaClientes.validarCodigo(DisplayValue)) then begin
    //Comprueba que le numero es lo sufucientemente pequeño para ser un entero
    if not EsSmallInt(DisplayValue) then
    begin
      VerMensajeFmt(msgCliCodCliIncorrecto,[DisplayValue]);
      DisplayValue := '0';
      Codigo.SetFocus;
    end
    else
    begin
      DisplayValue := dmTablaClientes.formatearCodigo(DisplayValue);
      if (dmTablaClientes.existeCodigo(DisplayValue)) then
        CodigoCliente := DisplayValue
      else begin
        VerMensajeFmt(msgCliCodCliNoExiste, [DisplayValue]);
        Paginas.ActivePageIndex := 0;
        CodCliente.SetFocus;
      end;
    end;
  end
  else begin
    VerMensajeFmt(msgCliCodCliIncorrecto, [DisplayValue]);
    Paginas.ActivePageIndex := 0;
    CodCliente.SetFocus;
  end;
end;

procedure TfrPresupuestoCliente.CodClienteFinalPropertiesButtonClick(
  Sender: TObject; AButtonIndex: Integer);
begin
  ContenidoModal := TfrClientes.Create(Self);
  CodigoClienteFinal := FCodigoClienteAux;
end;

procedure TfrPresupuestoCliente.CodClienteFinalPropertiesValidate(
  Sender: TObject; var DisplayValue: Variant; var ErrorText: TCaption;
  var Error: Boolean);
begin
  if not (Modo in [Anadir, Modificar]) then
    Exit;

  if EsCadenaVacia(DisplayValue) then
    Exit;

  if (dmTablaClientes.validarCodigo(DisplayValue)) then begin
    //Comprueba que le numero es lo sufucientemente pequeño para ser un entero
    if not EsSmallInt(DisplayValue) then
    begin
      VerMensajeFmt(msgCliCodCliIncorrecto,[DisplayValue]);
      DisplayValue := '0';
      Codigo.SetFocus;
    end
    else
    begin
      DisplayValue := dmTablaClientes.FormatearCodigo(DisplayValue);
      if (dmTablaClientes.ExisteCodigo(DisplayValue)) then
        CodigoClienteFinal := DisplayValue
      else
      begin
        VerMensajeFmt(msgCliCodCliNoExiste, [DisplayValue]);
        Paginas.ActivePage := pagCliente;
        CodClienteFinal.SetFocus;
      end;
    end;
  end
  else begin
    VerMensajeFmt(msgCliCodCliIncorrecto, [DisplayValue]);
    Paginas.ActivePage := pagCliente;
    CodClienteFinal.SetFocus;
  end;
end;

procedure TfrPresupuestoCliente.cxBonificacionPropertiesChange(
  Sender: TObject);
begin
  if cxBonificacion.Checked then
  begin
    DesBonificacion.Enabled := True;
    ImpBonificacion.Enabled := True;
    TablaPresupuestos.FieldByName('IMPBONIFICACION').OnSetText := ImpBonificacionSetText;
  end
  else
  begin
    DesBonificacion.Enabled := False;
    ImpBonificacion.Enabled := False;
    TablaPresupuestos.FieldByName('IMPBONIFICACION').OnSetText := Nil;    
    TablaPresupuestos.FieldByName('DESBONIFICACION').AsVariant := Null;
    TablaPresupuestos.FieldByName('IMPBONIFICACION').AsVariant := Null;
  end;
end;

procedure TfrPresupuestoCliente.ImpBonificacionSetText(Sender: TField;
  const Text: String);
begin
  Sender.AsString := Text;
  if not EsCadenaVacia(Text) then
     CalcularTotalPresupuesto;
end;

procedure TfrPresupuestoCliente.DetalleAfterInsert(DataSet: TDataSet);
begin
  DataSet.DisableControls;
  try
    DataSet.Edit;
    DataSet.FieldByName('TIPO').AsString := 'CON';
    DataSet.Post;   
  finally
    DataSet.EnableControls;
  end;
end;

procedure TfrPresupuestoCliente.gridDetallesViewEditing(
  Sender: TcxCustomGridTableView; AItem: TcxCustomGridTableItem;
  var AAllow: Boolean);
var
  IndiceCol : Integer;
begin
  AAllow := True;
  IndiceCol := (Sender as TcxGridDBTableView).GetColumnByFieldName('TIPO').Index;
  if ((UpperCase(AItem.GridView.Items[IndiceCol].EditValue) = 'CON') or
    EsCadenaVacia(AItem.GridView.Items[IndiceCol].EditValue))
  then begin
    AAllow := True;
    Exit;
  end
  else begin
    if (AItem.DataBinding as TcxGridItemDBDataBinding).FieldName <> 'DESCRIPCION' then
      AAllow := False;
  end;
end;

procedure TfrPresupuestoCliente.gridDetallesViewCustomDrawCell(
  Sender: TcxCustomGridTableView; ACanvas: TcxCanvas;
  AViewInfo: TcxGridTableDataCellViewInfo; var ADone: Boolean);
var
  IndiceCol : Integer;
begin
  IndiceCol := (Sender as TcxGridDBTableView).GetColumnByFieldName('TIPO').Index;
  if ((UpperCase(AViewInfo.GridRecord.DisplayTexts[IndiceCol]) <> 'CON') and
    (not EsCadenaVacia(AViewInfo.GridRecord.DisplayTexts[IndiceCol]))) then
  begin
    ACanvas.Font.Style := ACanvas.Font.Style + [fsBold];

    if (UpperCase(AViewInfo.GridRecord.DisplayTexts[IndiceCol]) = 'OPC') then
      ACanvas.Font.Style := ACanvas.Font.Style + [fsItalic];

    if (not AViewInfo.Selected) and (not AViewInfo.Focused) then
      ACanvas.Brush.Color := rdxLightGreen;
  end;
end;

procedure TfrPresupuestoCliente.GridBotonCodigoArticuloClick(
  Sender: TObject; AButtonIndex: Integer);
begin
  TablaDetallesMem.Edit;
  ContenidoModal := TfrArticulos.Create(Self);
end;

end.

