unit uGenerarFacturasProvPedProvUtils; interface uses Windows, SysUtils, Classes, uBizPedidosProveedor, uBizFacturasProveedor, pngimage, JSDialog; type TdmGenerarFacturasProv = class(TDataModule) JsListaFacturasGeneradas: TJSDialog; end; function GenerarFacturaProv(const IDPedido : Integer) : Boolean; overload; function GenerarFacturasProv : Boolean; overload; function GenerarFacturasProv(APedidos : IBizPedidoProveedor) : Boolean; overload; function GenerarFacturasdeListaPedidos(AFacturas: IBizFacturaProveedor; AListaPedidos: IBizPedidoProveedor): Boolean; implementation {$R *.dfm} uses uDialogUtils, uControllerDetallesBase, DB, uDADataTable, schFacturasProveedorClient_Intf, uBizDetallesPedidoProveedor, schPedidosProveedorClient_Intf, uPedidosProveedorController, uDetallesPedidoProveedorController, uFacturasProveedorController, uBizDetallesFacturaProveedor; var dmGenerarFacturasProv: TdmGenerarFacturasProv; APedidosProveedorController : IPedidosProveedorController; ADetallesPedidosProveedorController : IDetallesPedidoProveedorController; AFacturasProveedorController : IFacturasProveedorController; { Métodos auxiliares } procedure CopiarPedidoAFactura(APedido: IBizPedidoProveedor; AFactura : IBizFacturaProveedor); begin if not Assigned(AFactura) then raise Exception.Create ('Albarán no asignado (CopiarPedidoAAlbaran)'); if not Assigned(APedido) then raise Exception.Create ('Pedido no asignado (CopiarPedidoAAlbaran)'); if not APedido.DataTable.Active then APedido.DataTable.Active := True; APedidosProveedorController.RecuperarProveedor(APedido); if not APedido.Proveedor.DataTable.Active then APedido.Proveedor.DataTable.active := true; // La factura tiene que venir ya abierta y posicionado donde hay que copiar AFactura.ID_PROVEEDOR := APedido.ID_PROVEEDOR; AFactura.CALLE := APedido.CALLE; AFactura.CODIGO_POSTAL := APedido.CODIGO_POSTAL; AFactura.POBLACION := APedido.POBLACION; AFactura.PROVINCIA := APedido.PROVINCIA; AFactura.IMPORTE_NETO := APedido.IMPORTE_NETO; AFactura.IMPORTE_PORTE := APedido.IMPORTE_PORTE; AFactura.DESCUENTO := APedido.DESCUENTO; AFactura.IMPORTE_DESCUENTO := APedido.IMPORTE_DESCUENTO; AFactura.BASE_IMPONIBLE := APedido.BASE_IMPONIBLE; AFactura.IVA := APedido.IVA; AFactura.IMPORTE_IVA := APedido.IMPORTE_IVA; AFactura.IMPORTE_TOTAL := APedido.IMPORTE_TOTAL; AFactura.DataTable.FieldByName(fld_FacturasProveedorOBSERVACIONES).AsVariant := APedido.DataTable.FieldByName(fld_PedidosProveedorOBSERVACIONES).AsVariant; AFactura.NIF_CIF := APedido.Proveedor.NIF_CIF; AFactura.NOMBRE_COMERCIAL_PROVEEDOR := APedido.Proveedor.NOMBRE_COMERCIAL; AFactura.ID_FORMA_PAGO := APedido.Proveedor.ID_FORMA_PAGO; end; procedure CopiarArticulosAFactura(APedido: IBizPedidoProveedor; AFactura: IBizFacturaProveedor); var i : integer; ADetalles : IBizDetallesFacturaProveedor; begin if not Assigned(AFactura) then raise Exception.Create ('Factura no asignada (CopiarArticulosAFactura)'); if not Assigned(APedido) then raise Exception.Create ('Factura no asignada (CopiarArticulosAFactura)'); // La factura tiene que venir ya abierta y posicionada donde hay que copiar ADetalles := AFactura.Detalles; 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 AFacturasProveedorController.DetallesController.BeginUpdate(ADetalles); APedido.Detalles.DataTable.First; for i := 0 to APedido.Detalles.DataTable.RecordCount - 1 do begin AFacturasProveedorController.DetallesController.Add(ADetalles, TIPO_DETALLE_CONCEPTO); ADetalles.Edit; ADetalles.REFERENCIA := APedido.Detalles.REFERENCIA; ADetalles.ID_ARTICULO := APedido.Detalles.ID_ARTICULO; ADetalles.CONCEPTO := APedido.Detalles.CONCEPTO; ADetalles.IMPORTE_UNIDAD := APedido.Detalles.IMPORTE_UNIDAD; ADetalles.DESCUENTO := APedido.Detalles.DESCUENTO; ADetalles.IMPORTE_PORTE := APedido.Detalles.IMPORTE_PORTE; ADetalles.CANTIDAD := APedido.Detalles.CANTIDAD; ADetalles.IMPORTE_TOTAL := APedido.Detalles.IMPORTE_TOTAL; ADetalles.REFERENCIA_PROVEEDOR := APedido.Detalles.REFERENCIA_PROVEEDOR; ADetalles.Post; APedido.Detalles.Next; end; finally AFacturasProveedorController.DetallesController.EndUpdate(ADetalles); // AFacturasProveedorController.DetallesController.ActualizarTotales(ADetalles); end; end; procedure Inicializar; begin dmGenerarFacturasProv := TdmGenerarFacturasProv.Create(nil); APedidosProveedorController := TPedidosProveedorController.Create; ADetallesPedidosProveedorController := TDetallesPedidoProveedorController.Create; AFacturasProveedorController := TFacturasProveedorController.Create; // AProveedoresController := TProveedoresController.Create; end; procedure Finalizar; begin FreeAndNIL(dmGenerarFacturasProv); APedidosProveedorController := nil; ADetallesPedidosProveedorController := nil; AFacturasProveedorController := nil; // AProveedoresController := nil; end; function GenerarFacturaProv(const IDPedido : Integer) : Boolean; overload; var APedido : IBizPedidoProveedor; begin Result := False; if not Assigned(APedidosProveedorController) then Inicializar; APedido := APedidosProveedorController.Buscar(IDPedido); Result := GenerarFacturasProv(APedido); if Assigned(APedidosProveedorController) then Finalizar; end; function GenerarFacturasProv : Boolean; overload; var APedidos : IBizPedidoProveedor; begin Result := False; if not Assigned(APedidosProveedorController) then Inicializar; APedidos := APedidosProveedorController.ElegirPedidos(APedidosProveedorController.BuscarSinFacturar, 'Elija el pedido/s de proveedor que desea utilizar para dar de alta la factura.' + #10#13 + 'Si elige Pedidos de proveedores diferentes se dará de alta una factura por cada uno de ellos.' , True); if Assigned(APedidos) then Result := GenerarFacturasProv(APedidos); if Assigned(APedidosProveedorController) then Finalizar; end; function GenerarFacturasProv(APedidos : IBizPedidoProveedor) : Boolean; overload; var AFacturasNuevas : IBizFacturaProveedor; i: Integer; ARespuesta : Integer; begin Result := False; if not Assigned(APedidosProveedorController) then Inicializar; if not Assigned(APedidos) then raise Exception.Create('Pedidos de proveedor no asignado (GenerarFacturasProv)'); if not APedidos.DataTable.Active then APedidos.DataTable.Active := True; try AFacturasNuevas := AFacturasProveedorController.Nuevo(False); if GenerarFacturasdeListaPedidos(AFacturasNuevas, APedidos) then begin if AFacturasNuevas.DataTable.RecordCount = 1 then begin with dmGenerarFacturasProv.JsListaFacturasGeneradas do begin Content.Clear; Content.Add(Format('Se ha generado correctamente la factura %s a partir del pedido de proveedor' + #10#13, [AFacturasNuevas.REFERENCIA])); end; end else begin dmGenerarFacturasProv.JsListaFacturasGeneradas.CustomButtons[1].Destroy; with dmGenerarFacturasProv.JsListaFacturasGeneradas.Content do begin Clear; AFacturasNuevas.DataTable.Last; for i := 0 to AFacturasNuevas.DataTable.RecordCount - 1 do begin if Length(AFacturasNuevas.REFERENCIA) > 0 then Add(AFacturasNuevas.REFERENCIA + ': ' + AFacturasNuevas.NOMBRE); AFacturasNuevas.DataTable.Prior; end; end; end; dmGenerarFacturasProv.JsListaFacturasGeneradas.Execute; ARespuesta := dmGenerarFacturasProv.JsListaFacturasGeneradas.CustomButtonResult; case ARespuesta of 100 : begin // Ver la factura AFacturasProveedorController.Ver(AFacturasNuevas); end; 200 : // Continuar; end; end; finally AFacturasNuevas := NIL; end; end; function GenerarFacturasdeListaPedidos(AFacturas: IBizFacturaProveedor; AListaPedidos: IBizPedidoProveedor): Boolean; var AFacturaActual : IBizFacturaProveedor; APedidosController : IPedidosProveedorController; AArticulosPendientes : IBizDetallesPedidoProveedorPend; I: Integer; bEnEdicion : Boolean; begin Result := False; // ATENCIÓN!!! AFacturas tiene que estar vacio para no pisar facturas // ya generados. if not Assigned(AFacturas) then raise Exception.Create ('Facturas no asignado (Anadir)'); if not Assigned(AListaPedidos) then raise Exception.Create ('Pedidos no asignados (Anadir)'); if not AFacturas.DataTable.Active then AFacturas.DataTable.Active := True; if not AListaPedidos.DataTable.Active then AListaPedidos.DataTable.Active := True; APedidosController := TPedidosProveedorController.Create; try // Ordenar por fecha de pedido AListaPedidos.DataTable.Sort([fld_PedidosProveedorFECHA_PEDIDO], [uDADataTable.sdAscending]); AListaPedidos.First; for I := 0 to AListaPedidos.DataTable.RecordCount - 1 do begin AListaPedidos._Proveedor := NIL; AFacturaActual := NIL; // Busco si hay alguna factura ya hecha de ese Proveedor AFacturas.DataTable.First; if AFacturas.DataTable.Locate(fld_FacturasProveedorID_Proveedor, AListaPedidos.ID_Proveedor, []) then AFacturaActual := AFacturas else begin // No hay factura de ese proveedor. Creo una nueva AFacturasProveedorController.Anadir(AFacturas); AFacturaActual := AFacturas; end; //Asignamos el proveedor del pedido en la factura siempre APedidosController.RecuperarProveedor(AListaPedidos); AFacturaActual.Proveedor := AListaPedidos.Proveedor; //Tanto si es nueva como ya existe añadimos la referencia del pedido a añadir bEnEdicion := (AFacturaActual.DataTable.State in dsEditModes); if not bEnEdicion then AFacturaActual.Edit; //Por cada pedido a añadir lo asignamos al campo manual de referencias de pedidos asociados REF_PEDIDOS_PROV AFacturaActual.REF_PEDIDOS_PROV := AFacturaActual.REF_PEDIDOS_PROV + ' ' + AListaPedidos.REFERENCIA; AFacturaActual.Post; if bEnEdicion then AFacturaActual.Edit; AFacturaActual.Detalles.DataTable.Last; // Añado el título AFacturasProveedorController.DetallesController.Add(AFacturaActual.Detalles, TIPO_DETALLE_TITULO); with AFacturaActual.Detalles do begin Edit; CONCEPTO := 'Pedido ' + AListaPedidos.REFERENCIA + ' del ' + DateToStr(AListaPedidos.FECHA_PEDIDO); Post; end; // Añado el contenido del pedido CopiarArticulosAFactura(AListaPedidos, AFacturaActual); {En los albaranes a proveedor el porte es a nivel del artículo Self.DetallesController.Add(AFacturaActual.Detalles, TIPO_DETALLE_CONCEPTO); with AFacturaActual.Detalles do begin Edit; CONCEPTO := 'Porte del albarán'; CANTIDAD := 1; IMPORTE_UNIDAD := AListaAlbaranes.IMPORTE_PORTE; Post; end; } // Añado el resumen AFacturasProveedorController.DetallesController.Add(AFacturaActual.Detalles, TIPO_DETALLE_SUBTOTAL); with AFacturaActual.Detalles do begin Edit; CONCEPTO := 'Total del pedido ' + AListaPedidos.REFERENCIA; Post; end; // Añado una línea en blanco AFacturasProveedorController.DetallesController.Add(AFacturaActual.Detalles, TIPO_DETALLE_CONCEPTO); with AFacturaActual.Detalles do begin Edit; CONCEPTO := ''; Post; end; // Guardo el albaran que acabo de generar o editar AFacturaActual.CalcularImporteTotal; AFacturasProveedorController.Guardar(AFacturaActual); // No se asocia la factura al pedido ya que un pedido, solo puede estar asociado a una factura y una factura puede tener asociados varios pedidos //09/06/2025 ahora Stefy nos dice que puede venir un pedido en varias facturas diferentes por lo que no podemos asociar la factura al pedido AListaPedidos.Edit; AListaPedidos.ID_FACTURA := AFacturaActual.ID; AListaPedidos.REF_FACTURA := AFacturaActual.REFERENCIA; AListaPedidos.Post; APedidosController.Guardar(AListaPedidos); AListaPedidos.Next; end; Result := True; finally APedidosController := NIL; end; end; end.