Implicit DataTable name registration is not working

Hello,

I have an issue with Report.AddTable method. Implicit datatable detection is not working as expected (or I am doing something wrong).

See bellow the code used to fill my lists (fetching data from a dataset and feeding my lists).
In my case, Docs object is created once, and Docs[0].Records list will have at minimum 2 records.

I'm always getting Report.GetDataTables.Count = 1 ('Documents' table but no 'Records' table).
Report.Run will raise an exception telling me the Records range is failling because Records datatble doesn't exists.

How can I solve this ?


procedure TDataModule2.AddNewRecord(aDocs: TDocuments; aRecordType: TRecordType; aDataset: TDataSet);
var
  RecIdx: Integer;
begin
  aDocs.Records.Add(TRecords.Create);
  RecIdx := aDocs.Records.Count - 1;

  case aRecordType of
    TRecordType.MasterRecord:
      begin
        if UpperCase(Trim(aDocs.DocumentType)) = 'INVOICE' then
          aDocs.Records[RecIdx].DebitCredit := 'C'
        else
          aDocs.Records[RecIdx].DebitCredit := 'D';

        aDocs.Records[RecIdx].Name := aDataset['Description'];
        aDocs.Records[RecIdx].RecordType := '1;3;6';
        aDocs.Records[RecIdx].AD5 := aDataset['Vendor_Analytical_ID_AD5'];

      end;
    TRecordType.DetailRecord:
      begin
        if UpperCase(Trim(aDocs.DocumentType)) = 'INVOICE' then
          aDocs.Records[RecIdx].DebitCredit := 'D'
        else
          aDocs.Records[RecIdx].DebitCredit := 'C';

        aDocs.Records[RecIdx].Name := aDataset['Description_Line'];
        aDocs.Records[RecIdx].RecordType := '3;6';
        aDocs.Records[RecIdx].AD4 := aDataset['Project_Number_AD4'];

        aDocs.Records[RecIdx].AD6 := aDataset['Tax_Code_AD6'];
        aDocs.Records[RecIdx].AD9 := aDataset['Misc_Analytical_Number_AD9'];
      end;

  end;

  aDocs.Records[RecIdx].Account := aDataset['Amount_Due'];
  aDocs.Records[RecIdx].Name := aDataset['Description'];
  aDocs.Records[RecIdx].TransactionAmount := aDataset['Amount_Due'];
  aDocs.Records[RecIdx].DebitCredit := aDataset['DC'];
  aDocs.Records[RecIdx].TransactionCurrencyCode := aDataset['Currency'];
  aDocs.Records[RecIdx].Description := aDataset['Description'];
  aDocs.Records[RecIdx].TransactionDate := aDataset['Issue_Date'];
  aDocs.Records[RecIdx].DueDate := aDataset.FieldByName('Due_Date').AsDateTime;

end;

procedure TDataModule2.actExportSelectedRecordExecute(Sender: TObject);
var
  Bookmkt: TBookmark;
  Docs: TObjectList<TDocuments>;
  DocIdx: integer;
  Report: TFlexCelReport;
begin
  FdInvoiceSelected.EmptyDataSet;
  Bookmkt := FdInvoices.GetBookmark;
  FdInvoices.DisableControls;
  Docs := TObjectList<TDocuments>.Create;
  Report := TFlexCelReport.Create(true);
  try
    FdInvoices.Filter := 'Customer_ID=' + quotedstr(FdInvoices['Customer_ID']) + ' AND Invoice_Number=' + quotedstr(FdInvoices['Invoice_Number']) + ' AND Vendor_ID=' + quotedstr(FdInvoices['Vendor_ID']);
    FdInvoices.Filtered := true;

    FdInvoices.first;
    Docs.Add(TDocuments.Create);
    DocIdx := Docs.Count - 1;
    Docs[DocIdx].BusinessUnit := FdInvoices['Customer_ID'];
    Docs[DocIdx].Ledger := 'A';
    Docs[DocIdx].LAAVersion := '';
    Docs[DocIdx].JournalSource := 'AK';
    Docs[DocIdx].JournalType := 'FACT';
    Docs[DocIdx].Period := '0012024';
    Docs[DocIdx].TransactionReference := FdInvoices['Invoice_Number'];
    Docs[DocIdx].DocumentType := FdInvoices['Invoice_Type'];
    //Adding Master record
    AddNewRecord(Docs[DocIdx], TRecordType.MasterRecord, FdInvoices);
    while not FdInvoices.Eof do
    begin
      //Adding Detail record
      AddNewRecord(Docs[DocIdx], TRecordType.DetailRecord, FdInvoices);
      FdInvoices.next;
    end;

    Report.AddTable<TDocuments>('Documents', Docs);
    Report.Run(TPath.Combine(GetDataPath, 'Q&A_Template.xlsx', false), TPath.Combine(GetDataPath,'Q&A.xlsx', false));
  finally
    FdInvoices.Filtered := false;
    FdInvoices.Filter := '';
    FdInvoices.GotoBookmark(Bookmkt);
    FdInvoices.enableControls;
    Docs.free;
     Report.Free;
  end;

end;

Classes used to populate XLReport

unit Unit3;

interface

uses
  Generics.Collections;

type
  TRecordType = (MasterRecord,DetailRecord);

type
  //We can use classes or records as data sources
  TRecords = class
  private
    FAccount: string;
    FAD1: string;
    FAD2: string;
    FAD3: string;
    FAD4: string;
    FAD5: string;
    FAD6: string;
    FAD7: string;
    FAD8: string;
    FAD9: string;
    FAssetCode: Integer;
    FAssetIndicator: String;
    FDebitCredit: String;
    FDescription: string;
    FDueDate: TDate;
    FName: string;
    FRecordType: string;
    FTransactionAmount: Double;
    FTransactionCurrencyCode: string;
    FTransactionDate: TDate;
  public
    property Account: string read FAccount write FAccount;
    property AD1: string read FAD1 write FAD1;
    property AD2: string read FAD2 write FAD2;
    property AD3: string read FAD3 write FAD3;
    property AD4: string read FAD4 write FAD4;
    property AD5: string read FAD5 write FAD5;
    property AD6: string read FAD6 write FAD6;
    property AD7: string read FAD7 write FAD7;
    property AD8: string read FAD8 write FAD8;
    property AD9: string read FAD9 write FAD9;
    property AssetCode: Integer read FAssetCode write FAssetCode;
    property AssetIndicator: String read FAssetIndicator write FAssetIndicator;
    property DebitCredit: String read FDebitCredit write FDebitCredit;
    property Description: string read FDescription write FDescription;
    property DueDate: TDate read FDueDate write FDueDate;
    property Name: string read FName write FName;
    property RecordType: string read FRecordType write FRecordType;
    property TransactionAmount: Double read FTransactionAmount write
        FTransactionAmount;
    property TransactionCurrencyCode: string read FTransactionCurrencyCode write
        FTransactionCurrencyCode;
    property TransactionDate: TDate read FTransactionDate write FTransactionDate;
  end;

  TDocuments = class
  private
    FRecords: TObjectList<TRecords>;
    FBusinessUnit: string;
    FDocumentType: string;
    FJournalSource: string;
    FJournalType: string;
    FLedger: string;
    FLAAVersion: string;
    FPeriod: string;
    FTransactionReference: string;
  public
    constructor Create;
    destructor Destroy; override;

    property Records: TObjectList<TRecords> read FRecords;
    property BusinessUnit: string read FBusinessUnit write FBusinessUnit;
    property DocumentType: string read FDocumentType write FDocumentType;
    property JournalSource: string read FJournalSource write FJournalSource;
    property JournalType: string read FJournalType write FJournalType;
    property Ledger: string read FLedger write FLedger;
    property LAAVersion: string read FLAAVersion write FLAAVersion;
    property Period: string read FPeriod write FPeriod;
    property TransactionReference: string read FTransactionReference write FTransactionReference;
  end;

implementation

{ TDocuments }

constructor TDocuments.Create;
begin
  FRecords := TObjectList<TRecords>.Create;
end;

destructor TDocuments.Destroy;
begin
  Records.Free;
  inherited;
end;

end.

Hi,
Code looks good to me, I am not sure of the exact error you are getting, but might be template related.

I'm always getting Report.GetDataTables.Count = 1 ('Documents' table but no 'Records' table)

Yes, that is fine. Globally, you have only one table (Documents). Records is a child table of Documents, and can only be used inside a __Documents__ name. But globally you have a single table, documents.

Report.Run will raise an exception telling me the Records range is failling because Records datatble doesn't exists.

The "Records" datatable only exists as a child of "Documents", not on its own (which makes sense because each Document record has a different Records subtable). Is the name "Records" inside a "Documents" name in the template?

I made a small demo here using your classes, and it works as expected, it would be great if you can find what you are doing different. Take a look below:
https://download.tmssoftware.com/flexcel/samples/mdimplicit.zip