Bring Vendor Name as a column in LedgerTransAccount form - axapta

I am trying to bring the vendor name on each line in the TransAccountForm.
I have written a small piece of code which gets the vendor name when LedgerDimension from LedgerJournalTrans is available:
static void GetVendorName(Args _args)
{
CustAccount custAccount;
VendTable vendTable;
LedgerJournalTrans ledgerJournalTrans;
while select ledgerJournalTrans
{
if (ledgerJournalTrans.AccountType == LedgerJournalACType::Vend)
{
custAccount = DimensionStorage::ledgerDimension2AccountNum(LedgerJournalTrans.LedgerDimension);
select firstOnly vendTable
where vendTable.AccountNum == custAccount;
info(strFmt("Vendor Name: %1, Voucher: %2", DirPartyTable::getName(vendTable.Party), ledgerJournalTrans.Voucher));
}
}
}
But how can I get to run this code in order to bring that new column with the vendor name?
Thanks to Jan B. Kjeldsen I got to this solution:
One of the data source in LedgerTransAccount is GeneralJournalEntry on wich i add the display method.
With the help of SubLedgerVoucher i am able to get one line from LedgerJournalTrans.
public display Name VendorName()
{
Name ret;
LedgerJournalTrans ledgerJournalTrans;
select firstFast firstOnly ledgerJournalTrans
where ledgerJournalTrans.Voucher == this.SubledgerVoucher &&
ledgerJournalTrans.TransDate == this.AccountingDate;
ret = ledgerJournalTrans.AccountType == LedgerJournalACType::Vend ?
vendTable::find(DimensionStorage::ledgerDimension2AccountNum
(ledgerJournalTrans.LedgerDimension)).name() : '';
return ret;
}
After this, I just drag and drop this method on my form's grid.

You can add a display method to the ledgerJournalTrans table:
[SysClientCacheDataMethodAttribute(true)]
display VendName vendName()
{
return this.AccountType == LedgerJournalACType::Vend ? vendTable::find(DimensionStorage::ledgerDimension2AccountNum(this.LedgerDimension)).name() : '';
}
A one-liner.

Related

Mark checkbox in all companies AX2012

I added a checkbox in PurchParameters table which name is setExchRateVal and I want to mark true this field in my all companies without sql operations.
How can i do this in AX with job?
I tried this but it's not done,
PurchParameters purchParameters ;
while select forUpdate crossCompany purchParameters
{
purchParameters.setExchRateVal = NoYes::Yes;
purchParameters.update();
//info(strFmt("%1 - %2", purchParameters.SetExchRateVal, purchParameters.dataAreaId));
}
AX ERROR :
Update operations are not allowed across companies.
The error is clear. You can't do crossCompany and updates in the same select query. Method 2 below is closer to what you're doing. When updating parameter tables, it can be done a few ways because of the Key on the table.
See below:
PurchParameters purchParametersUpdate;
PurchParameters purchParametersSeek;
DataArea dataArea;
// Method 1
ttsBegin;
while select dataArea
{
changeCompany(dataArea.id)
{
purchParametersUpdate = PurchParameters::find(true);
purchParametersUpdate.setExchRateVal = NoYes::Yes;
purchParametersUpdate.update();
}
}
ttsCommit;
// Method 2
ttsBegin;
while select crossCompany purchParametersSeek
{
purchParametersUpdate = null;
select firstOnly forUpdate purchParametersUpdate
where purchParametersUpdate.RecId == purchParametersSeek.RecId;
if (purchParametersUpdate)
{
//purchParametersUpdate.setExchRateVal = NoYes::Yes;
purchParametersUpdate.update();
}
}
ttsCommit;
info("Done");

How to use active() method x++

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.

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");
}

Add display method in a listpage form

I want to add a display method in the datasource of a listpage form. I can't add straightly because datasources come from an AOT query. How can I do it?
Thanks for help in advance.
The display method:
public display String255 UserNames()
{
DirPartyName partyName;
DirPersonUser personUser;
DirPerson person;
UserInfo userInfo;
String255 userList = "";
partyName = DirPersonUser::userId2Name(this.UserId);
if(partyName)
{
while select Name from person
exists join personUser
where personUser.PersonParty == person.RecId
&& personUser.User == this.UserId
{
userList += person.Name + ",";
}
}
if (!partyName)
{
while select Name from userInfo
where userInfo.Id == this.UserId
{
userList += userInfo.name + ",";
}
}
partyName = (select firstonly Name from userInfo where userInfo.Id == this.UserId).Name;
if (!partyName)
userList += this.UserId + ",";
strDel(userList,strLen(userList),1);
return userList;
}
I had a same requirement and we did it with a real physical field in the table TrvExpTable after the field is in the table we fill it on opening the list page.
In the init(), before the super(), of the form you can call that method:
public void updateTrvExpTableApprovers()
{
TrvExpTable trvExpTable;
TrvExpTrans trvExpTrans;
WorkflowWorkItemTable workflowItemTable;
String255 approversNames;
HcmWorker HcmWorker;
DirPersonUser dirPersonUser;
Name name;
ttsBegin;
while select forUpdate trvExpTable where trvExpTable.ApprovalStatus == TrvAppStatus::Pending
{
approversNames = "";
while select userId from workflowItemTable
where workflowItemTable.RefRecId == trvExpTable.RecId &&
workflowItemTable.RefTableId == trvExpTable.TableId &&
workflowItemTable.Status == WorkflowWorkItemStatus::Pending
{
select firstonly hcmWorker
join firstonly PersonParty, ValidFrom, ValidTo from dirPersonUser
where dirPersonUser.User == workflowItemTable.userId &&
hcmWorker.Person == dirPersonUser.PersonParty;
name = HcmWorker.name();
if (!name)
{
name = workflowItemTable.userId;
}
if(approversNames)
{
if (!strScan(approversNames, name, 0, 255))
{
approversNames += ', ' + name;
}
}
else
{
approversNames = name;
}
}
trvExpTable.ApproversNames = approversNames;
trvExpTable.update();
}
update_recordSet trvExpTable
setting ApproversNames = ""
where trvExpTable.ApprovalStatus != TrvAppStatus::Pending && trvExpTable.ApproversNames != "";
ttsCommit;
}
It is not the most efficient way but in our case it is working perfect for more than a year now.
Also that way the user could CTRL+G on that field in the grid, which is not a option using the display methods.
Best Regards,
Kristian
Why don't you try writing display method in table method as use same in list page? That is good option.
If you still want to write display method in form data-source level then change your display method like below.
public display String255 UserNames(DataSourcetablename _tableName)
{ ....
Use _tableName where ever you are using "this".
You can refer PurchEditLines form in standard Ax 2012 and see
display ImageRes backOrder(PurchParmLine _purchParmLine).
For more details on display method click here

how to read each value of a column in a table

Using x++ how to create a job to read each value of a column in a table in Microsoft dynamics AX 2009?
This code will display all the column values for a record.
static void Job1(Args _args)
{
DictTable dictTable = new DictTable(tableNum(CustTable));
DictField dictField;
int counter, fieldId;
CustTable custTable;
anytype value;
select firstonly custTable;
for (counter = 1; counter <= dictTable.fieldCnt(); counter++)
{
fieldId = dictTable.fieldCnt2Id(counter);
dictField = new DictField(tableNum(CustTable), fieldId);
if (!dictField.isSystem())
{
value = custTable.(fieldId);
if(value)
{
info(strFmt('%1 = %2',
dictField.label(),
any2str(value)));
}
}
}
}
For getting all the values for a specific column, please use Carlos Heuberger's code.
One possibility: in the AOT (Ctrl-D) right-click on Jobs and select New Job. In the new window enter something like (using the correct table and column name you want to read):
static void Job()
{
YourTable yourTable;
;
while select TheColumn from yourTable
{
// process yourTable.TheColumn
info(strFmt("value: %1", yourTable.TheColumn));
}
}
but thera are some other ways: Select Statements
Just a slight mod, took out any2str to make my table work:
strFmt('%1 = %2 \r\n', dictField.label(), value);

Resources