How to update temp table data during run time AX 2012 - axapta

I'm new to X++ development. I'm trying to add a field in Vendor aging report. It was done as excepted.
my problem is updating the field value during run time.
Scenario,
We have a Invoice field contain "AA_BBBBBB". What I need to do is I need to split the value as AA, BBBBBB and update BBBBBB to invoice field and AA to new field (Invoice type).
Issue,
Once i got the values to temptable VendAgingReportTmp in the method VendAgingReportDP\insertVendAgingReportTmp, I'm tried to update the above scenario but code is not selecting the records from VendAgingReportTmp. Can someone help me to get this thing done.

In VendAgingReportDP class insertVendAgingReportTmp the last line of standard code is vendAgingReportTmp.insert();
If your code is before vendAgingReportTmp.insert(); You do not need to perform the update. If you put vendAgingReportTmp.update(); before vendAgingReportTmp.insert(); you get that error.
Put your code inside //YourCode and //YourCode END withhout vendAgingReportTmp.update();
Example:
/// <summary>
/// Inserts records into the temporary <c>VendAgingReportTmp</c> table.
/// </summary>
/// <param name="_reverseAmountsAndHeadings">
/// A boolean value which indicates whether the column values should be reversed.
/// </param>
private void insertVendAgingReportTmp(boolean _reverseAmountsAndHeadings)
{
vendAgingReportTmp.AsOfDate = strFmt("#SYS84682", date2StrUsr(contract.parmZeroDate(), DateFlags::FormatAll), contract.parmDateTransactionDuedate());
vendAgingReportTmp.HeadingAccount = strFmt("#SYS24500");
vendAgingReportTmp.HeadingName = strFmt("#SYS7399");
switch (contract.parmDateTransactionDuedate())
{
case DateTransactionDuedate::DocumentDate : vendAgingReportTmp.HeadingDate = "#SYS2587";
break;
case DateTransactionDuedate::TransactionDate : vendAgingReportTmp.HeadingDate = "#SYS67";
break;
case DateTransactionDuedate::DueDate : vendAgingReportTmp.HeadingDate = "#SYS14588";
break;
default : vendAgingReportTmp.HeadingDate = "#SYS14588";
break;
}
if (_reverseAmountsAndHeadings)
{
this.setVendAgingReportTmpInReverse();
}
else
{
this.setVendAgingReportTmp();
}
vendAgingReportTmp.TransDate = tmpAccountSum.TransDate;
vendAgingReportTmp.InvoiceId = tmpAccountSum.InvoiceId;
vendAgingReportTmp.Voucher = tmpAccountSum.Voucher;
vendAgingReportTmp.AccountNum = tmpAccountSum.AccountNum;
vendAgingReportTmp.Name = vendTable.name();
vendAgingReportTmp.VendAccount = tmpAccountSum.AccountNum;
vendAgingReportTmp.Txt = tmpAccountSum.Txt;
vendAgingReportTmp.Balance = 100;
vendAgingReportTmp.CurrencyCode = tmpAccountSum.CurrencyCode;
vendAgingReportTmp.VendGroup = vendTable.VendGroup;
//YourCode
//...
//...
//...
//YourCode END
vendAgingReportTmp.insert();
}

I got a solution by adding below,
Added InvoiceType field to temptable VendTmpAccountSum Since this is declared as global variable.
Updated our custom Invoice type to InvoiceType field in VendTmpAccountSum.
Then insert the whole data to VendAgingReportTmp from VendTmpAccountSum table by using insert_recordset to increase the performance.
Thanks,

Related

Number of records in grid AX 2012

I tried to count num of rows in grid in runtime with this code
FormRun caller;
FormDataSource fds;
QueryRun queryRun;
int64 rows;
fds = caller.dataSource();
query = fds.query();
queryRun = new QueryRun(query);
rows = SysQuery::countTotal(queryRun); //this returns -1587322268
rows = SysQuery::countLoops(queryRun); //this returs 54057
The last line of code is closest to what i need because there are 54057 lines but if i add filters it still returns 54057.
I want logic to get the number rows that grid has in the moment of calling the method.
Your query has more than one datasource.
The best way to explain your observation is to look at the implementation of countTotal and countLoops.
public client server static Integer countTotal(QueryRun _queryRun)
{
container c = SysQuery::countPrim(_queryRun.pack(false));
return conpeek(c,1);
}
public client server static Integer countLoops(QueryRun _queryRun)
{
container c = SysQuery::countPrim(_queryRun.pack(false));
return conpeek(c,2);
}
private server static container countPrim(container _queryPack)
{
...
if (countQuery.dataSourceCount() == 1)
qbds.addSelectionField(fieldnum(Common,RecId),SelectionField::Count);
countQueryRun = new QueryRun(countQuery);
while (countQueryRun.next())
{
common = countQueryRun.get(countQuery.dataSourceNo(1).table());
counter += common.RecId;
loops++;
}
return [counter,loops];
}
If your datasource contains one datasource it adds count(RecId).
countTotal returns the number of records.
countLoops returns 1.
Pretty fast, as fast as the SQL allows.
If your datasource contains more than one datasource it does not add count(RecId).
countTotal returns the sum of recIds (makes no sense).
countLoops returns the number of records.
Also countLoops is slow if there are many records as they are counted one by one.
If you have two datasources and want a fast count, you are on your own:
fds = caller.dataSource();
queryRun = new QueryRun(fds.queryRun().query());
queryRun.query().dataSourceNo(2).joinMode(JoinMode::ExistsJoin);
queryRun.query().dataSourceNo(1).clearFields();
queryRun.query().dataSourceNo(1).addSelectionField(fieldnum(Common,RecId),SelectionField::Count);
queryRun.next();
rows = queryRun.getNo(1).RecId;
The reason your count did not respect the filters was because you used datasource.query() rather than datasource.queryRun().query(). The former is the static query, the latter is the dynamic query with user filters included.
Update, found some old code with a more general approach:
static int tableCount(QueryRun _qr)
{
QueryRun qr;
Query q = new Query(_qr.query());
int dsN = _qr.query().dataSourceCount();
int ds;
for (ds = 2; ds <= dsN; ++ds)
{
if (q.dataSourceNo(ds).joinMode() == JoinMode::OuterJoin)
q.dataSourceNo(ds).enabled(false);
else if (q.dataSourceNo(ds).joinMode() == JoinMode::InnerJoin)
{
q.dataSourceNo(ds).joinMode(JoinMode::ExistsJoin);
q.dataSourceNo(ds).fields().clearFieldList();
}
}
q.dataSourceNo(1).fields().clearFieldList();
q.dataSourceNo(1).addSelectionField(fieldNum(Common,RecId), SelectionField::Count);
qr = new QueryRun(q);
qr.next();
return any2int(qr.getNo(1).RecId);
}

Symfony insert into a table, all colums foreign key

I want to insert data into a middle table Builds_Perks with columns idBuild and idPerks. The problem is with idPerks, I take the id from some checkbox and when I want to isnert those id the following error appears:
Argument 2 passed to App\Entity\BuildsPerks::__construct() must be an instance of App\Entity\Perks, int given...
This is part of the code where I take the checkbox id to INSERT them:
$idAllPerks = $request->get('chk');
foreach($idAllPerks as $idPerk) {
$idPerkInt = (int) $idPerk; // string into int
$newBuildPerk = new BuildsPerks(
$usuBuild,
$idPerkInt
);
$this->getDoctrine()->getManager()->persist($newBuildPerk );
}
Thanks.
The error message is very clear. It expects to receive an object of type Perks but you are giving the ID of that object instead of the object itself. This might work.
$idAllPerks = $request->get('chk');
foreach($idAllPerks as $idPerk) {
$em = $this->getDoctrine()->getManager();
$perk = $em->getRepository(Perks::class)->find((int) $idPerk);
$newBuildPerk = new BuildsPerks(
$usuBuild,
$perk
);
$em->persist($newBuildPerk );
}

X++ assign Enum Value to a table column

I am trying to pull the Enum chosen from a dialog and assign the label to a table's column.
For example: Dialog opens and allows you to choose from:
Surface
OutOfSpec
Other
These are 0,1,2 respectively.
The user chooses OutOfSpec (the label for this is Out Of Spec), I want to put this enum's Name, or the label, into a table. The column I'm inserting into is set to be a str.
Here's the code I've tried, without success:
SysDictEnum dictEnum = new SysDictEnum(enumNum(SDILF_ScrapReasons));
reason = dialog.addField(enumStr(SDILF_ScrapReasons),"Scrap Reason");
dialog.run();
if (!dialog.closedOk())
{
info(reason.value());
return;
}
ttsBegin;
// For now, this will strip off the order ID from the summary fields.
// No longer removing the Order ID
batchAttr = PdsBatchAttributes::find(itemId, invDim.inventBatchId, "OrderId");
orders = SDILF_BreakdownOrders::find(batchAttr.PdsBatchAttribValue, true);
if (orders)
{
orders.BoxProduced -= 1;
orders.update();
}
// Adding a batch attribute that will include the reason for scrapping
select forUpdate batchAttr;
batchAttr.PdsBatchAttribId = "ScrapReason";
//batchAttr.PdsBatchAttribValue = any2str(dictEnum.index2Value(reason.value()));
batchAttr.PdsBatchAttribValue = enum2str(reason.value());
batchAttr.InventBatchId = invDim.inventBatchId;
batchAttr.ItemId = itemId;
batchAttr.insert();
Obviously this is not the whole code, but it should be enough to give the issue that I'm trying to solve.
I'm sure there is a way to get the int value and use that to assign the label, I've just not been able to figure it out yet.
EDIT
To add some more information about what I am trying to accomplish. We make our finished goods, sometimes they are out of spec or damaged when this happens we then have to scrap that finished good. When we do this we want to keep track of why it is being scrapped, but we don't want just a bunch of random reasons. I used an enum to limit the reasons. When the operator clicks the button to scrap something they will get a dialog screen pop-up that allows them to select a reason for scrapping. The code will then, eventually, put that assigned reason on that finished items batch attributes so that we can track it later in a report and have a list of all the finished goods that were scrapped and why they were scrapped.
I'm not entirely sure of your question, but I think you're just missing one of the index2[...] calls or you're not getting the return value from your dialog correctly. Just create the below as a new job, run it, make a selection of Open Order and click ok.
I don't know the difference between index2Label and index2Name.
static void Job67(Args _args)
{
Dialog dialog = new dialog();
SysDictEnum dictEnum = new SysDictEnum(enumNum(SalesStatus));
DialogField reason;
SalesStatus salesStatusUserSelection;
str label, name, symbol;
int value;
reason = dialog.addField(enumStr(SalesStatus), "SalesStatus");
dialog.run();
if (dialog.closedOk())
{
salesStatusUserSelection = reason.value();
// Label
label = dictEnum.index2Label(salesStatusUserSelection);
// Name
name = dictEnum.index2Name(salesStatusUserSelection);
// Symbol
symbol = dictEnum.index2Symbol(salesStatusUserSelection);
// Value
value = dictEnum.index2Value(salesStatusUserSelection);
info(strFmt("Label: %1; Name: %2; Symbol: %3; Value: %4", label, name, symbol, value));
}
}

Upper and/lower queriable values jdeveloper

I have a query form in a jspx file and i'm trying to define some of the values as case sensitive, meaning that i want to be able to find, for example, a name with all letters upper case and/or lower case and obtain the values that i would obtain if i've inserted the name correctly.
Can someone indicate me where can i find something to accomplish that?
Thanks in advance
--------Update
Code from my jspx file
<af:query id="qryId1" headerText="Search" disclosed="true"
value="#bindings.ImplicitViewCriteriaQuery.queryDescriptor}"
model="#bindings.ImplicitViewCriteriaQuery.queryModel}"
queryListener="#bindings.ImplicitViewCriteriaQuery.processQuery}"
queryOperationListener="#{bindings.ImplicitViewCriteriaQuery.processQueryOperation}"
resultComponentId="::resId1"
binding="#{backingBeanScope.backing_SearchCustomer.qryId1}"
maxColumns="3" rows="2" fieldWidth="30%"
displayMode="compact" saveResultsLayout="never"
saveQueryMode="hidden" modeChangeVisible="false"/>
In a view criteria, for each criteria item there is a check box Ignore Case. Uncheck it if you want to make that search field case sensitive.
If you are using All Queriable Attributes to create your search then you can set it in queryListner method of the query component. Here are the steps:
Create a queryListener method for your query component
<af:query id="qryId1" headerText="Search" disclosed="true"
value="#{bindings.ImplicitViewCriteriaQuery.queryDescriptor}"
model="#{bindings.ImplicitViewCriteriaQuery.queryModel}"
queryListener="#{backingBeanScope.searchBean.queryListener}"
queryOperationListener="#{bindings.ImplicitViewCriteriaQuery.processQueryOperation}"
resultComponentId="::resId1"/>
Make query attributes case insensitive in queryListener method
public void queryListener(QueryEvent queryEvent)
{
QueryDescriptor qdesc = (QueryDescriptor) queryEvent.getDescriptor();
ConjunctionCriterion conCrit = qdesc.getConjunctionCriterion();
//access the list of search fields
List<Criterion> criterionList = conCrit.getCriterionList();
for (Criterion criterion: criterionList)
{
((AttributeCriterion) criterion).setMatchCase(false);
}
invokeMethodExpression( "#{bindings.ImplicitViewCriteriaQuery.processQuery}", queryEvent);
}
private void invokeMethodExpression(String expr, QueryEvent queryEvent)
{
FacesContext fctx = FacesContext.getCurrentInstance();
ELContext elContext = fctx.getELContext();
ExpressionFactory eFactory =
fctx.getApplication().getExpressionFactory();
MethodExpression mexpr =
eFactory.createMethodExpression(elContext, expr, Object.class,
new Class[]
{ QueryEvent.class });
mexpr.invoke(elContext, new Object[]
{ queryEvent });
}

. The An object with the same key already exists in the ObjectStateManagerObjectStateManager cannot track multiple objects with the same key

I am trying to simply update the entity object and I get this error.. All the googling on the error I did takes me to complex explanations... can anyone put it simply?
I am working of of this simple tutorial
http://aspalliance.com/1919_ASPNET_40_and_the_Entity_Framework_4__Part_2_Perform_CRUD_Operations_Using_the_Entity_Framework_4.5
else
{
//UPDATE
int iFid = Int32.Parse(fid.First().fid.ToString());
oFinancial.fid = iFid;
oFinancial.mainqtr = currentQuarter;
oFinancial.mainyear = currentYear;
oFinancial.qtr = Int32.Parse(currentQuarter);
oFinancial.year = Int32.Parse(currentYear);
oFinancial.updatedate = DateTime.Now;
// ObjectStateEntry ose = null;
// if (!dc.ObjectStateManager.TryGetObjectStateEntry(oFinancial.EntityKey, out ose))
// {
dc.financials.Attach(oFinancial);
// }
dc.ObjectStateManager.ChangeObjectState(oFinancial, System.Data.EntityState.Modified);
}
dc.SaveChanges();
here is what is higher up in the code that I use simple to get me the primary key value.. probably a better way but it works.
var fid = from x in dc.financials
where iPhaseID == x.phaseid &&
strTaskID == x.ftaskid &&
strFundType == x.fundtype &&
iCurrentQuarter == x.qtr &&
iCurrentYear == x.year
select x;
If the oFinancial object came from your dc and you never manually detached it, then there is no reason to call the Attach method or to mess with the ObjectStateManager. As long as the dc knows about the object (which it does unless you detach it), then the ObjectStateManager will keep track of any changes you make and update them accordingly when you call dc.SaveChanges().
EDIT: Here's a refactored version of what you posted, hope it helps:
else {
//UPDATE
// as long as oFinancial was never detatched after you retrieved
// it from the "dc", then you don't have to re-attach it. And
// you should never need to manipulate the primary key, unless it's
// not generated by the database, and you don't already have another
// object in the "dc" with the same primary key value.
int iFid = Int32.Parse(fid.First().fid.ToString());
oFinancial.fid = iFid;
oFinancial.mainqtr = currentQuarter;
oFinancial.mainyear = currentYear;
oFinancial.qtr = Int32.Parse(currentQuarter
oFinancial.year = Int32.Parse(currentYear);
oFinancial.updatedate = DateTime.Now;
}
dc.SaveChanges();
One other thing: if iFid is the primary key, then you shouldn't mess with it as long as this object came from the dc. I believe the problem is that you're resetting the primary key (iFid) to the same value of another object within the dc, and EF4 is barking because you can't have two rows with the same primary key value in a table.

Resources