A separate report format for each row: How?

edited 6:09AM in FastReport 4.0
Hi, I'm trying to use FR to generate invoices for customers, based off a standard master (the invoice itself) - detail (invoice line items) database structure. Each invoice can be 1 or more pages.

The problem is that there about 8-10 different invoice formats, and any single customer can use any of the formats. I don't want to run this as 10 different reports, but them all together as a single report job. I can't quite figure out how to structure this to make it work. Any help much appreciated, thanks!

Comments

  • Anu de DeusAnu de Deus Hampshire, UK
    edited May 2010
    I did the same, but it's not for beginners, and I will not give you any working example.
    Ok, here it goes:
    Do it by code from your delphi source. The secret is all about the objects at runtime, not the designer.
    Create/use 2 TfrxReports objects. 1 (call it A)will be your final report, another one ( B ) is a helper object.
    Clear A.
    Use B to open or generate each report for each of your formats/customer.
    When B is done for a specific customer, list and make a copy of each page of the TfrxReports object and assign/add it to A.
    Clear B, repeat for the remaining customers.
    In short: append to A all pages from the reports loaded in B.

    Now, the difficult bits:
    - you will have to rename all components of each page. EVERY ONE!!!. You are copying objects from one parent object into another. Delphi doesn't allow 2 objects with the same name, you know that. So, just before you load each page into B, you run a procedure to rename all objects, what I do is to first give the page object a proper name (not just 'Page1', but 'PageInvoceABC'), and add that name (the new page name) as a prefix to every object in that page, so you will have PageInvoiceABC_MemoView1 instead of MemoView1.
    - same problem with datasets: they will have to have different names. The easiest way is to give them unique names when you first drop them in the designer, in this way you don't need to rename them later. What I mean is if you have 1 datasource in subreport X, name it ABC, and if you have 1 in subreport Y, name it XYZ, or anything different than any existing datasource in any report that will be part of your big master one. Now, if you can't do that, and you have to rename the datasources, then you will have to find EVERY reference to EVERY field across your pages and update them to use the right name.
    - you will need to add/load the individual datasets to the main (A) report at runtime, by code (similar to what has to be done with the objects, but you may end up with duplicate open datasets, that's the way it is)
    - when you are done, prepare and show report A, discard B.

    Recomendations: if you are going to do this, start with very simple reports just to get the grips with copying objects and pages across the TfrxReport objects. I would say if you can merge 3 reports (1 page each is enough), you are ready for the next step: adding the datasources. Again, when adding datasources, start with very simple ones, single masterbands each showing different data. If you get this right, you are nearly there.

    More tricky bits: you can have only one scripts page in your report (like you see in the designer). So you will have to be very clever about merging them all in the final report. Avoid scripts code if you can. However, if you master this bit, you will have a wonderful tool at your disposal, because you will be able to have one mega-scripts page full with functions to be used across all your reports. Again, try this as different step, after you made the others work (pages + datasources).

    Last hint: if your reports are very very simple, all you need to do is to copy and paste the pages from the XML (in the FR3 files) into any other FR3 file, renaming duplicate objects if necessary. The problem is that it doesn't work with datasources, you would have to load them separately after merging the XML.

    Well, I hope it helps.
  • edited 6:09AM
    Thanks Anu!

    I had another idea for another option that might be simpler. Since you are so much more familiar with FR than I, could you give me your opinion of whether its possible? Create each format as a separate subreport, then the master invoice report will be basically empty, except for the page header/footer (which luckily is the same for all invoices) and some script to control which of the 8 nested subreports is the one that's actually visible or not. I've never used nested reports though so I don't know if that would actually work or not.
  • Anu de DeusAnu de Deus Hampshire, UK
    edited 6:09AM
    It all depends on how complex your subreports are.
    If each one is made of a single masterdata band, then you can simply put all those bands in one single page, and control their Visible property.
    In that case, put a OnBeforePrint event in Page1, and set something like this:

    procedure Page1OnBeforePrint(sender...);
    begin
    MasterData1.visible := <your condition to print 1st part>
    MasterData2.visible := <your condition to print 2nd part>
    MasterData3.visible := <your condition to print 3rd part>
    etc...
    end;

    I suggest you read in the manual how to get user parameters using a dialog box, then you can use checkboxes to decide which reports to print (initially, so you learn how it works).
    Later you can do something more advanced like reading a bool value from a field in the database. The manual has some examples too.
    The demos supplied with the downloads also tells you good stuff.
  • edited 6:09AM
    The part that changes in each format is Header/Footer, Group Header & Footer, and Detail Data. The static part is the page header/footer, and the master band. Does that mean I can put 8 of each type in a single report and just control visibility? I started down that path originally, but then decided I must be doing something wrong.
  • Anu de DeusAnu de Deus Hampshire, UK
    edited 6:09AM
    Ah, in that case, create one page in the designer for each group of headers/footers/data you have, and control the pages' visible property from the TfrxReport onbeforeprint event.
  • edited 6:09AM
    Hrm, ok obviously I don't understand the concept of multi-page reports like I should. (I've never used one before)

    So if I create a report with 3 pages, then print it for a data source that has 2 rows, the output would be like this?

    Row 1, Page 1
    Row 1, Page 2
    Row 1, Page 3
    Row 2, Page 1
    Row 2, Page 2
    Row 2, Page 3

    And then to get the effect I want of different formats, I just turn off everything but the page with the format I need for each row (client) ?

    VISIBLE: Row 1, Format 1 (Page 1)
    HIDDEN: Row 1, Format 2 (Page 2)
    HIDDEN:Row 1, Format 3 (Page 3)
    HIDDEN:Row 2, Format 1 (Page 1)
    VISIBLE: Row 2, Format 2 (Page 2)
    HIDDEN:Row 2, Format 3 (Page 3)

    Something like that is what you mean? If so, that would certainly be a lot easier than dynamically generating the report!



  • Anu de DeusAnu de Deus Hampshire, UK
    edited 6:09AM
    No, nothing like that.
    The report will process the entire page1 first, then the page2. So if you have 100000 rows to be printed in page1, you might have hundreds of the page1 in the preview before starting page2.
    As I said, create simple examples to see how it works, just put a datasource in each, with a masterband, each one returning a few hundred rows.
  • edited 6:09AM
    I'll work on that approach and report back. Thanks for your help!
  • edited September 2010
    Ok, yes believe it or not I'm still struggling with this. I tried creating a multi-page report and setting Page1.Visible (or Page2, 3, etc) to true or false depending on the row value, but changing the page visibility in the OnBeforePagePrint event does nothing if I use default engine values. If I turn on the engine second pass option, then the first the event fires and the page visible is set false, the event stops firing. If I try to outsmart it and reset the page to visible in the OnAfterPagePrint event, the page stays visible for all rows no matter what. So this doesn't seem a workable approach. So how can I generate a different format for each row? Maybe make each invoice type a subreport, and the master report is used just to link them all together?
  • edited 6:09AM
    I thought I could do this by putting multiple detail bands together on the same report page, and just controlling their visibility (turning off all the bands but the one active for the current format). This works ok, except it seems to cause the group header/footer bands to freak out. Example, I define the report like this:

    Master (this is the customer, band is set to start a new page)
    - Group Header
    --- Detail Line Version 1 (invoice line detail, format #1)
    --- Detail Line Version 2 (invoice line detail, format #2)
    --- Detail Line Version 3 (invoice line detail, format #3)
    - Group Footer

    In Master's before-print event, I turn off all but one of the detail lines. But when it prints, I get something like this:

    Master Record 1
    - Group Header for first group
    - Group Footer for first group
    - Group Header for second group
    - Group Footer for second group
    - ....
    --- Detail Line 1
    --- Detail Line 2
    --- ...

    In other words, all the group bands first print, then the detail lines all print. If I eliminate the extra (invisible) detail bands, I get what I would expect:


    Master Record 1
    - Group Header for first group
    --- Detail Line 1
    - Group Footer for first group
    - Group Header for second group
    --- Detail Line 2
    - Group Footer for second group
    - ....

    Is this a bug, or is there something I can do about this?

Leave a Comment

Rich Text Editor. To edit a paragraph's style, hit tab to get to the paragraph menu. From there you will be able to pick one style. Nothing defaults to paragraph. An inline formatting menu will show up when you select text. Hit tab to get into that menu. Some elements, such as rich link embeds, images, loading indicators, and error messages may get inserted into the editor. You may navigate to these using the arrow keys inside of the editor and delete them with the delete or backspace key.