VendTransOpen marking with CustVendOpenTransManager - axapta

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)

Related

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.

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

Ax 2012 tts error

HI i am facing an error while updating a record in the invent table. I am using the following sample code.
static void Job4(Args _args)
{
CsInvBOMSplitQtyCalcHelper bomCalc;
Qty qty;
InventTable inventTable;
InventTable updateInventTable;
BOM bom;
boolean result;
BOMId bomId;
BOMVersion bomVersion;
ItemId item = "1000M-3C-Pcs";
select firstOnly * from bomversion
where bomversion.Active == true
&& bomversion.ItemId == item
&& csIsLengthItem(item) == false;
if (0 != bomVersion.RecId)
{
select * from bom
where bom.BOMId == bomversion.BOMId
exists join inventTable
where bom.ItemId == inventTable.ItemId
&& inventTable.CsIsLengthItem == true;
}
if (0 != bom.RecId)
{
result = true;
bomCalc = CsInvBOMSplitQtyCalcHelper::construct(item);
qty = bomCalc.getAdvicedBOMSpoolQty();
}
ttsBegin;
while select forUpdate updateInventTable
where updateInventTable.ItemId == item
{
updateInventTable.CsInvBOMSplitQty = qty;
updateInventTable.update();
}
ttsCommit;
info(strFmt('%1, %2, %3', result, qty, inventTable.CsInvBOMSplitQty));
}
This is the error I get:
Please help me in resolving this issue.
The error is obviously not caused by this job (but maybe an earlier version).
Just run this small job to reset the TTS level:
static ttsAbort(Args args)
{
ttsabort;
}
TTS level errors are usually caused by programming errors, say calling return before ttsCommit.

Linq to XML single or default

I am querying an xml and i am storing the results using singleordefault
var query = from nm in xelement.Descendants("EmployeeFinance")
where (int)nm.Element("EmpPersonal_Id") == empID
select new AllowancePaid
{
gradeTaxId = nm.Element("Allow-GradeTax").Elements("Amount").Attributes("BenListId").Select(a => (int)a).ToList(),
gradeTaxAmt = nm.Element("Allow-GradeTax").Elements("Amount").Select(a => (double)a).ToList()
};
Debug.WriteLine("2");
var resultquery = query.SingleOrDefault();
now this line: var resultquery = query.SingleOrDefault(); works fine if it found in the xml file. However, i have a case where my query will result in a null. If i have no value, it would make an entry in the xml file and my query obviously results in null. My question is how do i cater for this without causing my programe to crash. obviously, singleordefault() doesnt work.
***************** EDITED *************************
I read what everyone said so far and it make sense but i am still having a problem.
if (query.Count() == 0)
{
Debug.WriteLine("NULL");
}
else {
var resultquery = query.SingleOrDefault();
Debug.WriteLine("NOT NULL");
}
OR
if (query == null)
{
Debug.WriteLine("NULL");
}
else {
var resultquery = query.SingleOrDefault();
Debug.WriteLine("NOT NULL");
}
OR
var resultquery = query.SingleOrDefault();
if (resultquery == null)
{
Debug.WriteLine("NULL Result");
}
else
{
Debug.WriteLine("NOT NULL");
}
I am getting a System.NullReferenceException error when the first part of the if statement is true. One user said to do this: var resultquery = query.SingleOrDefault(); then use my if..else statement to do the comparison. However i am getting the error at the point of assign query.singleofdefault() to resultquery. So i am lost.. hope someone can help. thank you
what i am trying to understand is this. the documentation states if the result query is 0 it will give a default value, if it is not, it will be a single value. so why doesnt this give a default value? [taken from the comments]
null is the default value for reference types. Apparently AllowancePaid is a reference type (a custom class).
What is the value you want when the there is no value found.
You could either do:
if (resultquery == null) {
// Logic for No result
} else {
// Logic for result found
}
Or you could force a default value
eg.
var resultquery = query.SingleOrDefault() ?? new AllowancePaid();
UPDATE
From the comments posted it appears that the null reference exception is actually caused within the query itself rather than by the assignment to resultquery and use of later.
This updated query should solve the issue
var query = from nm in xelement.Descendants("EmployeeFinance")
where nm.Element("EmpPersonal_Id") != null
&& (int)nm.Element("EmpPersonal_Id") == empID
&& nm.Element("Allow-GradeTax") != null
&& nm.Element("Allow-GradeTax").Elements("Amount") != null
select new AllowancePaid
{
gradeTaxId = nm.Element("Allow-GradeTax").Elements("Amount").Attributes("BenListId").Select(a => (int)a).ToList(),
gradeTaxAmt = nm.Element("Allow-GradeTax").Elements("Amount").Select(a => (double)a).ToList()
};
var resultquery = query.SingleOrDefault();
if (resultquery == null) {
Debug.WriteLine("NULL Result");
} else {
// Logic here
}

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