unit uGenerarFacturasProPreCliUtils; interface uses Windows, SysUtils, Classes, uBizFacturasProforma, uBizPresupuestosCliente, pngimage, JSDialog; type TdmGenerarFacturasProPre = class(TDataModule) JsListaFacturasGeneradas: TJSDialog; end; function GenerarFacturaProPre(const IDPresupuesto : Integer; const CopiarDetalles: Boolean = True) : Boolean; overload; function GenerarFacturaProPre(APresupuestos : IBizPresupuestoCliente; const CopiarDetalles: Boolean = True) : Boolean; overload; function GenerarFacturaProPre : Boolean; overload; function GenerarFacturas(AFacturas : IBizFacturaProforma; AListaPresupuestos : IBizPresupuestoCliente; const CopiarDetalles: Boolean = True): Boolean; implementation {$R *.dfm} uses uDialogUtils, uDADataTable, uControllerDetallesBase, uBizDetallesPresupuestoCliente, schPresupuestosClienteClient_Intf, schFacturasProformaClient_Intf, uDetallesFacturaProformaController, uPresupuestosClienteController, uDetallesPresupuestoClienteController, uFacturasProformaController, uBizDetallesFacturaProforma; var dmGenerarFacturasProPre: TdmGenerarFacturasProPre; APresupuestosClienteController : IPresupuestosClienteController; ADetallesPresupuestosClienteController : IDetallesPresupuestoClienteController; AFacturasProformaController : IFacturasProformaController; { Métodos auxiliares } procedure CopiarArticulosPresupuesto(AOrigen: IBizDetallesPresupuestoCliente; ADestino : IBizDetallesFacturaProforma); var i : integer; ADetallesController : IDetallesFacturaProformaController; begin if not Assigned(AOrigen) then raise Exception.Create ('Origen no asignado (CopiarArticulosPresupuesto)'); if not Assigned(ADestino) then raise Exception.Create ('Destino no asignado (CopiarArticulosPresupuesto)'); if not AOrigen.DataTable.Active then AOrigen.DataTable.Active := True; if not ADestino.DataTable.Active then ADestino.DataTable.Active := True; ADetallesController := TDetallesFacturaProformaController.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 dmGenerarFacturasProPre := TdmGenerarFacturasProPre.Create(nil); APresupuestosClienteController := TPresupuestosClienteController.Create; ADetallesPresupuestosClienteController := TDetallesPresupuestoClienteController.Create; AFacturasProformaController := TFacturasProformaController.Create; end; procedure Finalizar; begin FreeAndNIL(dmGenerarFacturasProPre); APresupuestosClienteController := nil; ADetallesPresupuestosClienteController := nil; AFacturasProformaController := nil; end; function GenerarFacturaProPre(const IDPresupuesto : Integer; const CopiarDetalles: Boolean = True) : Boolean; overload; var APresupuesto : IBizPresupuestoCliente; begin Result := False; if not Assigned(APresupuestosClienteController) then Inicializar; APresupuesto := APresupuestosClienteController.Buscar(IDPresupuesto); Result := GenerarFacturaProPre(APresupuesto, CopiarDetalles); if Assigned(APresupuestosClienteController) then Finalizar; end; function GenerarFacturaProPre(APresupuestos : IBizPresupuestoCliente; const CopiarDetalles: Boolean = True) : Boolean; overload; var ARespuesta : Integer; AFacturasNuevas : IBizFacturaProforma; i: Integer; begin Result := False; if not Assigned(APresupuestos) then raise Exception.Create('Presupuesto de cliente no asignado (GenerarFacturaProPre)'); if not APresupuestos.DataTable.Active then APresupuestos.DataTable.Active := True; if not Assigned(APresupuestosClienteController) then Inicializar; try AFacturasNuevas := AFacturasProformaController.Nuevo(False); if GenerarFacturas(AFacturasNuevas, APresupuestos, CopiarDetalles) then begin if AFacturasNuevas.DataTable.RecordCount = 1 then begin ShowInfoMessage('La factura proforma se ha dado de alta con el código ' + AFacturasNuevas.REFERENCIA) end else begin with dmGenerarFacturasProPre.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; dmGenerarFacturasProPre.JsListaFacturasGeneradas.Execute; end; Result := True; end; finally AFacturasNuevas := NIL; if Assigned(APresupuestosClienteController) then Finalizar; end; end; function GenerarFacturaProPre : Boolean; overload; var APresupuestos : IBizPresupuestoCliente; begin Result := False; try if not Assigned(APresupuestosClienteController) then Inicializar; APresupuestos := APresupuestosClienteController.ElegirPresupuestos(APresupuestosClienteController.BuscarTodos, 'Elija el presupuesto o presupuestos de proveedor que desea utilizar para dar de alta la factura.' + #10#13 + 'Si elige presupuestos de proveedores diferentes se dará de alta una factura por cada uno de ellos.' , True); if Assigned(APresupuestos) then begin if (ShowConfirmMessage('Generar factura', Format('¿Desea copiar todos los conceptos de/los presupuesto/s seleccionados a sus facturas correspondientes?', [])) = IDYES) then Result := GenerarFacturaProPre(APresupuestos) else Result := GenerarFacturaProPre(APresupuestos, False); end; if Assigned(APresupuestosClienteController) then Finalizar; finally APresupuestos := Nil; end; end; function GenerarFacturas(AFacturas : IBizFacturaProforma; AListaPresupuestos : IBizPresupuestoCliente; const CopiarDetalles: Boolean = True): Boolean; var AFacturaActual : IBizFacturaProforma; APresupuestosController : IPresupuestosClienteController; 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(AListaPresupuestos) then raise Exception.Create ('Presupuestos no asignados (Anadir)'); if not AFacturas.DataTable.Active then AFacturas.DataTable.Active := True; if not AListaPresupuestos.DataTable.Active then AListaPresupuestos.DataTable.Active := True; APresupuestosController := TPresupuestosClienteController.Create; try // Ordenar por fecha de albaran AListaPresupuestos.DataTable.Sort([fld_PresupuestosClienteFECHA_PRESUPUESTO], [uDADataTable.sdAscending]); AListaPresupuestos.First; for I := 0 to AListaPresupuestos.DataTable.RecordCount - 1 do begin AListaPresupuestos._Cliente := NIL; AFacturaActual := NIL; // Busco si hay alguna factura ya hecha de ese Cliente AFacturas.DataTable.First; if AFacturas.DataTable.Locate(fld_FacturasProformaID_CLIENTE, AListaPresupuestos.ID_Cliente, []) then begin AFacturaActual := AFacturas; AFacturasProformaController.RecuperarCliente(AFacturaActual); AFacturaActual.Cliente.DataTable.Active := True; end else begin // No hay factura de ese Cliente. Creo una nueva AFacturasProformaController.Anadir(AFacturas); APresupuestosController.RecuperarCliente(AListaPresupuestos); AFacturas.Cliente := AListaPresupuestos.Cliente; // AFacturas.OBSERVACIONES.Add('Importe de factura por trabajos realizados según indicaciones de nuestro presupuesto ' + AListaPresupuestos.REFERENCIA + ' con fecha ' + DateToStr(AListaPresupuestos.FECHA_PRESUPUESTO)); AFacturaActual := AFacturas; end; // Ya tengo la factura. Le añado los conceptos del presupuesto AFacturaActual.Detalles.DataTable.Last; //Se pone la referencia del presupuesto y el total y nos olvidamos de los detalles if not CopiarDetalles then begin AFacturasProformaController.DetallesController.Add(AFacturaActual.Detalles, TIPO_DETALLE_CONCEPTO); with AFacturaActual.Detalles do begin Edit; CONCEPTO := 'Presupuesto ' + AListaPresupuestos.REFERENCIA; CANTIDAD := 1; IMPORTE_UNIDAD := AListaPresupuestos.IMPORTE_TOTAL; //Tecsitel no utiliza el IVA en los presupuestos por lo tanto el //importe total es lo que queremos (IMPORTE_NETO+IMPORTE_PORTE) Post; end; end //Se copian los detalles del presupuesto a la factura else begin // Añado el título AFacturasProformaController.DetallesController.Add(AFacturaActual.Detalles, TIPO_DETALLE_TITULO); with AFacturaActual.Detalles do begin Edit; CONCEPTO := 'Presupuesto ' + AListaPresupuestos.REFERENCIA + ' del ' + DateToStr(AListaPresupuestos.FECHA_PRESUPUESTO); Post; end; // Añado el contenido del presupuesto CopiarArticulosPresupuesto(AListaPresupuestos.Detalles, AFacturaActual.Detalles); //En el caso de tener porte el presupuesto se añade una fila con el importe if (AListaPresupuestos.IMPORTE_PORTE > 0) then begin AFacturasProformaController.DetallesController.Add(AFacturaActual.Detalles, TIPO_DETALLE_CONCEPTO); with AFacturaActual.Detalles do begin Edit; CONCEPTO := 'Porte del presupuesto'; CANTIDAD := 1; IMPORTE_UNIDAD := AListaPresupuestos.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 AFacturasProformaController.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 AFacturasProformaController.DetallesController.Add(AFacturaActual.Detalles, TIPO_DETALLE_SUBTOTAL); with AFacturaActual.Detalles do begin Edit; CONCEPTO := 'Total del presupuesto ' + AListaPresupuestos.REFERENCIA; Post; end; end; // Añado una línea en blanco AFacturasProformaController.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; AFacturasProformaController.Guardar(AFacturaActual); // Asocio la factura con el presupuesto AListaPresupuestos.Edit; AListaPresupuestos.Post; APresupuestosController.Guardar(AListaPresupuestos); AListaPresupuestos.Next; end; Result := True; finally APresupuestosController := NIL; end; end; end.