unit uFacturasProveedorController; interface uses Classes, SysUtils, uDADataTable, uControllerBase, uIDataModuleFacturasProveedor, uProveedoresController, uDetallesFacturaProveedorController, uBizFacturasProveedor, uBizAlbaranesProveedor; type IFacturasProveedorController = interface(IControllerBase) ['{3868267C-E61A-4B79-AF61-648B2D627F56}'] function GetProveedorController: IProveedoresController; procedure SetProveedorController(const Value: IProveedoresController); property ProveedorController: IProveedoresController read GetProveedorController write SetProveedorController; function GetDetallesController: IDetallesFacturaProveedorController; procedure SetDetallesController(const Value: IDetallesFacturaProveedorController); property DetallesController: IDetallesFacturaProveedorController read GetDetallesController write SetDetallesController; function Buscar(const ID: Integer): IBizFacturaProveedor; function BuscarTodos: IBizFacturaProveedor; overload; function BuscarTodos(const ID_Proveedor : Integer): IBizFacturaProveedor; overload; function BuscarTodosDelPedido(const ID_Pedido : Integer): IBizFacturaProveedor; procedure Ver(AFactura : IBizFacturaProveedor); procedure VerTodos(AFacturas: IBizFacturaProveedor; const AVerModal : Boolean = False; const AWindowCaption: String = ''; const AHeaderText: String = ''); function Nuevo (withInsert: Boolean = True) : IBizFacturaProveedor; function Anadir(AFactura : IBizFacturaProveedor) : Boolean; overload; function AnadirAbono(AFactura : IBizFacturaProveedor) : Boolean; // function Anadir(AFacturas : IBizFacturaProveedor; AListaAlbaranes : IBizAlbaranProveedor): Boolean; overload; function Anadir(AFactura : IBizFacturaProveedor; const IDPedido : Integer): Boolean; overload; function Eliminar(const ID : Integer): Boolean; overload; function Eliminar(AFactura : IBizFacturaProveedor; AllItems: Boolean = false): Boolean; overload; function Guardar(AFactura : IBizFacturaProveedor): Boolean; procedure DescartarCambios(AFactura : IBizFacturaProveedor); function Existe(const ID: Integer) : Boolean; procedure RecuperarProveedor(AFactura : IBizFacturaProveedor); function Duplicar(AFactura: IBizFacturaProveedor): IBizFacturaProveedor; function GenerarAbono(AFactura: IBizFacturaProveedor): IBizFacturaProveedor; procedure Preview(AFactura : IBizFacturaProveedor; AllItems: Boolean = false); procedure Print(AFactura : IBizFacturaProveedor; AllItems: Boolean = false); procedure RecalcularImportes(FFactura: IBizFacturaProveedor); function EsModificable(AFactura: IBizFacturaProveedor): Boolean; function EsEliminable(AFactura: IBizFacturaProveedor): Boolean; function ElegirFacturas(AFacturas : IBizFacturaProveedor; AMensaje: String; AMultiSelect: Boolean): IBizFacturaProveedor; function ExtraerSeleccionados(ARecibosProveedor: IBizFacturaProveedor) : IBizFacturaProveedor; function DarListaAnosFacturas: TStringList; procedure FiltrarAno(AFactura: IBizFacturaProveedor; ADynWhereDataTable: WideString; const Ano: String); function AsignarCuentaBancaria(AFacturas: IBizFacturaProveedor): TStringList; function AsignarVencimiento(AFacturas: IBizFacturaProveedor): TStringList; end; TFacturasProveedorController = class(TControllerBase, IFacturasProveedorController) private FDataModule : IDataModuleFacturasProveedor; FProveedorController : IProveedoresController; FDetallesController : IDetallesFacturaProveedorController; function GetProveedorController: IProveedoresController; procedure SetProveedorController(const Value: IProveedoresController); function GetDetallesController: IDetallesFacturaProveedorController; procedure SetDetallesController(const Value: IDetallesFacturaProveedorController); function CreateEditor(const AName : String; const IID: TGUID; out Intf): Boolean; function _Vacio : IBizFacturaProveedor; procedure FiltrarEmpresa(AFactura: IBizFacturaProveedor); function ValidarFactura(AFactura: IBizFacturaProveedor): Boolean; procedure GenerarRecibos(AFactura: IBizFacturaProveedor); protected procedure RecibirAviso(ASujeto: ISujeto; ADataTable: IDAStronglyTypedDataTable); override; public property ProveedorController: IProveedoresController read GetProveedorController write SetProveedorController; property DetallesController: IDetallesFacturaProveedorController read GetDetallesController write SetDetallesController; constructor Create; override; destructor Destroy; override; function Eliminar(const ID : Integer): Boolean; overload; function Eliminar(AFactura : IBizFacturaProveedor; AllItems: Boolean = false): Boolean; overload; function Guardar(AFactura : IBizFacturaProveedor): Boolean; procedure DescartarCambios(AFactura : IBizFacturaProveedor); virtual; function Existe(const ID: Integer) : Boolean; virtual; function Anadir(AFactura : IBizFacturaProveedor) : Boolean; overload; function AnadirAbono(AFactura : IBizFacturaProveedor) : Boolean; // function Anadir(AFacturas : IBizFacturaProveedor; AListaAlbaranes : IBizAlbaranProveedor): Boolean; overload; function Anadir(AFactura : IBizFacturaProveedor; const IDPedido : Integer): Boolean; overload; function Buscar(const ID: Integer): IBizFacturaProveedor; function BuscarTodos: IBizFacturaProveedor; overload; function BuscarTodos(const ID_Proveedor : Integer): IBizFacturaProveedor; overload; function BuscarTodosDelPedido(const ID_Pedido : Integer): IBizFacturaProveedor; // function BuscarTodasPendientesComision(IdAgente: Integer; IdComision: Integer; IdFacturasAsociadas: String): IBizFacturaProveedor; function Nuevo (withInsert: Boolean = True): IBizFacturaProveedor; procedure Ver(AFactura : IBizFacturaProveedor); procedure VerTodos(AFacturas: IBizFacturaProveedor; const AVerModal : Boolean = False; const AWindowCaption: String = ''; const AHeaderText: String = ''); function Duplicar(AFactura: IBizFacturaProveedor): IBizFacturaProveedor; function GenerarAbono(AFactura: IBizFacturaProveedor): IBizFacturaProveedor; procedure RecuperarProveedor(AFactura : IBizFacturaProveedor); procedure Preview(AFactura : IBizFacturaProveedor; AllItems: Boolean = false); procedure Print(AFactura : IBizFacturaProveedor; AllItems: Boolean = false); procedure RecalcularImportes(FFactura: IBizFacturaProveedor); function EsModificable(AFactura: IBizFacturaProveedor): Boolean; function EsEliminable(AFactura: IBizFacturaProveedor): Boolean; function ElegirFacturas(AFacturas : IBizFacturaProveedor; AMensaje: String; AMultiSelect: Boolean): IBizFacturaProveedor; function ExtraerSeleccionados(AFacturasProveedor: IBizFacturaProveedor) : IBizFacturaProveedor; function DarListaAnosFacturas: TStringList; procedure FiltrarAno(AFactura: IBizFacturaProveedor; ADynWhereDataTable: WideString; const Ano: String); function AsignarCuentaBancaria(AFacturas: IBizFacturaProveedor): TStringList; function AsignarVencimiento(AFacturas: IBizFacturaProveedor): TStringList; end; implementation uses Windows, Controls, cxControls, DB, uEditorRegistryUtils, schFacturasProveedorClient_Intf, uBizContactos, uIEditorFacturasProveedor, uIEditorFacturaProveedor, uFactuGES_App, uDataModuleFacturasProveedor, uBizDetallesFacturaProveedor, uControllerDetallesBase, uDataModuleUsuarios, uDAInterfaces, uDataTableUtils, uDateUtils, uROTypes, uAlbaranesProveedorController, schAlbaranesProveedorClient_Intf, uDetallesAlbaranProveedorController, uBizPedidosProveedor, uPedidosProveedorController, uBizDetallesPedidoProveedor, uRecibosProveedorController, uBizRecibosProveedor, uNumUtils, uFacturasProveedorReportController, DateUtils, Forms, Dialogs, uFormasPagoController, uBizFormasPago, uStringsUtils, uIEditorElegirDomiciliacion, uIEditorElegirFechaVencimiento, cxEdit; procedure CopiarArticulosPedido(AOrigen: IBizDetallesPedidoProveedor; ADestino : IBizDetallesFacturaProveedor); var i : integer; ADetallesController : IDetallesFacturaProveedorController; begin if not Assigned(AOrigen) then raise Exception.Create ('Origen no asignado (CopiarArticulosPedido)'); if not Assigned(ADestino) then raise Exception.Create ('Destino no asignado (CopiarArticulosPedido)'); if not AOrigen.DataTable.Active then AOrigen.DataTable.Active := True; if not ADestino.DataTable.Active then ADestino.DataTable.Active := True; ADetallesController := TDetallesFacturaProveedorController.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; ADestino.CONCEPTO := AOrigen.CONCEPTO; ADestino.CANTIDAD := AOrigen.CANTIDAD; ADestino.IMPORTE_UNIDAD := AOrigen.IMPORTE_UNIDAD; ADestino.IMPORTE_TOTAL := AOrigen.IMPORTE_TOTAL; ADestino.DESCUENTO := AOrigen.DESCUENTO; ADestino.IMPORTE_PORTE := AOrigen.IMPORTE_PORTE; ADestino.VISIBLE := AOrigen.VISIBLE; ADestino.REFERENCIA_PROVEEDOR := AOrigen.REFERENCIA_PROVEEDOR; ADestino.Post; AOrigen.Next; end; finally ADetallesController.EndUpdate(ADestino); ADetallesController := NIL; end; end; { TFacturasProveedorController } function TFacturasProveedorController.Anadir(AFactura: IBizFacturaProveedor) : Boolean; begin if not Assigned(AFactura) then raise Exception.Create ('Factura no asignada (Anadir)'); AFactura.Insert; Result := True; end; function TFacturasProveedorController.Anadir(AFactura: IBizFacturaProveedor; const IDPedido: Integer): Boolean; var APedidosController : IPedidosProveedorController; APedido : IBizPedidoProveedor; 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 := TPedidosProveedorController.Create; try APedido := APedidosController.Buscar(IDPedido); if not Assigned(APedido) then raise Exception.Create (Format('No se ha encontrado un pedido de Proveedor con ID %d (Anadir)', [IDPedido])); APedido.DataTable.Active := True; APedidosController.RecuperarProveedor(APedido); Self.Anadir(AFactura); AFactura.Proveedor := APedido.Proveedor; 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 TFacturasProveedorController.AnadirAbono(AFactura: IBizFacturaProveedor): Boolean; begin Result := Anadir(AFactura); AFactura.TIPO := CTE_TIPO_ABONO; end; function TFacturasProveedorController.AsignarCuentaBancaria(AFacturas: IBizFacturaProveedor): TStringList; //Devolverá la lista de facturas que no han podido ser modificadas referencia=nombreproveedor var AEditor : IEditorElegirDomiciliacion; ACuentaBancaria: String; begin Result := TStringList.Create; if Assigned(AFacturas) then begin CreateEditor('EditorElegirDomiciliacion', IEditorElegirDomiciliacion, AEditor); if Assigned(AEditor) then try if (AEditor.ShowModal = mrOk) then ACuentaBancaria := AEditor.CuentaBancaria; finally AEditor.Release; AEditor := NIL; end; with AFacturas.DataTable do begin First; while not EOF do begin if (AFacturas.SITUACION = CTE_PENDIENTE) then begin Edit; AFacturas.DATOS_BANCARIOS := ACuentaBancaria; Post; //Se generan los recibos automáticamente a partir de la forma de pago GenerarRecibos(AFacturas); end else Result.Add(Format('%s=%s', [AFacturas.REFERENCIA, AFacturas.NOMBRE])); Next; end; ApplyUpdates; end; end; end; function TFacturasProveedorController.AsignarVencimiento(AFacturas: IBizFacturaProveedor): TStringList; //Devolverá la lista de facturas que no han podido ser modificadas referencia=nombreproveedor var AEditor : IEditorElegirFechaVencimiento; AFechaVencimiento: Datetime; begin Result := TStringList.Create; if Assigned(AFacturas) then begin CreateEditor('EditorElegirFechaVencimiento', IEditorElegirFechaVencimiento, AEditor); if Assigned(AEditor) then try if (AEditor.ShowModal = mrOk) then AFEchaVencimiento := AEditor.FechaVencimiento; finally AEditor.Release; AEditor := NIL; end; with AFacturas.DataTable do begin First; while not EOF do begin if (AFacturas.SITUACION = CTE_PENDIENTE) then begin Edit; AFacturas.FECHA_VENCIMIENTO := AFechaVencimiento; Post; //Se generan los recibos automáticamente a partir de la forma de pago GenerarRecibos(AFacturas); end else Result.Add(Format('%s=%s', [AFacturas.REFERENCIA, AFacturas.NOMBRE])); Next; end; ApplyUpdates; end; end; end; function TFacturasProveedorController.Buscar(const ID: Integer): IBizFacturaProveedor; begin Result := (FDataModule as IDataModuleFacturasProveedor).GetItem(ID); FiltrarEmpresa(Result); end; function TFacturasProveedorController.BuscarTodos( const ID_Proveedor: Integer): IBizFacturaProveedor; var Condicion: TDAWhereExpression; begin ShowHourglassCursor; try Result := BuscarTodos; with Result.DataTable.DynamicWhere do begin // ID_CLIENTE Condicion := NewBinaryExpression(NewField('', fld_FacturasProveedorID_PROVEEDOR), NewConstant(ID_Proveedor, datInteger), dboEqual); if IsEmpty then Expression := Condicion else Expression := NewBinaryExpression(Expression, Condicion, dboAnd); end; finally HideHourglassCursor; end; end; function TFacturasProveedorController.BuscarTodosDelPedido( const ID_Pedido: Integer): IBizFacturaProveedor; var Condicion: TDAWhereExpression; begin ShowHourglassCursor; try Result := BuscarTodos; with Result.DataTable.DynamicWhere do begin // ID_CLIENTE Condicion := NewBinaryExpression(NewField('', fld_FacturasProveedorID_PEDIDO), NewConstant(ID_Pedido, datInteger), dboEqual); if IsEmpty then Expression := Condicion else Expression := NewBinaryExpression(Expression, Condicion, dboAnd); end; finally HideHourglassCursor; end; end; {REPASARRRRR function TFacturasProveedorController.BuscarTodasPendientesComision(IdAgente:Integer; IdComision: Integer; IdFacturasAsociadas: String): IBizFacturaProveedor; begin ShowHourglassCursor; try Result := BuscarTodos; with Result.DataTable.Where do begin if NotEmpty then AddOperator(opAND); //Todas las facturas de un agente determinado OpenBraket; AddText(fld_FacturasProveedorID_AGENTE + ' = ' + IntToStr(IdAgente)); CloseBraket; //Todas aquellas que no esten asociadas a ninguna comisión o asociadas a la comisión, //pero no asociadas en el editor de la comision, esto es porque se puede agregar y quitar //facturas y todos los cambios estan el cache y por lo tanto al pedir las facturas a seleccionar //debemos tener en cuenta dichso cambios en cache AddOperator(opAND); OpenBraket; OpenBraket; //En el caso de ser facturas sin asociar OpenBraket; AddText(fld_FacturasProveedorID_COMISION_LIQUIDADA + ' IS NULL '); CloseBraket; //Quitamos aquellas que ya están asociadas if length(IdFacturasAsociadas) > 0 then begin AddOperator(opAND); OpenBraket; AddText(fld_FacturasProveedorID + ' not in (' + IdFacturasAsociadas + ')'); CloseBraket; end; CloseBraket; AddOperator(opOR); OpenBraket; //En caso de ser facturas ya asociadas lo limitamos a la comision actual //ya que no debemos poder elegir facturas asociadas a otras comisiones OpenBraket; AddText(fld_FacturasProveedorID_COMISION_LIQUIDADA + ' = ' + IntToStr(IdComision)); CloseBraket; //En el caso de que halla facturas asociadas if length(IdFacturasAsociadas) > 0 then begin AddOperator(opAND); OpenBraket; AddText(fld_FacturasProveedorID + ' not in (' + IdFacturasAsociadas + ')'); CloseBraket; end; CloseBraket; CloseBraket; end; finally HideHourglassCursor; end; end; } function TFacturasProveedorController.BuscarTodos: IBizFacturaProveedor; begin Result := FDataModule.GetItems; FiltrarEmpresa(Result); end; constructor TFacturasProveedorController.Create; begin inherited; FDataModule := TDataModuleFacturasProveedor.Create(Nil); FProveedorController := TProveedoresController.Create; FDetallesController := TDetallesFacturaProveedorController.Create; FDetallesController.addObservador(Self); end; function TFacturasProveedorController.CreateEditor(const AName: String; const IID: TGUID; out Intf): Boolean; begin Result := Supports(EditorRegistry.CreateEditor(AName), IID, Intf); end; function TFacturasProveedorController.DarListaAnosFacturas: TStringList; begin Result := FDataModule.GetAnosItems; end; procedure TFacturasProveedorController.DescartarCambios(AFactura: IBizFacturaProveedor); 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 TFacturasProveedorController.Destroy; begin FDataModule := Nil; FProveedorController := Nil; FDetallesController := Nil; inherited; end; function TFacturasProveedorController.Duplicar(AFactura: IBizFacturaProveedor): IBizFacturaProveedor; 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; USUARIO := AppFactuGES.UsuarioActivo.UserName; REFERENCIA := ''; //Para que se asigne una nueva SITUACION := CTE_PENDIENTE; //Una factura nueva debe estar pendiente FECHA_FACTURA := DateOf(Now); end; Result.Post; finally HideHourglassCursor; end; end; function TFacturasProveedorController.ValidarFactura(AFactura: IBizFacturaProveedor): 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_PROVEEDOR < 0) or (AFactura.ID_PROVEEDOR = 0) then // No comprobar el objeto Proveedor por que puede fallar la validación // cuando se generan facturas automáticamente. { (not Assigned(AFactura.Proveedor)) or (AFactura.Proveedor.IsEmpty) then} raise Exception.Create('Debe indicar el Proveedor de esta factura'); if (EsFechaVacia(AFactura.FECHA_FACTURA)) then raise Exception.Create('Debe indicar la fecha de esta factura'); if (AFactura.Detalles.DataTable.RecordCount = 0) then raise Exception.Create('La factura debe tener al menos un concepto en su contenido'); { Esta validación puede saltar cuando se generan facturas automáticamente por albaranes o pedidos y el Proveedor no tiene Tipo de IVA puesto. } { if (AFactura.ID_TIPO_IVA = 0) then raise Exception.Create('Debe indicar un tipo de IVA 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 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; //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'); { Asegurarse de valores en campos "automáticos" tanto en MODIFICACIÓN como en INSERCIÓN. } AFactura.Edit; try AFactura.USUARIO := AppFactuGES.UsuarioActivo.UserName; if Assigned(AFactura.Proveedor) and (AFactura.ID_Proveedor <> AFactura.Proveedor.ID) then AFactura.ID_Proveedor := AFactura.Proveedor.ID; Result := True; finally AFactura.Post; end; end; procedure TFacturasProveedorController.Ver(AFactura: IBizFacturaProveedor); var AEditor : IEditorFacturaProveedor; begin AEditor := NIL; RecuperarProveedor(AFactura); CreateEditor('EditorFacturaProveedor', IEditorFacturaProveedor, AEditor); if Assigned(AEditor) then try AEditor.Controller := Self; //OJO ORDEN MUY IMPORTANTE AEditor.Factura := AFactura; //MODO CONSULTAR if not EsModificable(AFactura) then begin SetDataTableReadOnly(AFactura.DataTable, True); AEditor.ReadOnly := True; 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 TFacturasProveedorController.VerTodos(AFacturas: IBizFacturaProveedor; const AVerModal : Boolean = False; const AWindowCaption: String = ''; const AHeaderText: String = ''); var AEditor : IEditorFacturasProveedor; begin AEditor := NIL; CreateEditor('EditorFacturasProveedor', IEditorFacturasProveedor, AEditor); try if not EsCadenaVacia(AWindowCaption) then AEditor.WindowCaption := AWindowCaption; if not EsCadenaVacia(AHeaderText) then AEditor.HeaderText := AHeaderText; AEditor.Controller := Self; //OJO ORDEN MUY IMPORTANTE AEditor.Facturas := AFacturas; AEditor.MultiSelect := True; if AVerModal then AEditor.ShowModal else AEditor.ShowEmbedded; finally if AVerModal then AEditor.Release; AEditor := Nil; end; end; function TFacturasProveedorController._Vacio: IBizFacturaProveedor; begin Result := Buscar(ID_NULO); end; function TFacturasProveedorController.Eliminar(const ID: Integer): Boolean; var AFactura : IBizFacturaProveedor; 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 TFacturasProveedorController.ElegirFacturas(AFacturas: IBizFacturaProveedor; AMensaje: String; AMultiSelect: Boolean): IBizFacturaProveedor; {var AEditor : IEditorElegirFacturasProveedor;} begin Result := NIL; { CreateEditor('EditorElegirFacturasProveedor', IEditorElegirFacturasProveedor, AEditor); if Assigned(AEditor) then with AEditor do begin try Controller := Self; Facturas := AFacturas; MultiSelect := AMultiSelect; Mensaje := AMensaje; if IsPositiveResult(ShowModal) then Result := FacturasProveedoreSeleccionados; finally AEditor.Release; AEditor := NIL; end; end; } end; function TFacturasProveedorController.Eliminar(AFactura: IBizFacturaProveedor; AllItems: Boolean = false): Boolean; //En el caso de eliminar almenos un elemento del conjunto se devuelve true var bEliminado: Boolean; begin bEliminado := False; 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 if EsEliminable(AFactura) then begin AFactura.Delete; bEliminado := True; end; //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 EsEliminable(AFactura) then begin AFactura.Delete; bEliminado := True end else Next; end; end; end; if bEliminado then begin try AFactura.DataTable.ApplyUpdates; Result := True 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; end else Result := False; finally HideHourglassCursor; end; end; function TFacturasProveedorController.EsEliminable(AFactura: IBizFacturaProveedor): Boolean; begin Result := EsModificable(AFactura); end; function TFacturasProveedorController.EsModificable(AFactura: IBizFacturaProveedor): Boolean; begin if not Assigned(AFactura) then raise Exception.Create ('Factura no asignado: EsModificable'); Result := (AFactura.SITUACION = CTE_PENDIENTE); end; procedure TFacturasProveedorController.RecalcularImportes( FFactura: IBizFacturaProveedor); var bEnEdicion : Boolean; ADetallePosAct : Integer; AListaIVAs : TImporteIVADetallesArray; begin if not Assigned(FFactura) then raise Exception.Create ('Factura no asignada (RecalcularImportes)'); if FFactura.DataTable.Active then FFactura.DataTable.Active := True; { Hay que guardar la posición en la que estamos en los detalles por que la asignación de valores a los campos IMPORTE_NETO e IMPORTE_PORTE (ver más adelante) colocan el puntero en la tabla detalle al principio. No he encontrado la razón por la que mueve el puntero. } ADetallePosAct := FFactura.Detalles.POSICION; bEnEdicion := (FFactura.DataTable.State in dsEditModes); if not bEnEdicion then FFactura.Edit; ShowHourglassCursor; try FFactura.IMPORTE_NETO := FDetallesController.DarTotalImporteTotal(FFactura.Detalles); FFactura.IMPORTE_PORTE := FDetallesController.DarTotalPorteTotal(FFactura.Detalles); {AListaIVAs := FDetallesController.CalcularTotalesIVA(FFactura.Detalles.DataTable); FFactura.IMPORTE_IVA := FDetallesController.CalcularSumaIVA(AListaIVAs); FFactura.DataTable.FieldByName('IVA').Clear;} if not bEnEdicion then FFactura.Post; finally HideHourglassCursor; // Restaurar la posición que teníamos en los detalles. FDetallesController.LocalizarPosicion(FFactura.Detalles, ADetallePosAct); end; end; procedure TFacturasProveedorController.RecibirAviso(ASujeto: ISujeto; ADataTable: IDAStronglyTypedDataTable); var AFactura : IBizFacturaProveedor; ADetalles : IBizDetallesFacturaProveedor; begin inherited; if Supports(ADataTable, IBizDetallesFacturaProveedor, ADetalles) and Supports(ADetalles.DataTable.MasterSource.DataTable, IBizFacturaProveedor, AFactura) then begin RecalcularImportes(AFactura); end; end; procedure TFacturasProveedorController.RecuperarProveedor(AFactura: IBizFacturaProveedor); begin AFactura._Proveedor := (FProveedorController.Buscar(AFactura.ID_Proveedor) as IBizProveedor); end; function TFacturasProveedorController.Existe(const ID: Integer): Boolean; var AFactura : IBizFacturaProveedor; begin try AFactura := Buscar(ID); Result := Assigned(AFactura) and (AFactura.ID = ID); finally AFactura := NIL; end; end; function TFacturasProveedorController.ExtraerSeleccionados(AFacturasProveedor: IBizFacturaProveedor): IBizFacturaProveedor; var ASeleccionados : IBizFacturaProveedor; begin ASeleccionados := (Self.Buscar(ID_NULO) as IBizFacturaProveedor); CopyDataTableDA5(AFacturasProveedor.DataTable, ASeleccionados.DataTable, True); Result := ASeleccionados; end; procedure TFacturasProveedorController.FiltrarAno(AFactura: IBizFacturaProveedor; 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_FacturasProveedorFECHA_FACTURA), NewConstant(FechaIni, datString), dboGreaterOrEqual); Condicion := NewBinaryExpression(NewBinaryExpression(NewField('', fld_FacturasProveedorFECHA_FACTURA), NewConstant(FechaFin, datString), dboLessOrEqual), Condicion, dboAnd); if IsEmpty then Expression := Condicion else Expression := NewBinaryExpression(Condicion, Expression, dboAnd); end; end; end; procedure TFacturasProveedorController.FiltrarEmpresa(AFactura: IBizFacturaProveedor); 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_FacturasProveedorID_EMPRESA), NewConstant(AppFactuGES.EmpresaActiva.ID, datInteger), dboEqual); if IsEmpty then Expression := Condicion else Expression := NewBinaryExpression(Expression, Condicion, dboAnd); end; end; procedure TFacturasProveedorController.SetProveedorController(const Value: IProveedoresController); begin FProveedorController := Value; end; procedure TFacturasProveedorController.SetDetallesController(const Value: IDetallesFacturaProveedorController); begin FDetallesController := Value; end; function TFacturasProveedorController.Guardar(AFactura: IBizFacturaProveedor): Boolean; 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án bien. RecalcularImportes(AFactura); try AFactura.DataTable.ApplyUpdates; //Se generan los recibos automáticamente a partir de la forma de pago GenerarRecibos(AFactura); Result := True; finally HideHourglassCursor; end; end; end; function TFacturasProveedorController.Nuevo(withInsert: Boolean = True): IBizFacturaProveedor; var AFactura : IBizFacturaProveedor; begin AFactura := FDataModule.NewItem; FiltrarEmpresa(AFactura); AFactura.DataTable.Active := True; if withInsert then AFactura.Insert; Result := AFactura; end; procedure TFacturasProveedorController.Preview(AFactura: IBizFacturaProveedor; AllItems: Boolean = false); var AReportController : IFacturasProveedorReportController; ID_Facturas: TStringList; begin AReportController := TFacturasProveedorReportController.Create; try ID_Facturas := TStringList.Create; //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(IntToStr(AFactura.ID)); Next; end; end; end //Solo previsualizamos el item seleccionado else ID_Facturas.Add(IntToStr(AFactura.ID)); AReportController.Preview(ID_Facturas.CommaText); finally AReportController := NIL; FreeANDNIL(ID_Facturas); end; end; procedure TFacturasProveedorController.Print(AFactura: IBizFacturaProveedor; AllItems: Boolean = false); var AReportController : IFacturasProveedorReportController; ID_Facturas: TStringList; begin AReportController := TFacturasProveedorReportController.Create; try ID_Facturas := TStringList.Create; //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(IntToStr(AFactura.ID)); Next; end; end; end //Solo previsualizamos el item seleccionado else ID_Facturas.Add(IntToStr(AFactura.ID)); AReportController.Print(ID_Facturas.CommaText); finally AReportController := NIL; FreeANDNIL(ID_Facturas); end; end; function TFacturasProveedorController.GenerarAbono(AFactura: IBizFacturaProveedor): IBizFacturaProveedor; 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 TFacturasProveedorController.GenerarRecibos(AFactura: IBizFacturaProveedor); var AFormasPagoController : IFormasPagoController; AFormaPago: IBizFormaPago; ARecibosProveedorController: IRecibosProveedorController; ARecibos: IBizRecibosProveedor; AFechaVencimiento: TDateTime; i: Integer; ADiaVencimiento: Integer; ADiasMas: Integer; BSemaforo: Boolean; begin if not Assigned(AFactura) then Exit; AFormasPagoController := TFormasPagoController.Create; AFormaPago := AFormasPagoController.Buscar(AFactura.ID_FORMA_PAGO); AFormaPago.DataTable.Active := True; ARecibosProveedorController := TRecibosProveedorController.Create; //Eliminamos todos los recibos que tuviera la factura porque sabemos que todos //estarán pendientes (solo permitiremos modificar y eliminar facturas pendientes, //parcialmente pagadas o pagadas no ARecibos := ARecibosProveedorController.BuscarRecibosFactura(AFactura.ID); ARecibosProveedorController.EliminarTodo(ARecibos); //Se cambia la lógica a peticion de tecsitel, en el caso de meter una fecha de vencimiento, //los plazos de la forma de pago no tendrán efecto, se generará un recibo con el 100% y fecha de vencimiento //de la factura. With AFormaPago.Plazos.DataTable do begin i := 1; First; repeat ARecibos := ARecibosProveedorController.Nuevo; ARecibos.Edit; ARecibos.ID_FACTURA := AFactura.ID; ARecibos.REFERENCIA := AFactura.REFERENCIA + ' - ' + IntToStr(i); ARecibos.FECHA_EMISION := AFactura.FECHA_FACTURA; ARecibos.DATOS_BANCARIOS := AFactura.DATOS_BANCARIOS; if AFormaPago.Plazos.RecordCount < 1 then begin ARecibos.FECHA_VENCIMIENTO := AFactura.FECHA_VENCIMIENTO; ARecibos.IMPORTE := AFactura.IMPORTE_TOTAL; end else begin AFechaVencimiento := AFactura.FECHA_FACTURA + AFormaPago.Plazos.NUM_DIAS; ADiasMas := 0; BSemaforo := False; if (AFactura.Proveedor.VENCIMIENTO_FACTURAS_1 <> 0) or (AFactura.Proveedor.VENCIMIENTO_FACTURAS_2 <> 0) or (AFactura.Proveedor.VENCIMIENTO_FACTURAS_3 <> 0) then begin ADiaVencimiento := DayOf(AFechaVencimiento); while (ADiaVencimiento <> AFactura.Proveedor.VENCIMIENTO_FACTURAS_1) and (ADiaVencimiento <> AFactura.Proveedor.VENCIMIENTO_FACTURAS_2) and (ADiaVencimiento <> AFactura.Proveedor.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 := AFactura.IMPORTE_TOTAL * (AFormaPago.Plazos.PORCENTAJE / 100); end; ARecibos.DESCRIPCION := 'Pago de factura ' + AFactura.REFERENCIA + ': son ' + CifraToLetras(ARecibos.IMPORTE); ARecibosProveedorController.Guardar(ARecibos); Inc(i); Next; until (eof); end; //Liberamos AFormasPagoController := Nil; AFormaPago := Nil; ARecibosProveedorController := Nil; ARecibos := Nil; end; function TFacturasProveedorController.GetProveedorController: IProveedoresController; begin Result := FProveedorController; end; function TFacturasProveedorController.GetDetallesController: IDetallesFacturaProveedorController; begin Result := FDetallesController; end; end.