unit uEditorFacturaCliente;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, uEditorDBItem, DB, uDADataTable, JvAppStorage,
  JvAppRegistryStorage, JvComponent, JvFormPlacement, ImgList,
  PngImageList, StdActns, ActnList, ComCtrls, TBX, TB2Item, TB2Dock,
  TB2Toolbar, ExtCtrls, JvExControls, JvNavigationPane,
  uViewFacturaCliente, uCustomView, uViewBase, uViewTotales,
  StdCtrls, pngimage, AppEvnts, JvComponentBase,
  uBizFacturasCliente, uBizTiposIVA,


  uIEditorFacturaCliente, uFacturasClienteController, uViewDetallesBase,
  uViewDetallesFacturaCliente, dxLayoutLookAndFeels, JvExComCtrls, JvStatusBar,
  uViewDetallesDTO, uViewDetallesArticulos, uTiposIVAController, uDAInterfaces,
  cxControls, cxContainer, cxEdit, cxTextEdit, cxDBEdit, Grids, DBGrids,
  cxCheckBox, uViewListaSubCuentas;


type
  TfEditorFacturaCliente = class(TfEditorDBItem, IEditorFacturaCliente)
    frViewFacturaCliente1: TfrViewFacturaCliente;
    frViewTotales1: TfrViewTotales;
    frViewDetallesFacturaCliente1: TfrViewDetallesFacturaCliente;
    pagContabilidad: TTabSheet;
    frViewListaSubcuentas1: TfrViewListaSubcuentas;
    procedure FormShow(Sender: TObject);
    procedure frViewClienteFactura1edtlNombrePropertiesEditValueChanged(Sender: TObject);
    procedure dsDataTableDataChange(Sender: TObject; Field: TField);
    procedure CustomEditorClose(Sender: TObject; var Action: TCloseAction);
    procedure frViewClienteFacturaedtlNombrePropertiesChange(Sender: TObject);
    procedure pgPaginasChanging(Sender: TObject; var AllowChange: Boolean);
    procedure frViewTotales1edtDescuentoPropertiesValidate(Sender: TObject;
      var DisplayValue: Variant; var ErrorText: TCaption; var Error: Boolean);
    procedure frViewTotales1bTiposIVAClick(Sender: TObject);
    procedure frViewTotales1eIVAPropertiesValidate(Sender: TObject;
      var DisplayValue: Variant; var ErrorText: TCaption; var Error: Boolean);
    procedure frViewTotales1cbRecargoEquivalenciaPropertiesEditValueChanged(Sender: TObject);
    procedure frViewTotales1ePortePropertiesValidate(Sender: TObject;
      var DisplayValue: Variant; var ErrorText: TCaption; var Error: Boolean);
    procedure frViewTotales1ePorteEditing(Sender: TObject; var CanEdit: Boolean);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); override; //Importante en este punto se deben de quitar los eventos que puedan afectar a la tabla una vez se cierre el editor.

  private
    procedure RecalcularPortePorUnidad;

  protected
    FController : IFacturasClienteController;
    FFactura: IBizFacturaCliente;
    FTiposIVAController : ITiposIVAController;
    FTiposIVA: IBizTipoIVA;
    FViewFactura: IViewFacturaCliente;
    function GetController : IFacturasClienteController;
    procedure SetController (const Value : IFacturasClienteController);
    function GetFactura: IBizFacturaCliente;
    procedure SetFactura(const Value: IBizFacturaCliente);

    function GetViewFactura: IViewFacturaCliente;
    procedure SetViewFactura(const Value: IViewFacturaCliente);

    property ViewFacturaCliente: IViewFacturaCliente read GetViewFactura write SetViewFactura;

    procedure OnClienteChanged(Sender: TObject);

    procedure GuardarInterno; override;
    procedure EliminarInterno; override;
    procedure ImprimirInterno; override;
    procedure PrevisualizarInterno; override;

    procedure PonerTitulos(const ATitulo: string = ''); override;
  public
    destructor Destroy; override;
    property Controller : IFacturasClienteController read GetController write SetController;
    property Factura: IBizFacturaCliente read GetFactura write SetFactura;
    constructor Create(AOwner: TComponent); override;
  end;

implementation
{$R *.dfm}
{$INCLUDE ..\..\..\FactuGES.inc}

uses
  uBizContactos, uDataModuleUsuarios, uFactuGES_App, uSubCuentasController,
  uDetallesFacturaClienteController, uDialogUtils, uDataTableUtils,
  uViewClienteFactura, uBizDireccionesContacto, uClientesController;
//  uGenerarAlbaranesCliFacCliUtils;


{ TfEditorFacturaCliente }

{
**************************** TfEditorFacturaCliente ****************************
}

constructor TfEditorFacturaCliente.Create(AOwner: TComponent);
begin
  inherited;
  pgPaginas.ActivePageIndex := 0;
  ViewFacturaCliente := frViewFacturaCliente1;
  FTiposIVAController := TTiposIVAController.Create;

  //CONTABILIDAD
  frViewListaSubcuentas1.TipoSubCuenta := tVentas;
end;

procedure TfEditorFacturaCliente.CustomEditorClose(Sender: TObject;
  var Action: TCloseAction);
begin
  inherited;
  Factura := NIL;
  FTiposIVA := NIL;
  
  FTiposIVAController := Nil;
  FController := NIL;
  FViewFactura := NIL;
end;

destructor TfEditorFacturaCliente.Destroy;
begin
  inherited;
end;

procedure TfEditorFacturaCliente.dsDataTableDataChange(Sender: TObject;
  Field: TField);
begin
  inherited;
  if Assigned(FFactura) and (not (FFactura.DataTable.Fetching) or
    not (FFactura.DataTable.Opening) or not (FFactura.DataTable.Closing)) then
    PonerTitulos;
end;

procedure TfEditorFacturaCliente.EliminarInterno;
var
  ACadena : String;
begin
   if Factura.TIPO = CTE_TIPO_FACTURA then
      ACadena := '¿Desea borrar esta factura de cliente?'
   else
      ACadena := '¿Desea borrar este abono a cliente?';

  if (Application.MessageBox(PChar(ACadena), 'Atención', MB_YESNO) = IDYES) then
  begin
    //Es el caso de querer borrar una factura pendiente cuyos recibos tienen devoluciones
    if not FController.Eliminar(Factura) then
       Application.MessageBox('La factura no ha podido ser eliminada porque tiene recibos con pagos o devoluciones emitidas.', 'Atención', MB_OK);
    inherited;
  end;
end;

procedure TfEditorFacturaCliente.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  inherited;

  frViewTotales1.cbRecargoEquivalencia.Properties.OnEditValueChanged := nil;
  frViewTotales1.eIVA.Properties.OnValidate := nil;
  frViewTotales1.ePorte.Properties.OnValidate := nil;
end;

procedure TfEditorFacturaCliente.FormShow(Sender: TObject);
begin
  inherited;

  if not Assigned(FViewFactura) then
    raise Exception.Create('No hay ninguna vista asignada');

  if not Assigned(Factura) then
    raise Exception.Create('No hay ninguna factura asignada');

  Factura.DataTable.Active := True;
end;

procedure TfEditorFacturaCliente.frViewClienteFactura1edtlNombrePropertiesEditValueChanged(Sender: TObject);
begin
  inherited;
  with (Sender as TcxDBTextEdit) do
    Enabled := (FFactura.ID <> 0)
end;

procedure TfEditorFacturaCliente.frViewClienteFacturaedtlNombrePropertiesChange(
  Sender: TObject);
begin
  inherited;
  PonerTitulos;
end;

procedure TfEditorFacturaCliente.frViewTotales1bTiposIVAClick(Sender: TObject);
begin
  inherited;
  FTiposIVAController.VerTodos(FTiposIVA);
end;

procedure TfEditorFacturaCliente.frViewTotales1cbRecargoEquivalenciaPropertiesEditValueChanged(
  Sender: TObject);
begin
  inherited;

  if assigned(Factura) then
  begin
    if not Factura.datatable.Editing then
       Factura.datatable.Edit;

    if frViewTotales1.cbRecargoEquivalencia.Checked then
      Factura.RECARGO_EQUIVALENCIA := 1
    else
      Factura.RECARGO_EQUIVALENCIA := 0;
  end;
end;

procedure TfEditorFacturaCliente.frViewTotales1edtDescuentoPropertiesValidate(
  Sender: TObject; var DisplayValue: Variant; var ErrorText: TCaption;
  var Error: Boolean);
begin
  inherited;
  Factura.DESCUENTO := DisplayValue;
end;

procedure TfEditorFacturaCliente.frViewTotales1eIVAPropertiesValidate(
  Sender: TObject; var DisplayValue: Variant; var ErrorText: TCaption;
  var Error: Boolean);
begin
  inherited;
  Factura.Edit;
  Factura.ID_TIPO_IVA := FTiposIVA.ID; // ((frViewTotales1.dsTiposIVA.DataTable) as IBizTipoIVA).ID;
end;

procedure TfEditorFacturaCliente.frViewTotales1ePorteEditing(Sender: TObject;
  var CanEdit: Boolean);
begin
  inherited;

  if FFactura.TIPO = CTE_TIPO_ABONO then
     CanEdit := False;
end;

procedure TfEditorFacturaCliente.frViewTotales1ePortePropertiesValidate(
  Sender: TObject; var DisplayValue: Variant; var ErrorText: TCaption;
  var Error: Boolean);
begin
  inherited;

	if not VarIsNull(DisplayValue) and (Length(DisplayValue) > 0) then
    FFactura.IMPORTE_PORTE := DisplayValue
  else
    FFactura.IMPORTE_PORTE := 0;

//  RecalcularPortePorUnidad; No se desglosa el importe del porte por articulo
end;

function TfEditorFacturaCliente.GetController: IFacturasClienteController;
begin
  Result := FController;
end;

function TfEditorFacturaCliente.GetFactura: IBizFacturaCliente;
begin
  Result := FFactura;
end;

function TfEditorFacturaCliente.GetViewFactura: IViewFacturaCliente;
begin
  Result := FViewFactura;
end;

procedure TfEditorFacturaCliente.GuardarInterno;
var
  bEsNuevo : Boolean;

begin
  inherited;

  ShowHourglassCursor;
  //frViewDetallesFacturaCliente1.SaveGridStatus; // Para guardar estado del grid
  frViewDetallesFacturaCliente1.BeginUpdate;  // Para que no se mueva el foco
  try
    bEsNuevo := FFactura.EsNuevo;

    {$IFDEF CONTABILIDAD}
      FFactura.Edit;
      FFactura.ID_SUBCUENTA := frViewListaSubCuentas1.IdSubCuenta;
      FController.SetIgnorarContabilidad(FFactura, frViewListaSubCuentas1.eContabilizar.EditValue);
    {$ENDIF}

    FController.Guardar(FFactura);

  finally
    frViewDetallesFacturaCliente1.EndUpdate;
    //frViewDetallesFacturaCliente1.RestoreGridStatus;
    HideHourglassCursor;
  end;

  if bEsNuevo then
  begin
    if FFactura.TIPO = CTE_TIPO_FACTURA then
      ShowInfoMessage('La factura se ha dado de alta con el código ' + FFactura.REFERENCIA)
    else
    begin
      ShowInfoMessage('El abono se ha dado de alta con el código ' + FFactura.REFERENCIA);
      //Preguntamos is desea hacer una orden de devolución asociada
//      if (Application.MessageBox('¿Desea crear una orden de devolución para el abono?', 'Atención', MB_YESNO) = IDYES) then
//         GenerarAlbaranCli(FFactura);
    end;
  end;

  Modified := False;
end;

procedure TfEditorFacturaCliente.ImprimirInterno;
begin
  inherited;
  FController.Print(FFactura);
end;

procedure TfEditorFacturaCliente.OnClienteChanged(Sender: TObject);
var
  FDetallesController : IDetallesFacturaClienteController;
  AClientesController : IClientesController;
  ADireccion : IBizDireccionesContacto;
begin
  FFactura.Cliente := frViewFacturaCliente1.frViewClienteFactura1.Cliente;

  if not (FFactura.DataTable.State in dsEditModes) then
     FFactura.DataTable.Edit;

  // Actualizar IVA y RE a partir del tipo de IVA del cliente.
  Factura.IVA := FTiposIVA.IVA; //((frViewTotales1.dsTiposIVA.DataTable) as IBizTipoIVA).IVA;
  if FFactura.Cliente.RECARGO_EQUIVALENCIA = 1 then
    Factura.RE := FTiposIVA.RE
  else
    Factura.RE := 0;

  // En el caso de tener direcciones asociadas, se debe dar la posibilidad de elegir la dirección principal o las secundarias para la factura
  AClientesController := TClientesController.Create;
  try
    case FFactura.Cliente.Direcciones.RecordCount of
    0   : //No hay direcciones secundarias asociadas
    else  ADireccion := AClientesController.ElegirDireccion(FFactura.Cliente, 'Seleccione la dirección del proveedor que quiere utilizar como dirección fiscal de esta factura.');
    end;

    // Si hay dirección de envio, copiarla al albarán y poner el coste del porte
    if Assigned(ADireccion) then
    begin
      try
       FFactura.Edit;
       FFactura.IMPORTE_PORTE := ADireccion.PORTE;
       FController.CopiarDireccion(ADireccion, FFactura);
      finally
       ADireccion := NIL;
      end;
    end
  finally
    AClientesController := Nil;
  end;


  // Si la factura tiene detalles hay que mirar si los descuentos y otros campos
  // para los artículos hay que cambiarlos.
  if (FFactura.Detalles.RecordCount > 0) then
     FController.DetallesController.ActualizarDetalles(FFactura.Detalles, FFactura.Cliente);
end;

procedure TfEditorFacturaCliente.pgPaginasChanging(Sender: TObject;
  var AllowChange: Boolean);
var
  ACadena : String;
begin
  inherited;

  if (not Assigned(FFactura)) or (FFactura.ID_CLIENTE = ID_NULO) then
  begin
    if FFactura.TIPO = CTE_TIPO_FACTURA then
      ACadena := 'Antes debe elegir un cliente para esta factura'
    else
      ACadena := 'Antes debe elegir un cliente para este abono';
    ShowWarningMessage(ACadena);
    AllowChange := False;
  end;
end;

procedure TfEditorFacturaCliente.PonerTitulos(const ATitulo: string);
var
  FTitulo : String;
begin
  FTitulo := ATitulo;
  if (FTitulo = '') and Assigned(Factura) then
  begin
    if Factura.EsNuevo then
       if Factura.TIPO = CTE_TIPO_FACTURA then
          FTitulo := 'Nueva factura de cliente'
       else
          FTitulo := 'Nuevo abono a cliente'
    else
       if Factura.TIPO = CTE_TIPO_FACTURA then
          FTitulo := 'Factura de cliente'  + ' - ' + FFactura.Cliente.Nombre
       else
          FTitulo := 'Abono a cliente'  + ' - ' + FFactura.Cliente.Nombre       
  end;

  inherited PonerTitulos(FTitulo);

  Self.Caption := FTitulo + ' (' + AppFactuGES.EmpresaActiva.NOMBRE + ')';
end;

procedure TfEditorFacturaCliente.PrevisualizarInterno;
begin
  inherited;
  FController.Preview(FFactura);
end;

procedure TfEditorFacturaCliente.RecalcularPortePorUnidad;
begin
  //Esta lógica se llamará en el editor porque es para facilitar el rellenado de información del documento
  //no puede ir en la clase de negocio porque no es una lógica que tenga sentido fuera del editor.
  if Assigned(Controller)
  and Assigned(Controller.DetallesController) then
      Controller.DetallesController.DesglosarPorteDetalles(FFactura.IMPORTE_PORTE, FFactura.Detalles)
end;

procedure TfEditorFacturaCliente.SetController(const Value: IFacturasClienteController);
begin
  FController := Value;

  if Assigned(FController) then
  begin
     ViewFacturaCliente.Controller := FController;
     frViewDetallesFacturaCliente1.Controller := Controller.DetallesController;
  end;
end;

procedure TfEditorFacturaCliente.SetFactura(const Value: IBizFacturaCliente);
begin
  FFactura := Value;

  if Assigned(FFactura) then
  begin
    dsDataTable.DataTable := FFactura.DataTable;

    frViewTotales1.DADataSource.DataTable := FFactura.DataTable;

    FTiposIVA := FTiposIVAController.BuscarTodos;
    frViewTotales1.dsTiposIVA.DataTable := FTiposIVA.DataTable;
    FTiposIVA.DataTable.Active := True;

    if Assigned(FViewFactura) then
    begin
      frViewFacturaCliente1.frViewClienteFactura1.Cliente := FFactura.Cliente;
      frViewFacturaCliente1.frViewClienteFactura1.OnClienteChanged := OnClienteChanged;

      FViewFactura.Factura := FFactura;
      frViewDetallesFacturaCliente1.Detalles := FFactura.Detalles;
      frViewDetallesFacturaCliente1.Factura := FFactura; //Para poder sacar los descuento del articulos segun el cliente seleccionado
    end;

    {$IFDEF CONTABILIDAD}
      frViewListaSubCuentas1.eContabilizar.EditValue := FFactura.IGNORAR_CONTABILIDAD;
      frViewListaSubCuentas1.ElegirSubCuenta(FFactura.ID_SUBCUENTA);
    {$ENDIF}

  end
  else begin
    frViewFacturaCliente1.frViewClienteFactura1.OnClienteChanged := NIL;
    dsDataTable.DataTable := NIL;
    frViewTotales1.DADataSource.DataTable := NIL;
    frViewTotales1.dsTiposIVA.DataTable := NIL;
  end

end;

procedure TfEditorFacturaCliente.SetViewFactura(const Value: IViewFacturaCliente);
begin
  FViewFactura := Value;

  if Assigned(FViewFactura) and Assigned(Factura) then
    FViewFactura.Factura := Factura;
end;

end.
  