How to use active() method x++ - axapta

Ok I did it. It works fine. Thanks for help. Here is my code. Now I only need to call my command button in a differend form to disable it and create a info there. Anyone could look about it ? In my code I got reference errors.
[ExtensionOf(formdatasourcestr(ProdTableListPage, ProdTable))]
final class ProdParmReportFinishedActiveWG_Extension
{
public int active()
{
int ret;
next Active();
{
ProdTable tableBuffer = this.cursor();
ProdTable prodtable;
if(tableBuffer.ProdId == tableBuffer.CollectRefProdId
&& tableBuffer.ProdStatus != ProdStatus::ReportedFinished)
{
select firstonly RecId,ProdId from ProdTable where
ProdTable.CollectRefProdId == tableBuffer.ProdId
&& ProdTable.Prodstatus != ProdStatus::ReportedFinished
&& tableBuffer.RecId != prodtable.RecId;
{
Global::info(strFmt("%1 , %2",
prodtable.prodid, prodtable.recid));
// FormButtonControl mybutton = this.FormRun().design().controlname(formControlStr(ProdParmReportFinished, Ok)) as FormButtonControl;
// mybutton.enabled(false);
}
}
else
{
Global::info(strFmt("%1 , %2, %3, %4",
tableBuffer.prodid, tableBuffer.CollectRefProdId, tableBuffer.InventRefType, tableBuffer.ProdStatus));
}
}
return ret;
}
}

"I want to use this code everytime user changes his actual row but instead it runs just once and apply to all my rows."
Use the selectionChanged() method instead of active().
In fact most use cases where you think you should use active(), you're probably looking for selectionChanged() (or the OnSelectionChanged event for handlers) instead.

Related

Change allowedit on statement

I'm trying to change allowedit value on a single field but can't get into it.
This is my actuall code but I get error:
Okay did rebuild the models and it's fine
[ExtensionOf(formStr(ProdParmReportFinished))]
final class ProdParmReportFinishedWG_Extension
{
public void init()
{
next init();
ProdTable prodTable;
select firstOnly RecId from prodTable
where prodTable.InventRefType != InventRefType::None
&& prodTable.ProdId == prodTable.InventRefId
&& prodTable.ProdStatus != ProdStatus::ReportedFinished;
prodParmReportFinished_ds.object(fieldNum(ProdParmReportFinished, EndJob)).allowEdit(prodTable.RecId != 0);
}
}
if you are working with extension try something like this
[PostHandlerFor(formStr(YourForm), formMethodStr(YourForm, YourMethod))]
public static void YourForm_xxx(XppPrePostArgs args)
{
FormRun sender = Args.getThis();
sender.control(sender.controlId(formControlStr(YourForm, YourDatasource_Field))).allowEdit(false);
}
With the right click and select copy event handler method the correct structure of the method is copied to you, then you enter your code

How to enable Security Logging AX2012 (SecurityTasks to SecurityRoles)

I want to log SecurityRole - SecurityTask changes, and since the EeUserRoleChangeLog logs User – SecurityRole changes (for Estonia, but commenting out language detection, it logs also for us here in Holland perfectly). I think that basis can be used to log those changes.
So I first created the table:
EeRoleTaskChangeLog with the following fields:
AddRemove EnumType: AddRemove
ChangedBy EDT: UserID
SecurityRole EDT: RefRecID
SecurityTask EDT: RefRecId
I then noticed that within the class SysSecRole, User-Role changes logging is triggered within method removeFromSelectedUser. So whenever someone changes something from the AOT or the front-end, all these changes are then logged within the EeUserRoleChangeLog.
So I extended SysSecTask with the method removeFromSelectedRole:
public void removeFromSelectedRole()
{
RefRecId SecurityRole;
SysSecTreeTasks taskTree;
SecurityRoleTaskGrant SecurityRoleTaskGrant;
taskTree = tree as SysSecTreeTasks;
securityRole = taskTree.getSecurityRole();
ttsbegin;
EePersonalDataAccessLogging::logRoleTaskChange(recId, 0, securityRole, AddRemove::Remove);
delete_from securityRoleTaskGrant where securityRoleTaskGrant.SecurityRole == securityRole && securityRoleTaskGrant.SecurityTask == recId;
ttscommit;
if (treeControl)
{
tree.deleteTreeItem(treeControl, idx);
}
}
However, it somehow doesn’t recognize the triggers and so it does not fill my table.
I hoped to add a delete/insert trigger to the SecuryRoleTaskGrant systemtable, but this is completely closed, so I have no idea how or where this method can be triggered.
So then I thought as a ‘semi-working’ work around, let’s only log changes made in the front-end, since that already fixes the problem for the regular workers. So I decided to find a similar trigger within Forms, and I found the form SysSecUserAddRoles with method assignRolesToSelectedUser. This method has the following trigger:
if (added)
{
EePersonalDataAccessLogging::logUserRoleChange(secRole.RecId,0, userId, AddRemove::Add);
}
I decided to add this trigger to a Form that allows workers to change Task-Roles: SysSecRoleAddTasks method addTasksFromRole, and somehow this also does not seem to fix the problem. It doesn’t fill the table. I use the following code, and front-end changes are still not logged within my created EeRoleTaskChangeLog table.
public int addTasksFromRole(SecurityRole _role, boolean _recursive = false)
{
SecurityRole childRole;
SecuritySubRole subRole;
SecurityTask task;
SecurityRoleTaskGrant srtGrant;
int nAdded = 0;
RefRecId securityRole;
boolean added;
if (_role.RecId == targetRoleId)
{
return 0;
}
startLengthyOperation();
while select task
join SecurityRole, SecurityTask from srtGrant
where srtGrant.SecurityRole == _role.RecId
&& srtGrant.SecurityTask == task.RecId
{
nAdded += this.addTask(task);
}
if (_recursive)
{
while select childRole
where childRole.RecId != targetRoleId
join SecurityRole, SecuritySubRole from subRole
where subRole.SecuritySubRole == childRole.RecId
&& subRole.SecurityRole == _role.RecId
{
this.addTasksFromRole(childRole, true);
}
}
endLengthyOperation();
if (added) //Added
{
EePersonalDataAccessLogging::logRoleTaskChange(securityTask.RecId,0, securityRole, AddRemove::Add);
}
return nAdded;
}
Why doesn’t this trigger the logging?
Do I need to provide any more information?
The SysSecRoleAddTasks Form has also the addTask method, I tried it here as well, but this again doesn’t trigger the logtable to be filled.
public int addTask(SecurityTask _task, boolean _trialAdd = false)
{
SecurityRoleTaskGrant srtGrant;
int nAdded = 0;
boolean added; //Added
RefRecId securityRole; //Added
select targetRole
where targetRole.RecId == targetRoleId; // make sure in sync
select forupdate srtGrant
where srtGrant.SecurityTask == _task.RecId
&& srtGrant.SecurityRole == targetRoleId;
if (!srtGrant)
{
if (!_trialAdd)
{
ttsbegin;
srtGrant.SecurityTask = _task.RecId;
srtGrant.SecurityRole = targetRoleId;
srtGrant.insert();
nAdded++;
myObjects.insert(_task.RecId, true);
if (added) //Added
{
EePersonalDataAccessLogging::logRoleTaskChange(securityTask.RecId,0, securityRole, AddRemove::Add);
}
ttscommit;
}
else if (targetRoleId != 0)
{
nAdded++;
}
//info('Added task "' + _task.Name + '" (' + int2str(appl.ttsLevel()) + ')');
}
/*
else
{
info('Not adding task "' + _task.Name + '"');
} */
return nAdded;
}
Any suggestions?
This question requires a lot of hands-on debugging I would think to solve, which I'm not sure many posters are going to do unfortunately. Have you tried just using the system's database log?
SecurityRole and SecurityTask are system tables, stored under \System Documentation\Tables\SecurityRole, so I didn't know where to find them in the DB log wizard, but I wrote a manual job that I think should work.
I've only tested it with UserInfo, which is another system table and it appears to have logged changes correctly.
static void AddTablesToDBLog(Args _args)
{
void logTable(TableId _tableId, DatabaseLogType _logType)
{
DatabaseLog dblog;
dblog.logTable = _tableId;
dblog.logField = 0;
dblog.logType = _logType;
dblog.insert();
}
ttsBegin;
logTable(tableNum(SecurityRole), DatabaseLogType::Insert);
logTable(tableNum(SecurityRole), DatabaseLogType::Update);
logTable(tableNum(SecurityRole), DatabaseLogType::Delete);
logTable(tableNum(SecurityTask), DatabaseLogType::Insert);
logTable(tableNum(SecurityTask), DatabaseLogType::Update);
logTable(tableNum(SecurityTask), DatabaseLogType::Delete);
ttsCommit;
SysFlushDatabaseLogSetup::main();
new MenuFunction(menuitemDisplayStr(SysDatabaseLogSetup), MenuItemType::Display).run(null);
info("Done");
}

VendTransOpen marking with CustVendOpenTransManager

I have a button on VendOpenTrans and implemented its clicked method.
I thought this would work but i get an exception and AX closes..
void clicked()
{
LedgerJournalTrans ledgerJournalTrans;
VendTransOpen vto;
super();
switch (originator.TableId)
{
case tableNum(LedgerJournalTrans):
ledgerJournalTrans = element.args().record();
}
for ( vto = vendTransOpen_ds.getFirst(0); vto; vto = vendTransOpen_ds.getNext() )
{
//vendTransOpen_ds.markRecord(vto, 1);
if (vto.RecId)
{
if (manager.getTransMarked(vto) == NoYes::No)
{
select Invoice from vendTrans
where vto.AccountNum == vendTrans.AccountNum &&
vto.RefRecId == vendTrans.RecId;
if (ledgerJournalTrans.Invoice == vendTrans.Invoice)
{
// Mark transaction for settlement
showError = NoYes::No;
manager.updateTransMarked(vto, NoYes::Yes);
showError = NoYes::Yes;
}
}
}
// Update dynamic controls & refresh form as auto-redraw is not triggered
element.updateDesignDynamic();
element.redraw();
}
vendTransOpen_ds.refreshEx(-2);
}
If i comment out the following lines it will work, basically marking all the lines in the grid.
//select Invoice from vendTrans
//where vto.AccountNum == vendTrans.AccountNum &&
//vto.RefRecId == vendTrans.RecId;
//if (ledgerJournalTrans.Invoice == vendTrans.Invoice)
//{
// Mark transaction for settlement
showError = NoYes::No;
manager.updateTransMarked(vto, NoYes::Yes);
showError = NoYes::Yes;
//}
So, to be more clear, what stays is: manager.updateTransMarked(vto, NoYes::Yes);
and this way, it works. As far as i see something happens when i add that select.
Using debug i was able to check it and i think the exception is thrown by the for loop ..
Is there any chance to get a hint about this ?
Try changing your for loop definition to this:
for (vto = vendTransOpen_ds.getFirst(0) ? vendTransOpen_ds.getFirst(0) : vendTransOpen_ds.cursor(); vto; vto = vendTransOpen_ds.getNext())
And change this:
select Invoice from vendTrans
where vto.AccountNum == vendTrans.AccountNum &&
vto.RefRecId == vendTrans.RecId;
if (ledgerJournalTrans.Invoice == vendTrans.Invoice)
{
To this:
if (ledgerJournalTrans.Invoice == vto.vendTrans().Invoice)

X++ passing current selected records in a form for your report

I am trying to make this question sound as clear as possible.
Basically, I have created a report, and it now exists as a menuitem button so that the report can run off the form.
What I would like to do, is be able to multi-select records, then when I click on my button to run my report, the current selected records are passed into the dialog form (filter screen) that appears.
I have tried to do this using the same methods as with the SaleLinesEdit form, but had no success.
If anyone could point me in the right direction I would greatly appreciate it.
Take a look at Axaptapedia passing values between forms. This should help you. You will probably have to modify your report to use a form for the dialog rather than using the base dialog methods of the report Here is a good place to start with that!
Just wanted to add this
You can use the MuliSelectionHelper class to do this very simply:
MultiSelectionHelper selection = MultiSelectionHelper::createFromCaller(_args.caller());
MyTable myTable = selection.getFirst();
while (myTable)
{
//do something
myTable = selection.getNext();
}
Here is the resolution I used for this issue;
Two methods on the report so that when fields are multi-selected on forms, the values are passed to the filter dialog;
private void setQueryRange(Common _common)
{
FormDataSource fds;
LogisticsControlTable logisticsTable;
QueryBuildDataSource qbdsLogisticsTable;
QueryBuildRange qbrLogisticsId;
str rangeLogId;
set logIdSet = new Set(Types::String);
str addRange(str _range, str _value, QueryBuildDataSource _qbds, int _fieldNum, Set _set = null)
{
str ret = _range;
QueryBuildRange qbr;
;
if(_set && _set.in(_Value))
{
return ret;
}
if(strLen(ret) + strLen(_value) + 1 > 255)
{
qbr = _qbds.addRange(_fieldNum);
qbr.value(ret);
ret = '';
}
if(ret)
{
ret += ',';
}
if(_set)
{
_set.add(_value);
}
ret += _value;
return ret;
}
;
switch(_common.TableId)
{
case tableNum(LogisticsControlTable):
qbdsLogisticsTable = element.query().dataSourceTable(tableNum(LogisticsControlTable));
qbrLogisticsId = qbdsLogisticsTable.addRange(fieldNum(LogisticsControlTable, LogisticsId));
fds = _common.dataSource();
for(logisticsTable = fds.getFirst(true) ? fds.getFirst(true) : _common;
logisticsTable;
logisticsTable = fds.getNext())
{
rangeLogId = addrange(rangeLogId, logisticsTable.LogisticsId, qbdsLogisticsTable, fieldNum(LogisticsControlTable, LogisticsId),logIdSet);
}
qbrLogisticsId.value(rangeLogId);
break;
}
}
// This set the query and gets the values passing them to the range i.e. "SO0001, SO0002, SO000£...
The second methods is as follows;
private void setQueryEnableDS()
{
Query queryLocal = element.query();
;
}
Also on the init method this is required;
public void init()
{
;
super();
if(element.args() && element.args().dataset())
{
this.setQueryRange(element.args().record());
}
}
Hope this helps in the future for anyone else who has the issue I had.

leave if statement

I have an if statement inside an if statement.
If the condition in the second if statement returns false, I want to go to the first else
because there it sets my validation controls automatically.
I hope you understand
if (page.isvalid() )
{
if (datetime.tryparse (date) == true)
{
// ok
}
else
{
//go to the other else
}
}
else
{
// want to go here
}
Edit:
Important is that I have to first validate the page because after the validation, I know I can parse the datetimes from the 2 input controls and check if the second one is greater than the first one. Otherwise it throws an exception, maybe, if the date is not valid.
instead of DateTime.Parse(date) use
DateTime dt;
bool isParsed = DateTime.TryParse(date, out dt);
//if ( page.isvalid() && (datetime.parse (date) == true) )
if ( page.isvalid() && isParsed )
{
// ok
}
else
{
// want to go here
}
Take out the elses, and it should be what you're looking for. Also, add a return statement after everything is good to go.
if ( page.isvalid() )
{
if (datetime.parse (date) == true)
{
// ok
}
return;
}
// code here happens when it's not valid.
This does exactly what you want, I believe.
if (page.isvalid() && datetime.tryparse(date) == true)
{
// ok
}
else
{
// want to go here
}
It is not clear whether the '== true' is necessary; you might be able to drop that condition.
Exactly what you want to do is impossible. There are two options. One is to determine both answers at the top of your if clause. This is what the other posters are telling you to do. Another option would be something like this:
bool isvalid = true;
if ( page.isvalid() )
{
if (datetime.tryparse (date) == true)
{
// ok
}
else
{
isvalid = false;
}
}
else
{
isvalid = false;
}
if (isvalid == false)
{
//do whatever error handling you want
}
This extracts the error handling code from your else clause and puts it somewhere both code paths can reach.

Resources