{
===============================================================================
  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.1.7
  Fecha versión actual: 07-03-2004
===============================================================================
  Modificaciones:

    Fecha         Comentarios
    ---------------------------------------------------------------------------
    09-10-2001    Se ha reestructurado la pantalla en pestañas.

    21-10-2001    Las facturas de proveedor pasan a contener pedidos en vez de
                  material.

    21-10-2001    Se utiliza una tabla de memoria para el contenido.

    23-10-2001    Hay que comprobar que todos los pedidos pertenezcan al
                  proveedor que figura en la factura.

    23-10-2001    El campo 'domiciliación bancaria' pasa a ser NO obligatorio.

    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 de la factura.

    29-10-2001    Se ha cambiado el literal 'Notas' por 'Concepto de factura'.

    29-10-2001    El campo 'Banco' se ha cambiado a campo con lista desplegable.
                  En esa lista aparecerán los campos dados de alta en la aplica-
                  ción. Se puede dejar en blanco.

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

    31-10-2001    Se ha cambiado el literal 'Contenido de la factura' por
                  'Lista de pedidos'.

    27-11-2001    Si en los detalles hay alguno que es un pedido libre
                  saltarse la comprobación del cód.proveedor del pedido
                  con el cód.proveedor de la factura.

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

    10-02-2002    Repaso de CalcularTotalFactura ya que no calculaba el importe
                  se ha añadido CalcularTotalFactura en AnadirDatos, ModificarDatos,
                  setCodigoPedido, setCodigoProveedor.

    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    Adaptación al grid 'TdxDBGrid'.

    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.                                   

    24-09-2002    Se producía una excepción si el cursor 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.

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

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

===============================================================================
}

unit FacturaProveedor;

interface

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

type
  TfrFacturaProveedor = class(TRdxFrameFacturasProveedor)
    pnlTitulo: TRdxPanelTituloOperacion;
    pnlScroll: TRdxScrollPanel;
    pnlFactura: TRdxPanel;
    cDatosFactura: TRdxCabecera;
    eNumFacProve: TLabel;
    eCodigoFactura: TLabel;
    eFecha: TLabel;
    eFechaVto: TLabel;
    eFormaPago: TLabel;
    eTipo: TLabel;
    eBanco: TLabel;
    eUsuario: TLabel;
    eDescripcion: TLabel;
    Codigo: TRdxDBEdit;
    cbxFormaPago: TRdxDBComboBox;
    cbxTipo: TRdxDBComboBox;
    CodigoFacturaProv: TRdxDBEdit;
    Usuario: TRdxDBEdit;
    Notas: TRdxDBMemo;
    dsFactura: TDataSource;
    dsDetallesFacturas: TDataSource;
    eSituacion: TLabel;
    cbxSituacion: TRdxDBComboBox;
    brDoble: TRdxBarraInferior;
    bGuardar: TRdxBoton;
    bCancelar: TRdxBoton;
    brSimple: TRdxBarraInferior;
    bSalir: TRdxBoton;
    pnlPaginas: TRdxPanel;
    paginas: TRdxPagesControl;
    pagProveedor: TTabSheet;
    pagContenido: TTabSheet;
    pagImporte: TTabSheet;
    pnlProveedor: TRdxPanel;
    eCodigo: TLabel;
    eNIFCIF: TLabel;
    eCodigoAsignado: TLabel;
    eNombre: TLabel;
    ePersonaContacto: TLabel;
    eFax: TLabel;
    NIFCIF: TRdxDBEdit;
    CodigoCliente: TRdxDBEdit;
    Nombre: TRdxDBEdit;
    PersonaContacto: TRdxDBEdit;
    Fax: TRdxDBEdit;
    pnlGridArticulos: TPanel;
    pnlBarraGrid: TRdxPanel;
    bAnadir: TRdxBoton;
    bEliminar: TRdxBoton;
    bEliminarTodo: TRdxBoton;
    cbxBanco: TRdxDBComboBox;
    pnlImporteAlbaran: TRdxPanel;
    Label4: TLabel;
    eDto: TLabel;
    eIVA: TLabel;
    Label6: TLabel;
    Shape1: TShape;
    BaseImponible: TRdxDBEdit;
    Descuento: TRdxDBEdit;
    IVA: TRdxDBEdit;
    ImporteTotal: TRdxDBEdit;
    ImporteDescuento: TRdxDBEdit;
    ImporteIVA: TRdxDBEdit;
    gridDetalles: TdxDBGrid;
    Fecha: TcxDBDateEdit;
    FechaVencimiento: TcxDBDateEdit;
    CodProveedor: TcxDBButtonEdit;
    procedure bSalirClick(Sender: TObject);
    procedure bGuardarClick(Sender: TObject);
    procedure bCancelarGuardarClick(Sender: TObject);
    procedure CodigoButtonClick(Sender: TObject);
    procedure bAnadirClick(Sender: TObject);
    procedure bEliminarClick(Sender: TObject);
    procedure bEliminarTodoClick(Sender: TObject);
    procedure CodigoExit(Sender: TObject);
    procedure FechaExit(Sender: TObject);
    procedure FechaVencimientoExit(Sender: TObject);
    procedure CodProveedorPropertiesButtonClick(Sender: TObject;
      AButtonIndex: Integer);
    procedure CodProveedorPropertiesValidate(Sender: TObject;
      var DisplayValue: Variant; var ErrorText: TCaption;
      var Error: Boolean);
  private
    FCodigoProveedor : Variant;
    FCodigoPedido : Variant;
    FTablaDetallesMem : TRxMemoryData;
    procedure CalcularTotalFactura;
    procedure BorrarDetalles;
    procedure SalvarDetalles;
    procedure CargarDetalles;
    procedure BorrarDetallesIB;
    function NoFacturarPedidos : boolean;
    function FacturarPedidos : boolean;
    procedure ActivarEventosCampos;
    procedure DetalleAfterDelete (DataSet: TDataSet);
    procedure IVASetText(Sender: TField; const Text: String);
    procedure DtoSetText(Sender: TField; const Text: String);
  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 SetCodigoProveedor (Value : Variant);
    procedure SetCodigoPedido (Value : Variant);
    procedure FreeContenido; override;
    procedure BuscarFactura; override;
    procedure VerModal; override;
  public
    property CodigoProveedor : Variant read FCodigoProveedor write SetCodigoProveedor;
    property CodigoPedido : Variant read FCodigoPedido write SetCodigoPedido;
    constructor Create (AOwner : TComponent); override;
    destructor Destroy; override;
  published
    property TablaFacturasProveedor;
    property TablaDetallesFacturas;
    property TablaDetallesMem : TRxMemoryData read FTablaDetallesMem write FTablaDetallesMem;
    property CodigoFactura;
    procedure GridBotonCodigoPedidoClick(Sender: TObject);
    procedure PrecioDetalleSetText(Sender: TField; const Text: String);
    procedure CodigoPedidoDetalleSetText(Sender: TField; const Text: String);
  end;

var
  frFacturaProveedor: TfrFacturaProveedor;

implementation

uses
  BaseDatos, TablaFacturasProveedor, IB, Mensajes, TablaArticulos,
  Tipos, IBCustomDataSet, TablaFormasPago, RdxFrameArticulos,
  FacturasProveedores, PedidosProveedores, Proveedores, TablaProveedores,
  Articulos, RdxFrameProveedores, TablaPedidosProveedor, NumFunc,  
  RdxFramePedidosProveedor, StrFunc, IBErrorCodes, Excepciones,
  TablaBancos, dxDBTLCL, RdxEmpresaActiva, Literales;

{$R *.DFM}

{ TfrFacturaProveedor }

procedure TfrFacturaProveedor.ActivarModoAnadir;
var
  CodNuevo : Variant;
begin
  dsFactura.AutoEdit := True;
  dsDetallesFacturas.AutoEdit := True;
  Codigo.VerBoton := False;
  Codigo.ReadOnly := False;
  cbxTipo.ReadOnly := False;
  CodProveedor.Properties.Buttons[0].Visible := True;
  CodProveedor.Properties.OnValidate := CodProveedorPropertiesValidate;
  
  ActivarEdicionGridDetalles(gridDetalles);

  (gridDetalles.ColumnByFieldName('CODIGOPEDIDO')
    as TdxDBTreeListButtonColumn).OnEditButtonClick := GridBotonCodigoPedidoClick;

  pnlBarraGrid.Visible := True;
  try
    { Antes de aplicar la caché hay que asegurarse de que la
      tabla está cerrada. }
    TablaFacturasProveedor.DisableControls;
    TablaDetallesFacturas.DisableControls;

    { Inicializar la tabla de Facturas }
    TablaFacturasProveedor.Close;
    CodNuevo := dmTablaFacturasProveedor.darNuevoCodigo;
    with TablaFacturasProveedor do
    begin
      CachedUpdates := True;
      Prepare;
      Open;
      EnableControls;
      Insert;
      FieldByName('CODIGOEMPRESA').AsInteger := EmpresaActiva.Codigo;
    end;

    Codigo.Field.asString := CodNuevo;
    Fecha.DataBinding.Field.AsString := DateToStr(Date);
    Usuario.Field.AsString := dmBaseDatos.Usuario;
    cbxSituacion.Field.AsString := cbxSituacion.Items[0];
    cbxTipo.Field.AsString := cbxTipo.Items[0];

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

    TablaDetallesMem.Close;
    TablaDetallesMem.Open;
    ActivarEventosCampos;

    dmTablaFacturasProveedor.InicializarTablaFacturas(@TablaFacturasProveedor);
    dmTablaFacturasProveedor.InicializarTablaDetalles(@TablaDetallesMem);

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

procedure TfrFacturaProveedor.ActivarModoConsultar;
begin
  dsFactura.AutoEdit := False;
  dsDetallesFacturas.AutoEdit := False;

  Codigo.VerBoton := True;
  CodProveedor.Properties.Buttons[0].Visible := False;
  CodProveedor.Properties.OnValidate := nil;

  DesactivarEdicionGridDetalles(gridDetalles);

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

  pnlBarraGrid.Visible := False;

  try
    TablaFacturasProveedor.Prepare;
    TablaFacturasProveedor.Open;

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

    TablaFacturasProveedor.Cancel;

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

    TablaDetallesMem.Close;
    TablaDetallesMem.Open;
    CargarDetalles;

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

procedure TfrFacturaProveedor.ActivarModoEliminar;
begin
  dsFactura.AutoEdit := False;
  dsDetallesFacturas.AutoEdit := False;
  Codigo.VerBoton := True;
  CodProveedor.Properties.Buttons[0].Visible := False;
  CodProveedor.Properties.OnValidate := nil;

  DesactivarEdicionGridDetalles(gridDetalles);

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

  pnlBarraGrid.Visible := False;

  try
    TablaFacturasProveedor.Prepare;
    TablaFacturasProveedor.Open;

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

    TablaFacturasProveedor.Cancel;

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

    TablaDetallesMem.Close;
    TablaDetallesMem.Open;
    CargarDetalles;

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

procedure TfrFacturaProveedor.ActivarModoModificar;
begin
  dsFactura.AutoEdit := True;
  dsDetallesFacturas.AutoEdit := True;
  Codigo.VerBoton := True;
  Codigo.ReadOnly := True;
  cbxTipo.ReadOnly := True;
  CodProveedor.Properties.Buttons[0].Visible := True;
  CodProveedor.Properties.OnValidate := CodProveedorPropertiesValidate;

  ActivarEdicionGridDetalles(gridDetalles);

  (gridDetalles.ColumnByFieldName('CODIGOPEDIDO')
    as TdxDBTreeListButtonColumn).OnEditButtonClick := GridBotonCodigoPedidoClick;

  pnlBarraGrid.Visible := True;

  try
    { Antes de aplicar la caché hay que asegurarse de que la
      tabla está cerrada. }
    TablaFacturasProveedor.Prepare;
    TablaFacturasProveedor.Open;

    if TablaFacturasProveedor.RecordCount = 0 then
    begin
      VerMensajeFmt(msgFacProNoExiste, [CodigoFactura]);
      CancelarModificar;
      CloseFrame;
      Exit;
    end;

    TablaFacturasProveedor.Edit;

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

    TablaDetallesMem.Close;
    TablaDetallesMem.Open;
    CargarDetalles;
    ActivarEventosCampos;

    TablaDetallesMem.FieldByName('PRECIO').OnSetText := PrecioDetalleSetText;
    TablaDetallesMem.FieldByName('CODIGOPEDIDO').OnSetText := CodigoPedidoDetalleSetText;

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

function TfrFacturaProveedor.AnadirDatos: Boolean;
begin
  Result := False;
  try
    CalcularTotalFactura;
    TablaFacturasProveedor.Post;
    TablaFacturasProveedor.ApplyUpdates;

    BorrarDetallesIB;
    SalvarDetalles;

    FCodigoFactura := TablaFacturasProveedor.FieldByName('CODIGO').AsString;
    NoFacturarPedidos;
    FacturarPedidos;

    dmTablaFacturasProveedor.IncrementarCodigo;
    Commit;
    TablaFacturasProveedor.CachedUpdates := False;
    TablaFacturasProveedor.Close;
    TablaDetallesFacturas.Close;
    TablaDetallesMem.Close;
    Result := True;
  except
    on E : EIBError do begin
      if E.IBErrorCode = isc_unique_key_violation then
      begin
        VerMensajeFmt(msgFacProCodFacRepetido, [Codigo.Field.AsString]);
        TablaFacturasProveedor.Edit;
      end
      else
        TratarExcepcion(E);
      TablaFacturasProveedor.Edit;
    end;
    on E : Exception do begin
      TratarExcepcion(E);
      TablaFacturasProveedor.Edit;
    end;
  end;
end;

procedure TfrFacturaProveedor.BuscarFactura;
begin
  if Transaccion = NIL then
    exit;
  try
    TablaFacturasProveedor.DisableControls;
    TablaDetallesFacturas.DisableControls;
    TablaDetallesMem.DisableControls;

    TablaFacturasProveedor.Close;
    TablaDetallesFacturas.Close;

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

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

    TablaDetallesFacturas.Prepare;
    TablaDetallesFacturas.Open;

    TablaDetallesMem.Close;
    TablaDetallesMem.Open;

    BorrarDetalles;
    CargarDetalles;

    dmTablaFacturasProveedor.InicializarTablaFacturas(@TablaFacturasProveedor);
    dmTablaFacturasProveedor.InicializarTablaDetalles(@TablaDetallesMem);

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

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

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

      TablaFacturasProveedor.Edit;
      TablaFacturasProveedor.FieldByName('BASEIMPONIBLE').AsFloat := ImporteBaseImponible;
      TablaFacturasProveedor.FieldByName('IMPORTEDESCUENTO').AsFloat := ImporteDto;
      TablaFacturasProveedor.FieldByName('IMPORTEIVA').AsFloat := ImporteIVA;
      TablaFacturasProveedor.FieldByName('IMPORTETOTAL').AsFloat := ImporteTotal;
    finally
      Bookmark := CurBookmark;
      EnableControls;
    end;
  end;
end;

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

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

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

function TfrFacturaProveedor.ComprobarDatos: Boolean;
var
  Situacion : string;
  CodPedAux : string;
  CodProvPed : string;
begin
  Result := False;

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

  if EsCadenaVacia(Fecha.DataBinding.Field.AsString) then
  begin
    VerMensaje(msgFacProFaltaFecha);
    Fecha.SetFocus;
    Exit;
  end;

  if EsCadenaVacia(FechaVencimiento.DataBinding.Field.AsString) then
  begin
    VerMensaje(msgFacProFaltaFechaVto);
    FechaVencimiento.SetFocus;
    Exit;
  end
  else
    if (FechaVencimiento.DataBinding.Field.AsDateTime < Fecha.DataBinding.Field.AsDateTime) then
    begin
      VerMensaje(msgFacProFechaVtoAnterior);
      FechaVencimiento.SetFocus;
      Exit;
    end;

  if EsCadenaVacia(Nombre.Field.AsString) then
  begin
    VerMensaje(msgFacProFaltaNombreProv);
    Paginas.ActivePage := pagProveedor;
    Nombre.SetFocus;
    Exit;
  end;

  if EsCadenaVacia(cbxFormaPago.Field.AsString) then
  begin
    VerMensaje(msgFaltaFormaPago);
    cbxFormaPago.SetFocus;
    Exit;
  end;

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

  with TablaDetallesMem do
  begin
    DisableControls;
    First;
    while not EOF do
    begin
      CodPedAux := FieldByName('CODIGOPEDIDO').AsString;
      // Comprobar la situación del pedido.
      Situacion := UpperCase(dmTablaPedidosProveedor.DarSituacion(EmpresaActiva.Codigo, CodPedAux));
      if not EsCadenaVacia(Situacion) then
      begin
        if (cbxTipo.Field.AsString = 'NORMAL') and (Situacion <> 'TOTALMENTE RECIBIDO') then
        begin
          VerMensajeFmt(msgFacProSitPedInc, [CodPedAux, Situacion, cbxTipo.Field.AsString]);
          EnableControls;
          Exit;
        end;

        if (cbxTipo.Field.AsString = 'ABONO') and (Situacion <> 'DEVUELTO') then
        begin
          VerMensajeFmt(msgFacProSitPedInc, [CodPedAux, Situacion, cbxTipo.Field.AsString]);
          EnableControls;
          Exit;
        end;
      end;

      // Comprobar si el proveedor de la factura es el mismo que el proveedor
      // del pedido.
      CodProvPed := FieldByName('CODIGOPROVEEDOR').AsString;
      if (not EsCadenaVacia(CodProvPed)) and (CodProvPed <> CodProveedor.DataBinding.Field.AsString) then
      begin
          VerMensajeFmt(msgFacProPedNoPro, [CodPedAux]);
          EnableControls;
          Exit;
      end;
      Next;
    end;
    EnableControls;
  end;

  Result := True;
end;

constructor TfrFacturaProveedor.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FCodigoProveedor := NULL;
  FCodigoPedido := NULL;

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

  BaseDatos := dmBaseDatos.BD;

  Transaccion := dmBaseDatos.Transaccion;

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

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

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

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

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

  dmTablaFacturasProveedor.InicializarGridDetalles(gridDetalles);
  cbxFormaPago.Items := dmTablaFormasPago.DarFormasPago;
  cbxSituacion.Items := dmTablaFacturasProveedor.DarSituaciones;
  cbxBanco.Items := dmTablaBancos.DarBancos;
  Paginas.ActivePage := pagProveedor;
end;

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

  TablaDetallesMem.Close;
  TablaDetallesMem.Free;

  TablaFacturasProveedor.Close;
  TablaFacturasProveedor.UnPrepare;
  TablaFacturasProveedor.Free;

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

  inherited;
end;

function TfrFacturaProveedor.EliminarDatos: Boolean;
begin
  Result := False;
  if (VerMensajePregunta(msgFacProBorrarFacPed) <> mrYes) then
      Exit;

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

procedure TfrFacturaProveedor.FreeContenido;
begin
  if (ContenidoModal is TRdxFrameFacturasProveedor) then begin
    CodigoFactura := (ContenidoModal as TRdxFrameFacturasProveedor).CodigoFactura;
    ActivarModo;
  end;
  if (ContenidoModal is TRdxFramePedidosProveedor) then
    CodigoPedido := (ContenidoModal as TRdxFramePedidosProveedor).CodigoPedido;
  if (ContenidoModal is TRdxFrameProveedores) then
    CodigoProveedor := (ContenidoModal as TRdxFrameProveedores).CodigoProveedor;
  inherited FreeContenido;
end;

procedure TfrFacturaProveedor.GridBotonCodigoPedidoClick(Sender: TObject);
begin
  if EsCadenaVacia(CodProveedor.DataBinding.Field.AsString) then
  begin
    VerMensaje(msgFacProFaltaNombreProv);
    paginas.ActivePage := pagProveedor;
    CodProveedor.SetFocus;
    Exit;
  end;
  TablaDetallesMem.Edit;
  ModoModal := Facturar;
  ContenidoModal := TfrPedidosProveedores.Create(Self);
end;

function TfrFacturaProveedor.ModificarDatos: Boolean;
begin
  Result := False;
  try
    CalcularTotalFactura;
    TablaFacturasProveedor.Post;
    BorrarDetallesIB;
    SalvarDetalles;
    Commit;
    TablaFacturasProveedor.Close;
    TablaDetallesFacturas.Close;
    TablaDetallesMem.Close;
    Result := True;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

procedure TfrFacturaProveedor.PrecioDetalleSetText(Sender: TField;
  const Text: String);
begin
  try
    if Length(Text) = 0 then
      Sender.AsString := '0'
    else
      Sender.AsString := Text;
    CalcularTotalFactura;
  except
    on E : EConvertError do
      VerMensaje(msgPrecioNoValido);
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
end;

procedure TfrFacturaProveedor.SetCodigoProveedor(Value: Variant);
var
  DatosProveedor : TDatosProveedor;
begin
  if VarIsNull(Value) then
    exit;

  FCodigoProveedor := Value;
  DatosProveedor := TDatosProveedor.Create;
  try
    DatosProveedor.Codigo := FCodigoProveedor;
    dmTablaProveedores.darDatosProveedor(DatosProveedor);
    CodProveedor.DataBinding.Field.AsString := DatosProveedor.Codigo;
    NIFCIF.Field.AsString := DatosProveedor.Nifcif;
    CodigoCliente.Field.AsString := dmTablaProveedores.darCodigoClienteProveedor(DatosProveedor.Codigo);
    Nombre.Field.AsString := DatosProveedor.Nombre;
    PersonaContacto.Field.AsString := DatosProveedor.PersonaContacto;
    Fax.Field.AsString := DatosProveedor.Fax;
    CalcularTotalFactura;
  finally
    DatosProveedor.Free;
  end;
end;

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

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

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

procedure TfrFacturaProveedor.CodigoButtonClick(Sender: TObject);
begin
  inherited;
  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 TablaFacturasProveedor.Active then
    BuscarFactura;
  ContenidoModal := TfrFacturasProveedores.Create(Self);
end;

procedure TfrFacturaProveedor.SetCodigoPedido(Value: Variant);
var
  SituacionAux : String;
  FacturadoAux : String;
  DatosPedido : TDatosPedidoProveedor;
begin
  if EsCadenaVacia(CodProveedor.DataBinding.Field.AsString) then
    raise Exception.Create(msgFacProFaltaNombreProv);

  if EsCadenaVacia(Value) then
    Exit;

  FCodigoPedido := Trim(Value);
  if not dmTablaPedidosProveedor.ValidarCodigo(FCodigoPedido) then
    raise Exception.CreateFmt(msgPedCodPedIncorrecto, [FCodigoPedido]);

  FCodigoPedido := dmTablaPedidosProveedor.FormatearCodigo(FCodigoPedido);

  DatosPedido := TDatosPedidoProveedor.Create;
  DatosPedido.Codigo := FCodigoPedido;
  DatosPedido.CodigoEmpresa := EmpresaActiva.Codigo;
  try
    if not dmTablaPedidosProveedor.DarDatosPedido(DatosPedido) then
      raise Exception.CreateFmt(msgPedPedProvNoExiste, [FCodigoPedido]);

    if (CodProveedor.DataBinding.Field.AsString <> DatosPedido.CodigoProveedor) then
      raise Exception.CreateFmt(msgFacProPedNoPro, [DatosPedido.Codigo]);

    SituacionAux := UpperCase(DatosPedido.Situacion);
    FacturadoAux := UpperCase(DatosPedido.CodigoFactura);

    if (SituacionAux <> 'TOTALMENTE RECIBIDO') and
       (SituacionAux <> 'DEVUELTO') then
      raise Exception.CreateFmt(msgPedidoNoFacturar, [LowerCase(SituacionAux)]);

    if not EsCadenaVacia(FacturadoAux) then
      raise Exception.CreateFmt(msgPedYaFacturado, [FCodigoPedido]);

    if not EsCadenaVacia(FCodigoFactura) then
    begin
      if not dmTablaPedidosProveedor.FacturarPedido(EmpresaActiva.Codigo, FCodigoPedido, FCodigoFactura) then
        raise Exception.CreateFmt(msgFacProErrorFacPed, [FCodigoPedido]);
    end;
    
    with TablaDetallesMem do
    begin
      Edit;
      FieldByName('CODIGOPEDIDO').AsString := DatosPedido.Codigo;
      FieldByName('SITUACION').AsString := DatosPedido.Situacion;
      FieldByName('PRECIO').AsString := DatosPedido.ImporteTotal;
      FieldByName('DESCRIPCION').AsString := Format('Pedido a proveedor %s con fecha %s', [DatosPedido.Codigo, DatosPedido.FechaAlta]);
      FieldByName('CODIGOPROVEEDOR').AsString := DatosPedido.CodigoProveedor;
    end;
    CalcularTotalFactura;
  finally
    DatosPedido.Free;
  end;
end;

procedure TfrFacturaProveedor.bAnadirClick(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 TfrFacturaProveedor.bEliminarClick(Sender: TObject);
var
  CodPedAux : string;
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
    CodPedAux := TablaDetallesMem.FieldByName('CODIGOPEDIDO').AsString;
    if not EsCadenaVacia(CodPedAux) then
      dmTablaPedidosProveedor.NoFacturarPedido(EmpresaActiva.Codigo, CodPedAux);
    TablaDetallesMem.Delete;
  except
    on E : EIBError do
      TratarExcepcion(E);
    on E : Exception do
      TratarExcepcion(E);
  end;
  CalcularTotalFactura;
end;

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

procedure TfrFacturaProveedor.CodigoExit(Sender: TObject);
begin
  inherited;
  if (Modo <> Anadir) or (Visible = false) then
    exit;
  if (Length(Codigo.Text) = 0) then
    Codigo.Field.AsString := dmTablaFacturasProveedor.DarNuevoCodigo;
  if (dmTablaFacturasProveedor.ValidarCodigo(Codigo.Text)) then
  begin
    Codigo.Field.asString := dmTablaFacturasProveedor.FormatearCodigo(Codigo.Text);
    if (dmTablaFacturasProveedor.ExisteCodigo(Codigo.Text)) then begin
      VerMensajeFmt(msgFacProCodFacRepetido, [Codigo.Text]);
      Codigo.SetFocus;
    end;
  end
  else begin
    VerMensajeFmt(msgFacProCodFacIncorrecto, [Codigo.Text]);
    Codigo.SetFocus;
  end;
end;

procedure TfrFacturaProveedor.FechaExit(Sender: TObject);
begin
  if not (Modo in [Anadir, Modificar]) then
    exit;
  if EsCadenaVacia(Fecha.Text) then
  begin
    VerMensaje(msgFacProFaltaFecha);
    Fecha.DataBinding.Field.AsString := DateToStr(Date);
    Fecha.SetFocus;
  end;
end;

procedure TfrFacturaProveedor.FechaVencimientoExit(Sender: TObject);
begin
  if not (Modo in [Anadir, Modificar]) then
    exit;
  if EsCadenaVacia(FechaVencimiento.Text) then
  begin
    VerMensaje(msgFacProFaltaFechaVto);
    FechaVencimiento.SetFocus;
  end;
end;

procedure TfrFacturaProveedor.bEliminarTodoClick(Sender: TObject);
begin
  if (VerMensajePregunta(msgDeseaBorrarTodo) = IDYES) then
    Exit;
  NoFacturarPedidos;
  BorrarDetalles;
  BorrarDetallesIB;
  CalcularTotalFactura;
end;

procedure TfrFacturaProveedor.BorrarDetallesIB;
var
  CodPedAux : string;
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 TfrFacturaProveedor.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 TfrFacturaProveedor.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
                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 Exception.CreateFmt(msgFacProCodPedRepetido, [TablaDetallesMem.FieldByName('CODIGOPEDIDO').AsString]);
    end;
  end;
end;

function TfrFacturaProveedor.NoFacturarPedidos: boolean;
begin
  Result := True;
  with TablaDetallesMem do
  begin
    DisableControls;
    First;
    while not EOF do
    begin
      if (not EsCadenaVacia(FieldByName('CODIGOPEDIDO').AsString)) and
         (not dmTablaPedidosProveedor.NoFacturarPedido(EmpresaActiva.Codigo, FieldByName('CODIGOPEDIDO').AsString))
      then begin
        Result := False;
        Break;
      end;
      Next;
    end;
    EnableControls;
  end;
end;

procedure TfrFacturaProveedor.VerModal;
begin
  if (ContenidoModal is TfrPedidosProveedores) then
    (ContenidoModal as TfrPedidosProveedores).CodigoProveedor := CodProveedor.DataBinding.Field.AsString;
  inherited;
end;

procedure TfrFacturaProveedor.CodigoPedidoDetalleSetText(Sender: TField;
  const Text: String);
begin
  CodigoPedido := Text;
end;

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

  with TablaDetallesMem do
  begin
    FieldByName('PRECIO').OnSetText := PrecioDetalleSetText;
    FieldByName('CODIGOPEDIDO').OnSetText := CodigoPedidoDetalleSetText;
    AfterDelete := DetalleAfterDelete;
  end;
end;

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

procedure TfrFacturaProveedor.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 TfrFacturaProveedor.IVASetText(Sender: TField;
  const Text: String);
begin
  if EsCadenaVacia(Text) then
    Sender.AsString := '0'
  else begin
    ValidarIVA(Text);
    Sender.AsString := Text;
  end;
  CalcularTotalFactura;
end;

function TfrFacturaProveedor.FacturarPedidos: boolean;
begin
  Result := True;
  with TablaDetallesMem do
  begin
    DisableControls;
    First;
    while not EOF do
    begin
      if (not EsCadenaVacia(FieldByName('CODIGOPEDIDO').AsString)) and
         (not dmTablaPedidosProveedor.FacturarPedido(EmpresaActiva.Codigo, FieldByName('CODIGOPEDIDO').AsString, FCodigoFactura))
      then begin
        Result := False;
        Break;
      end;
      Next;
    end;
    EnableControls;
  end;
end;

procedure TfrFacturaProveedor.CodProveedorPropertiesButtonClick(
  Sender: TObject; AButtonIndex: Integer);
begin
  ContenidoModal := TfrProveedores.Create(Self);
end;

procedure TfrFacturaProveedor.CodProveedorPropertiesValidate(
  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 (dmTablaProveedores.validarCodigo(DisplayValue)) then begin
    //Comprueba que le numero es lo sufucientemente pequeño para ser un entero
    if not EsInteger(DisplayValue) then
    begin
      VerMensajeFmt(msgProCodProvIncorrecto,[DisplayValue]);
      DisplayValue := '0';
      CodProveedor.SetFocus;
    end
    else
    begin
      DisplayValue := dmTablaProveedores.formatearCodigo(DisplayValue);
      if (dmTablaProveedores.existeCodigo(DisplayValue)) then
        CodigoProveedor := DisplayValue
      else begin
        VerMensajeFmt(msgProCodProvNoExiste, [DisplayValue]);
        Paginas.ActivePage := pagProveedor;
        CodProveedor.SetFocus;
      end;
    end;
  end
  else begin
    VerMensajeFmt(msgProCodProvIncorrecto, [DisplayValue]);
    Paginas.ActivePage := pagProveedor;
    CodProveedor.SetFocus;
  end;
end;

end.
