Pb with report

Hi, The problem is… I have a form with a grid. The datasource of this grid is a view. In this form there is a button which calls a report. This report displays a list of departments (countyId) and the number of clients in each county. What I would like to do: If the user makes a filter on the grid in order to display only the county numbers 33 and 79 for example, and cliks on the report button, I would like the report shows only the counties 33 and 79 and the number of clients in this counties. I don’t know how to do… Thanks, Vince

You should use the Args class and pass the datasource in the form as an object to the report. Args = new Args(‘ReportName’) ; Args.parmObject(FormDataSource_ds.queryrun().query().datasourceno(1)) then in the init() method in the report loop for each range found and make it also a range for the report’s datasource. Regards, Cip

Thanks, But I don’t know how to loop for each range in the datasource of the report… The problem I have is the same one (thread number 5850): http://www.microsoft.com/Businesssolutions/Community/Newsgroups/dgbrowser/en-us/default.mspx?query=get+range+report&dg=microsoft.public.axapta&cat=&lang=en&cr=US&pt=&catlist=8d3f188d-a0E9-40e4-86e2-46508a35c759&dglist=&ptlist=&exp=&sloc=en-us I have a problem of initialisation. If you can help me… Vince

Mugur is right. If the query of the grid is exactly the same as the one of the report, you can simply substitute it in the init method of the report get the query from the caller object something like q = args.caller().ParmQuery(); Substitute this.query(q); And if you need only specific ranges, than you need to go through all the ranged of the query and select only the ones you need by their name. I can write the code if this is what you need.

I still have the same problem. My code is: In the clicked method of the button of my form: void clicked() { args args; ReportRun rr; ; args = new Args(reportstr(reportTest)); rr = new ReportRun(args,’’); args.parmObject(Vue_Clients_Light_ds.queryrun().query().datasourceno(1)); rr.query().interactive(false); rr.init(); rr.run(); super(); } And in the init method of my report: public void init() { Query q; args args = new args(); ; q = args.caller().ParmQuery(); this.query(q); super(); } When I click on the button I have an error message that says that the class is empty, the object is not initialized and this message \Classes<unknown>\ParmQuery. …I don’t know what appens… Vince

No, Vince, you missunderstood. I meant that a ParmQuery method must exist on the form (caller object) and you are not using args in the init method right. Here is an example of code from Axapta initFromArgs is a method on the report BankDepositSlip. It is called from the init method. private void initFromArgs() { BankAccountTrans bankAccountTransLocal; BankDeposit bankDepositLocal; args args = element.args(); object obj; ; if (args) { switch (args.dataset()) { case tablenum(BankDeposit) : bankDepositLocal = args.record(); depositNumRange = bankDepositLocal.depositNum; break; case tablenum(BankAccountTrans) : bankAccountTransLocal = args.record(); depositNumRange = bankAccountTransLocal.depositNum; break; } } if (! depositNumRange && args && args.parmObject() && formHasMethod(args.parmObject(), identifierStr(depositNum))) { depositNumRange = args.parmObject().depositNum(); } if (depositNumRange) { element.query().dataSourceTable(tablenum(BankAccountTrans)).findRange(fieldnum(BankAccountTrans, depositNum)).value(depositNumRange); } } So in your case you should do something like this: public void init() { Query q; args args = element.args(); ; super(); q = args.caller().ParmObject(); box::info(q.datasourceNo(1).toString()); this.query(q); } and in the void clicked replace the line args.parmObject(Vue_Clients_Light_ds.queryrun().query().datasourceno(1)); with args.parmObject(Vue_Clients_Light_ds.queryrun().query());

You wrote:

quote:

I meant that a ParmQuery method must exist on the form (caller object)

What is ParmQuery method? where do I have to create it? Do I have to call it? Sorry for being so bad!! [:I]Vince

I don’t think you need this method anymore. I think the code I wrote should do the job. But what I meant was: you create a method on the form which calls the report. Name the method parmQuery Code of the method: Query parmQuery() { return Vue_Clients_Light_ds.queryrun().query(); } Now you have a method that returns your form’s query. So in your init method on the report you can write this: Object obj; Query q; ; //obj is your form, that calls the report obj = element.args().caller(); //you can call it’s methods (they don’t show up after the .) q = obj.parmQuery(); this.query(q); But it’s just a different way to do the job.

I still have the problem of initialisation… [xx(] My code: In the form: Query parmQuery() { return Vue_Clients_Light_ds.queryrun().query(); } The click method of the button of the form: void clicked() { args a; ReportRun rr; ; a = new Args(reportstr(reportTest)); // as I use the method parmQuery I don’t need this line…(anyway with or without this line it doesn’t work) // a.parmObject(Vue_Clients_Light_ds.queryrun().query()); rr = new ReportRun(a,’’); rr.query().interactive(false); rr.init(); rr.run(); super(); } In the init method of the report: public void init() { Object obj; Query q; ; super(); //obj is your form, that calls the report obj = element.args().caller(); //you can call it’s methods (they don’t show up after the .) q = obj.parmQuery(); this.query(q); } And I have this error message (the message is in french but it looks like Inglish- “pile” is a stack): I don’t understand nothing!!!

Well, :slight_smile: I can’t see your error message, the picture doesn’t load. If you insist that it is an initialization error, than But my guess is that your problem is in the parmQuery method. You call it to early, and so the queryRun is not yet initialized. So modify the method parmQuery a bit Query parmQuery() { if (Vue_Clients_Light_ds.queryrun()) return Vue_Clients_Light_ds.queryrun().query(); return Vue_Clients_Light_ds.query(); } This means that if the queryRun is already initialized (filters used, etc.) than it will return this, else it will return the query(); Will be waiting for your reply

It doesn’t work… As you can’t see the picture, this is the error message (the translation): Execution code error:The object is not initialized Stack: \Classes\Object\parmQuery \Reports\reportTest\Methods\init - line 26 \Classes\FormCommandButtonControl\Clicked - line 19 \Classes\FormMenuButtonControl\Clicked The line 26 is : q = obj.parmQuery(); and the line 19 is : rr.init(); I have put a print in the parmQuery method but the message is never displayed, so the method is never called… I need a miracle! Vince

well, of course it doesn’t exist You missed one very important line in clicked method on the button(). you have to specify the caller. a.caller(element); because if you don’t - the caller will be the button, or even unknown. and in the init() insert a line that tests if obj exists (after obj = ) if (obj) { //replace query here }

You’re the king of Axapta Ivan!!! Does Axapta Land is your country? Thanks a lot!!![:D] But the obj is never initialized, so the condition if(obj) is never true. So I have used the first code you gave me: public void init() { Query q; args args = element.args(); ; super(); q = args.caller().parmQuery(); //box::info(q.datasourceNo(1).toString()); this.query(q); this.query().interactive(false); } And it works very well!!! Thanks you very much one more time. Vince

Hi, I’m back… What you told me works very well but I need to do an over thing that is a little bit different. With your method the report is initialized with the datasource of the form that calls the report. All is OK. But this functions only when there is 1 datasource in the report. In my “new” case, I have 2 datasources in my report. I would like the report presents a column with all countyId ( coming from the table County) and for each countyId the number of clients. So, the user opens the form with my famous Grid (which contains all the clients of the company with some informations about them), then uses filters on the Grid to choose what kind of clients he wants, and then by clicking on a button, the report is launched. When I initialized the report with the datasource of my form, I can’t use the datasource “County”. Thanks… Vince

then you have to do what was advised in the very beginning. Something like this: static void Job7(Args _args) { Query qCustTable = new Query(); QueryBuildDataSource qCustTable_ds = qCustTable.addDataSource(tableNum(CustTable)); Query reportQuery = new Query(); QueryBuildDataSource qBDS = reportQuery.addDataSource(tableNum(Address)); QueryBuildDataSource qBDSCustTable = qBDS.addDataSource(tableNum(CustTable)); int RangeCount; int i; ; qBDSCustTable.relations(true); qBDSCustTable.clearRanges(); // this is a test query - this is what you get from your form qCustTable_ds.addRange(fieldNum(CustTable, CustGroup)).value(“Value1”); qCustTable_ds.addRange(fieldNum(CustTable, Currency)).value(“Value2”); // before info(qCustTable.dataSourceNo(1).toString()); info(reportQuery.dataSourceNo(1).toString()); for (i = 1; i <= qCustTable_ds.rangeCount(); i++) { qBDSCustTable.addRange(qCustTable_ds.range(i).field()).value(qCustTable_ds.range(i).value()); } // after info(reportQuery.dataSourceNo(1).toString()); }

Sorry but where do I have to put this code? I still need this part of code: void clicked() { args a; ReportRun rr; ; a = new Args(reportstr(NOV_TxClientsAffiches)); a.caller(element); rr = new ReportRun(a,’’); rr.query().interactive(false); rr.init(); rr.run(); super(); } You know, I just want to pass the datasource of the form to the report as I did before and add the table “County” as datasource of the report. In order to have the list of all countyId on the left part of the report, and the number of clients in each county. Vince

This was just an example of how you can go through the ranges of a query and assing their values to identical ranges of another query you have to add it to the init method on the report (starting from //before) (modify the names) q = args.caller().parmQuery(); //box::info(q.datasourceNo(1).toString()); after this - you have your qCustTable_ds as q.dataSourceTable(tableNum(CustTable)) //it’s the name of this in the Job then: reportQuery = this.query(); and: qBDSCustTable = this.query().datasourceTable(tablenum(CustTable)); Try it this way. By the way, it’s not the only way to solve this. you can overload the fetch method and go through all the records for each address in it. but try the first one. it’s better.

The problem of this method is that it’s impossible to get the ranges of the datasource when you use the request window (the funnel icon). Does the following method is possible? You get the sql code of the request like this: Vue_Clients_Light_ds.queryRun().query().dataSourceNo(1).toString() so you will obtain something like: SELECT * FROM Vue_Clients_Light ORDER BY Vue_Clients_Light.AccountNum ASC WHERE ((City = paris)) EXISTS JOIN * FROM CustTable WHERE Vue_Clients_Light.AccountNum = CustTable.AccountNum EXISTS JOIN * FROM SalesLine WHERE CustTable.AccountNum = SalesLine.CustAccount EXISTS JOIN * FROM InventTable WHERE SalesLine.ItemId = InventTable.ItemId EXISTS JOIN * FROM NOV_Concepts WHERE InventTable.ItemId = NOV_Concepts.Article AND ((TypeConcept = POP)) You pass this sql request on argument to the report and then you execute this request in the init method of the report ( on the corresponding datasource ). However I don’t know how to initialize a datasource with sql code… Could it function? Vince

the job I sent earlier goes through all the ranges of a query (this is you q from this line it the init method on the report q = args.caller().parmQuery(); ) you can see which field it was put on, what value was specified, etc. So, yes, it’s possible to add all the ranges and tables to your report query if you have the query you want to add( in your case, q) and you are passing not the text of the query, but the query itself: Vue_Clients_Light_ds.queryRun().query(); that is a big difference - because you can go through all the datasources in a query, through all the ranges in a datasource, etc. But in your case, what I would advise you to do instead of trying to make the query of the report as the one on the form, is to overload the fetch method (leave only the Country datasource in the report, add programmable sections to output data) and go through all the countries , executing your query from form for each country. But to do this you will first have to read about doing reports (calling programmable sections, sending records in the fetch method, executing a query using a QueryRun object) Or you can stick to trying to modify the query. It’s simple, really. You have your report query. and you just go through all the datasources of your form query and add them to the one of the report (it’s very similar to adding ranges in the job I sent) Look at that job again, ask questions if you don’t understand something. It actually shows everything you need to do to modify the query the way you want.

I am very near from what I want. I have done like this: In the click method of the from: void clicked() { args a; ReportRun rr; ; a = new Args(reportstr(NOV_TxClientsAffiches)); a.caller(element); rr = new ReportRun(a,’’); rr.query().interactive(false); rr.init(); rr.run(); super(); } And in the init method of the report: public void init() { args args = element.args(); Query qVue_Clients_Light = new Query(); QueryBuildDataSource qVue_Clients_Light_ds; int rangeCount; int i,j=0; qVue_Clients_Light = args.caller().parmQuery(); infolog.add(1,qVue_Clients_Light.dataSourceNo(1).toString()); qVue_Clients_Light_ds = qVue_Clients_Light.dataSourceNo(1); infolog.add(1,qVue_Clients_Light_ds.toString()); for (i = 1; i <= qVue_Clients_Light.dataSourceNo(1).rangeCount(); i++) { this.query().dataSourceNo(2).addRange(qVue_Clients_Light_ds.range(i).field()).value(qVue_Clients_Light_ds.range(i).value()); } } In my report there are 2 datasources, the first one is County and the second one is Vue_Clients_Light_1 (it is the second one I want to initialized). With this code, it works when I make filter (by clicking with the left button for example) on fields in the grid (Vue_Clients_Light) of the form. But if I use the funnel icon to do a request joining some tables, it just takes the ranges of the datasource Vue_Clients_Light. For example when I use the funnel icon to have the clients who have a kind of product ( Vue_Clients_light → Clients → SalesLine → Product → Concept == POP) and wha have the countyID == 79. But when I do : infolog.add(1,qVue_Clients_Light.dataSourceNo(1).toString()); or infolog.add(1,qVue_Clients_Light_ds.toString()); I obtain: SELECT * FROM Vue_Clients_Light ORDER BY Vue_Clients_Light.AccountNum ASC WHERE ((County = 79)) EXISTS JOIN * FROM CustTable WHERE Vue_Clients_Light.AccountNum = CustTable.AccountNum EXISTS JOIN * FROM SalesLine WHERE CustTable.AccountNum = SalesLine.CustAccount EXISTS JOIN * FROM InventTable WHERE SalesLine.ItemId = InventTable.ItemId EXISTS JOIN * FROM NOV_Concepts WHERE InventTable.ItemId = NOV_Concepts.Article AND ((TypeConcept = POP)) So the query is well passed but only the county is used to initialized the datasource in the report. … Vince