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,
  uViewDetallesArticulosParaVenta, cxLabel;


type
  TfEditorFacturaCliente = class(TfEditorDBItem, IEditorFacturaCliente)
    frViewFacturaCliente1: TfrViewFacturaCliente;
    frViewTotales1: TfrViewTotales;
    frViewDetallesFacturaCliente1: TfrViewDetallesFacturaCliente;
    actEnviarEMail: TAction;
    TBXSeparatorItem6: TTBXSeparatorItem;
    TBXItem7: TTBXItem;
    TBXSubmenuItem2: TTBXSubmenuItem;
    TBXItem33: TTBXItem;
    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 actEnviarEMailExecute(Sender: TObject);
    procedure actEnviarEMailUpdate(Sender: TObject);

  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;
    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.
  end;

implementation
{$R *.dfm}

uses
  uBizContactos, uDataModuleUsuarios, uFactuGES_App,
  uDetallesFacturaClienteController, uDialogUtils, uDataTableUtils,
  uDialogOpcionesImpresionFacturasCliente;
//  uGenerarAlbaranesCliFacCliUtils;


{ TfEditorFacturaCliente }

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

procedure TfEditorFacturaCliente.actEnviarEMailExecute(Sender: TObject);
begin
  inherited;
  FController.EnviarFacturaPorEMail(Factura);
end;

procedure TfEditorFacturaCliente.actEnviarEMailUpdate(Sender: TObject);
begin
  inherited;
  (Sender as TAction).Enabled := HayDatos;
end;

constructor TfEditorFacturaCliente.Create(AOwner: TComponent);
begin
  inherited;
  pgPaginas.ActivePageIndex := 0;
  ViewFacturaCliente := frViewFacturaCliente1;
  FTiposIVAController := TTiposIVAController.Create;
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
    Factura.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 := ((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; En los documentos de cliente el porte no se desglosa 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;
    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;
var
  AVerSello: Boolean;
  AVerCopia: Boolean;
  AllItems: Boolean;

begin
  inherited;
  AllItems := False;
  AVerSello := True;
  AVerCopia := True;

  //Preguntamos si desea que en las facturas se vea el Sello
  if ElegirOpcionesImpresionFacturaCliente(AVerSello, AVerCopia) then
     FController.Print(FFactura, AllItems, AVerSello, AVerCopia);
end;

procedure TfEditorFacturaCliente.OnClienteChanged(Sender: TObject);
begin
  FFactura.Cliente := ViewFacturaCliente.ViewClienteFactura.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 := ((frViewTotales1.dsTiposIVA.DataTable) as IBizTipoIVA).IVA;
  if FFactura.Cliente.RECARGO_EQUIVALENCIA = 1 then
    Factura.RE := ((frViewTotales1.dsTiposIVA.DataTable) as IBizTipoIVA).RE
  else
    Factura.RE := 0;

//Desactivado porque en presupuestos no utilizan el catálogo de clientes
  // 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;
var
  AVerSello: Boolean;
  AVerCopia: Boolean;
  AllItems: Boolean;

begin
  inherited;
  AllItems := False;
  AVerSello := True;
  AVerCopia := True;

  //Preguntamos si desea que en las facturas se vea el Sello
  if ElegirOpcionesImpresionFacturaCliente(AVerSello, AVerCopia) then
     FController.Preview(FFactura, AllItems, AVerSello, AVerCopia);
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
      ViewFacturaCliente.ViewClienteFactura.OnClienteChanged := NIL;
      try
        FViewFactura.Factura := FFactura;
        frViewDetallesFacturaCliente1.Detalles := FFactura.Detalles;
        frViewDetallesFacturaCliente1.Factura := FFactura; //Para poder sacar los descuento del articulos segun el cliente seleccionado
      finally
        ViewFacturaCliente.ViewClienteFactura.OnClienteChanged := OnClienteChanged;
      end;
    end;
  end
  else begin
    ViewFacturaCliente.ViewClienteFactura.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.
