{
===============================================================================
  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.3
  Fecha versión actual:  18-03-2005
===============================================================================
  Modificaciones:

    Fecha         Comentarios
    ---------------------------------------------------------------------------
    15-10-2001    Se han añadido las comprobaciones para el campo 'IVA' y para
                  el campo 'Descuento' porque no estaban.

    20-10-2001    Se ha ampliado el campo 'F. de pago' porque pasa a tener
                  50 caracteres.

    21-10-2001    Al pasar del modo Añadir/Modificar a Consultar/Eliminar se
                  quedaban activados algunos botones con lupa.

    23-10-2001    Los conceptos se han implementado como una tabla de memoria.

    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.

    27-10-2001    En el campo 'domiciliación bancaria' debe aparecer una lista
                  desplegable con todas las cuentas bancarias dadas de alta
                  en la aplicación.

    27-10-2001    Se ha eliminado la pestaña 'Notas' porque en facturas de
                  cliente no hay.

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

    30-10-2001    Se ha añadido cliente final en facturas de cliente.

    31-10-2001    Se han añadido los campos IMPORTEDESCUENTO e IMPORTEIVA.

    27-11-2001    Recuperar la unidad de medida del artículo.

    17-01-2002    Cuando se copian conceptos de un presupuestos, los conceptos
                  de tipo 'OPC' se cambian por 'TIT'.

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

    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.

    07-05-2002    Adaptación al grid 'TdxDBGrid'.

    07-05-2002    Se han eliminado los procedimientos 'DesactivarColumnasTitulo'
                  y 'ActivarColumnasTitulo'.

    11-08-2002    P236. Cuando se borra una factura de cliente hay que
                  comprobar si es la última para decrementar el contador de
                  facturas y no dejar un hueco.

    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 cursos estaba en el código
                  de la factura, 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.     

    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 facturar un presupuesto, albarán o abono.
                  No estaba bien adaptado a multiempresa.

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

unit FacturaCliente;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Grids, DBGrids, RdxBotones, RdxTitulos, StdCtrls,
  RdxMemo, RdxCampos, ExtCtrls, Tipos, Configuracion,
  RdxComboBox, RdxPaneles, RdxBarras, ComCtrls, RdxRichEdit, RXDBCtrl,
  RdxPageControl, RdxFrameFacturasCliente, Db,
  RdxRadioButton, RxMemDS, IBCustomDataSet, TablaPresupuestos, dxCntner,
  dxTL, dxDBCtrl, dxDBGrid, dxEditor, dxExEdtr, dxEdLib, dxDBELib,
  cxControls, cxContainer, cxEdit, cxTextEdit, cxMaskEdit, cxDropDownEdit,
  cxCalendar, cxDBEdit, cxButtonEdit;

type
  TClaseFactura = (cfFactLibre, cfFactPre, cfFactAlb, cfFactAbono);

  TfrFacturaCliente = class(TRdxFrameFacturasCliente)
    brSalir: TRdxBarraInferior;
    bSalir: TRdxBoton;
    brGuardar: TRdxBarraInferior;
    bGuardar: TRdxBoton;
    bCancelar: TRdxBoton;
    pnlScroll: TRdxScrollPanel;
    pnlFactura: TRdxPanel;
    cDatosAlbaran: TRdxCabecera;
    eFormaPago: TLabel;
    eCuentaBancaria: TLabel;
    eCodigo: TLabel;
    Codigo: TRdxDBEdit;
    Label1: TLabel;
    Situacion: TRdxDBComboBox;
    Label8: TLabel;
    Titulo: TRdxPanelTituloOperacion;
    eEstadoFactura: TLabel;
    eRealizadoPor: TLabel;
    Usuario: TRdxDBEdit;
    RdxPanel1: TRdxPanel;
    Paginas: TRdxPagesControl;
    pagCliente: 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;
    pagContenido: TTabSheet;
    pnlGridArticulos: TPanel;
    pnlBarraGrid: TRdxPanel;
    bAnadirCon: TRdxBoton;
    bEliminar: TRdxBoton;
    bEliminarTodo: TRdxBoton;
    bAnadirCap: TRdxBoton;
    pagImportes: TTabSheet;
    pagDescripcion: TTabSheet;
    RdxPanel4: TRdxPanel;
    Label3: TLabel;
    RdxPanel5: TRdxPanel;
    Descripcion: TRdxDBRichEdit;
    pnlImporteAlbaran: TRdxPanel;
    Label4: TLabel;
    eDto: TLabel;
    eIVA: TLabel;
    Label6: TLabel;
    BaseImponible: TRdxDBEdit;
    Descuento: TRdxDBEdit;
    IVA: TRdxDBEdit;
    ImporteTotal: TRdxDBEdit;
    dsFactura: TDataSource;
    dsDetallesFacturas: TDataSource;
    FormaPago: TRdxDBComboBox;
    CuentaBancaria: TRdxDBComboBox;
    RdxPanel2: TRdxPanel;
    RdxCabecera1: TRdxCabecera;
    Label2: TLabel;
    Label5: TLabel;
    NombreClienteFinal: TRdxDBEdit;
    Shape1: TShape;
    ImporteDescuento: TRdxDBEdit;
    ImporteIVA: TRdxDBEdit;
    gridDetalles: TdxDBGrid;
    pnlPresupuesto: TPanel;
    Label7: TLabel;
    Label9: TLabel;
    CodPresupuesto: TRdxDBEdit;
    pnlAlbaran: TPanel;
    Label10: TLabel;
    Label11: TLabel;
    CodAlbaran: TRdxDBEdit;
    pnlAbono: TPanel;
    Label12: TLabel;
    Label13: TLabel;
    CodFacturaCargo: TRdxDBEdit;
    FechaAlta: TcxDBDateEdit;
    Vencimiento: TcxDBDateEdit;
    CodCliente: TcxDBButtonEdit;
    CodClienteFinal: TcxDBButtonEdit;
    procedure bCancelarClick(Sender: TObject);
    procedure bSalirClick(Sender: TObject);
    procedure bGuardarClick(Sender: TObject);
    procedure CodigoButtonClick(Sender: TObject);
    procedure CodigoExit(Sender: TObject);
    procedure ProvinciaButtonClick(Sender: TObject);
    procedure PoblacionButtonClick(Sender: TObject);
    procedure rbPresupuestoClick(Sender: TObject);
    procedure rbFacturaLibreClick(Sender: TObject);
    procedure rbAlbaranClick(Sender: TObject);
    procedure bAnadirConClick(Sender: TObject);
    procedure bAnadirCapClick(Sender: TObject);
    procedure bEliminarClick(Sender: TObject);
    procedure bEliminarTodoClick(Sender: TObject);
    procedure gridDetallesCustomDrawCell(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 gridDetallesEditing(Sender: TObject; Node: TdxTreeListNode;
      var Allow: 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);
  private
    FCodigoProvincia : Variant;
    FCodigoPoblacion : Variant;
    FCodigoCliente : Variant;
    FCodigoClienteAux : Variant;
    FCodigoArticulo : Variant;
    FCodigoPresupuesto : String;
    FCodigoAlbaran : String;
    FTablaDetallesMem : TRxMemoryData;
    FCodigoClienteFinal: Variant;
    FCodigoFacturaCargo : String;
    FClaseFactura : TClaseFactura;
    procedure CalcularTotalDetalle;
    procedure CalcularTotalFactura;
    procedure ActivarEventosCampos;
    procedure ActivarFacturaLibre;
    procedure ActivarPresupuesto;
    procedure ActivarAlbaran;
    procedure ActivarAbono;
    procedure CopiarConceptosAlbaran;
    procedure CopiarConceptosPresupuesto(DatosPre: TDatosPresupuesto);
    procedure CopiarConceptosFacturaCargo;
    procedure IVASetText(Sender: TField; const Text: String);
    procedure DtoSetText(Sender: TField; const Text: String);
    procedure InsertarReferenciaAPresupuesto (DatosPre : TDatosPresupuesto);
    procedure BorrarDetalles;
    procedure SalvarDetalles;
    procedure CargarDetalles;
    procedure BorrarDetallesIB;
    procedure DetalleAfterDelete (DataSet: TDataSet);
    procedure SetClaseFactura(Value : TClaseFactura);
    property ClaseFactura : TClaseFactura read FClaseFactura write SetClaseFactura;
    procedure GridBotonCodigoArticuloClick(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 GridBotonDescripcionClick(Sender: TObject);
    procedure ProvinciaSetText(Sender: TField; const Text: String);
    function ComprobarAbono : Boolean;
  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 SetCodigoPresupuesto (Value : String);
    procedure SetCodigoAlbaran (Value : String);
    procedure SetCodigoFacturaCargo (Value : String);
    procedure FreeContenido; override;
    procedure BuscarFactura; 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;
    property CodigoPresupuesto : String read FCodigoPresupuesto write SetCodigoPresupuesto;
    property CodigoAlbaran : String read FCodigoAlbaran write SetCodigoAlbaran;
    property CodigoFacturaCargo : String read FCodigoFacturaCargo write SetCodigoFacturaCargo;
    constructor Create (AOwner : TComponent); override;
    destructor Destroy; override;
  published
    property TablaFacturas;
    property TablaDetallesFacturas;
    property TablaDetallesMem : TRxMemoryData read FTablaDetallesMem write FTablaDetallesMem;
    property CodigoFactura;
  end;

var
  frFacturaCliente: TfrFacturaCliente;

implementation

{$R *.DFM}

uses
  FacturasClientes, BaseDatos, TablaFacturasCliente, IBDatabase, NumFunc, 
  Mensajes, Clientes, RdxFrameProvincias, RdxFramePoblaciones,
  TablaProvincias, Provincias, Poblaciones, TablaClientes, RdxFrameClientes,
  IB, Articulos, RdxFrameArticulos, TablaArticulos, RdxEmpresaActiva,
  StrFunc, TablaPoblaciones, TablaFormasPago, TablaBancos,
  IBSQL, Excepciones, IBErrorCodes, TablaAlbaranesCliente,
  dxDBTLCL, Colores, EditorDescripcion, Literales, Constantes;

var
  NuevoConcepto : Integer;

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

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

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

procedure TfrFacturaCliente.ActivarEventosCampos;
begin
  with TablaFacturas do
  begin
    FieldByName('IVA').OnSetText := IVASetText;
    FieldByName('DESCUENTO').OnSetText := DtoSetText;
  end;

  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;

  end;
end;

procedure TfrFacturaCliente.ActivarModoAnadir;
var
  CodNuevo : Variant;
begin
  dsFactura.AutoEdit := True;
  dsDetallesFacturas.AutoEdit := True;
  Codigo.VerBoton := False;
  Codigo.ReadOnly := False;
  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(gridDetalles);

  (gridDetalles.ColumnByFieldName('CODIGOARTICULO')
    as TdxDBTreeListButtonColumn).OnEditButtonClick := GridBotonCodigoArticuloClick;

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

  pnlBarraGrid.Visible := True;

  try
    { Antes de aplicar la caché hay que asegurarse de que la
      tabla está cerrada. }
    TablaFacturas.DisableControls;
    TablaDetallesFacturas.DisableControls;

    { Inicializar la tabla de facturas }
    TablaFacturas.Close;
    CodNuevo := dmTablaFacturasCliente.darNuevoCodigo;

    with TablaFacturas do
    begin
      CachedUpdates := True;
      Prepare;
      Open;
      FieldByName('PROVINCIA').OnSetText := ProvinciaSetText;   
      EnableControls;
      Insert;
      FieldByName('CODIGOEMPRESA').AsInteger := EmpresaActiva.Codigo;
    end;
    Codigo.Field.asString := CodNuevo;
    FechaAlta.DataBinding.Field.AsString := DateToStr(Date);
    Vencimiento.DataBinding.Field.AsString := DateToStr(Date);
    Situacion.Field.AsString := Situacion.Items.Strings[0];
    Usuario.Field.AsString := dmBaseDatos.Usuario;
    TablaFacturas.FieldByName('CLASEFACTURA').AsString := 'C';
    ActivarFacturaLibre;

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

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

    dmTablaFacturasCliente.InicializarTablaFacturas(@TablaFacturas);
    dmTablaFacturasCliente.InicializarTablaDetalles(@TablaDetallesMem);
    Visible := True;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

procedure TfrFacturaCliente.ActivarModoConsultar;
var
  CodPreAlb : string;
  CodCargo : string;
begin
  dsFactura.AutoEdit := False;
  dsDetallesFacturas.AutoEdit := False;
  Codigo.VerBoton := True;
  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(gridDetalles);

  (gridDetalles.ColumnByFieldName('CODIGOARTICULO')
    as TdxDBTreeListButtonColumn).OnEditButtonClick := NIL;

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

  pnlBarraGrid.Visible := False;

  try
    TablaFacturas.Prepare;
    TablaFacturas.Open;

    if TablaFacturas.RecordCount = 0 then
    begin
      VerMensajeFmt(msgFacCliNoExisteFac, [CodigoFactura]);
      CloseFrame;
      Exit;
    end;

    TablaFacturas.Cancel;

    CodPreAlb := TablaFacturas.FieldByName('CODIGOPRESUPUESTOALBARAN').AsString;
    if EsCadenaVacia(CodPreAlb) then
      ClaseFactura := cfFactLibre
    else begin
      if dmTablaPresupuestos.ValidarCodigo(CodPreAlb) then
        ClaseFactura := cfFactPre
      else begin
        if dmTablaAlbaranesCliente.ValidarCodigo(CodPreAlb) then
        ClaseFactura := cfFactAlb
        else
          raise Exception.Create(msgFacCliCodPreAlbInvalido);
      end;
    end;

    CodCargo := TablaFacturas.FieldByName('CODIGOCARGO').AsString;
    if (not EsCadenaVacia(CodCargo) or (ImporteTotal.Field.AsFloat < 0)) then
    begin
      ClaseFactura := cfFactAbono;
      FCodigoFacturaCargo := CodCargo;
    end;

    with TablaDetallesFacturas do
    begin
      Close;
      ParamByName('CODIGOEMPRESA').AsInteger := EmpresaActiva.Codigo;
      Params.ByName('CODIGOFACTURA').AsString := CodigoFactura;
      Prepare;
      Open;
      Cancel;
    end;

    TablaDetallesMem.Close;
    TablaDetallesMem.Open;
    TablaDetallesMem.Cancel;
    CargarDetalles;

    dmTablaFacturasCliente.InicializarTablaFacturas(@TablaFacturas);
    dmTablaFacturasCliente.InicializarTablaDetalles(@TablaDetallesMem);
    Visible := True;    
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

procedure TfrFacturaCliente.ActivarModoEliminar;
var
  CodPreAlb : string;
  CodCargo : string;

begin
  dsFactura.AutoEdit := False;
  dsDetallesFacturas.AutoEdit := False;
  Codigo.VerBoton := True;
  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(gridDetalles);

  (gridDetalles.ColumnByFieldName('CODIGOARTICULO')
    as TdxDBTreeListButtonColumn).OnEditButtonClick := NIL;

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

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

    if TablaFacturas.RecordCount = 0 then
    begin
      VerMensajeFmt(msgFacCliNoExisteFac, [CodigoFactura]);
      CancelarEliminar;
      CloseFrame;
      Exit;
    end;

    TablaFacturas.Cancel;

    CodPreAlb := TablaFacturas.FieldByName('CODIGOPRESUPUESTOALBARAN').AsString;
    if EsCadenaVacia(CodPreAlb) then
      ClaseFactura := cfFactLibre
    else begin
      if dmTablaPresupuestos.ValidarCodigo(CodPreAlb) then
        ClaseFactura := cfFactPre
      else begin
        if dmTablaAlbaranesCliente.ValidarCodigo(CodPreAlb) then
          ClaseFactura := cfFactAlb
        else
          raise Exception.Create(msgFacCliCodPreAlbInvalido);
      end;
    end;

    CodCargo := TablaFacturas.FieldByName('CODIGOCARGO').AsString;
    if (not EsCadenaVacia(CodCargo) or (ImporteTotal.Field.AsFloat < 0)) then
    begin
      ClaseFactura := cfFactAbono;
      FCodigoFacturaCargo := CodCargo;
    end;

    with TablaDetallesFacturas do
    begin
      Close;
      ParamByName('CODIGOEMPRESA').AsInteger := EmpresaActiva.Codigo;
      Params.ByName('CODIGOFACTURA').AsString := CodigoFactura;
      Prepare;
      Open;
      Cancel;
    end;

    TablaDetallesMem.Close;
    TablaDetallesMem.Open;
    TablaDetallesMem.Cancel;
    CargarDetalles;

    dmTablaFacturasCliente.InicializarTablaFacturas(@TablaFacturas);
    dmTablaFacturasCliente.InicializarTablaDetalles(@TablaDetallesMem);
    Visible := True;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

procedure TfrFacturaCliente.ActivarModoModificar;
var
  CodPreAlb : String;
  CodCargo : string;  
begin
  dsFactura.AutoEdit := True;
  dsDetallesFacturas.AutoEdit := True;
  Codigo.VerBoton := True;
  Codigo.ReadOnly := True;
  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(gridDetalles);

  (gridDetalles.ColumnByFieldName('CODIGOARTICULO')
    as TdxDBTreeListButtonColumn).OnEditButtonClick := GridBotonCodigoArticuloClick;

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

  pnlBarraGrid.Visible := True;
  try
    { Antes de aplicar la caché hay que asegurarse de que la
      tabla está cerrada. }
    TablaFacturas.Prepare;
    TablaFacturas.Open;
    TablaFacturas.FieldByName('PROVINCIA').OnSetText := ProvinciaSetText;
    if TablaFacturas.RecordCount = 0 then
    begin
      VerMensajeFmt(msgFacCliNoExisteFac, [CodigoFactura]);
      CancelarModificar;
      CloseFrame;
      Exit;
    end;

    TablaFacturas.Edit;
    TablaFacturas.Post;
    TablaFacturas.Edit;

    CodPreAlb := TablaFacturas.FieldByName('CODIGOPRESUPUESTOALBARAN').AsString;
    if EsCadenaVacia(CodPreAlb) then
      ClaseFactura := cfFactLibre
    else begin
      if dmTablaPresupuestos.ValidarCodigo(CodPreAlb) then
      ClaseFactura := cfFactPre
      else begin
        if dmTablaAlbaranesCliente.ValidarCodigo(CodPreAlb) then
      ClaseFactura := cfFactAlb
        else
          raise Exception.Create(msgFacCliCodPreAlbInvalido);
      end;
    end;

    CodCargo := TablaFacturas.FieldByName('CODIGOCARGO').AsString;
    if (not EsCadenaVacia(CodCargo) or (ImporteTotal.Field.AsFloat < 0)) then
    begin
      ClaseFactura := cfFactAbono;
      FCodigoFacturaCargo := CodCargo;
    end;

    with TablaDetallesFacturas do
    begin
      Close;
      ParamByName('CODIGOEMPRESA').AsInteger := EmpresaActiva.Codigo;
      Params.ByName('CODIGOFACTURA').AsString := CodigoFactura;
      Prepare;
      Open;
    end;

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

    dmTablaFacturasCliente.InicializarTablaFacturas(@TablaFacturas);
    dmTablaFacturasCliente.InicializarTablaDetalles(@TablaDetallesMem);
    CalcularTotalFactura;
    Visible := True;    
  except
    on E : EIBError do
    begin
      case E.IBErrorCode of
        isc_lock_conflict : begin
                              VerMensajeFmt(msgFacCliBloqueado, [CodigoFactura]);
                              CancelarModificar;
                              CloseFrame;
                              Exit;
                            end
        else
          TratarExcepcion(E);
      end;
    end;
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

function TfrFacturaCliente.AnadirDatos: Boolean;
var
  CodPreAlb : string;
begin
  Result := False;
  try
    CalcularTotalFactura;
    TablaFacturas.Post;
    TablaFacturas.ApplyUpdates;

    CodPreAlb := TablaFacturas.FieldByName('CODIGOPRESUPUESTOALBARAN').AsString;
    if not EsCadenaVacia(CodPreAlb) then
    begin
      if dmTablaPresupuestos.ValidarCodigo(CodPreAlb) then
        dmTablaPresupuestos.FacturarPresupuesto(EmpresaActiva.Codigo, CodPreAlb, Codigo.Field.AsString)
      else begin
        if dmTablaAlbaranesCliente.ValidarCodigo(CodPreAlb) then
          dmTablaAlbaranesCliente.FacturarAlbaran(EmpresaActiva.Codigo, CodPreAlb, Codigo.Field.AsString)
        else
          raise Exception.Create(msgFacCliCodPreAlbInvalido);
      end;
    end;

    BorrarDetallesIB;
    SalvarDetalles;

    dmTablaFacturasCliente.IncrementarCodigo;
    FCodigoFactura := TablaFacturas.FieldByName('CODIGO').AsString;
    Commit;
    TablaFacturas.CachedUpdates := False;
    TablaFacturas.Close;
    TablaDetallesFacturas.Close;
    TablaDetallesMem.Close;
    Result := True;
  except
    on E : EIBError do begin
      if E.IBErrorCode = isc_unique_key_violation then begin
        VerMensajeFmt(msgFacCliCodFacRepetido, [Codigo.Field.AsString]);
        TablaFacturas.Edit;
      end
      else
        TratarExcepcion(E);
    end;
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

procedure TfrFacturaCliente.BuscarFactura;
begin
  if Transaccion = NIL then
    exit;
  try
    TablaFacturas.DisableControls;
    TablaDetallesFacturas.DisableControls;
    TablaDetallesMem.DisableControls;

    TablaFacturas.Close;
    TablaDetallesFacturas.Close;
    TablaDetallesMem.Close;

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

      TablaDetallesFacturas.ParamByName('CODIGOEMPRESA').AsInteger := EmpresaActiva.Codigo;
      TablaDetallesFacturas.ParamByName('CODIGOFACTURA').AsString := FCodigoFactura;
    end;
    TablaFacturas.Prepare;
    TablaFacturas.Open;

    TablaDetallesFacturas.Prepare;
    TablaDetallesFacturas.Open;

    TablaDetallesMem.Close;
    TablaDetallesMem.Open;
    CargarDetalles;

    dmTablaFacturasCliente.InicializarTablaFacturas(@TablaFacturas);
    dmTablaFacturasCliente.InicializarTablaDetalles(@TablaDetallesMem);

    TablaFacturas.EnableControls;
    TablaDetallesFacturas.EnableControls;
    TablaDetallesMem.EnableControls;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

procedure TfrFacturaCliente.CalcularTotalDetalle;
var
  auxCantidad,
  auxPrecio,
  auxMinutos,
  auxPlus,
  auxTotal : double;
begin
  with TablaDetallesMem do
  begin
    auxCantidad := FieldByName('CANTIDAD').AsFloat;
    if (ClaseFactura = cfFactAbono) then
        FieldByName('PRECIOUNIDAD').AsFloat := -1 * System.Abs(FieldByName('PRECIOUNIDAD').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;
    FieldByName('TOTAL').AsFloat := auxTotal;
  end;
end;

procedure TfrFacturaCliente.CalcularTotalFactura;
var
  BaseImponible,
  ImporteIVA,
  ImporteDto,
  ImporteTotal : Double;
  FDetallesBookmark : string;
begin
  BaseImponible := 0;
  ImporteTotal := 0;
  with TablaDetallesMem do
  begin
    DisableControls;
    FDetallesBookmark := Bookmark;
    try
      First;
      while not EOF do begin
        BaseImponible := BaseImponible + FieldByName('TOTAL').AsFloat;
        Next;
      end;

      ImporteDto := BaseImponible * (TablaFacturas.FieldByName('DESCUENTO').AsFloat/100);
      ImporteTotal := BaseImponible - ImporteDto;
      ImporteIVA := ImporteTotal * (TablaFacturas.FieldByName('IVA').AsFloat/100);
      ImporteTotal := ImporteTotal + ImporteIVA;

      TablaFacturas.FieldByName('BASEIMPONIBLE').AsFloat := BaseImponible;
      TablaFacturas.FieldByName('IMPORTEDESCUENTO').AsFloat := ImporteDto;
      TablaFacturas.FieldByName('IMPORTEIVA').AsFloat := ImporteIVA;
      TablaFacturas.FieldByName('IMPORTETOTAL').AsFloat := ImporteTotal;
    finally
      Bookmark := FDetallesBookmark;
      EnableControls;
    end;
  end;
end;

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

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

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

function TfrFacturaCliente.ComprobarDatos: Boolean;
begin
  Result := False;

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

  if EsCadenaVacia(Vencimiento.DataBinding.Field.AsString) then
  begin
    VerMensaje(msgFacCliFaltaFecVto);
    Vencimiento.SetFocus;
    Exit;
  end
  else begin
    if Vencimiento.DataBinding.Field.AsDateTime < FechaAlta.DataBinding.Field.AsDateTime then
    begin
      VerMensaje(msgFacCliFecVtoMenorFecAlta);
      Vencimiento.SetFocus;
      Exit;
    end
  end;

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

  if TablaDetallesMem.IsEmpty then
  begin
    VerMensaje(msgFacCliFaltaArticulos);
    Paginas.ActivePage := pagContenido;
    gridDetalles.SetFocus;
    Exit;
  end;

  if (ClaseFactura = cfFactAbono) and (Modo <> Eliminar) then
    if (ComprobarAbono = False) then
      Exit;

  if (ClaseFactura <> cfFactAbono) and (Modo = Eliminar) then
    if (dmTablaFacturasCliente.ExistenAbonos(EmpresaActiva.Codigo, Codigo.Field.AsString)) then
    begin
      VerMensaje(msgFacCliFacConAbonos);
      Exit;
    end;


  Result := True;
end;

function TfrFacturaCliente.ComprobarAbono : Boolean;
var
  dImporteAbonado : Double;
  dImporteCargo : Double;
  DatosCargo : TDatosFacturaCliente;
begin
  Result := True;

  if (ImporteTotal.Field.AsFloat > 0) then
  begin
    VerMensaje(msgFacCliImpDebeSerNeg);
    Result := False;
    Exit;
  end;

  try
    DatosCargo := TDatosFacturaCliente.Create;
    DatosCargo.Codigo := CodigoFacturaCargo;
    DatosCargo.CodigoEmpresa := EmpresaActiva.Codigo;
    
    dmTablaFacturasCliente.DarDatosFactura(DatosCargo);
    dImporteCargo := DatosCargo.ImporteTotal;
  finally
    DatosCargo.Free;
  end;

  dImporteAbonado := dmTablaFacturasCliente.DarImporteOtrosAbonos(EmpresaActiva.Codigo, CodigoFacturaCargo, Codigo.Field.AsString);
  if (Modo = Anadir) then
    dImporteAbonado := dImporteAbonado + ImporteTotal.Field.AsFloat;

  if (Redondear(dImporteCargo,2) < Redondear(abs(dImporteAbonado), 2)) then
  begin
    if (dImporteAbonado <> 0) then
      VerMensaje(msgFacCliImpAbonadoSuperior)
    else
      VerMensaje(msgFacCliImpAbonoSuperior);
    Result := False;
  end;
end;

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

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

  BaseDatos := dmBaseDatos.BD;
  Transaccion := dmBaseDatos.Transaccion;

  TablaFacturas := TIBDataSet.Create(Self);
  TablaDetallesFacturas := TIBDataSet.Create(Self);
  TablaDetallesMem := TRxMemoryData.Create(Self);

  dsFactura.DataSet := TablaFacturas;
  dsDetallesFacturas.DataSet := TablaDetallesMem;

  with TablaFacturas do
  begin
    Database := BaseDatos;
    Transaction := Transaccion;
    SelectSQL.Assign(dmTablaFacturasCliente.sqlConsultarFactura);
    InsertSQL.Assign(dmTablaFacturasCliente.sqlInsertarFactura);
    ModifySQL.Assign(dmTablaFacturasCliente.sqlModificarFactura);
    DeleteSQL.Assign(dmTablaFacturasCliente.sqlEliminarFactura);
  end;

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

  TablaDetallesMem.CopyStructure(TablaDetallesFacturas);
  TablaDetallesMem.FieldByName('CODIGOEMPRESA').Required := False;
  TablaDetallesMem.FieldByName('CODIGOFACTURA').Required := False;
  TablaDetallesMem.FieldByName('NUMCONCEPTO').Required := False;

  dmTablaFacturasCliente.InicializarGridDetalles(gridDetalles);
  Situacion.Items := dmTablaFacturasCliente.DarSituaciones;
  FormaPago.Items := dmTablaFormasPago.DarFormasPago;
  CuentaBancaria.Items := dmTablaBancos.DarBancos;
  Paginas.ActivePage := pagCliente;
end;

destructor TfrFacturaCliente.Destroy;
begin
  gridDetalles.DataSource := NIL;

  TablaDetallesMem.Close;
  TablaDetallesMem.Free;

  TablaFacturas.Close;
  TablaFacturas.UnPrepare;
  TablaFacturas.Free;

  TablaDetallesFacturas.Close;
  TablaDetallesFacturas.Unprepare;
  TablaDetallesFacturas.Free;

  inherited;
end;

function TfrFacturaCliente.EliminarDatos: Boolean;
var
  FacturaPre,
  FacturaAlb : Boolean;
begin
  Result := False;

  try
    if ClaseFactura = cfFactAlb then
    begin
      if (VerMensajePreguntaFmt(msgFacCliBorrarFacAlb, [CodAlbaran.Field.AsString]) <> mrYes) then
        Exit
      else
        dmTablaAlbaranesCliente.NoFacturarAlbaran(EmpresaActiva.Codigo, CodAlbaran.Field.AsString);
    end;

    if ClaseFactura = cfFactPre then
    begin
      if (VerMensajePreguntaFmt(msgFacCliBorrarFacPre, [CodPresupuesto.Field.AsString]) <> mrYes) then
        Exit
      else
        dmTablaPresupuestos.NoFacturarPresupuesto(EmpresaActiva.Codigo, CodPresupuesto.Field.AsString);
    end;

    { P236. Cuando se borra una factura de cliente hay que comprobar si es
      la última para decrementar el contador de facturas y no dejar un hueco.}
    if dmTablaFacturasCliente.EsUltimaFactura(EmpresaActiva.Codigo, Codigo.Field.AsString) then
      dmTablaFacturasCliente.DecrementarCodigo;

    TablaFacturas.Delete;
    BorrarDetalles;
    Commit;
    TablaFacturas.Close;
    TablaDetallesFacturas.Close;
    TablaDetallesMem.Close;
    Result := True;
  except
    on E : EIBError do
    begin
      case E.IBErrorCode of
        isc_lock_conflict : VerMensajeFmt(msgFacCliBloqueado, [Codigo.Field.AsString]);
        else
          TratarExcepcion(E);
      end;
    end;
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

procedure TfrFacturaCliente.FreeContenido;
var
  Contador : integer;
  ListaCodigos : TStringList;
begin
  if (ContenidoModal is TRdxFrameFacturasCliente) then begin
    CodigoFactura := (ContenidoModal as TRdxFrameFacturasCliente).CodigoFactura;
    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 TfrFacturaCliente.ModificarDatos: Boolean;
begin
  Result := False;
  try
    CalcularTotalFactura;
    TablaFacturas.Post;
    BorrarDetallesIB;
    SalvarDetalles;
    Commit;
    TablaFacturas.Close;
    TablaDetallesFacturas.Close;
    TablaDetallesMem.Close;    
    Result := True;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

procedure TfrFacturaCliente.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;
        FieldByName('CANTIDAD').AsString := '1';
        FieldByName('UNIDADESMEDIDA').AsString := DatosArticulo.Unidadesmedida;
        FieldByName('PRECIOUNIDAD').AsString := DatosArticulo.Precio;
        FieldByName('PRECIO').AsString := DatosArticulo.Precio;
        FieldByName('TOTAL').AsString := DatosArticulo.Precio;
        Post;
      end;
      FCodigoArticulo := Value;
      CalcularTotalFactura;
    end
    else
      raise Exception.CreateFmt(msgArtCodArtNoExiste, [Value]);
  finally
    DatosArticulo.Free;
  end;
end;

procedure TfrFacturaCliente.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;
    IVA.Field.AsString := DatosCliente.IVA;
    Descuento.Field.AsString := DatosCliente.Descuento;
    CuentaBancaria.Field.AsString := DatosCliente.Banco;
    FCodigoProvincia := dmTablaProvincias.darCodigoProvincia(DatosCliente.Provincia);
    CalcularTotalFactura;
  finally
    DatosCliente.Free;
  end;
end;

procedure TfrFacturaCliente.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 TfrFacturaCliente.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 TfrFacturaCliente.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 TfrFacturaCliente.CantidadDetalleSetText(Sender: TField;
  const Text: String);
begin
  if EsCadenaVacia(Text) then
    Sender.AsString := '1'
  else
    Sender.AsString := Text;
  CalcularTotalDetalle;
  CalcularTotalFactura;
end;

procedure TfrFacturaCliente.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 TfrFacturaCliente.GridBotonCodigoArticuloClick(Sender: TObject);
begin
  TablaDetallesMem.Edit;
  ContenidoModal := TfrArticulos.Create(Self);
end;

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

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

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

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

procedure TfrFacturaCliente.CodigoButtonClick(Sender: TObject);
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, FCodigoFactura es NULL y da error al activar modo porque
    no se inicializa los parámetros de la sql. Lo hace BuscarFactura. }
  if not TablaFacturas.Active then
    BuscarFactura;
  ContenidoModal := TfrFacturasClientes.Create(Self);
end;

procedure TfrFacturaCliente.CodigoExit(Sender: TObject);
begin
  if (Modo <> Anadir) or (Visible = false) then
    Exit;
  if EsCadenaVacia(Codigo.Text) then
    Codigo.Field.AsString := dmTablaFacturasCliente.darNuevoCodigo;
  if (dmTablaFacturasCliente.validarCodigo(Codigo.Text)) then
  begin
    Codigo.Field.asString := dmTablaFacturasCliente.FormatearCodigo(Codigo.Text);
    if (dmTablaFacturasCliente.existeCodigo(EmpresaActiva.Codigo, Codigo.Text)) then begin
      VerMensajeFmt(msgFacCliCodFacRepetido, [Codigo.Text]);
      Codigo.SetFocus;
    end;
  end
  else begin
    VerMensajeFmt(msgFacCliCodFacIncorrecto, [Codigo.Text]);
    Codigo.SetFocus;
  end;
end;

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

procedure TfrFacturaCliente.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 TfrFacturaCliente.SetCodigoPresupuesto(Value: String);
var
  CodPre : String;
  DatosPre : TDatosPresupuesto;
begin
  if EsCadenaVacia(Value) then
    Exit;

  CodPre := Trim(Value);
  if FCodigoPresupuesto = CodPre then
    Exit;

  if not dmTablaPresupuestos.ValidarCodigo(CodPre) then
  begin
    VerMensajeFmt(msgPreCodPreIncorrecto, [CodPre]);
    CodPresupuesto.SetFocus;
    Exit;
  end;

  CodPre := dmTablaPresupuestos.FormatearCodigo(CodPre);
  if not (dmTablaPresupuestos.ExisteCodigo(EmpresaActiva.Codigo, CodPre)) then
  begin
    VerMensajeFmt(msgPreNoExistePre, [CodPre]);
    CodPresupuesto.SetFocus;
    Exit;
  end;

  if dmTablaPresupuestos.DarSituacionPresupuesto(EmpresaActiva.Codigo, CodPre) <> CTE_ACEPTADO then
  begin
    VerMensajeFmt(msgPreNoSePuedeFacturar, [CodPre]);
    CodPresupuesto.SetFocus;
    Exit;
  end;

  ClaseFactura := cfFactPre;
  FCodigoPresupuesto := CodPre;
  CodPresupuesto.Field.AsString := CodPre;

  DatosPre := TDatosPresupuesto.Create;
  DatosPre.Codigo := CodPre;
  DatosPre.CodigoEmpresa := EmpresaActiva.Codigo;
  try
    if dmTablaPresupuestos.DarDatosPresupuesto(DatosPre) then
    begin
      with TablaFacturas do
      begin
        if not EsCadenaVacia(DatosPre.CodigoFactura) then
        begin
          VerMensajeFmt(msgPreYaFacturado, [FCodigoPresupuesto]);
          CodPresupuesto.SelectAll;
          CodPresupuesto.SetFocus;
          Exit;
        end;

        { Saco el IVA y el descuento que tiene el cliente si estuviera
          dado de alta }
        if not EsCadenaVacia(DatosPre.CodigoCliente) then
          CodigoCliente := DatosPre.CodigoCliente;

        FieldByName('CODIGOCLIENTE').AsString := DatosPre.CodigoCliente;
        FieldByName('NIFCIF').AsString := DatosPre.NIFCIF;
        FieldByName('NOMBRE').AsString := DatosPre.Nombre;
        FieldByName('CALLE').AsString := DatosPre.Calle;
        FieldByName('NUMERO').AsString := DatosPre.Numero;
        FieldByName('PISO').AsString := DatosPre.Piso;
        FieldByName('CODIGOPOSTAL').AsString := DatosPre.CodigoPostal;
        FieldByName('POBLACION').AsString := DatosPre.Poblacion;
        FieldByName('PROVINCIA').AsString := DatosPre.Provincia;
        FieldByName('PERSONACONTACTO').AsString := DatosPre.PersonaContacto;
        FieldByName('TELEFONO').AsString := DatosPre.Telefono;
        FieldByName('FAX').AsString := DatosPre.Fax;
        FieldByName('DESCRIPCION').AsString := DatosPre.Descripcion;
      end;
      if VerMensajePreguntaFmt(msgFacCliCopiarConPre, [FCodigoPresupuesto]) = mrYES then
        CopiarConceptosPresupuesto(DatosPre)
      else
        InsertarReferenciaAPresupuesto(DatosPre);
      CalcularTotalFactura;
    end
    else
      raise Exception.CreateFmt(msgPreNoExistePre, [CodPre]);
  finally
    DatosPre.Free;
  end;
end;

procedure TfrFacturaCliente.rbPresupuestoClick(Sender: TObject);
begin
  ActivarPresupuesto;
  CodPresupuesto.SetFocus;
end;

procedure TfrFacturaCliente.rbFacturaLibreClick(Sender: TObject);
begin
  ActivarFacturaLibre;
end;

procedure TfrFacturaCliente.rbAlbaranClick(Sender: TObject);
begin
  ActivarAlbaran;
  CodAlbaran.SetFocus;
end;

procedure TfrFacturaCliente.ActivarAlbaran;
begin
  pnlAlbaran.Left := 273;
  pnlAlbaran.Top := 48;
  pnlAlbaran.Visible := True;
end;

procedure TfrFacturaCliente.ActivarFacturaLibre;
begin
  //
end;

procedure TfrFacturaCliente.ActivarPresupuesto;
begin
  pnlPresupuesto.Left := 273;
  pnlPresupuesto.Top := 48;
  pnlPresupuesto.Visible := True;
end;

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

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

      DisableControls;
      while not oSQL.EOF do
      begin
        Append;
        FieldByName('CODIGOFACTURA').AsString := Codigo.Field.AsString;
        FieldByName('NUMCONCEPTO').AsInteger := oSQL.FieldByName('NUMCONCEPTO').AsInteger;
        FieldByName('TIPO').AsString := 'CON';
        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('PRECIOUNIDAD').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 TfrFacturaCliente.CopiarConceptosPresupuesto(DatosPre: TDatosPresupuesto);
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 ');
    SQL.Add('and CODIGOEMPRESA = :CODIGOEMPRESA ');
    SQL.Add('order by NUMCONCEPTO');
  end;

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

      DisableControls;
      while not oSQL.EOF do
      begin
        Append;
        FieldByName('CODIGOFACTURA').AsString := Codigo.Field.AsString;
        FieldByName('NUMCONCEPTO').AsInteger := oSQL.FieldByName('NUMCONCEPTO').AsInteger;
        if (oSQL.FieldByName('TIPO').AsString = 'OPC') then
          FieldByName('TIPO').AsString := 'TIT'
        else
          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;

      //En el caso de tener bonificación añadimos un concepto más a la factura
      if not VarIsNull(DatosPre.DesBonificacion) then
      begin
        Append;
        FieldByName('CODIGOFACTURA').AsString := Codigo.Field.AsString;
        FieldByName('NUMCONCEPTO').AsInteger := (oSQL.RecordCount + 1);
        FieldByName('TIPO').AsString := 'CON';
        FieldByName('DESCRIPCION').AsString := DatosPre.DesBonificacion;
        FieldByName('CANTIDAD').AsInteger := 1;
        FieldByName('PRECIOUNIDAD').AsFloat := (-1)* DatosPre.ImpBonificacion;
        FieldByName('PRECIO').AsFloat := (-1)* DatosPre.ImpBonificacion;
        FieldByName('TOTAL').AsFloat := (-1)* DatosPre.ImpBonificacion;
        Post;
      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 TfrFacturaCliente.bAnadirConClick(Sender: TObject);
begin
  try
    with TablaDetallesMem do
    begin
      DisableControls;
      Next;
      if EOF then
        Append
      else
        Insert;
      FieldByName('TIPO').AsString := 'CON';
      EnableControls;
    end;
    Paginas.ActivePage := pagContenido;
    gridDetalles.SetFocus;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

procedure TfrFacturaCliente.bAnadirCapClick(Sender: TObject);
begin
  try
    with TablaDetallesMem do
    begin
      DisableControls;
      Next;
      if EOF then
        Append
      else
        Insert;
      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 TfrFacturaCliente.bEliminarClick(Sender: TObject);
begin
  if (VerMensajePregunta(msgDeseaBorrar) <> 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
    TablaDetallesMem.Delete;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
  CalcularTotalFactura;
end;

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

procedure TfrFacturaCliente.DtoSetText(Sender: TField; const Text: String);
begin
  if EsCadenaVacia(Text) then
    Sender.AsString := '0'
  else begin
    ValidarDto(Text);
    Sender.AsString := Text;
  end;
  CalcularTotalFactura;
end;

procedure TfrFacturaCliente.IVASetText(Sender: TField; const Text: String);
begin
  if EsCadenaVacia(Text) then
    Sender.AsString := '0'
  else begin
    ValidarIVA(Text);
    Sender.AsString := Text;
  end;
  CalcularTotalFactura;
end;

procedure TfrFacturaCliente.InsertarReferenciaAPresupuesto (DatosPre : TDatosPresupuesto);
var
  FechaAux : String;
begin
  FechaAux := FormatDateTime('d "de" mmmm "de" yyyy', StrToDate(DatosPre.FechaAlta));
  TablaFacturas.FieldByName('DESCRIPCION').AsString := Format(msgFacCliDesFacPre, [DatosPre.Codigo, FechaAux]);

  // Añadir un concepto con el importe del presupuesto
  try
    with TablaDetallesMem do
    begin
      DisableControls;
      Append;
      FieldByName('CODIGOFACTURA').AsString := Codigo.Field.AsString;
      FieldByName('NUMCONCEPTO').AsInteger := 0;
      FieldByName('TIPO').AsString := 'CON';
      FieldByName('DESCRIPCION').AsString := 'Presupuesto ' + DatosPre.Codigo;
      FieldByName('CANTIDAD').AsString := '1';
      FieldByName('PRECIOUNIDAD').AsString := DatosPre.ImporteTotal;
      FieldByName('PRECIO').AsString := DatosPre.ImporteTotal;
      FieldByName('TOTAL').AsString := DatosPre.ImporteTotal;
      Post;
      EnableControls;
    end;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

procedure TfrFacturaCliente.SetCodigoAlbaran(Value: String);
var
  CodAlb : String;
  DatosAlb : TDatosAlbaranCliente;
begin
  if EsCadenaVacia(Value) then
    exit;

  CodAlb := Trim(Value);
  if FCodigoAlbaran = CodAlb then
    Exit;

  if not dmTablaAlbaranesCliente.ValidarCodigo(CodAlb) then
  begin
    VerMensajeFmt(msgAlbCodAlbIncorrecto, [CodAlb]);
    CodAlbaran.SetFocus;
    Exit;
  end;

  CodAlb := dmTablaAlbaranesCliente.FormatearCodigo(CodAlb);
  if not (dmTablaAlbaranesCliente.ExisteCodigo(EmpresaActiva.Codigo, CodAlb)) then
  begin
    VerMensajeFmt(msgAlbNoExisteAlb, [CodAlb]);
    CodAlbaran.SetFocus;
    Exit;
  end;

  ClaseFactura := cfFactAlb;
  FCodigoAlbaran := CodAlb;
  CodAlbaran.Field.AsString := CodAlb;

  DatosAlb := TDatosAlbaranCliente.Create;
  DatosAlb.Codigo := CodAlb;
  DatosAlb.CodigoEmpresa := EmpresaActiva.Codigo;

  try
    if dmTablaAlbaranesCliente.DarDatosAlbaran(DatosAlb) then
    begin
      with TablaFacturas do
      begin
        if not EsCadenaVacia(DatosAlb.CodigoFactura) then
        begin
          VerMensajeFmt(msgAlbYaFacturado, [FCodigoAlbaran]);
          CodAlbaran.SelectAll;
          CodAlbaran.SetFocus;
          Exit;
        end;

        { Saco el IVA y el descuento que tiene el cliente si estuviera
          dado de alta }
        if not EsCadenaVacia(DatosAlb.CodigoCliente) then
          CodigoCliente := DatosAlb.CodigoCliente;

        FieldByName('CODIGOCLIENTE').AsString := DatosAlb.CodigoCliente;
        FieldByName('NIFCIF').AsString := DatosAlb.NIFCIF;
        FieldByName('NOMBRE').AsString := DatosAlb.Nombre;
        FieldByName('CALLE').AsString := DatosAlb.Calle;
        FieldByName('NUMERO').AsString := DatosAlb.Numero;
        FieldByName('PISO').AsString := DatosAlb.Piso;
        FieldByName('CODIGOPOSTAL').AsString := DatosAlb.CodigoPostal;
        FieldByName('POBLACION').AsString := DatosAlb.Poblacion;
        FieldByName('PROVINCIA').AsString := DatosAlb.Provincia;
        FieldByName('PERSONACONTACTO').AsString := DatosAlb.PersonaContacto;
        FieldByName('TELEFONO').AsString := DatosAlb.Telefono;
        FieldByName('FAX').AsString := DatosAlb.Fax;

        FieldByName('DESCRIPCION').AsString := DatosAlb.Descripcion;
      end;
      CopiarConceptosAlbaran;
      CalcularTotalFactura;
    end
    else
      raise Exception.CreateFmt(msgAlbNoExisteAlb, [CodAlb]);
  finally
    DatosAlb.Free;
  end;
end;

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

procedure TfrFacturaCliente.BorrarDetallesIB;
begin
  with TablaDetallesFacturas 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 TfrFacturaCliente.CargarDetalles;
var
  NumeroCampo : Integer;
begin
  with TablaDetallesMem do
  begin
    if TablaDetallesFacturas.IsEmpty then
      Exit;
    DisableControls;
    TablaDetallesFacturas.First;
    while not TablaDetallesFacturas.EOF do
    begin
      Append;
      for NumeroCampo := 0 to TablaDetallesFacturas.FieldCount-1 do
        Fields[NumeroCampo].AsString := TablaDetallesFacturas.Fields[NumeroCampo].AsString;
      Post;
      TablaDetallesFacturas.Next;
    end;
    EnableControls;
  end;
end;

procedure TfrFacturaCliente.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
        TablaDetallesFacturas.Append;
        for NumeroCampo := 0 to FieldCount-1 do
        begin
          if Fields[NumeroCampo].FieldName = 'CODIGOEMPRESA' then
            TablaDetallesFacturas.Fields[NumeroCampo].AsInteger := EmpresaActiva.Codigo
          else begin
            if Fields[NumeroCampo].FieldName = 'CODIGOFACTURA' then
              TablaDetallesFacturas.Fields[NumeroCampo].AsString := Codigo.Field.asString
            else
              if Fields[NumeroCampo].FieldName = 'NUMCONCEPTO' then
                TablaDetallesFacturas.Fields[NumeroCampo].AsInteger := NumConcepto
              else
                if (Fields[NumeroCampo].FieldName = 'TIPO') and EsCadenaVacia(Fields[NumeroCampo].AsString) then
                  TablaDetallesFacturas.Fields[NumeroCampo].AsString := 'CON'
                else
                  TablaDetallesFacturas.Fields[NumeroCampo].AsString := Fields[NumeroCampo].AsString;
          end;
        end;
        TablaDetallesFacturas.Post;
        Next;
        NumConcepto := NumConcepto + 1;
      end;
      EnableControls;
    end
  except
    on E : EIBError do begin
      if E.IBErrorCode = isc_unique_key_violation then
      begin
        TablaDetallesFacturas.Delete;
        TablaDetallesMem.EnableControls;
      end;
      raise EIBError.Create(E.SQLCode, E.IBErrorCode, E.Message);
    end;
  end;
end;

procedure TfrFacturaCliente.DetalleAfterDelete(DataSet: TDataSet);
begin
  CalcularTotalFactura;
end;

procedure TfrFacturaCliente.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 TfrFacturaCliente.gridDetallesCustomDrawCell(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] = 'TIT' then
  begin
    AFont.Style := AFont.Style + [fsBold];
    if (not ASelected) and (not Focused) then
      AColor := rdxLightGreen;
  end;
{  if TablaDetallesMem.FieldByName('TIPO').AsString <> 'TIT' then
  begin
    gridDetalles.DefaultDrawColumnCell(ARect, DataCol, Column, AState);
    Exit;
  end;}

  { El concepto es el título de un capítulo }
{  gridDetalles.Canvas.Font.Style := [fsBold];
  if not (gdSelected in AState) then
    gridDetalles.Canvas.Brush.Color := gridDetalles.FixedColor;
  if Column.FieldName = 'DESCRIPCION' then
    gridDetalles.DefaultDrawColumnCell(ARect, DataCol, Column, AState)
  else
    gridDetalles.Canvas.FillRect(ARect);}
end;

procedure TfrFacturaCliente.gridDetallesEditing(Sender: TObject;
  Node: TdxTreeListNode; var Allow: Boolean);
var
  IndiceCol : Integer;
begin
  IndiceCol := (Sender as TdxDBGrid).ColumnByFieldName('TIPO').Index;
  if (Node.Strings[IndiceCol] = 'TIT') and
     (gridDetalles.FocusedField.FieldName <> 'DESCRIPCION')
  then
    Allow := False;
end;

procedure TfrFacturaCliente.SetCodigoFacturaCargo(Value: String);
var
  CodCargo : String;
  DatosCargo : TDatosFacturaCliente;
begin
  if EsCadenaVacia(Value) then
    Exit;

  CodCargo := Trim(Value);
  if FCodigoFacturaCargo = CodCargo then
    Exit;

  if not dmTablaFacturasCliente.ValidarCodigo(CodCargo) then
  begin
    VerMensajeFmt(msgFacCliCodFacCargoIncorrecto, [CodCargo]);
    Exit;
  end;

  CodCargo := dmTablaFacturasCliente.FormatearCodigo(CodCargo);
  if not (dmTablaFacturasCliente.ExisteCodigo(EmpresaActiva.Codigo, CodCargo)) then
  begin
    VerMensajeFmt(msgFacCliCodFacCargoNoExiste, [CodCargo]);
    Exit;
  end;

  if (dmTablaFacturasCliente.DarClaseFactura(EmpresaActiva.Codigo, CodCargo) <> 'C') then
  begin
    VerMensajeFmt(msgFacCliClaseFacDistinta, [CodCargo]);
    Exit;
  end;

  ClaseFactura := cfFactAbono;
  FCodigoFacturaCargo := CodCargo;
  CodFacturaCargo.Field.AsString := CodCargo;

  DatosCargo := TDatosFacturaCliente.Create;
  DatosCargo.Codigo := CodCargo;
  DatosCargo.CodigoEmpresa := EmpresaActiva.Codigo;

  try
    if dmTablaFacturasCliente.DarDatosFactura(DatosCargo) then
    begin
      with TablaFacturas do
      begin
          FieldByName('FORMAPAGO').AsString := DatosCargo.FormaPago;
          FieldByName('DESCRIPCION').AsString := DatosCargo.Descripcion;
          FieldByName('CODIGOCLIENTE').AsString := DatosCargo.CodigoCliente;
          FieldByName('NIFCIF').AsString := DatosCargo.NifCif;
          FieldByName('NOMBRE').AsString := DatosCargo.Nombre;
          FieldByName('CALLE').AsString := DatosCargo.Calle;
          FieldByName('NUMERO').AsString := DatosCargo.Numero;
          FieldByName('PISO').AsString := DatosCargo.Piso;
          FieldByName('CODIGOPOSTAL').AsString := DatosCargo.CodigoPostal;
          FieldByName('POBLACION').AsString := DatosCargo.Poblacion;
          FieldByName('PROVINCIA').AsString := DatosCargo.Provincia;
          FieldByName('PERSONACONTACTO').AsString := DatosCargo.PersonaContacto;
          FieldByName('TELEFONO').AsString := DatosCargo.Telefono;
          FieldByName('FAX').AsString := DatosCargo.Fax;
          FieldByName('DESCUENTO').AsInteger := DatosCargo.Descuento;
          FieldByName('IVA').AsInteger := DatosCargo.Iva;
          FieldByName('BANCO').AsString := DatosCargo.Banco;
          FieldByName('NOTAS').AsString := DatosCargo.Notas;
          FieldByName('CODIGOCLIENTEFINAL').AsString := DatosCargo.CodigoClienteFinal;
          FieldByName('NOMBRECLIENTEFINAL').AsString := DatosCargo.NombreClienteFinal;
          TablaFacturas.FieldByName('CLASEFACTURA').AsString := 'A';
          FieldByName('CODIGOCARGO').AsString := FCodigoFacturaCargo;
      end;
      CopiarConceptosFacturaCargo;
      CalcularTotalFactura;
    end
    else
      raise Exception.CreateFmt(msgFacCliCodFacCargoNoExiste, [CodCargo]);
  finally
    DatosCargo.Free;
  end;
end;

procedure TfrFacturaCliente.SetClaseFactura(Value: TClaseFactura);
begin
  if (FClaseFactura = Value) then
    exit;
  FClaseFactura := Value;

  case FClaseFactura of
    cfFactLibre   : ActivarFacturaLibre;
    cfFactPre     : ActivarPresupuesto;
    cfFactAlb     : ActivarAlbaran;
    cfFactAbono   : ActivarAbono;
    else            ActivarFacturaLibre;
  end;
end;

procedure TfrFacturaCliente.ActivarAbono;
begin
  pnlAbono.Left := 273;
  pnlAbono.Top := 48;
  pnlAbono.Visible := True;
end;

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

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

      DisableControls;
      while not oSQL.EOF do
      begin
        Append;
        FieldByName('CODIGOFACTURA').AsString := Codigo.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('UNIDADESMEDIDA').AsString := oSQL.FieldByName('UNIDADESMEDIDA').AsString;
        FieldByName('CANTIDAD').AsString := oSQL.FieldByName('CANTIDAD').AsString;
        FieldByName('PRECIOUNIDAD').AsFloat := (-1) * oSQL.FieldByName('PRECIOUNIDAD').AsFloat;
        FieldByName('PRECIO').AsString := oSQL.FieldByName('PRECIO').AsString;
        FieldByName('MINUTOS').AsString := oSQL.FieldByName('MINUTOS').AsString;
        FieldByName('PRECIOMINUTO').AsFloat := (-1) * oSQL.FieldByName('PRECIOMINUTO').AsFloat;
        FieldByName('PLUS').AsString := oSQL.FieldByName('PLUS').AsString;
        FieldByName('TOTAL').AsString := oSQL.FieldByName('TOTAL').AsString;
        CalcularTotalDetalle;
        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 TfrFacturaCliente.GridBotonDescripcionClick(Sender: TObject);
begin
  TablaDetallesMem.Edit;
  WidthModal := 420;
  HeightModal := 435;
  ModoModal := Modo;
  ContenidoModal := TfrEditorDescripcion.Create(Self);
end;

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

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

procedure TfrFacturaCliente.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, [CodCliente.Text]);
    Paginas.ActivePageIndex := 0;
    CodCliente.SetFocus;
  end;
end;

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

procedure TfrFacturaCliente.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, [CodClienteFinal.Text]);
    Paginas.ActivePage := pagCliente;
    CodClienteFinal.SetFocus;
  end;
end;

end.
