unit uBizFacturasCliente;

interface

uses
  uDAInterfaces, uDADataTable, Classes, uBizContacto, DB,
  uBizImportesDetalleBase, uBizImportesCabeceraBase, uDBSelectionList,
  uExceptions, uBizInformesBase, schFacturasClienteClient_Intf;

const
  BIZ_FACTURASCLIENTE = 'Client.FacturasCliente';
  BIZ_DETALLESFACTURASCLIENTE = 'Client.DetallesFacturasCliente';
//  BIZ_FACTURASOBRA = 'Client.FacturasObra';

  SITUACION_PENDIENTE = 'N';
  SITUACION_PAGADO = 'S';

  CTE_NORMAL = 'N';
  CTE_ABONO = 'A';
  CTE_PROFORMA = 'P';

  CTE_IVA1 = 16;
  CTE_IVA2 = 1.16;

type
  IBizDetallesFacturasCliente = interface(IDetallesFacturasCliente)
  ['{A628B3DE-2EF0-4A6E-AAFD-8BE582BDEE9A}']
    procedure CopyFrom(ADetallesFacturas : IBizDetallesFacturasCliente);
    procedure cambiarSigno;
  end;

  IBizFacturasCliente = interface(IFacturasCliente)
  ['{CE8B2685-0FA5-404C-B8FA-90618A815BFF}']
    function GetDetalles: IBizDetallesFacturasCliente;
    procedure SetDetalles(Value: IBizDetallesFacturasCliente);
    property Detalles: IBizDetallesFacturasCliente read GetDetalles write
            SetDetalles;

    function GetCliente: IBizContacto;
    procedure SetCliente(Value: IBizContacto);
    property Cliente: IBizContacto read GetCliente write SetCliente;

{    function GetObra: IBizObraRelacionada;
    procedure SetObra(const Value: IBizObraRelacionada);
    property Obra: IBizObraRelacionada read GetObra write SetObra;}

    procedure Show;

    procedure setReferencia(const ClaseFactura: String);
    procedure CopyFrom(AFacturaCliente : IBizFacturasCliente);
    procedure cambiarSigno;
  end;

{  IBizFacturasObra = interface(IBizFacturasCliente)}
//  ['{FE4F53AD-CBF6-442A-8D22-01A1419DF6BE}']
{  end;}

  TBizDetallesFacturasCliente = class(TDetallesFacturasClienteDataTableRules,
                                  IBizDetallesFacturasCliente,
                                  IBizImportesDetalle,
                                  IBizPuntosDetalle,
                                  IBizVisibleDetalle,
                                  IParche)    // PARCHE ***********************
  private
    FIsAppend : Boolean;
    FPosicionNueva : Integer;
    FPuedoLanzarEvento : Boolean; // PARCHE ***********************

  protected
    procedure SetCANTIDADValue(const aValue: Integer); override;
    procedure SetIMPORTEUNIDADValue(const aValue: Currency); override;
    procedure SetIMPORTETOTALValue(const aValue: Currency); override;

    procedure OnNewRecord(Sender: TDADataTable); override;
    procedure BeforeInsert(Sender: TDADataTable); override;
    procedure AfterPost(Sender: TDADataTable); override;
    procedure AfterInsert(Sender: TDADataTable); override;
    procedure AfterDelete(Sender: TDADataTable); override;
    procedure BeforeDelete(Sender: TDADataTable); override;

    // PARCHE ***********************
    procedure ActivarEventos;
    procedure DesactivarEventos;
    procedure Refrescar;
    function PuedoLanzarEvento : Boolean;
  public
    procedure RecalcularImporte;
    function DarSumaTotalImportes : Currency;
    constructor Create(aDataTable: TDADataTable); override;
    procedure CopyFrom(ADetallesFacturas : IBizDetallesFacturasCliente);
    procedure cambiarSigno;
  end;


  TBizFacturasCliente = class(TFacturasClienteDataTableRules, IBizFacturasCliente,
                            IBizImportesCabecera, ISelectedRowList,
                            IApplyUpdateFailedException, IBizInformesAware)
  private
    FCliente : IBizContacto;
//    FObra : IBizObraRelacionada;
    FDetalles: IBizDetallesFacturasCliente;
    FDetallesLink: TDADataSource;
    FSelectedRows : TSelectedRowList;
  protected
    procedure ShowApplyUpdateFailed (const Error: EDAApplyUpdateFailed);
    function GetDetalles: IBizDetallesFacturasCliente;
    procedure SetDetalles(Value: IBizDetallesFacturasCliente);

    function GetCliente: IBizContacto;
    procedure SetCliente(Value: IBizContacto);

{    function GetObra: IBizObraRelacionada;
    procedure SetObra(const Value: IBizObraRelacionada);}

    procedure OnNewRecord(Sender: TDADataTable); override;

    function GetSelectedRows : TSelectedRowList;
    procedure BeforeDelete(Sender: TDADataTable); override;
    procedure AfterDelete(Sender: TDADataTable); override;
    procedure OnPostError(DataTable: TDADataTable; Error: EDatabaseError;
      var Action: TDataAction); override;
    procedure BeforeApplyUpdates(Sender : TDADataTable; const Delta : IDADelta);

//    procedure SetCLASEFACTURAValue(const aValue: String); override;
  public

    procedure RecalcularImporte;
    property Cliente: IBizContacto read GetCliente write SetCliente;
//    property Obra: IBizObraRelacionada read GetObra write SetObra;
    property Detalles: IBizDetallesFacturasCliente read GetDetalles write SetDetalles;
    constructor Create(aDataTable: TDADataTable); override;
    destructor Destroy; override;

    procedure Show; virtual;
    procedure Preview;
    procedure Print;
    property SelectedRows : TSelectedRowList read GetSelectedRows;
    procedure CopyFrom(AFacturaCliente : IBizFacturasCliente);
    procedure cambiarSigno;
    procedure setReferencia(const ClaseFactura: String);
  end;

{  TBizFacturasObra = class(TBizFacturasCliente, IBizFacturasObra)
  public
    procedure Show; override;
  end;}

  procedure ValidarFacturaCliente (const AFacturaCliente : IBizFacturasCliente);


implementation

uses
  Windows, Dialogs, uDACDSDataTable, SysUtils, uEditorUtils, Variants, Math,
  uDataModuleContactos, Controls, Forms, LiteralesFacturasCliente,
  uDataModuleBase, uDataTableUtils, uDataModuleFacturasCliente;

var
  FMasterDeleting : Boolean;
  FCancelInsert : Boolean;

procedure ValidarFacturaCliente (const AFacturaCliente : IBizFacturasCliente);
begin
  if (FloatToStr(AFacturaCliente.FECHAFACTURA) = '0') then
    raise Exception.Create(msgLitFechaObligatorio);

  if not Assigned(AFacturaCliente.Cliente) or
      (AFacturaCliente.Cliente.DataTable.IsEmpty) then
    raise Exception.Create(msgLitClienteObligatorio);
end;

constructor TBizFacturasCliente.Create(aDataTable: TDADataTable);
begin
  inherited;
  FCliente := NIL;
  FDetallesLink := TDADataSource.Create(NIL);
  FSelectedRows := TSelectedRowList.Create(aDataTable);
  aDataTable.OnBeforeApplyUpdates := BeforeApplyUpdates;
end;

destructor TBizFacturasCliente.Destroy;
begin
  FCliente := NIL;
  FDetalles := NIL;
  FDetallesLink.Free;
  FSelectedRows.Free;  
  inherited;
end;

function TBizFacturasCliente.GetCliente: IBizContacto;
begin
  if not Assigned(FCliente) or
    ((CODIGOCONTACTO <> FCliente.Codigo) and
    not (FCliente.DataTable.State in dsEditModes)) then
  begin
    FCliente := dmContactos.GetContacto(CODIGOCONTACTO);
    if not FCliente.DataTable.Active then
      FCliente.DataTable.Active := True;
    if not FCliente.DataTable.IsEmpty then  // Está vacío si la factura es nueva y no tiene cliente
    begin
      FCliente.Edit;
      FCliente.NOMBRE := NOMBRE;
      FCliente.NIFCIF := NIFCIF;
      FCliente.CALLE := CALLE;
      FCliente.CODIGOPOSTAL := CODIGOPOSTAL;
      FCliente.PROVINCIA := PROVINCIA;
      FCliente.POBLACION := POBLACION;
      FCliente.Post;
    end;
  end;
  Result := FCliente;
end;

function TBizFacturasCliente.GetDetalles: IBizDetallesFacturasCliente;
begin
  Result := FDetalles;
end;

procedure TBizFacturasCliente.CopyFrom(AFacturaCliente : IBizFacturasCliente);
var
  ACursor: TCursor;
begin
  if not (State in dsEditModes) then
    Edit;

  ACursor := Screen.Cursor;
  Screen.Cursor := crHourGlass;
  Application.ProcessMessages;
  try
    CODIGO := dmFacturasCliente.GetNextAutoinc;
    FECHAALTA := Date;
    USUARIO := 'eeee';  //dmUsuarios.LoginInfo.UserID;
    CLASEFACTURA := AFacturaCliente.CLASEFACTURA;
    REFERENCIA := AFacturaCliente.REFERENCIA;
    FECHAFACTURA := AFacturaCliente.FECHAFACTURA;
    PAGADA := AFacturaCliente.PAGADA;
    BASEIMPONIBLE := AFacturaCliente.BASEIMPONIBLE;
    IVA := AFacturaCliente.IVA;
    OBSERVACIONES := AFacturaCliente.OBSERVACIONES;
    FORMAPAGO := AFacturaCliente.FORMAPAGO;
    CODIGOCONTACTO := AFacturaCliente.CODIGOCONTACTO;
    Cliente := AFacturaCliente.Cliente;

{    if not AFacturaCliente.DataTable.FieldByName(fld_FacturasClienteCODIGOOBRA).IsNull then
       CODIGOOBRA := AFacturaCliente.CODIGOOBRA;}
    if not AFacturaCliente.DataTable.FieldByName(fld_FacturasClienteFECHAVENCIMIENTO).IsNull then
       FECHAVENCIMIENTO := AFacturaCliente.FECHAVENCIMIENTO;

    Detalles.CopyFrom(AFacturaCliente.Detalles);
    RecalcularImporte;
    Post;
    MessageBox(0, 'Se ha duplicado correctamente la factura elegida.', 'Factura duplicada', MB_ICONWARNING or MB_OK);
  finally
    Screen.Cursor := ACursor;
  end;
end;

procedure TBizFacturasCliente.OnNewRecord(Sender: TDADataTable);
begin
  inherited;
  USUARIO := 'eeee';  //dmUsuarios.LoginInfo.UserID;
  FECHAALTA := Date;
  FECHAFACTURA := Date;
  CODIGO := dmFacturasCliente.GetNextAutoinc;
  IVA := CTE_IVA1;
end;

procedure TBizFacturasCliente.Preview;
begin
  dmFacturasCliente.Preview(Self.CODIGO);
end;

procedure TBizFacturasCliente.SetCliente(Value: IBizContacto);
var
  bEnEdicion : Boolean;
begin
  bEnEdicion := (DataTable.State in dsEditModes);
  if not bEnEdicion then
    Edit;
  FCliente := Value;
  if Assigned(FCliente) then
  begin
    CODIGOCONTACTO := FCliente.CODIGO;
    NOMBRE := FCliente.NOMBRE;
    NIFCIF := FCliente.NIFCIF;
    CALLE := FCliente.CALLE;
    CODIGOPOSTAL := FCliente.CODIGOPOSTAL;
    PROVINCIA := FCliente.PROVINCIA;
    POBLACION := FCliente.POBLACION;
    if not bEnEdicion then
      Post;
  end
end;

procedure TBizFacturasCliente.SetDetalles(Value: IBizDetallesFacturasCliente);
begin
  FDetalles := Value;
  FDetallesLink.DataTable := Self.DataTable;
  FDetalles.DataTable.MasterSource := FDetallesLink;
end;

procedure TBizFacturasCliente.Show;
begin
  ShowEditor(IBizFacturasCliente, Self, etItem);
end;

procedure TBizDetallesFacturasCliente.ActivarEventos;
begin
  FPuedoLanzarEvento := True;
end;

procedure TBizDetallesFacturasCliente.AfterDelete(Sender: TDADataTable);
var
  ACabecera : IBizImportesCabecera;
begin
  inherited;

  // PARCHE *******************
  if not PuedoLanzarEvento then
    Exit;

  if (not FMasterDeleting) and (not FCancelInsert) then
  begin
    ReasignarPosiciones(Self.DataTable);
    if Assigned(DataTable.MasterSource) and
      Supports(DataTable.MasterSource.DataTable, IBizImportesCabecera, ACabecera) then
      ACabecera.RecalcularImporte;
  end;
  FCancelInsert := False;
end;

procedure TBizDetallesFacturasCliente.AfterInsert(Sender: TDADataTable);
begin
  inherited;

  // PARCHE *******************
  if not PuedoLanzarEvento then
    Exit;

  FIsAppend := DataTable.EOF;
  Post;
  Edit; // Para volver a dejarlo en modo de edición
end;

procedure TBizDetallesFacturasCliente.AfterPost(Sender: TDADataTable);
begin
  inherited;

  // PARCHE *******************
  if not PuedoLanzarEvento then
    Exit;

  if POSICION < 0 then
    AsignarPosicion(Self.DataTable, FIsAppend);

  if NUMCONCEPTO < 0  then
    AsignarNumConcepto(Self.DataTable);

  FIsAppend := False;
end;

procedure TBizDetallesFacturasCliente.BeforeDelete(Sender: TDADataTable);
begin
  inherited;

  // PARCHE *******************
  if not PuedoLanzarEvento then
    Exit;

  if (DataTable.State in dsEditModes) then
    DataTable.Cancel;

  if not FMasterDeleting then
    FCancelInsert := not (DataTable.MasterSource.DataTable.FieldByName('CODIGO').AsInteger = CODIGOFACTURA);
end;

procedure TBizDetallesFacturasCliente.BeforeInsert(Sender: TDADataTable);
begin
  inherited;

  // PARCHE *******************
  if not PuedoLanzarEvento then
    Exit;

  if Assigned(DataTable.MasterSource) and
    (DataTable.MasterSource.DataTable.State in dsEditModes) then
    DataTable.MasterSource.DataTable.Post;

  if GetRecordCount = 0 then
    FPosicionNueva := -1
  else
    FPosicionNueva := POSICION * (-1);
end;

procedure TBizDetallesFacturasCliente.cambiarSigno;
begin



  DataTable.First;
  while not DataTable.EOF do
  begin
//    DataTable.DisableEventHandlers;
    if not (DataTable.State in dsEditModes) then
       DataTable.Edit;
    if not DataTable.FieldByName(fld_DetallesFacturasClienteIMPORTEUNIDAD).IsNull then
       IMPORTEUNIDAD := (-1)* IMPORTEUNIDAD;
//    if not ADetallesPedido.DataTable.FieldByName(fld_DetallesPedidosProveedorIMPORTETOTAL).IsNull then
//       IMPORTETOTAL := ADetallesPedido.IMPORTETOTAL;
//    DataTable.EnableEventHandlers;
//    DataTable.Post;
    DataTable.Next;
  end;


end;

procedure TBizDetallesFacturasCliente.CopyFrom(ADetallesFacturas : IBizDetallesFacturasCliente);
begin
  ADetallesFacturas.First;
  while not ADetallesFacturas.EOF do
  begin
    Append;
    DataTable.DisableControls;
    DataTable.DisableEventHandlers;
    try
      TIPO := ADetallesFacturas.TIPO;
      DESCRIPCION := ADetallesFacturas.DESCRIPCION;
      CANTIDAD := ADetallesFacturas.CANTIDAD;
      IMPORTEUNIDAD := ADetallesFacturas.IMPORTEUNIDAD;
      IMPORTETOTAL := ADetallesFacturas.IMPORTETOTAL;
      POSICION := ADetallesFacturas.POSICION;
    finally
      DataTable.EnableControls;
      DataTable.EnableEventHandlers;
    end;
    Post;
    ADetallesFacturas.Next;
  end;
end;

constructor TBizDetallesFacturasCliente.Create(aDataTable: TDADataTable);
begin
  inherited;
  FPosicionNueva := 1;  // Los conceptos empiezan a contar en 1

  // PARCHE *******************
  FPuedoLanzarEvento := True;
end;

function TBizDetallesFacturasCliente.DarSumaTotalImportes: Currency;
begin
  Result := DarTotalDetalles(Self.DataTable, True, False);
end;

procedure TBizDetallesFacturasCliente.DesactivarEventos;
begin
  FPuedoLanzarEvento := False;
end;

procedure TBizDetallesFacturasCliente.OnNewRecord(Sender: TDADataTable);
begin
  inherited;

  // PARCHE *******************
  if not PuedoLanzarEvento then
    Exit;

  POSICION := FPosicionNueva;
  NUMCONCEPTO := -1;
  TIPO := TIPODETALLE_CONCEPTO;
end;


function TBizFacturasCliente.GetSelectedRows: TSelectedRowList;
begin
  Result := FSelectedRows;
end;

procedure TBizFacturasCliente.ShowApplyUpdateFailed(const Error: EDAApplyUpdateFailed);
begin
  if (Pos(AUF_FKVIOLATION, Error.Message) > 0) then
    MessageBox(0, PChar(msgLitErrorBorrar), 'Atención', MB_ICONWARNING or MB_OK);
end;


procedure TBizFacturasCliente.BeforeDelete(Sender: TDADataTable);
begin
  inherited;
  FMasterDeleting := True;  // Para que los detalles de borren de golpe y no recalcule posiciones ni totales
end;

procedure TBizFacturasCliente.AfterDelete(Sender: TDADataTable);
begin
  inherited;
  FMasterDeleting := False;
end;

procedure TBizFacturasCliente.Print;
begin
  dmFacturasCliente.Print(Self.CODIGO);
end;

procedure TBizFacturasCliente.OnPostError(DataTable: TDADataTable;
  Error: EDatabaseError; var Action: TDataAction);
begin
  inherited;
  Action := daAbort;
  if (Pos('Nombre', Error.Message) > 0) then
     MessageBox(0, PChar(msgLitClienteObligatorio), 'Atención', MB_ICONWARNING or MB_OK)
  else if (Pos('Fecha', Error.Message) > 0) then
     MessageBox(0, PChar(msgLitFechaObligatorio), 'Atención', MB_ICONWARNING or MB_OK)
  else
     raise Error;
end;

procedure TBizFacturasCliente.BeforeApplyUpdates(Sender: TDADataTable;
  const Delta: IDADelta);
var
  i : integer;
begin
  for i := 0 to Delta.Count - 1 do
    case Delta.Changes[i].ChangeType of
      ctInsert, ctUpdate : ValidarFacturaCliente(Self);
      //ctDelete : 
    end;
end;

function TBizDetallesFacturasCliente.PuedoLanzarEvento: Boolean;
begin
  Result := FPuedoLanzarEvento;
end;

procedure TBizDetallesFacturasCliente.RecalcularImporte;
begin
  RecalcularImporteDetalle(Self.DataTable, True, False);
end;

procedure TBizFacturasCliente.RecalcularImporte;
begin
  RecalcularImportesCabecera(Self.DataTable, Detalles.DataTable);
end;

procedure TBizDetallesFacturasCliente.Refrescar;
begin
  DataTable.Refresh;
end;

procedure TBizDetallesFacturasCliente.SetCANTIDADValue(const aValue: Integer);
begin
  if aValue = 0
  then DataTable.Fields[idx_DetallesFacturasClienteCANTIDAD].AsVariant := Null
  else inherited;
end;

procedure TBizDetallesFacturasCliente.SetIMPORTETOTALValue(const aValue: Currency);
begin
  if aValue = 0
  then DataTable.Fields[idx_DetallesFacturasClienteIMPORTETOTAL].AsVariant := Null
  else inherited;
end;

procedure TBizDetallesFacturasCliente.SetIMPORTEUNIDADValue(const aValue: Currency);
begin
  if aValue = 0 then
    DataTable.Fields[idx_DetallesFacturasClienteIMPORTEUNIDAD].AsVariant := Null
  else
    inherited;
end;

procedure TBizFacturasCliente.setReferencia(const ClaseFactura: String);
begin
  if not (Self.DataTable.State in dsEditModes) then
     Self.DataTable.Edit;

  if ClaseFactura = CTE_PROFORMA
  then Self.REFERENCIA := dmFacturasCliente.DarNuevaReferencia(CTE_PROFORMA)
  else Self.REFERENCIA := dmFacturasCliente.DarNuevaReferencia(CTE_NORMAL);
end;

{ TBizClaseFacturaFieldRules }

procedure TBizFacturasCliente.cambiarSigno;
var
  ACursor: TCursor;
begin
  if not (State in dsEditModes) then
    Edit;
  ACursor := Screen.Cursor;
  Screen.Cursor := crHourGlass;
  Application.ProcessMessages;
  try

    Detalles.cambiarSigno;
    RecalcularImporte;

  finally
    Screen.Cursor := ACursor;
  end;
end;

{procedure TBizFacturasCliente.SetCLASEFACTURAValue(const aValue: String);
begin
  showmessage('Antiguo valor' + CLASEFACTURA);
  showmessage('Nuevo valor' + aValue);

  inherited;
end;}

{function TBizFacturasCliente.GetObra: IBizObraRelacionada;
begin
  if not Assigned(FObra) then
    FObra := GetItem(CODIGOOBRA)
  else
    if (CODIGOOBRA <> FObra.Codigo) and
       not (FObra.DataTable.State in dsEditModes) then
      FObra := GetItem(CODIGOOBRA);

  if not FObra.DataTable.Active then
     FObra.DataTable.Active := True;

  Result := FObra;
end;

procedure TBizFacturasCliente.SetObra(const Value: IBizObraRelacionada);
var
  bEnEdicion : Boolean;
begin
  bEnEdicion := (DataTable.State in dsEditModes);
  if not bEnEdicion then
    Edit;
  FObra := Value;
  if Assigned(FObra) then
  begin
    CODIGOOBRA := FObra.CODIGO;
    Cliente := FObra.Cliente;
    Post;

    if bEnEdicion then
      Edit;
  end
end;}

{ TBizFacturasObra }

{procedure TBizFacturasObra.Show;
begin
  inherited;
  ShowEditor(IBizFacturasObra, Self, etItem);
end;}

initialization
  FMasterDeleting := False;
  RegisterDataTableRules(BIZ_DETALLESFACTURASCLIENTE, TBizDetallesFacturasCliente);
  RegisterDataTableRules(BIZ_FACTURASCLIENTE, TBizFacturasCliente);
 // RegisterDataTableRules(BIZ_FACTURASOBRA, TBizFacturasObra);

finalization

end.
