Inside AX2012 R3, when creating a new Return Order from the Return Order list view page (using the button in the Header), the SalesCreateOrder form opens and functions as expected.
Upon close of this form, however, instead of opening the newly created Order, instead the order that was selected in the grid is opening.
Several developers have made customization to this form, but none that (at first glance) appear relevant to this behavior.
Where would I find the behavior to open a form upon close of the SalesCreateOrder dialog?
You can open the created order by changing the SalesCreateOrder.close method:
public void close()
{
Args args = new Args(this); //Change here
// Save user's customer search type
MCRCustSearch::saveCustSearchType(mcrCustSearchType.selection());
if (salesTableType)
{
salesTableType.formMethodClose();
}
//Change here -->
args.record(salesTable);
new MenuFunction(menuitemDisplayStr(SalesTable),MenuItemType::Display).run(args);
//End of change <--
super();
}
You may have to change the called menuitem if called from Return order.
Your understanding of how returns are created is wrong. A form isn't opened upon closing, it's opened upon creation.
When you do Ctrl+n or click to create a new return order, the ReturnTable form actually instantiates the SalesCreateOrder form eventually.
To see this, place a breakpoint in the init method of the ReturnTable at \Forms\ReturnTable\Methods\init and then try and create a new return order.
Related
I have created a command button in the CustGroup form action pane.
I have added a new base enum edt field to both the CustGroup and CustTable tables and forms.
When you click on the button the data that was previously changed in the CustGroup table must be reflected in the cust table form.
I have written code in button on click event handler but it's not updating.
What to do, any suggestions?
If I understand your question correctly, you want to transfer a change of a new field in a customer group to all customers that share this customer group.
This kind of mass data update is usually not done by code in a form, because that code is executed on the client tier, which results in a bad performance. Instead, you should create a class that is set to execute on the server tier. If you create a main method for this class, you can easily create an action menu item for it, which let's you easily integrate the call to this class as a button in the CustGroup form.
In the main method you can access the CustGroup record for which the button was clicked via the Args object. This gives you the value of your new field that was changed. With this value, you can then use code similar to the following to update your customers:
public void updateCustomersWithNewCustGroupFieldValue(CustGroup _custGroup)
{
CustTable custTable;
ttsBegin;
while select forUpdate custTable
where custTable.CustGroup == _custGroup.CustGroup
{
custTable.MyNewEnumField = _custGroup.MyNewEnumField;
if (custTable.validateWrite())
{
custTable.update();
}
else
{
error('Please implement some error handling');
}
}
ttsCommit;
}
I have created a report (no SSRS) in AX2012, via a Menu Item I am running this report, i want to achieve to show the AssetId, from the Asset Record i have selected.
My Dialog method:
public Object dialog(Object _dialog)
{
DialogRunbase dialog = _dialog;
;
dialogAssetIds = dialog.addField(ExtendedTypeStr(AssetId));
return dialog;
}
My getFromDialog method:
public boolean getFromDialog()
{
;
curAssetId = dialogAssetIds.value();
return true;
}
I also have created a display method to return the value:
display AssetId assetId()
{
return curAssetId;
}
On my report field, I have selected the above method to show the AssetID number, obviously I am missing the key link, but I am not sure what.
I am receiving the error:
Report is empty - Report
Eventually, I want to print the AssetId number without the dialog field, based on the selected record, I have built in the dialog so I am sure nothing was wrong with printing the value directly.
Guessing what went wrong with your report requires more data, but ...
You do not need a RunbaseReport class or any code to achieve this behavior.
Just set the AutoJoin property to Yes on your report's AOT node.
Change your menu item to reference the report.
Add the menu item to your Asset form, remember to set the DataSource property of the control to the AssetTable datasource.
Then by magic it works provided dynalink on form table and report table is established. If the report is called from the main menu there is no autojoin of cause, it will select whatever the user queried.
Works for MorphX reports, not for SSRS reports. SSRS sucks (again, and again ...).
I have created a wizard in Ax 2012 using wizard>wizard and i am calling this wizard from Custtablelistpage form... now, i have put some controls in this wizard like CustAccount, and i need to initialize value in this control from selected record in Custtablelistpage form....
I am trying to perform this using Args class, but it is not working, please suggest some solutions..
please create one wizard in AX 2012 using tools>wizard>wizard
then, please put menu item of this wizard somewhere on custtablelistpage.
After that, please put one field named Customer account on welcome tab of wizard.
Now, if you any record that is displayed in custtablelistpage form, please select that.
My task is to display the Account num of selected record to my wizard when i am clicking the menu item button which i have put on custtablelistpage.
Actually, i have written some code,, which is is working absolutely fine for normal forms. but it is not working for Wizard and i am not getting value to initialize in my control on wizard.
Ok, I took some time to try this out and I have two possible solutions for you.
You can do it by using unbound controls and pass in the selected record
Or you could use a datasource on the wizard form and filter on the selected values
First let's try and do it by using a simple unbound control. Start by adding a CustTable member variable and parameter method to your wizard class.
public class MyTestWizardWizard extends SysWizard
{
CustTable mySelectedCustomer;
}
public CustTable parmMySelectedCustomer(CustTable _mySelectedCustomer = mySelectedCustomer)
{
;
mySelectedCustomer = _mySelectedCustomer;
return mySelectedCustomer;
}
Then in your form, you can overwrite the init method and do the following :
void init()
{
int controlid;
FormStringControl fsControl;
;
super();
if (element.Args().caller())
{
sysWizard = element.Args().caller();
// Get the control id of the CustomerId control
controlid = element.controlId(formControlStr(MyTestWizardWizard, CustomerId));
// Check if we actually have a form string control
if(element.control(controlid) is FormStringControl)
{
// Cast to the FormStringControl type
fsControl = element.control(controlid) as FormStringControl;
// Now fill in the field value
fsControl.text(sysWizard.parmMySelectedCustomer().AccountNum);
}
}
else
{
MyTestWizardWizard::main(new args());
element.closeCancel();
}
}
So what you actually do here is just fetch the selected record stored in you wizard class. Then we check if the control we want to assign values to is actually the right control to put the value in.
Though this is working, I would prefer a second method. That would be to use a datasource on the form and put a range on the selected record like this. Just put the CustTable as a datasource on the form and place your control as you would normally do.
Then, make sure the init method is performing the super() call at the bottom to make sure initialisation is done before calling the datasource methods:
void init()
{
;
// make sure the sysWizard is already initialized before the super to make sure the init on the datasource has an instance of sysWizard
if (element.Args().caller())
{
sysWizard = element.Args().caller();
}
else
{
MyTestWizardWizard::main(new args());
element.closeCancel();
}
super();
}
Then overwrite the init method on the datasource to put a range on the recId field of the custTable.
Please mind the you could assign the value of the range in the ExecuteQuery method, but for this case, I just do it here.
public void init()
{
;
super();
SysQuery::findOrCreateRange(this.query().dataSourceTable(tableNum(CustTable)), fieldNum(CustTable, RecId)).value(queryValue(SysWizard.parmMySelectedCustomer().RecId));
}
Now when your wizard is run, the args passes the record to your wizard class, the form picks it up on the init of the datasource and puts a range on the record that you have selected. All the rest of the magic is normal Ax behavior with bound data controls.
So I hope this is what you needed. Please let me know if you have further questions.
I'm facing a problem with a view-based NSTableView running on 10.8 (target is 10.7, but I think this is not relevant).
I'm using an NSTableView, and I get content values for my custom NSTableCellView through bindings. I use the obejctValue of the NSTableCellView to get my data.
I added a button to my cell, and I'd like it to trigger some action when clicked. So far I have only been able to trigger an action within the custom NSTableCellView's subclass.
I can get the row that was clicked like this, using the chain:
NSButton *myButton = (NSButton*)sender;
NSTableView *myView = (NSTableView*)myButton.superview.superview.superview;
NSInteger rowClicked = [myView rowForView:myButton.superview];
From there I don't know how to reach my App Delegate or controller where the action is defined.
As I am using cocoa bindings, I do not have a delegate on the NSTableView that I could use to trigger my action.
Do you have any idea how I could talked back to controller ?
Many thanks in advance!
Although you are using bindings you can still set your controller as the delegate for your tableview in the interface builder.
I see that you already are able to access the table view from inside your cell. The next task must be simple, just set the table view delegate as the target for your button's action.
Thanks for your question, I also will be triggering an action from a button on a NSTableView. Your question helped to put me on the correct path.
First to address the your solution to finding which row number my NSTableView is on. I was able to find it without knowing the button, in my custom NSTableView I installed the following as a first attempt:
- (NSInteger)myRowNumber
{
return [(NSTableView*)self.superview.superview rowForView:self];
}
this works fine, however it is less than robust. It only works if you already know specifically how deep you are in the view hierarchy. A more robust and universal solution is:
- (NSInteger)myRowNumber
{
NSTableView* tableView = nil;
NSView* mySuperview = self;
do
{
NSView* nextSuper = mySuperview.superview;
if (nextSuper == nil)
{
NSException *exception =
[NSException exceptionWithName:#"NSTableView not found."
reason:[NSString stringWithFormat:#"%# search went too deep.",
NSStringFromSelector(_cmd)] userInfo:nil];
#throw exception;
}
if ([nextSuper isKindOfClass:[NSTableView class]])
tableView = (NSTableView*)nextSuper;
else
mySuperview = mySuperview.superview;
} while (tableView == nil);
return [tableView rowForView:self];
}
this not only works at the NSTableView level, but works with anything installed at any level above it, no matter how complex the view hierarchy.
As to the unanswered part of your question, I established an IBOutlet in my class and using interface builder tied if to my files owner (in my case my document class). Once I had a reference to the class I was sending my message to, and the row number, I call the function. In my case the call required that I pass the row number it originates from.
[self.myDoc doSomethingToRow:self.myRowNumber];
I tested this and it works at various levels of the view hierarchy above NSTableView. And it functions without having to have the row selected first (which appears to be assumed in Apples documentation).
Regards, George Lawrence Storm, Maltby, Washington, USA
Use rowForView: and the responder chain
To respond to a control's action embedded within an NSTableCellView, the control should issue the action to the First Responder. Alternatively, File Owner is possible but this is more tightly coupled.
Use rowForView: within the action method to determine which row's control issued the action:
- (IBAction)revealInFinder:(id)sender {
NSInteger row = [self.tableView rowForView:sender];
...
}
The action is implemented within any of the responder chain classes. Most likely, this will be your subclassed NSWindowController instance. The responder could also be the application delegate; assuming the delegate has a means to talk to the NSTableView.
See Apple's example TableViewPlayground: Using View-Based NSTableView and NSOutlineView to see this in action.
Suhas answer helped me.
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
if let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "EDIT_CELL_VIEW"), owner: self) as? SymbolManagerCell {
if let editButton = cell.subviews[0] as? NSButton {
editButton.target = cell // this is required to trigger action
}
return cell
}
return nil
}
I need to add an additional field to InventJournalTrans, that after posting will show up in the InventTrans table. The field is a reference column to a record in another table. What method(s) do I need to modify to make this behavior happen?
Currently, I have already added the fields to both tables and modified the Form to allow the user to enter and save the new field. I just can't seem to find the bottom of the rabbit hole on where the actual posting to InventTrans is occurring.
Ideally, it should just be a:
inventTrans.ReasonRefRecId = inventJournalTrans.ReasonRefRecId;
assignment statement before the
inventTrans.insert();
call. Anybody have a clue on where this is at?
The link above does contain the solution -- I have included the code from that page in case that page disappears or no longer becomes available. Thanks to gl00mie for answering on that site and providing this answer.
You should create a new InventMovement method like this:
public MyNewFieldType myNewField()
{
return MyNewFieldType::DefaultValue; // suppose your new field is an enum
}
Then modify \Classes\InventMovement\initInventTransFromBuffer
void initInventTransFromBuffer(InventTrans _inventTrans, InventMovement _movement_orig)
{
// ... append this line to the end of whatever else is already in this method
_inventTrans.MyNewField = this.myNewField();
}
And finally overload the new method in the InventMov_Journal class:
public MyNewFieldType myNewField()
{
return inventJournalTrans.MyNewField;
}