unit uGenerarFacturasProvPedUtils; interface uses Windows, SysUtils, Classes, uBizPedidosProveedor, uBizFacturasProveedor, pngimage, JSDialog; type TdmGenerarFacturasProvPed = class(TDataModule) JsListaFacturasGeneradas: TJSDialog; end; function GenerarFacturaProvPed(const IDPedido : Integer; const CopiarDetalles: Boolean = True) : Boolean; overload; function GenerarFacturaProvPed(APedidos : IBizPedidoProveedor; const CopiarDetalles: Boolean = True) : Boolean; overload; function GenerarFacturaProvPed : Boolean; overload; function GenerarFacturas(AFacturas : IBizFacturaProveedor; AListaPedidos : IBizPedidoProveedor; const CopiarDetalles: Boolean = True): Boolean; implementation {$R *.dfm} uses uDialogUtils, uDADataTable, uBizDetallesPedidoProveedor, uPedidosProveedorController, uDetallesPedidoProveedorController, uFacturasProveedorController, uControllerDetallesBase, schPedidosProveedorClient_Intf, schFacturasProveedorClient_Intf, uBizDetallesFacturaProveedor, uDetallesFacturaProveedorController; // , // , uProveedoresController, // , // , uBizContactos, // schPedidosProveedorClient_Intf; var dmGenerarFacturasProvPed: TdmGenerarFacturasProvPed; APedidosProveedorController : IPedidosProveedorController; ADetallesPedidosProveedorController : IDetallesPedidoProveedorController; AFacturasProveedorController : IFacturasProveedorController; // AProveedoresController : IProveedoresController; { Métodos auxiliares } {procedure CopiarPedidoAPedido(APedido: IBizPedidoCliente; APedido : IBizFacturaProveedor); begin if not Assigned(APedido) then raise Exception.Create ('Albarán no asignado (CopiarPedidoAPedido)'); if not Assigned(APedido) then raise Exception.Create ('Pedido no asignado (CopiarPedidoAPedido)'); if not APedido.DataTable.Active then APedido.DataTable.Active := True; // El albarán tiene que venir ya abierto y posicionado donde hay que copiar APedido.ID_CLIENTE := APedido.ID_CLIENTE; APedido.ID_PEDIDO := APedido.ID; APedido.CALLE := APedido.CALLE; APedido.CODIGO_POSTAL := APedido.CODIGO_POSTAL; APedido.POBLACION := APedido.POBLACION; APedido.PROVINCIA := APedido.PROVINCIA; APedido.PERSONA_CONTACTO := APedido.PERSONA_CONTACTO; APedido.TELEFONO := APedido.TELEFONO; APedido.IMPORTE_NETO := APedido.IMPORTE_NETO; APedido.IMPORTE_PORTE := APedido.IMPORTE_PORTE; APedido.DESCUENTO := APedido.DESCUENTO; APedido.IMPORTE_DESCUENTO := APedido.IMPORTE_DESCUENTO; APedido.BASE_IMPONIBLE := APedido.BASE_IMPONIBLE; APedido.IVA := APedido.IVA; APedido.IMPORTE_IVA := APedido.IMPORTE_IVA; APedido.IMPORTE_TOTAL := APedido.IMPORTE_TOTAL; APedido.DataTable.FieldByName(fld_PedidosClienteOBSERVACIONES).AsVariant := APedido.DataTable.FieldByName(fld_PedidosClienteOBSERVACIONES).AsVariant; APedido.ID_FORMA_PAGO := APedido.ID_FORMA_PAGO; end; procedure CopiarArticulosPendAPedido( APedido: IBizPedidoCliente; APedido: IBizFacturaProveedor; AArticulosPendientes: IBizPedidoClienteArticulosPend); var i : integer; ADetalles : IBizDetallesFacturaProveedor; ADetallesController : IDetallesFacturaProveedorController; begin if not Assigned(APedido) then raise Exception.Create ('Albarán no asignado (CopiarArticulosPendAPedido)'); if not Assigned(APedido) then raise Exception.Create ('Pedido no asignado (CopiarArticulosPendAPedido)'); if not Assigned(AArticulosPendientes) then raise Exception.Create ('Artículos pendientes no asignado (CopiarArticulosPendAPedido)'); if not AArticulosPendientes.DataTable.Active then AArticulosPendientes.DataTable.Active := True; // El albarán tiene que venir ya abierto y posicionado donde hay que copiar ADetalles := APedido.Detalles; 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(ADetalles); AArticulosPendientes.DataTable.First; for i := 0 to AArticulosPendientes.DataTable.RecordCount - 1 do begin APedido.Detalles.First; if (APedido.Detalles.Locate('ID_ARTICULO', AArticulosPendientes.ID_ARTICULO, [])) then if (AArticulosPendientes.CANTIDAD_PENDIENTE > 0) then begin ADetallesController.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.CANTIDAD := AArticulosPendientes.CANTIDAD_PENDIENTE; ADetalles.IMPORTE_UNIDAD := APedido.Detalles.IMPORTE_UNIDAD; ADetalles.IMPORTE_TOTAL := APedido.Detalles.IMPORTE_TOTAL; ADetalles.DESCUENTO := APedido.Detalles.DESCUENTO; ADetalles.IMPORTE_PORTE := APedido.Detalles.IMPORTE_PORTE; ADetalles.VISIBLE := APedido.Detalles.VISIBLE; ADetalles.REFERENCIA_PROVEEDOR := APedido.Detalles.REFERENCIA_PROVEEDOR; ADetalles.Post; AArticulosPendientes.Next; end; end; finally ADetallesController.EndUpdate(ADetalles); ADetallesController := NIL; end; end; } 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; procedure Inicializar; begin dmGenerarFacturasProvPed := TdmGenerarFacturasProvPed.Create(nil); APedidosProveedorController := TPedidosProveedorController.Create; ADetallesPedidosProveedorController := TDetallesPedidoProveedorController.Create; AFacturasProveedorController := TFacturasProveedorController.Create; end; procedure Finalizar; begin FreeAndNIL(dmGenerarFacturasProvPed); APedidosProveedorController := nil; ADetallesPedidosProveedorController := nil; AFacturasProveedorController := nil; end; function GenerarFacturaProvPed(const IDPedido : Integer; const CopiarDetalles: Boolean = True) : Boolean; overload; var APedido : IBizPedidoProveedor; begin Result := False; try if not Assigned(APedidosProveedorController) then Inicializar; APedido := APedidosProveedorController.Buscar(IDPedido); if Assigned(APedido) then Result := GenerarFacturaProvPed(APedido, CopiarDetalles); if Assigned(APedidosProveedorController) then Finalizar; finally APedido := Nil; end; end; function GenerarFacturaProvPed(APedidos : IBizPedidoProveedor; const CopiarDetalles: Boolean = True) : Boolean; overload; var AFacturasNuevas : IBizFacturaProveedor; i: Integer; begin Result := False; if not Assigned(APedidos) then raise Exception.Create('Pedido de proveedor no asignado (GenerarFacturaProvPed)'); if not APedidos.DataTable.Active then APedidos.DataTable.Active := True; if not Assigned(APedidosProveedorController) then Inicializar; try AFacturasNuevas := AFacturasProveedorController.Nuevo(False); if GenerarFacturas(AFacturasNuevas, APedidos, CopiarDetalles) then begin if AFacturasNuevas.DataTable.RecordCount = 1 then begin if AFacturasNuevas.TIPO = CTE_TIPO_FACTURA then ShowInfoMessage('La factura se ha dado de alta con el código ' + AFacturasNuevas.REFERENCIA) else ShowInfoMessage('El abono se ha dado de alta con el código ' + AFacturasNuevas.REFERENCIA); end else begin with dmGenerarFacturasProvPed.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; dmGenerarFacturasProvPed.JsListaFacturasGeneradas.Execute; end; Result := True; end; finally AFacturasNuevas := NIL; if Assigned(APedidosProveedorController) then Finalizar; end; end; function GenerarFacturaProvPed : Boolean; overload; var APedidos : IBizPedidoProveedor; begin Result := False; if not Assigned(APedidosProveedorController) then Inicializar; APedidos := APedidosProveedorController.ElegirPedidos(APedidosProveedorController.BuscarSinFacturar, 'Elija el pedido o pedidos 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 begin if (ShowConfirmMessage('Generar factura', Format('¿Desea copiar todos los conceptos de/los pedido/s seleccionados a sus facturas correspondientes?', [])) = IDYES) then Result := GenerarFacturaProvPed(APedidos) else Result := GenerarFacturaProvPed(APedidos, False); end; if Assigned(APedidosProveedorController) then Finalizar; end; function GenerarFacturas(AFacturas : IBizFacturaProveedor; AListaPedidos : IBizPedidoProveedor; const CopiarDetalles: Boolean = True): Boolean; var AFacturaActual : IBizFacturaProveedor; APedidosController : IPedidosProveedorController; I: Integer; bEnEdicion : Boolean; begin // ATENCIÓN!!! AFacturas tiene que estar vacio para no pisar facturas // ya generadas. if not Assigned(AFacturas) then raise Exception.Create ('Factura 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 albaran 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 begin AFacturaActual := AFacturas; AFacturasProveedorController.RecuperarProveedor(AFacturaActual); AFacturaActual.Proveedor.DataTable.Active := True; end else begin // No hay factura de ese Proveedor. Creo una nueva AFacturasProveedorController.Anadir(AFacturas); APedidosController.RecuperarProveedor(AListaPedidos); AListaPedidos.Proveedor.DataTable.Active := True; AFacturas.Proveedor := AListaPedidos.Proveedor; AFacturaActual := AFacturas; end; // Ya tengo la factura. Le añado los conceptos del pedido AFacturaActual.Detalles.DataTable.Last; //Se pone la referencia del pedido y el total y nos olvidamos de los detalles if not CopiarDetalles then begin AFacturasProveedorController.DetallesController.Add(AFacturaActual.Detalles, TIPO_DETALLE_CONCEPTO); with AFacturaActual.Detalles do begin Edit; CONCEPTO := 'Pedido ' + AListaPedidos.REFERENCIA; CANTIDAD := 1; IMPORTE_UNIDAD := AListaPedidos.IMPORTE_TOTAL; //Tecsitel no utiliza el IVA en los pedidos por lo tanto el //importe total es lo que queremos (IMPORTE_NETO+IMPORTE_PORTE) Post; end; end //Se copian los detalles del pedido a la factura else begin // 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 presupuesto CopiarArticulosPedido(AListaPedidos.Detalles, AFacturaActual.Detalles); //En el caso de tener porte el presupuesto se añade una fila con el importe if (AListaPedidos.IMPORTE_PORTE > 0) then begin AFacturasProveedorController.DetallesController.Add(AFacturaActual.Detalles, TIPO_DETALLE_CONCEPTO); with AFacturaActual.Detalles do begin Edit; CONCEPTO := 'Porte del pedido'; CANTIDAD := 1; IMPORTE_UNIDAD := AListaPedidos.IMPORTE_PORTE; Post; end; end; //En el caso de tener descuento (bonificación) el presupuesto se añade una fila con el importe { if (AListaPresupuestos.IMPORTE_DESCUENTO > 0) then begin AFacturasClienteController.DetallesController.Add(AFacturaActual.Detalles, TIPO_DETALLE_CONCEPTO); with AFacturaActual.Detalles do begin Edit; CONCEPTO := 'Bonificación ' + FloatToStr(AListaPresupuestos.DESCUENTO) + '%'; CANTIDAD := -1; IMPORTE_UNIDAD := AListaPresupuestos.IMPORTE_DESCUENTO; Post; end; 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; 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 la factura que acabo de generar o editar AFacturaActual.CalcularImporteTotal; AFacturasProveedorController.Guardar(AFacturaActual); // Asocio la factura con el presupuesto AListaPedidos.Edit; AListaPedidos.ID_FACTURA := AFacturaActual.ID; AListaPedidos.Post; APedidosController.Guardar(AListaPedidos); AListaPedidos.Next; end; Result := True; finally APedidosController := NIL; end; end; end.