AbetoDesign_FactuGES2/Source/Modulos/Facturas de cliente/Controller/uFacturasClienteController.pas

1480 lines
52 KiB
ObjectPascal
Raw Normal View History

unit uFacturasClienteController;
interface
uses
Classes, SysUtils, Variants, uDADataTable, uControllerBase, uIDataModuleFacturasCliente,
uClientesController, uDetallesFacturaClienteController, uBizAlbaranesCliente,
uBizFacturasCliente, uBizDireccionesContacto;
type
IFacturasClienteController = interface(IControllerBase)
['{CAD20B4E-6D0B-4A1C-9306-B195824B6CAD}']
function GetClienteController: IClientesController;
procedure SetClienteController(const Value: IClientesController);
property ClienteController: IClientesController read GetClienteController write SetClienteController;
function GetDetallesController: IDetallesFacturaClienteController;
procedure SetDetallesController(const Value: IDetallesFacturaClienteController);
property DetallesController: IDetallesFacturaClienteController read GetDetallesController write SetDetallesController;
function Buscar(const ID: Integer): IBizFacturaCliente;
function BuscarTodos: IBizFacturaCliente;
function BuscarTodasPendientesComision(IdAgente: Integer; IdComision: Integer; IdFacturasAsociadas: String): IBizFacturaCliente;
procedure Ver(AFactura : IBizFacturaCliente);
procedure VerTodos(AFacturas: IBizFacturaCliente);
function Nuevo (WithInsert: Boolean = True) : IBizFacturaCliente;
function Anadir(AFactura : IBizFacturaCliente) : Boolean; overload;
function AnadirAbono(AFactura : IBizFacturaCliente) : Boolean;
function Anadir(AFacturas : IBizFacturaCliente; AListaAlbaranes : IBizAlbaranCliente): Boolean; overload;
function Eliminar(const ID : Integer): Boolean; overload;
function Eliminar(AFactura : IBizFacturaCliente; AllItems: Boolean = false; AListaCausas: TStringList = nil): Boolean; overload;
function Guardar(AFactura : IBizFacturaCliente): Boolean;
procedure DescartarCambios(AFactura : IBizFacturaCliente);
function Existe(const ID: Integer) : Boolean;
procedure RecuperarCliente(AFactura : IBizFacturaCliente);
procedure ActualizarFormaDePago(AFactura : IBizFacturaCliente; ID_FORMA_PAGO: Integer);
function Duplicar(AFactura: IBizFacturaCliente): IBizFacturaCliente;
function GenerarAbono(AFactura: IBizFacturaCliente): IBizFacturaCliente;
procedure Preview(AFactura : IBizFacturaCliente; AllItems: Boolean = false; VerLogotipo: Boolean = true);
procedure Print(AFactura : IBizFacturaCliente; AllItems: Boolean = false; VerLogotipo: Boolean = true);
procedure RecalcularImportes(AFactura: IBizFacturaCliente);
function ElegirFacturas(AFacturas : IBizFacturaCliente; AMensaje: String; AMultiSelect: Boolean): IBizFacturaCliente;
function ExtraerSeleccionados(ARecibosCliente: IBizFacturaCliente) : IBizFacturaCliente;
procedure CopiarDireccion (const ADireccionEnvio: IBizDireccionesContacto; AFactura: IBizFacturaCliente);
procedure SetIgnorarContabilidad (AFactura: IBizFacturaCliente; const Ignorar: Integer);
function DarListaAnosFacturas: TStringList;
procedure FiltrarAno(AFactura: IBizFacturaCliente; ADynWhereDataTable: WideString; const Ano: String);
end;
TFacturasClienteController = class(TControllerBase, IFacturasClienteController)
private
FDataModule : IDataModuleFacturasCliente;
FClienteController : IClientesController;
FDetallesController : IDetallesFacturaClienteController;
function GetClienteController: IClientesController;
procedure SetClienteController(const Value: IClientesController);
function GetDetallesController: IDetallesFacturaClienteController;
procedure SetDetallesController(const Value: IDetallesFacturaClienteController);
function CreateEditor(const AName : String; const IID: TGUID; out Intf): Boolean;
function _Vacio : IBizFacturaCliente;
procedure FiltrarEmpresa(AFactura: IBizFacturaCliente);
function ValidarFactura(AFactura: IBizFacturaCliente): Boolean;
procedure GenerarRecibos(AFactura: IBizFacturaCliente);
protected
procedure RecibirAviso(ASujeto: ISujeto; ADataTable: IDAStronglyTypedDataTable); override;
public
property ClienteController: IClientesController read GetClienteController write SetClienteController;
property DetallesController: IDetallesFacturaClienteController read GetDetallesController write SetDetallesController;
constructor Create; override;
destructor Destroy; override;
function Eliminar(const ID : Integer): Boolean; overload;
function Eliminar(AFactura : IBizFacturaCliente; AllItems: Boolean = false; AListaCausas: TStringList = nil): Boolean; overload;
function Guardar(AFactura : IBizFacturaCliente): Boolean;
procedure DescartarCambios(AFactura : IBizFacturaCliente); virtual;
function Existe(const ID: Integer) : Boolean; virtual;
function Anadir(AFactura : IBizFacturaCliente): Boolean; overload;
function AnadirAbono(AFactura : IBizFacturaCliente) : Boolean;
function Anadir(AFacturas : IBizFacturaCliente; AListaAlbaranes : IBizAlbaranCliente): Boolean; overload;
function Buscar(const ID: Integer): IBizFacturaCliente;
function BuscarTodos: IBizFacturaCliente;
function BuscarTodasPendientesComision(IdAgente: Integer; IdComision: Integer; IdFacturasAsociadas: String): IBizFacturaCliente;
function Nuevo (WithInsert: Boolean = True) : IBizFacturaCliente;
procedure Ver(AFactura : IBizFacturaCliente);
procedure VerTodos(AFacturas: IBizFacturaCliente);
function Duplicar(AFactura: IBizFacturaCliente): IBizFacturaCliente;
function GenerarAbono(AFactura: IBizFacturaCliente): IBizFacturaCliente;
procedure RecuperarCliente(AFactura : IBizFacturaCliente);
procedure ActualizarFormaDePago(AFactura : IBizFacturaCliente; ID_FORMA_PAGO: Integer);
procedure Preview(AFactura : IBizFacturaCliente; AllItems: Boolean = false; VerLogotipo: Boolean = true);
procedure Print(AFactura : IBizFacturaCliente; AllItems: Boolean = false; VerLogotipo: Boolean = true);
procedure RecalcularImportes(AFactura: IBizFacturaCliente);
function EsModificable(AFactura: IBizFacturaCliente; var AComentario: Variant): Boolean;
function EsEliminable(AFactura: IBizFacturaCliente; var AComentario: Variant): Boolean;
function ElegirFacturas(AFacturas : IBizFacturaCliente; AMensaje: String; AMultiSelect: Boolean): IBizFacturaCliente;
function ExtraerSeleccionados(AFacturasCliente: IBizFacturaCliente) : IBizFacturaCliente;
procedure CopiarDireccion (const ADireccionEnvio: IBizDireccionesContacto; AFactura: IBizFacturaCliente);
procedure SetIgnorarContabilidad (AFactura: IBizFacturaCliente; const Ignorar: Integer);
function DarListaAnosFacturas: TStringList;
procedure FiltrarAno(AFactura: IBizFacturaCliente; ADynWhereDataTable: WideString; const Ano: String);
end;
implementation
{$INCLUDE ..\..\..\FactuGES.inc}
uses
Windows, uDateUtils, uNumUtils, Controls, cxControls, DB, uEditorRegistryUtils, schFacturasClienteClient_Intf,
uBizContactos, uIEditorFacturasCliente, uIEditorFacturaCliente, uFactuGES_App,
uDataModuleFacturasCliente, uBizDetallesFacturaCliente, uControllerDetallesBase,
uDataModuleUsuarios, uDAInterfaces, uDataTableUtils, uAlbaranesClienteController,
schAlbaranesClienteClient_Intf, uROTypes, uDetallesAlbaranClienteController,
uBizDetallesAlbaranCliente, uFacturasClienteReportController, DateUtils, Forms,
Dialogs, uIntegerListUtils, uIEditorElegirFacturasCliente,
uFormasPagoController, uBizFormasPago, uTiposIVAController, uBizTiposIVA,
uBizEjercicios, uRecibosClienteController, uBizRecibosCliente;
procedure CopiarArticulosAlbaran(AOrigen: IBizDetallesAlbaranCliente;
ADestino : IBizDetallesFacturaCliente);
var
i : integer;
ADetallesController : IDetallesFacturaClienteController;
begin
if not Assigned(AOrigen) then
raise Exception.Create ('Origen no asignado (CopiarArticulosAlbaran)');
if not Assigned(ADestino) then
raise Exception.Create ('Destino no asignado (CopiarArticulosAlbaran)');
if not AOrigen.DataTable.Active then
AOrigen.DataTable.Active := True;
if not ADestino.DataTable.Active then
ADestino.DataTable.Active := True;
ADetallesController := TDetallesFacturaClienteController.Create;
try
//OJO IMPORTANTE
//Siempre que vayamos a trabajar con los detalles debemos hacer un beginupdate de los mismos y un endupdate para
//obligarle siempre a recalcular los detalles una sola vez
ADetallesController.BeginUpdate(ADestino);
AOrigen.DataTable.First;
for i := 0 to AOrigen.DataTable.RecordCount - 1 do
begin
ADetallesController.Add(ADestino, TIPO_DETALLE_CONCEPTO);
ADestino.Edit;
// ADestino.REFERENCIA := AOrigen.REFERENCIA;
if AOrigen.ID_ARTICULO > 0 then
ADestino.ID_ARTICULO := AOrigen.ID_ARTICULO;
//En el caso de descuento de capitulo debemos a<>adirlo como una linea detalle con un descuento
if (AOrigen.TIPO_DETALLE = TIPO_DETALLE_DESCUENTO)
and (AOrigen.DESCUENTO > 0) then
begin
ADestino.CONCEPTO := AOrigen.CONCEPTO + AOrigen.DataTable.FieldByName(fld_AlbaranesCliente_DetallesDESCUENTO).AsString + ' %';
ADestino.CANTIDAD := 1;
ADestino.IMPORTE_UNIDAD := AOrigen.IMPORTE_TOTAL;
end
else
begin
ADestino.CONCEPTO := AOrigen.CONCEPTO;
ADestino.CANTIDAD := AOrigen.CANTIDAD;
ADestino.DESCUENTO := AOrigen.DESCUENTO;
ADestino.IMPORTE_UNIDAD := AOrigen.IMPORTE_UNIDAD;
end;
ADestino.IMPORTE_TOTAL := AOrigen.IMPORTE_TOTAL;
ADestino.IMPORTE_PORTE := AOrigen.IMPORTE_PORTE;
ADestino.VISIBLE := AOrigen.VISIBLE;
ADestino.VALORADO := AOrigen.VALORADO;
// ADestino.REFERENCIA_PROVEEDOR := AOrigen.REFERENCIA_PROVEEDOR;
ADestino.Post;
AOrigen.Next;
end;
finally
ADetallesController.EndUpdate(ADestino);
ADetallesController := NIL;
end;
end;
{ TFacturasClienteController }
function TFacturasClienteController.Anadir(AFactura: IBizFacturaCliente) : Boolean;
begin
if not Assigned(AFactura) then
raise Exception.Create ('Factura no asignada (Anadir)');
AFactura.Insert;
Result := True;
end;
function TFacturasClienteController.AnadirAbono(AFactura: IBizFacturaCliente): Boolean;
begin
Anadir(AFactura);
AFactura.TIPO := CTE_TIPO_ABONO;
Result := True;
end;
procedure TFacturasClienteController.ActualizarFormaDePago(
AFactura: IBizFacturaCliente; ID_FORMA_PAGO: Integer);
var
AFormasPago : IBizFormaPago;
AFormasPagoController : IFormasPagoController;
ATiposIVA : IBizTipoIVA;
ATiposIVAController : ITiposIVAController;
bEnEdicion : Boolean;
begin
AFormasPagoController := TFormasPagoController.Create;
AFormasPago := AFormasPagoController.Buscar(ID_FORMA_PAGO);
AFormasPago.Open;
//Se cambia tambien el tipo de IVA por el de la ficha a peticion de Angelica
ATiposIVAController := TTiposIVAController.Create;
ATiposIVA := ATiposIVAController.Buscar(AFactura.Cliente.ID_TIPO_IVA);
ATiposIVA.Open;
bEnEdicion := (AFactura.DataTable.State in dsEditModes);
if not bEnEdicion then
AFactura.Edit;
AFactura.ID_FORMA_PAGO := AFormasPago.ID;
// AFactura.DataTable.FieldByName(fld_FacturasClienteFORMA_PAGO).AsString := AFormasPago.DESCRIPCION;
AFactura.ID_TIPO_IVA := ATiposIva.ID;
if not bEnEdicion then
AFactura.Post;
AFormasPago := NIL;
AFormasPagoController := NIL;
ATiposIVA := NIL;
ATiposIVAController := NIL;
end;
function TFacturasClienteController.Anadir(AFacturas: IBizFacturaCliente;
AListaAlbaranes: IBizAlbaranCliente): Boolean;
var
AFacturaActual : IBizFacturaCliente;
AAlbaranesController : IAlbaranesClienteController;
ACadena: String;
I, x: Integer;
bEnEdicion : Boolean;
begin
Result := False;
// ATENCI<43>N!!! AFacturas tiene que estar vacio para no pisar facturas
// ya generadas.
if not Assigned(AFacturas) then
raise Exception.Create ('Factura no asignada (Anadir)');
if not Assigned(AListaAlbaranes) then
raise Exception.Create ('Albaranes no asignados (Anadir)');
if not AFacturas.DataTable.Active then
AFacturas.DataTable.Active := True;
if not AListaAlbaranes.DataTable.Active then
AListaAlbaranes.DataTable.Active := True;
ShowHourglassCursor;
Application.ProcessMessages;
AAlbaranesController := TAlbaranesClienteController.Create;
try
// Ordenar por fecha de albaran
AListaAlbaranes.DataTable.Sort([fld_AlbaranesClienteFECHA_ALBARAN], [uDADataTable.sdAscending]);
AListaAlbaranes.First;
for I := 0 to AListaAlbaranes.DataTable.RecordCount - 1 do
begin
AListaAlbaranes._Cliente := NIL;
AFacturaActual := NIL;
// Busco si hay alguna factura ya hecha de ese cliente
AFacturas.DataTable.First;
if AFacturas.DataTable.Locate(fld_FacturasClienteID_CLIENTE, AListaAlbaranes.ID_CLIENTE, []) then
begin
AFacturaActual := AFacturas;
RecuperarCliente(AFacturaActual);
AFacturaActual.Cliente.DataTable.Active := True;
//En este caso no queremos el descuento general del cliente asociado a su ficha, ya que partimos del valor que tengan las olbaranes
bEnEdicion := (AFacturaActual.DataTable.State in dsEditModes);
if not bEnEdicion then
AFacturaActual.Edit;
AFacturaActual.DESCUENTOIsNull := True;
AFacturaActual.Post;
if bEnEdicion then
AFacturaActual.Edit;
end
else begin
// No hay factura de ese cliente. Creo una nueva
Anadir(AFacturas);
AAlbaranesController.RecuperarCliente(AListaAlbaranes);
AListaAlbaranes.Cliente.DataTable.Active := True;
AFacturas.Cliente := AListaAlbaranes.Cliente;
//Establecemos la forma de pago establecido en la ficha del cliente
if AFacturas.Cliente.ID_FORMA_PAGO > 0 then
AFacturas.ID_FORMA_PAGO := AFacturas.Cliente.ID_FORMA_PAGO;
// if AFacturas.Cliente.ID_TIPO_IVA > 0 then
// AFacturas.ID_TIPO_IVA := AFacturas.Cliente.ID_TIPO_IVA;
//En este caso no queremos el descuento general del cliente asociado a su ficha, ya que partimos del valor que tengan las olbaranes
bEnEdicion := (AFacturas.DataTable.State in dsEditModes);
if not bEnEdicion then
AFacturas.Edit;
AFacturas.DESCUENTOIsNull := True;
AFacturas.Post;
if bEnEdicion then
AFacturas.Edit;
//Si el albaran es de tipo devoluci<63>n hacemos la factura de tipo abono
if (AListaAlbaranes.TIPO = CTE_TIPO_ALBARAN_DEV) then
begin
bEnEdicion := (AFacturas.DataTable.State in dsEditModes);
if not bEnEdicion then
AFacturas.Edit;
AFacturas.TIPO := CTE_TIPO_ABONO;
AFacturas.Post;
if bEnEdicion then
AFacturas.Edit;
end;
AFacturaActual := AFacturas;
end;
// Ya tengo la factura. Le a<>ado los conceptos del albar<61>n
AFacturaActual.Detalles.DataTable.Sort([fld_FacturasCliente_DetallesPOSICION], [uDADataTable.sdAscending]);
AFacturaActual.Detalles.DataTable.Last;
// A<>ado el t<>tulo, se cambia a petici<63>n por linea de concepto con resumen del albaran correspondiente, SE SOLICITA QUITAR POR M<>NICA 16/06/2020
Self.DetallesController.Add(AFacturaActual.Detalles, TIPO_DETALLE_CONCEPTO);
with AFacturaActual.Detalles do
begin
ACadena := '';
ACadena := 'Albar<61>n ' + AListaAlbaranes.REFERENCIA + ' de ' + DateToStr(AListaAlbaranes.FECHA_ALBARAN);
Edit;
CONCEPTO := ACadena;
Post;
end;
// A<>ado el contenido del albar<61>n
CopiarArticulosAlbaran(AListaAlbaranes.Detalles, AFacturaActual.Detalles);
//MUCHO CUIDADO NOS TENEMOS QUE ASEGURAR DE A<>ADIR AL FINAL DEL TODO, podr<64>a calcular mal los descuentos de capitulo de la factura si los hubiera
AFacturaActual.Detalles.DataTable.Sort([fld_FacturasCliente_DetallesPOSICION], [uDADataTable.sdAscending]);
AFacturaActual.Detalles.DataTable.Last;
//Sacamos el importe del porte en el caso de tener
if (AListaAlbaranes.IMPORTE_PORTE > 0) then
begin
Self.DetallesController.Add(AFacturaActual.Detalles, TIPO_DETALLE_CONCEPTO);
with AFacturaActual.Detalles do
begin
Edit;
CONCEPTO := 'Porte del albar<61>n';
CANTIDAD := 1;
IMPORTE_UNIDAD := AListaAlbaranes.IMPORTE_PORTE;
Post;
end;
end;
//Sacamos el descuento total del albaran en el caso de tener
if (AListaAlbaranes.IMPORTE_DESCUENTO > 0) then
begin
Self.DetallesController.Add(AFacturaActual.Detalles, TIPO_DETALLE_CONCEPTO);
with AFacturaActual.Detalles do
begin
Edit;
CONCEPTO := 'Descuento del albar<61>n ' + AListaAlbaranes.REFERENCIA + ' - ' + AListaAlbaranes.DataTable.FieldByName(fld_AlbaranesClienteDESCUENTO).AsString + '%';
CANTIDAD := -1;
IMPORTE_UNIDAD := AListaAlbaranes.IMPORTE_DESCUENTO;
Post;
end;
end;
// A<>ado el resumen SE SOLICITA QUITAR POR M<>NICA 16/06/2020
// Self.DetallesController.Add(AFacturaActual.Detalles, TIPO_DETALLE_SUBTOTAL);
// with AFacturaActual.Detalles do
// begin
// Edit;
// CONCEPTO := 'Total del albar<61>n ' + AListaAlbaranes.REFERENCIA;
// Post;
// end;
// A<>ado una l<>nea en blanco
Self.DetallesController.Add(AFacturaActual.Detalles, TIPO_DETALLE_CONCEPTO);
with AFacturaActual.Detalles do
begin
Edit;
CONCEPTO := '';
Post;
end;
// Guardo la factura que acabo de generar o editar
AFacturaActual.CalcularImporteTotal;
Self.Guardar(AFacturaActual);
// Asocio la factura con el albar<61>n
AListaAlbaranes.Edit;
AListaAlbaranes.ID_FACTURA := AFacturaActual.ID;
AListaAlbaranes.Post;
AAlbaranesController.Guardar(AListaAlbaranes);
AListaAlbaranes.Next;
end;
Result := True;
finally
AAlbaranesController := NIL;
HideHourglassCursor
end;
end;
{function TFacturasClienteController.Anadir(AFactura: IBizFacturaCliente;
const IDPedido: Integer): Boolean;
var
APedidosController : IPedidosClienteController;
APedido : IBizPedidoCliente;
begin
Result := False;
if not Assigned(AFactura) then
raise Exception.Create ('Factura no asignada (Anadir)');
if (IDPedido < 0) or (IDPedido = 0) then
raise Exception.Create (Format('ID de pedido (%d) incorrecto (Anadir)', [IDPedido]));
if not AFactura.DataTable.Active then
AFactura.DataTable.Active := True;
ShowHourglassCursor;
Application.ProcessMessages;
APedido := NIL;
APedidosController := TPedidosClienteController.Create;
try
APedido := APedidosController.Buscar(IDPedido);
if not Assigned(APedido) then
raise Exception.Create (Format('No se ha encontrado un pedido de cliente con ID %d (Anadir)', [IDPedido]));
APedido.DataTable.Active := True;
APedidosController.RecuperarCliente(APedido);
Self.Anadir(AFactura);
AFactura.Cliente := APedido.Cliente;
CopiarArticulosPedido(APedido.Detalles, AFactura.Detalles);
// Guardo la factura que acabo de generar
AFactura.CalcularImporteTotal;
Self.Guardar(AFactura);
Result := True;
finally
APedido := NIL;
APedidosController := NIL;
HideHourglassCursor;
Application.ProcessMessages;
end;
end;}
function TFacturasClienteController.Buscar(const ID: Integer): IBizFacturaCliente;
begin
Result := (FDataModule as IDataModuleFacturasCliente).GetItem(ID);
FiltrarEmpresa(Result);
end;
function TFacturasClienteController.BuscarTodasPendientesComision(IdAgente:Integer; IdComision: Integer; IdFacturasAsociadas: String): IBizFacturaCliente;
var
Condicion: TDAWhereExpression;
Condicion1: TDAWhereExpression;
Condicion2: TDAWhereExpression;
Condicion3: TDAWhereExpression;
Condicion4: TDAWhereExpression;
Cadena : TStringList;
i: Integer;
begin
ShowHourglassCursor;
try
Result := BuscarTodos;
with Result.DataTable.DynamicWhere do
begin
//Todas las facturas que sean comisionables
Condicion := NewBinaryExpression(NewField('', fld_FacturasClienteSIN_COMISION), NewConstant(0, datInteger), dboEqual);
if IsEmpty then
Expression := Condicion
else
Expression := NewBinaryExpression(Expression, Condicion, dboAnd);
end;
with Result.DataTable.DynamicWhere do
begin
//Todas las facturas de esta liquidaci<63>n
Condicion1 := NewBinaryExpression(NewField('', fld_FacturasClienteID_COMISION_LIQUIDADA), NewConstant(IdComision, datInteger), dboEqual);
//Todas aquellas facturas que ya esten asociadas a la liquidaci<63>n actual no deben salir
if (Length(IdFacturasAsociadas) > 0) then
begin
Cadena := TStringList.Create;
Cadena.CommaText := IdFacturasAsociadas;
Condicion2 := nil;
//Vamos generando todas las where de cada uno de los ID recibidos por parametro
for i := 0 to Cadena.Count - 1 do
with Result.DataTable.DynamicWhere do
begin
Condicion4 := NewBinaryExpression(NewField('', fld_FacturasClienteID), NewConstant(StrToInt(Cadena.Strings[i]), datInteger), dboNotEqual);
if Condicion2 = nil then
Condicion2 := Condicion4
else
Condicion2 := NewBinaryExpression(Condicion2, Condicion4, dboAnd);
end;
Cadena.Free;
end;
//Todas aquellas que no esten asociadas a ninguna liquidaci<63>n, y que tampoco esten en el editor, ya que en cache estan
//asociadas a la liquidadcion pero en datos me viene como nula
Condicion3 := NewBinaryExpression(NewField('', fld_FacturasClienteID_COMISION_LIQUIDADA), NewNull(), dboEqual);
//Si no hay facturas en el editor no las tenemos en cuenta
if (Condicion2 <> nil) then
begin
Condicion1 := NewBinaryExpression(Condicion1, Condicion2, dboAnd);
Condicion3 := NewBinaryExpression(Condicion3, Condicion2, dboAnd);
end;
// Todas aquellas facturas asociadas a la comisi<73>n actual y que no est<73>n asociadas al editor (IdFacturasAsociadas)
//esto es porque se puede agregar y quitar facturas y todos los cambios estan en cache
// y por lo tanto al pedir las facturas a seleccionar debemos tener en cuenta que en el
//almac<61>n dichos cambios cache todav<61>a no se han producido
Condicion := NewBinaryExpression(Condicion1, Condicion3, dboOr);
if IsEmpty then
Expression := Condicion
else
Expression := NewBinaryExpression(Expression, Condicion, dboAnd);
end;
finally
HideHourglassCursor;
end;
end;
function TFacturasClienteController.BuscarTodos: IBizFacturaCliente;
begin
Result := FDataModule.GetItems;
FiltrarEmpresa(Result);
end;
procedure TFacturasClienteController.CopiarDireccion(
const ADireccionEnvio: IBizDireccionesContacto; AFactura: IBizFacturaCliente);
var
bEnEdicion : Boolean;
begin
if not Assigned(AFactura) then
raise Exception.Create ('Factura no asignado (CopiarDireccionEnvio)');
if not Assigned(ADireccionEnvio) then
raise Exception.Create ('No se ha indicado la direcci<63>n (CopiarDireccionEnvio)');
if AFactura.DataTable.Active then
AFactura.DataTable.Active := True;
if ADireccionEnvio.DataTable.Active then
ADireccionEnvio.DataTable.Active := True;
bEnEdicion := (AFactura.DataTable.State in dsEditModes);
if not bEnEdicion then
AFactura.Edit;
ShowHourglassCursor;
AFactura.Edit;
try
AFactura.CALLE := ADireccionEnvio.CALLE;
AFactura.POBLACION := ADireccionEnvio.POBLACION;
AFactura.CODIGO_POSTAL := ADireccionEnvio.CODIGO_POSTAL;
AFactura.PROVINCIA := ADireccionEnvio.PROVINCIA;
AFactura.NIF_CIF := ADireccionEnvio.NIF_CIF;
AFactura.NOMBRE := ADireccionEnvio.NOMBRE;
if not bEnEdicion then
AFactura.Post;
finally
HideHourglassCursor;
end;
end;
constructor TFacturasClienteController.Create;
begin
inherited;
FDataModule := TDataModuleFacturasCliente.Create(Nil);
FClienteController := TClientesController.Create;
FDetallesController := TDetallesFacturaClienteController.Create;
FDetallesController.addObservador(Self);
end;
function TFacturasClienteController.CreateEditor(const AName: String;
const IID: TGUID; out Intf): Boolean;
begin
Result := Supports(EditorRegistry.CreateEditor(AName), IID, Intf);
end;
function TFacturasClienteController.DarListaAnosFacturas: TStringList;
begin
Result := FDataModule.GetAnosItems;
end;
procedure TFacturasClienteController.DescartarCambios(AFactura: IBizFacturaCliente);
begin
if not Assigned(AFactura) then
raise Exception.Create ('Factura no asignada');
ShowHourglassCursor;
try
if (AFactura.State in dsEditModes) then
AFactura.Cancel;
AFactura.DataTable.CancelUpdates;
finally
HideHourglassCursor;
end;
end;
destructor TFacturasClienteController.Destroy;
begin
FDataModule := Nil;
FClienteController := Nil;
FDetallesController := Nil;
inherited;
end;
function TFacturasClienteController.Duplicar(AFactura: IBizFacturaCliente): IBizFacturaCliente;
begin
Result := Self._Vacio;
ShowHourglassCursor;
try
DuplicarRegistros(AFactura.DataTable, Result.DataTable, mdrActual);
DuplicarRegistros(AFactura.Detalles.DataTable, Result.Detalles.DataTable, mdrTodos);
// Hay que dejar algunos campos como si fuera una factura nueva
Result.Edit;
with Result do
begin
ID_EMPRESA := AppFactuGES.EmpresaActiva.ID;
ID_TIENDA := AppFactuGES.TiendaActiva.ID;
USUARIO := AppFactuGES.UsuarioActivo.UserName;
REFERENCIA := ''; //Para que se asigne una nueva
SITUACION := CTE_PENDIENTE; //Al ser una nueva debe de estar pendiente
FECHA_FACTURA := DateOf(Now);
ID_COMISION_LIQUIDADA := 0;
{$IFDEF CONTABILIDAD}
ID_EJERCICIO := AppFactuGES.EjercicioActivo.ID;
ESTADO_EJERCICIO := AppFactuGES.EjercicioActivo.ESTADO;
ASIENTO_PUNTEADO := -1;
//En el caso de que el ejercicio este cerrado dejamos duplicar factura sin asociar a contabilidad.
if ESTADO_EJERCICIO = CTE_CERRADO then
begin
IGNORAR_CONTABILIDAD := 1;
ESTADO_EJERCICIO := '';
end;
{$ENDIF}
end;
Result.Post;
finally
HideHourglassCursor;
end;
end;
function TFacturasClienteController.ValidarFactura(AFactura: IBizFacturaCliente): Boolean;
var
AFormaPago: IBizFormaPago;
begin
Result := False;
if not Assigned(AFactura) then
raise Exception.Create ('Factura no asignada');
if (AFactura.DataTable.State in dsEditModes) then
AFactura.DataTable.Post;
//Tambien hacemos post de sus tablas hija
if (AFactura.Detalles.DataTable.State in dsEditModes) then
AFactura.Detalles.DataTable.Post;
if (AFactura.ID_CLIENTE < 0) or (AFactura.ID_CLIENTE = 0) then
// No comprobar el objeto Cliente por que puede fallar la validaci<63>n
// cuando se generan facturas autom<6F>ticamente.
{ (not Assigned(AFactura.Cliente)) or
(AFactura.Cliente.IsEmpty) then}
raise Exception.Create('Debe indicar el cliente de esta factura');
if (EsFechaVacia(AFactura.FECHA_FACTURA)) then
raise Exception.Create('Debe indicar la fecha de esta factura');
//En el caso de asignar una retenci<63>n a la factura ser<65> obligatorio meter la fecha de retenci<63>n.
if (AFactura.IMPORTE_RETENCION > 0) then
if (EsFechaVacia(AFactura.FECHA_RETENCION)) then
raise Exception.Create('Debe indicar la fecha de vencimiento de la retenci<63>n, para poder asociarla al recibo que contendr<64> el importe de la retenci<63>n.');
if (AFactura.Detalles.DataTable.RecordCount = 0) then
raise Exception.Create('La factura debe tener al menos un concepto en su contenido');
if (AFactura.ID_FORMA_PAGO = 0) then
raise Exception.Create('Debe indicar una forma de pago para esta factura');
//De esta forma obligaremos siempre a tener un recibo asociado a la factura,
//porque si la forma de pago no tiene plazos es obligatorio la fecha de vencimiento
//OJO-----En facturas de cliente para acana no es obligatorio porque deben de poder generar facturas sin recibos asociados
{ with TFormasPagoController.Create do
begin
try
AFormaPago := Buscar(AFactura.ID_FORMA_PAGO);
AFormaPago.DataTable.Active := True;
if (AFormaPago.Plazos.RecordCount = 0)
and (EsFechaVacia(AFactura.FECHA_VENCIMIENTO)) then
raise Exception.Create('Debe indicar una fecha de vencimiento para esta factura');
finally
AFormaPago := NIL;
Free;
end;
end;
}
{$IFDEF CONTABILIDAD}
if (AFactura.IGNORAR_CONTABILIDAD = 0) then
begin
if (AppFactuGES.EjercicioActivo.ESTADO = CTE_CERRADO) then
raise Exception.Create('Para que la factura pueda pasar a la parte contable el ejercicio activo debe esta ABIERTO');
if ((AFactura.Cliente.SubCuentas.ID < 1) or (AFactura.Cliente.SubCuentas.ID_EJERCICIO <> AppFactuGES.EjercicioActivo.ID)) then
raise Exception.Create('Para que la factura pueda pasar la parte contable es necesario que el cliente tenga asignada una subcuenta');
end;
{$ENDIF}
//En caso de ser un Abono no podra tener un importe total positivo
if (AFactura.TIPO = CTE_TIPO_ABONO) then
if (AFactura.IMPORTE_TOTAL > 0) then
raise Exception.Create('Un abono nunca no puede tener un importe positivo, asegurese que las cantidades sean negativas');
{ Esta validaci<EFBFBD>n puede saltar cuando se generan facturas autom<EFBFBD>ticamente
por albaranes o pedidos y el cliente no tiene Tipo de IVA puesto, se cambia,
para signar autom<EFBFBD>ticamente por defecto a la factura la primera forma de pago,
e iva disponible (CONTADO, IVA16), en la clase de negocio }
{ if (AFactura.ID_TIPO_IVA = 0) then
raise Exception.Create('Debe indicar un tipo de IVA para esta factura');}
{ Asegurarse de valores en campos "autom<6F>ticos" tanto
en MODIFICACI<EFBFBD>N como en INSERCI<EFBFBD>N. }
AFactura.Edit;
try
AFactura.USUARIO := AppFactuGES.UsuarioActivo.UserName;
if Assigned(AFactura.Cliente)
and (AFactura.ID_CLIENTE <> AFactura.Cliente.ID) then
AFactura.ID_CLIENTE := AFactura.Cliente.ID;
Result := True;
finally
AFactura.Post;
end;
end;
procedure TFacturasClienteController.Ver(AFactura: IBizFacturaCliente);
var
AEditor : IEditorFacturaCliente;
AComentario : Variant;
begin
AEditor := NIL;
RecuperarCliente(AFactura);
CreateEditor('EditorFacturaCliente', IEditorFacturaCliente, AEditor);
if Assigned(AEditor) then
try
AEditor.Controller := Self; //OJO ORDEN MUY IMPORTANTE
AEditor.Factura := AFactura;
//MODO CONSULTAR
if not EsModificable(AFactura, AComentario) then
begin
SetDataTableReadOnly(AFactura.DataTable, True);
AEditor.ReadOnly := True;
AEditor.Comentario := AComentario;
end;
AEditor.ShowModal;
//MODO CONSULTAR (Se deja la tabla como estaba)
if AEditor.ReadOnly then
SetDataTableReadOnly(AFactura.DataTable, False);
finally
AEditor.Release;
AEditor := NIL;
end;
end;
procedure TFacturasClienteController.VerTodos(AFacturas: IBizFacturaCliente);
var
AEditor : IEditorFacturasCliente;
begin
AEditor := NIL;
CreateEditor('EditorFacturasCliente', IEditorFacturasCliente, AEditor);
if Assigned(AEditor) then
with AEditor do
begin
Controller := Self; //OJO ORDEN MUY IMPORTANTE
Facturas := AFacturas;
MultiSelect := True;
ShowEmbedded;
end;
end;
function TFacturasClienteController._Vacio: IBizFacturaCliente;
begin
Result := Buscar(ID_NULO);
end;
function TFacturasClienteController.Eliminar(const ID: Integer): Boolean;
var
AFactura : IBizFacturaCliente;
begin
AFactura := Buscar(ID);
if not Assigned(AFactura) then
raise Exception.Create(Format('No se ha encontrado la factura con ID = %d', [ID]));
Result := Eliminar(AFactura);
AFactura := NIL;
end;
function TFacturasClienteController.ElegirFacturas(AFacturas: IBizFacturaCliente; AMensaje: String;
AMultiSelect: Boolean): IBizFacturaCliente;
var
AEditor : IEditorElegirFacturasCliente;
begin
Result := NIL;
CreateEditor('EditorElegirFacturasCliente', IEditorElegirFacturasCliente, AEditor);
if Assigned(AEditor) then
try
AEditor.Controller := Self;
AEditor.Facturas := AFacturas;
AEditor.MultiSelect := AMultiSelect;
AEditor.Mensaje := AMensaje;
if IsPositiveResult(AEditor.ShowModal) then
Result := AEditor.FacturasClienteSeleccionados;
finally
AEditor.Release;
AEditor := NIL;
end;
end;
function TFacturasClienteController.Eliminar(AFactura: IBizFacturaCliente; AllItems: Boolean = false; AListaCausas: TStringList = nil): Boolean;
//Solo devolver<65> true en el caso de eliminar todos y cada uno de los elementos a eliminar
var
bEliminado: Boolean;
ACausa: Variant;
begin
bEliminado := True;
if not Assigned(AFactura) then
raise Exception.Create ('Factura no asignada');
ShowHourglassCursor;
try
if not AFactura.DataTable.Active then
AFactura.DataTable.Active := True;
if (AFactura.State in dsEditModes) then
AFactura.Cancel;
//Siempre eliminaremos el seleccionado tanto si es una lista de facturas a eliminar como si es la propia lista del editor.
if not EsEliminable(AFactura, ACausa) then
begin
if Assigned(AListaCausas) then
AListaCausas.Add(Format('%d=%s', [AFactura.ID, ACausa]));
bEliminado := False;
end
else
AFactura.Delete;
//En el caso de querer eliminar todos los items del objeto AAlbaran
if AllItems then
begin
with AFactura.DataTable do
begin
First;
while not EOF do
begin
if not EsEliminable(AFactura, ACausa) then
begin
if Assigned(AListaCausas) then
AListaCausas.Add(Format('%d=%s', [AFactura.ID, ACausa]));
bEliminado := False;
Next;
end
else
AFactura.Delete;
end;
end;
end;
try
AFactura.DataTable.ApplyUpdates;
Result := bEliminado;
except
//En el caso de una factura que tiene recibos con devoluciones hechas no se puede borrar aunque la factura este en situacion de pendiente
AFactura.DataTable.CancelUpdates;
Result := False;
end;
finally
HideHourglassCursor;
end;
end;
function TFacturasClienteController.EsEliminable(AFactura: IBizFacturaCliente; var AComentario: Variant): Boolean;
begin
Result := True;
if not Assigned(AFactura) then
raise Exception.Create ('Factura no asignado: EsEliminable');
if (AFactura.SITUACION <> CTE_PENDIENTE) then
begin
Result := False;
AComentario := 'La factura esta parcial o totalmente pagada, por lo que no puede ser eliminada';
end;
{
else if (AFactura.ESTADO_EJERCICIO = CTE_CERRADO) then
begin
Result := False;
AComentario := 'La factura tiene un asiento asociado en la parte contable cuyo ejercicio esta cerrado, por lo que no puede ser eliminada';
end
else if (AFactura.ASIENTO_PUNTEADO > 0) then
begin
Result := False;
AComentario := 'La factura tiene un asiento asociado en la parte contable y est<73> punteado, por lo que no puede ser eliminada';
end;
}
end;
function TFacturasClienteController.EsModificable(AFactura: IBizFacturaCliente; var AComentario: Variant): Boolean;
var
AFormaPago: IBizFormaPago;
bFacturaConRecibos: Boolean;
begin
Result := True;
AComentario := Null;
if not Assigned(AFactura) then
raise Exception.Create ('Factura no asignado: EsModificable');
bFacturaConRecibos := not AFactura.FECHA_VENCIMIENTOIsNull;
if not bFacturaConRecibos then
with TFormasPagoController.Create do
begin
try
AFormaPago := Buscar(AFactura.ID_FORMA_PAGO);
AFormaPago.DataTable.Active := True;
bFacturaConRecibos := (AFormaPago.Plazos.RecordCount > 0) ;
finally
AFormaPago := NIL;
Free;
end;
end;
if (bFacturaConRecibos and (AFactura.SITUACION <> CTE_PENDIENTE)) then
begin
Result := False;
AComentario := 'La factura esta parcial o totalmente pagada, por lo que no puede ser modificada';
end;
{
else if (AFactura.ESTADO_EJERCICIO = CTE_CERRADO) then
begin
Result := False;
AComentario := 'La factura tiene un asiento asociado en la parte contable cuyo ejercicio esta cerrado, por lo que no puede ser modificada';
end
else if (AFactura.ASIENTO_PUNTEADO > 0) then
begin
Result := False;
AComentario := 'La factura tiene un asiento asociado en la parte contable y est<73> punteado, por lo que no puede ser modificada';
end;
}
end;
procedure TFacturasClienteController.RecalcularImportes(
AFactura: IBizFacturaCliente);
var
bEnEdicion : Boolean;
ADetallePosAct : Integer;
begin
if not Assigned(AFactura) then
raise Exception.Create ('Factura no asignado (RecalcularImportes)');
if AFactura.DataTable.Active then
AFactura.DataTable.Active := True;
{ Hay que guardar la posici<EFBFBD>n en la que estamos en los detalles por que
la asignaci<EFBFBD>n de valores a los campos IMPORTE_NETO e IMPORTE_PORTE
(ver m<EFBFBD>s adelante) colocan el puntero en la tabla detalle al principio.
No he encontrado la raz<EFBFBD>n por la que mueve el puntero. }
ADetallePosAct := AFactura.Detalles.POSICION;
bEnEdicion := (AFactura.DataTable.State in dsEditModes);
if not bEnEdicion then
AFactura.Edit;
ShowHourglassCursor;
try
AFactura.IMPORTE_NETO := FDetallesController.DarTotalImporteTotal(AFactura.Detalles);
AFactura.IMPORTE_PORTE := FDetallesController.DarTotalPorteTotal(AFactura.Detalles);
if not bEnEdicion then
AFactura.Post;
finally
HideHourglassCursor;
// Restaurar la posici<63>n que ten<65>amos en los detalles.
FDetallesController.LocalizarPosicion(AFactura.Detalles, ADetallePosAct);
end;
end;
procedure TFacturasClienteController.RecibirAviso(ASujeto: ISujeto; ADataTable: IDAStronglyTypedDataTable);
var
AFactura : IBizFacturaCliente;
ADetalles : IBizDetallesFacturaCliente;
begin
inherited;
if Supports(ADataTable, IBizDetallesFacturaCliente, ADetalles) and
Supports(ADetalles.DataTable.MasterSource.DataTable, IBizFacturaCliente, AFactura) then
begin
RecalcularImportes(AFactura);
end;
end;
procedure TFacturasClienteController.RecuperarCliente(
AFactura: IBizFacturaCliente);
begin
AFactura._Cliente := (FClienteController.Buscar(AFactura.ID_CLIENTE) as IBizCliente);
end;
function TFacturasClienteController.Existe(const ID: Integer): Boolean;
var
AFactura : IBizFacturaCliente;
begin
try
AFactura := Buscar(ID);
Result := Assigned(AFactura) and (AFactura.ID = ID);
finally
AFactura := NIL;
end;
end;
function TFacturasClienteController.ExtraerSeleccionados(AFacturasCliente: IBizFacturaCliente): IBizFacturaCliente;
var
ASeleccionados : IBizFacturaCliente;
begin
ASeleccionados := (Self.Buscar(ID_NULO) as IBizFacturaCliente);
CopyDataTableDA5(AFacturasCliente.DataTable, ASeleccionados.DataTable, True);
Result := ASeleccionados;
end;
procedure TFacturasClienteController.FiltrarAno(AFactura: IBizFacturaCliente; ADynWhereDataTable: WideString; const Ano: String);
var
Condicion: TDAWhereExpression;
FechaIni: String;
FechaFin: String;
begin
AFactura.DataTable.DynamicWhere.Clear;
AFactura.DataTable.DynamicWhere.Xml := ADynWhereDataTable;
if (Ano <> 'Todos') then
begin
// Filtrar las facturas actuales por empresa
FechaIni := '01/01/' + Ano;
FechaFin := '31/12/' + Ano;
with AFactura.DataTable.DynamicWhere do
begin
// (FECHA_INICIO between FECHA_FIN)
Condicion := NewBinaryExpression(NewField('', fld_FacturasClienteFECHA_FACTURA), NewConstant(FechaIni, datString), dboGreaterOrEqual);
Condicion := NewBinaryExpression(NewBinaryExpression(NewField('', fld_FacturasClienteFECHA_FACTURA), NewConstant(FechaFin, datString), dboLessOrEqual), Condicion, dboAnd);
if IsEmpty then
Expression := Condicion
else
Expression := NewBinaryExpression(Condicion, Expression, dboAnd);
end;
end;
end;
procedure TFacturasClienteController.FiltrarEmpresa(AFactura: IBizFacturaCliente);
var
Condicion: TDAWhereExpression;
begin
if AFactura.DataTable.Active then
AFactura.DataTable.Active := False;
// Filtrar las facturas actuales por empresa
with AFactura.DataTable.DynamicWhere do
begin
// (ID_EMPRESA >= ID)
Condicion := NewBinaryExpression(NewField('', fld_FacturasClienteID_EMPRESA), NewConstant(AppFactuGES.EmpresaActiva.ID, datInteger), dboEqual);
if IsEmpty then
Expression := Condicion
else
Expression := NewBinaryExpression(Expression, Condicion, dboAnd);
end;
end;
procedure TFacturasClienteController.SetClienteController(const Value: IClientesController);
begin
FClienteController := Value;
end;
procedure TFacturasClienteController.SetDetallesController(const Value: IDetallesFacturaClienteController);
begin
FDetallesController := Value;
end;
procedure TFacturasClienteController.SetIgnorarContabilidad(AFactura: IBizFacturaCliente; const Ignorar: Integer);
var
EnEdicion: Boolean;
begin
if Assigned(AFactura) then
begin
EnEdicion := AFactura.DataTable.Editing;
if not AFactura.DataTable.Editing then
AFactura.DataTable.Edit;
AFactura.IGNORAR_CONTABILIDAD := Ignorar;
AFactura.DataTable.Post;
if EnEdicion then
AFactura.DataTable.Edit;
end;
end;
function TFacturasClienteController.Guardar(AFactura: IBizFacturaCliente): Boolean;
var
IDNuevo : Integer;
begin
Result := False;
if not Assigned(AFactura) then
raise Exception.Create ('Factura no asignada');
if not Assigned(FDetallesController) then
raise Exception.Create ('Controller detalles no asignado');
if ValidarFactura(AFactura) then
begin
ShowHourglassCursor;
// Asegurarnos de que todos los importes est<73>n bien.
RecalcularImportes(AFactura);
try
AFactura.DataTable.ApplyUpdates;
//Se generan los recibos autom<6F>ticamente a partir de la forma de pago
GenerarRecibos(AFactura);
Result := True;
finally
HideHourglassCursor;
end;
end;
end;
function TFacturasClienteController.Nuevo (WithInsert: Boolean = True): IBizFacturaCliente;
var
AFactura : IBizFacturaCliente;
begin
AFactura := FDataModule.NewItem;
FiltrarEmpresa(AFactura);
AFactura.DataTable.Active := True;
if WithInsert then
AFactura.Insert;
Result := AFactura;
end;
procedure TFacturasClienteController.Preview(AFactura: IBizFacturaCliente; AllItems: Boolean = false; VerLogotipo: Boolean = true);
var
AReportController : IFacturasClienteReportController;
ID_Facturas: TIntegerList;
begin
AReportController := TFacturasClienteReportController.Create;
ID_Facturas := TIntegerList.Create;
try
//Si deseamos previsualizar todos los items del objeto albaran
if AllItems then
begin
with AFactura.DataTable do
begin
First;
while not EOF do
begin
ID_Facturas.Add(AFactura.ID);
Next;
end;
end;
end
//Solo previsualizamos el item seleccionado
else
ID_Facturas.Add(AFactura.ID);
AReportController.Preview(ID_Facturas, VerLogotipo);
finally
AReportController := NIL;
FreeANDNIL(ID_Facturas);
end;
end;
procedure TFacturasClienteController.Print(AFactura: IBizFacturaCliente; AllItems: Boolean = false; VerLogotipo: Boolean = true);
var
AReportController : IFacturasClienteReportController;
ID_Facturas: TIntegerList;
begin
AReportController := TFacturasClienteReportController.Create;
ID_Facturas := TIntegerList.Create;
try
//Si deseamos previsualizar todos los items del objeto albaran
if AllItems then
begin
with AFactura.DataTable do
begin
First;
while not EOF do
begin
ID_Facturas.Add(AFactura.ID);
Next;
end;
end;
end
//Solo previsualizamos el item seleccionado
else
ID_Facturas.Add(AFactura.ID);
AReportController.Print(ID_Facturas, VerLogotipo);
finally
AReportController := NIL;
FreeANDNIL(ID_Facturas);
end;
end;
function TFacturasClienteController.GenerarAbono(AFactura: IBizFacturaCliente): IBizFacturaCliente;
begin
ShowHourglassCursor;
try
Result := Duplicar(AFactura);
//A<>ade un concepto con los datos de la factura asociada al abono
FDetallesController.AnadirDetalleFacturaAsociadaAbono(Result.Detalles, AFactura.REFERENCIA, DateToStr(AFactura.FECHA_FACTURA));
//Convierte todos los articulos de la factura a negativos por se un abono
FDetallesController.CambiarSignoDetalles(Result.Detalles);
// Hay que dejar algunos campos como si fuera una factura nueva
Result.Edit;
Result.TIPO := CTE_TIPO_ABONO;
Result.Post;
finally
HideHourglassCursor;
end;
end;
procedure TFacturasClienteController.GenerarRecibos(AFactura: IBizFacturaCliente);
var
AFormasPagoController : IFormasPagoController;
AFormaPago: IBizFormaPago;
ARecibosClienteController: IRecibosClienteController;
ARecibos: IBizRecibosCliente;
AFechaVencimiento: TDateTime;
i: Integer;
ADiaVencimiento: Integer;
ADiasMas: Integer;
BSemaforo: Boolean;
AImporteAcumulado : Double;
AImporteTotal: Double;
begin
if not Assigned(AFactura) then
Exit;
AFormasPagoController := TFormasPagoController.Create;
AFormaPago := AFormasPagoController.Buscar(AFactura.ID_FORMA_PAGO);
AFormaPago.DataTable.Active := True;
ARecibosClienteController := TRecibosClienteController.Create;
//Eliminamos todos los recibos que tuviera la factura porque sabemos que todos
//estar<61>n pendientes (solo permitiremos modificar y eliminar facturas pendientes,
//parcialmente pagadas o pagadas no
ARecibos := ARecibosClienteController.BuscarRecibosFactura(AFactura.ID);
ARecibosClienteController.EliminarTodo(ARecibos);
//Si hay retenci<63>n, se generar<61> un recibo por ese importe, y el resto se generar<61>n recibos
//seg<65>n forma de pago
AImporteTotal := AFactura.IMPORTE_TOTAL - AFactura.IMPORTE_RETENCION;
//Se cambia la l<>gica a peticion de acana, en el caso de meter una fecha de vencimiento,
//los plazos de la forma de pago no tendr<64>n efecto, se generar<61> un recibo con el 100% y fecha de vencimiento
//de la factura. (Se permitir<69> para acana poder dar de alta facturas sin recibos asociados)
With AFormaPago.Plazos.DataTable do
begin
i := 1;
AImporteAcumulado := 0;
First;
repeat
//SOLO PARA ACANA (Leer comentario anterior
if (AFormaPago.Plazos.RecordCount > 0)
or (AFactura.FECHA_VENCIMIENTO <> 0) then
begin
ARecibos := ARecibosClienteController.Nuevo;
ARecibos.Edit;
ARecibos.ID_FACTURA := AFactura.ID;
ARecibos.ID_EMPRESA := AFactura.ID_EMPRESA;
ARecibos.ID_CLIENTE := AFactura.ID_CLIENTE;
ARecibos.ID_TIENDA := AFactura.ID_TIENDA;
ARecibos.REFERENCIA := AFactura.REFERENCIA + ' - ' + IntToStr(i);
ARecibos.NOMBRE := AFactura.NOMBRE; //Es la razon social de la factura
ARecibos.CALLE := AFactura.CALLE;
ARecibos.NIF_CIF := AFactura.NIF_CIF;
ARecibos.POBLACION := AFactura.POBLACION;
ARecibos.PROVINCIA := AFactura.PROVINCIA;
ARecibos.CODIGO_POSTAL := AFactura.CODIGO_POSTAL;
ARecibos.FECHA_EMISION := AFactura.FECHA_FACTURA;
if AFormaPago.Plazos.RecordCount < 1 then
begin
ARecibos.FECHA_VENCIMIENTO := AFactura.FECHA_VENCIMIENTO;
ARecibos.IMPORTE := AImporteTotal;
AImporteAcumulado := AImporteAcumulado + ARecibos.IMPORTE;
end
else
begin
AFechaVencimiento := AFactura.FECHA_FACTURA + AFormaPago.Plazos.NUM_DIAS;
ADiasMas := 0;
BSemaforo := False;
if (AFactura.Cliente.VENCIMIENTO_FACTURAS_1 <> 0)
or (AFactura.Cliente.VENCIMIENTO_FACTURAS_2 <> 0)
or (AFactura.Cliente.VENCIMIENTO_FACTURAS_3 <> 0) then
begin
ADiaVencimiento := DayOf(AFechaVencimiento);
while (ADiaVencimiento <> AFactura.Cliente.VENCIMIENTO_FACTURAS_1)
and (ADiaVencimiento <> AFactura.Cliente.VENCIMIENTO_FACTURAS_2)
and (ADiaVencimiento <> AFactura.Cliente.VENCIMIENTO_FACTURAS_3) do
begin
if ADiaVencimiento = DaysInMonth(AFechaVencimiento) then
begin
ADiaVencimiento := 1;
//Controlamos con una variable semaforo que no nos quedemos en un bucle infinito
//intentando encontrar el dia de pago establecido para el cliente (es el caso de tener
//asignado el dia de pago 30 y llegar febrero en el que no se encuentra dicho dia, o
//tener como dia de pago los d<>as 31 y en el caso de meses de 30 dias no encontrarlo.
if BSemaforo then
begin
ADiasMas := 0;
Break
end
else
BSemaforo := True;
end
else
Inc(ADiaVencimiento);
Inc(ADiasMas);
end;
end;
AFechaVencimiento := IncDay(AFechaVencimiento, ADiasMas);
ARecibos.FECHA_VENCIMIENTO := AFechaVencimiento;
ARecibos.IMPORTE := RoundCurrency(RoundCurrency(AImporteTotal) * (AFormaPago.Plazos.PORCENTAJE / 100));
AImporteAcumulado := AImporteAcumulado + ARecibos.IMPORTE;
if (i = AFormaPago.Plazos.RecordCount) then
begin
if (AImporteAcumulado < RoundCurrency(AImporteTotal)) then
ARecibos.IMPORTE := ARecibos.IMPORTE + (RoundCurrency(AImporteTotal) - AImporteAcumulado)
else if (AImporteAcumulado > RoundCurrency(AImporteTotal)) then
ARecibos.IMPORTE := ARecibos.IMPORTE - (AImporteAcumulado - RoundCurrency(AImporteTotal));
end;
end;
ARecibos.DESCRIPCION := 'RECIBO ' + ARecibos.REFERENCIA + ' - ' + ARecibos.NOMBRE; // CifraToLetras(ARecibos.IMPORTE);
ARecibosClienteController.Guardar(ARecibos);
end;
Inc(i);
Next;
until (eof);
end;
//Si hay retenci<63>n generaremos un recibo para dicha retenci<63>n
if AFactura.IMPORTE_RETENCION > 0 then
begin
ARecibos := ARecibosClienteController.Nuevo;
ARecibos.Edit;
ARecibos.ID_FACTURA := AFactura.ID;
ARecibos.ID_EMPRESA := AFactura.ID_EMPRESA;
ARecibos.ID_CLIENTE := AFactura.ID_CLIENTE;
ARecibos.ID_TIENDA := AFactura.ID_TIENDA;
ARecibos.REFERENCIA := AFactura.REFERENCIA + ' - ' + IntToStr(i);
ARecibos.NOMBRE := AFactura.NOMBRE; //Es la razon social de la factura
ARecibos.CALLE := AFactura.CALLE;
ARecibos.NIF_CIF := AFactura.NIF_CIF;
ARecibos.POBLACION := AFactura.POBLACION;
ARecibos.PROVINCIA := AFactura.PROVINCIA;
ARecibos.CODIGO_POSTAL := AFactura.CODIGO_POSTAL;
ARecibos.FECHA_EMISION := AFactura.FECHA_FACTURA;
ARecibos.FECHA_VENCIMIENTO := AFactura.FECHA_RETENCION;
ARecibos.IMPORTE := AFactura.IMPORTE_RETENCION;
ARecibos.DESCRIPCION := 'Pago de factura de retenci<63>n ' + AFactura.REFERENCIA + ' - ' + ARecibos.NOMBRE; // CifraToLetras(ARecibos.IMPORTE);
ARecibosClienteController.Guardar(ARecibos);
end;
//Liberamos
AFormasPagoController := Nil;
AFormaPago := Nil;
ARecibosClienteController := Nil;
ARecibos := Nil;
end;
function TFacturasClienteController.GetClienteController: IClientesController;
begin
Result := FClienteController;
end;
function TFacturasClienteController.GetDetallesController: IDetallesFacturaClienteController;
begin
Result := FDetallesController;
end;
end.