QRComposite de QRComposites
#1
Escrito 02 junio 2013 - 09:59
Tengo una lista de animales, digamos: a1, a2, a3, ... an
Cada uno de esos animales tiene una serie de informes particulares, tienen un informe de pesajes, otro de vacunas, otro de enfermedades. Todos ellos en QReport's diferentes.
En un momento dado tengo que mostrar una lista con "el informe completo" (historia clínica completa) que consiste en la unión de los informes particulares. Hasta aquí la cosa va bien. El informe combinado lo hago con un QRComposite. Muestro la vista previa e imprimo sin problemas.
Resulta que ahora necesito que me salga (aquí quiero hacer una vista previa también) una unión de los informes completos de una sola vez, esto es: a1 (pesajes, vacunas, enfermedades), a continuación a2 (pesajes, vacunas, enfermedades), a continuación a3 (pesajes, vacunas, enfermedades), ... . En la vista previa debo ver un solo informe con estos informes uno abajo del otro y que tengan la numeración de hojas de manera continua.
Esto es particularmente importante puesto que la cantidad de animales es muy elevada y no es operativo imprimir la "historia clínica completa" de a una por vez.
Lo primero que se me ocurre es hacer una composición de composiciones o como se lo llame, pero no he dado con la forma correcta. ¿Cómo puede resolverse este tema?
Espero que se haya entendido, gracias.
Santiago.
#2
Escrito 02 junio 2013 - 01:58
#3
Escrito 02 junio 2013 - 03:27
¿Podrías dar un ejemplo o la descripción de como es cada informe compuesto? ¿Cómo está "estructurado" el informe?
Esto también dependerá de como está diseñada la tabla.
Si resulta ser que la consultas para generar el informe desde a1 a an son similares, o es más... es la misma, y únicamente lo que las hace diferente es lo da unicidad, el ID de la tabla maestra de la cual se desprenden yo me imagino que tal vez... , y sólo tal vez... no podría asegurarlo sin demasiadas pruebas, se pueda diseñar un único informe que se alimente con una única consulta con un order-by y configurar la banda que da inicio a cada informe (que se corresponde a un id en particular) a que se inicie en una nueva hoja.
Es decir que si en realidad la consulta, en términos abstractos, consiste en un:
select <tus-campos|subconsulta-de-historia-clinica>
from <tus-tablas>
group by TablaMaestra.IDAnimal
order by TablaMaestra.IDAnimal
Siendo subconsulta la consulta que genera cada informe en particular.
Entonces el motor debiera de devolver TODOS los informes de las historias clínicas agrupados y ordenados por el ID.
Luego es el QR quien se encarga de mostrar la información de forma adecuada y dar inicio a cada informe en una nueva hoja.
Es una idea que se me ocurrió, ahora de que sea viable no se. Para tener algo más preciso me temo que habría que saber como está diseñada tu tabla y tus informes.
Ahora, si resulta ser que cada informe tiene sus particularidades... se me rompe los esquemas.
Admito que tengo el cerebro en OFF hoy y no estoy con todas las luces prendidas
Saludos,
#4
Escrito 02 junio 2013 - 04:42
Los animales son los bovinos: terneros, terneras, vacas, toros.
Los informes son varios y muy distintos, así tenemos informes de: pesajes, vacunaciones, enfermedades, evolución de terneros (datos del crecimiento del ternerito), evolución de los toros (datos del crecimiento cuando ya es toro adulto), evolución de vacas (datos cuando ya es vaca adulta), preñeces (de las vacas claro)
Cada uno de estos informes tiene relación (en líneas generales) con una tabla, mas otra que es en la que están los datos generales del animalito.
Ahora bien, cuando el dueño del ganado quiere vender a sus animales necesita saber, y el cliente, que condición tienen sus "bichos". De ahí que estos informes están por separado, al momento de la verdad es bueno tener un informe donde se vean todos los datos (algo así como una carpeta con la vida del animal, a esto le llamamos "historia clínica")
Las sql's para cada informe son todas distintas, lo único en lo que coinciden son en los datos de identificación del animal (caravana, marca, tatuaje, cabaña, fecha nacimiiento, sexo, edad actual...)
Si quiero saber un aspecto particular del animal, puedo hacerlo, por ejemplo: "deme el historial de vacunación del animal con caravana tal...", dice el comprador (a esto lo puedo ver en vista previa e imprimirlo)
Si quiero saber toda la historia clínica del animal, puedo hacerlo, por ejemplo: "deme la historia clínica del animal con caravana tal... que es el que quiero comprar", dice el comprador (a esto lo puedo ver en vista previa e imprimirlo) --> Aquí tengo la composición de todos los informes particulares y va muy bien.
Resulta que cuando el propietario se decide a vender, quiere vender la mayor cantidad posible de animales por supuesto y lo mas sensato es tener una "carpeta" con la historia clínica (en papel) de cada animal en venta y esto es lo que no puedo hacer. Selecciono, por ejemplo, 250 animales que van a la venta y quiero los datos de todos ellos; sería bueno que el sistema me muestre la vista previa y me imprima los 250 informes (uno a continuación del otro), pero dando click una sola vez y no hacer 250 click's, uno por cada animal. Aquí es donde yo "invento" eso de la composición de QrComposite's.
Bueno, espero haber aclarado mas la cosa.
Santiago.
#5
Escrito 02 junio 2013 - 06:06
Así si se complica la cosa.
No recuerdo si es posible con QR guardar un reporte. Porque la posibilidad que estuve considerando es que se tenga guardado cada reporte en disco. Luego cuando se selecciona el listado a imprimir, bastaría con leer el "tipo" de informe a imprimir, cargarlo en el componente, y mandar a imprimir.
De forma burda, algo como:
ListadoSeleccion.First; for i := 0 to ListadoSeleccion.RecordCount - 1 do begin // suponiendo que existiera un campo por el que se pudiera diferenciar un tipo de reporte... tipo := ListadoSeleccion.FieldByName('Tipo').AsInteger; id := ListadoSeleccion.FieldByName('IDAnimal').AsInteger; case tipo of 1: reporte := 'NombreReporteTipo1.qrp'; //nombre del archivo 2: reporte := 'NombreReporteTipo2.qrp'; ... end; QRForm.QRRep.LoadReport(reporte); // O quizá algo como QRForm.QRRep.QRPrinter.Load(); QRForm.QRRep.DataSet.SQL.add('WHERE IDAnimal = :ParamID'); QRForm.QRRep.DataSet.SQL.ParamByName('ParamID').AsInteger := id; QRForm.Print; end;
Siendo ListadoSeleccion un DataSet con el listado ya filtrado de los animales para el informe, QRForm el Form donde estará el TQuickRep/TQRCompositeReport al que llamo QRRep.
Es decir, estar abriendo el reporte para cada tipo. Luego a éste report le indicamos que a su dataset asociado lo filtramos con el where según el ID del animal para que efectivamente se muestre el dato del animal en cuestión y por último mandarlos a imprimir.
Esto suponiendo que tal apertura del reporte lleve consigo la SQL que su dataset necesite y sólo haga falta añadir algún filtro. Sino habrá que tener tales SQLs almacenada previamente en algún lado.
Lo escribí al vuelo, no tengo a Delphi a mano en estos momentos.
Es una posibilidad, aunque tengo mis reservas de si es posible algo como esto.
Tengo un vago recuerdo de que si es posible tener un reporte almacenado en Disco. Lo que no recuerdo es si QR tiene un Load/Save... como método, o si había que utilizar a TQRPrinter como intermediario.
Algo como:
QRForm.QRRep.QRPrinter.Load()
Quizá la principal desventaja, si es que es posible hacerlo de esta forma, será la lentitud para procesar e imprimir todo. Porque el QR deberá generar el reporte en tiempo de ejecución y luego filtrar los datos para su dataset. Se formará una cola de impresión con tantos archivos como animales tenga y podría ser posible que esto lleve a problemas.
Por ahora es a lo que llego. Seguramente hay otras alternativas de como enfocarlo. Habrá que ver que dicen el resto de los compañeros.
Saludos,
#6
Escrito 02 junio 2013 - 06:14
Cualquier avance, o retroceso, en el tema lo cuento aquí.
Gracias compañero.
Santiago.
#7
Escrito 03 junio 2013 - 04:51
Pude mandar cada "historia clínica" seleccionada a un archivo .qrp, eso lo he logrado de la siguiente manera:
for i:=0 to (nros_caravana.Count - 1) do begin //.... código que no viene al caso QRCompositeReport1.Prepare; //Esto ejecuta el OnAdd que levanta los informes particulares, anda bien. TQuickRep(QRCompositeReport1.Reports.Items[0]).Printer.Save('reportes\Reporte' + IntToStr(i) + '.QRP'); end; qrcmpstrprtJuegosCompletos.Preview;
Con esto puedo guardar masivamente todas las "historias", lo que no he podido hacer ha sido levantarlas y mostrarlas en el preview, que es la última línea del código.
En el OnAdd de qrcmpstrprtJuegosCompletos:
procedure TFrmBuscarPesajes.qrcmpstrprtJuegosCompletosAddReports( Sender: TObject); var i:Integer; r:TQuickRep; begin r:=TQuickRep.Create(nil); r.QRPrinter:=TQRPrinter.Create(r); with qrcmpstrprtJuegosCompletos.Reports do begin //Tenemos que recuperar los archivos .qrp que guardamos por ahí for i:=0 to (nros_caravana.Count - 1) do begin r.QRPrinter.Load('reportes\Reporte' + IntToStr(i) + '.QRP'); Add(r); end; end; end;
El código anterior no me da error pero al aparecer la ventana de vista previa no se ve nada, aparece vacía. Para colmo si lo intento nuevamente me dice que el "último .qrp está siendo usado por otro procedimiento y no se puede tocar"
Los avances han sido buenos pero me falta la frutilla del postre que sería poder levantar los .qrp y armar el informe completo.
¿Alguien tiene sugerencias?
Gracias.
#8
Escrito 03 junio 2013 - 09:41
En realidad lo que debes hacer es crear varios reportes y agregarlos.
Debes llamar al constructor en cada ciclo.
Algo como esto:
procedure TFrmBuscarPesajes.qrcmpstrprtJuegosCompletosAddReports( Sender: TObject); var i:Integer; r:TQuickRep; begin with qrcmpstrprtJuegosCompletos.Reports do begin //Tenemos que recuperar los archivos .qrp que guardamos por ahí for i:=0 to (nros_caravana.Count - 1) do begin r:=TQuickRep.Create(nil); r.QRPrinter:=TQRPrinter.Create(r); r.QRPrinter.Load('reportes\Reporte' + IntToStr(i) + '.QRP'); Add(r); end; end; end;
Saludos
#9
Escrito 04 junio 2013 - 12:48
En el código anterior solamente estás creando un reporte y en el ciclo for agregas el mismo muchas veces.
En realidad lo que debes hacer es crear varios reportes y agregarlos.
Debes llamar al constructor en cada ciclo.
He hecho lo que sugieres y nada, igual que antes. El preview me sale vacío.
Santiago.
#10
Escrito 04 junio 2013 - 01:14
Eso se debe a que el componente de QR no tiene asociado un DataSet del cual extraer los datos para confeccionar el informe.
He hecho lo que sugieres y nada, igual que antes. El preview me sale vacío.
Santiago.
De mi pseudo ejemplo notarás que lo que hago es añadir un filtro. Eso lo hice pensando en la posibilidad de que el QR en su Save() almacenara internamente la consulta SQL y creara el DataSet en cuestión.
Bueno, la cosa aparentemente no es tan así... deberás asociarle un DataSet que ejecute la consulta SQL especialmente diseñada para el informe.
En caso de que al crear el QR éste crea su propio DataSet, entonces bastará con asignarle a éste la consulta SQL apropiada para el informe y configurarlo si es necesario.
Sino no lo crea, pues ya será responsabilidad nuestra el hacerlo.
Entonces, de algún modo debes de asociar a cada reporte, con su SQL. Puedes tener a las consultas guardadas en disco, y hacer por ejemplo:
r.QRPrinter.Load('reportes\Reporte' + IntToStr(i) + '.QRP'); r.DataSet.SQL.LoadFromFile('SQLReporte' + IntToStr(i) + '.SQL'); // el DataSet debe estar creado
Fíjate que en mi código de ejemplo expuse un WHERE ID = algo. Es fundamental para garantizar de que el informe sólo presente la consulta con los datos específicos a dicho animal.
Esto debiera de bastar para que el componente ahora si pueda ejecutar la vista previa sin problemas.
Saludos,
#11
Escrito 04 junio 2013 - 01:36
Sin duda es algo que estoy haciendo mal...
Se supone que un .qrp es un archivo que se guarda en un formato distinto a como fue originado el informe.
Bueno, seguiré probando y les digo.
¿No será que esta versión de QReport tiene algún drama? Uso la 5.02
Gracias.
#12
Escrito 04 junio 2013 - 02:32
1) Guardé un .qrp con la ventana preview -- reporte0.qrp (lo he comprobado y tiene datos, lo abrí en preview)
2)
qckrpJuegos.Prepare; qckrpJuegos.Printer.Load('reportes\Reporte0.QRP'); qckrpJuegos.Preview;
qckrpJuegos es un componente QReport que puse en el formulario.
Resultado: Ventana vacía.
¿Alguna idea sobre esto?
Gracias.
#13
Escrito 04 junio 2013 - 07:06
Mañana por la tarde podré darle un tiempo a probar esto.
Intentaré recrear las cosas que se han venido comentando. Lástima que en D6, QuickReport no viene con los fuentes como para estudiar en profundidad el caso.
Sino estudiaré que otras posibilidades hay.
Saludos,
#14
Escrito 04 junio 2013 - 07:23
procedure TFrmBuscarPesajes.componer_informe_completo(una_pagina_por_animal:Boolean); var h:TQRPHandler; begin //..... //Esto sí funciona, pero individualmente h:=TQRPHandler.Create; h.Filename:='reportes\Reporte0.QRP'; h.Preview; h.Filename:='reportes\Reporte1.QRP'; h.Preview; end;
Puedo ver los dos preview's, uno a la vez, con el reporte cargado.
Espero que esto sirva de ayuda a la causa.
Santiago.
#15
Escrito 04 junio 2013 - 07:24
El correcto es el último de la lista.
Gracias.
Santiago.
#16
Escrito 05 junio 2013 - 07:40
Uhhh, metí la pata, lo mandé tres veces.
El correcto es el último de la lista.
Gracias.
Santiago.
Listo, también lo edité para eliminar las citas.
Saludos
#17
Escrito 06 junio 2013 - 07:18
Santiago14 no he podido darme el tiempo necesario para hechar luz, disculpas.
En estos próximas días si estaré investigando un poco más; lo más probable es que sea el fin de semana.
Tomaré en cuenta las últimas novedades que comentaste. Quizá por allí vayan los tiros... quien sabe.
Lo que hace un poco más difícil llegar a entenderle las cosas es que al menos en D6 QR no viene con las fuentes y la documentación no es del todo aclaratoria. Es todo a ensayo y error.
Voy a estar consultando en inglés a ver si de casualidad llego a algo más.
Saludos,
#18
Escrito 06 junio 2013 - 07:37
Santiago.
#19
Escrito 06 junio 2013 - 05:27
Encontré la manera de hacerlo, lo cuento:
1) Generamos los .qrp, uno por cada informe independiente que tengo
2) Los guardamos en disco, cada uno con nombre. reporte0.qrp, reporte1.qrp, ... reporteN.qrp
3) Los levantamos y juntamos en un solo .qrp
4) Lo mostramos usando TQRPHandler de la unit QRExtra
¿Cómo hacemos el paso 3?
Resulta que hace algún tiempo la gente de qusoft armó una pequeña unidad llamada "QRQRP", que no es mas que un .pas común y lo puso en un archivo llamado QR3RNGD4.ZIP, lo podemos encontrar en: http://www.quickrepo...x?WebInfoID=620
Este .zip tiene, entre otras cosas, un .pas (qrqrp.pas) donde encontramos un procedimiento llamado "combineQRP" que hace el trabajo. De igual manera, analizando un poco el procedimiento no lo hace de la manera convencional, usa TStream y otras cositas... pero eso es tema de debate posterior.
En definitiva, el código quedaría así:
procedure TFrmBuscarPesajes.componer_informe_completo(una_pagina_por_animal:Boolean); var i:Integer; caravana_particular:TStringList; reportes_previosQRP:TStringList; //directorio_actual:string; h:TQRPHandler; begin with Application, DataModule1 do begin //Código que no viene al caso, son las llamadas a sql's y voy armando los informes particulares end; //Caravanas particulares para los informes particulares de los animales caravana_particular:=TStringList.Create; caravana_particular.Add(''); //Creamos el espacio para guardar las direcciones donde se guardan los .qrp reportes_previosQRP:=TStringList.Create; //Creamos la estructura del directorio para guardar los archivos Crear_directorio('reportes'); for i:=0 to (nros_caravana.Count - 1) do begin //Más sql's //Me manda el reporte combinado a un archivo .qrp QRCompositeReport1.Prepare; TQuickRep(QRCompositeReport1.Reports.Items[0]).Printer.Save('reportes\Reporte' + IntToStr(i) + '.QRP'); reportes_previosQRP.Add('reportes\Reporte' + IntToStr(i) + '.QRP'); end; //¡¡Aquí el gran truco!! //El primer parámetro es donde se guarda el .qrp consolidado CombineQRP('reportes\Historia_clinica.qrp', reportes_previosQRP); //Lo vemos en el preview h:=TQRPHandler.Create; with h do begin FQuickrep.PreviewHeight:=700; FQuickrep.PreviewWidth:=1050; FQuickrep.PrevInitialZoom:=qrZoom100; Filename:='reportes\Historia_clinica.qrp'; Preview; Free; end; end;
Con esto resolví el dilema, mi cliente contento y las vaquitas preocupadas porque las probabilidades de ir al asador aumentan.
Saludos.
#20
Escrito 06 junio 2013 - 05:57