I'm customizing the Sales Order screen in Acumatica to add notes based on the product modifiers from eCommerce, below is the piece of code I grab from previous customization.
I
public virtual void SaveBucketImport(BCSalesOrderBucket bucket, IMappedEntity existing, String operation, SaveBucketImportDelegate baseMethod)
{
MappedOrder order = bucket.Order;
for (int i = 0; i < (order.Extern.OrderProducts?.Count ?? 0); i++)
{
OrdersProductData data = order.Extern.OrderProducts[i];
SalesOrderDetail detail = order.Local.Details.Where(x => x.Delete != true).Skip(i).Take(1).FirstOrDefault();
if(detail != null)
{
// HERE TO ADD NOTES PER LINE
}
}
}
I tried PXNoteAttribute.SetNote(sender, data, option.DisplayName) but still not working
I already debug and try to add PXCache but its seems not working
Related
I am adding the Tracking Number data field from SOPackageDetail to the Invoices screen (SO303000) on the Freight Details Tab. I know that it only shows one ShipmentNbr and this is what I'm using to join the two tables but I would like all of the tracking numbers, since there can be more than one per shipment number, to show in the field instead of just one. They can be just separated in the field value by a comma. Here is my code and it does work for just one tracking number.
Graph:
public class SOInvoiceEntry_Extension : PXGraphExtension<SOInvoiceEntry>
{
#region Event Handlers
protected void SOFreightDetail_RowSelecting(PXCache cache, PXRowSelectingEventArgs e, PXRowSelecting del)
{
if (del != null)
del(cache, e);
var row = (SOFreightDetail)e.Row;
if (row == null) return;
using (new PXConnectionScope())
{
SOPackageDetail track = PXSelect<SOPackageDetail, Where<SOPackageDetail.shipmentNbr, Equal<Required<SOFreightDetail.shipmentNbr>>>>.Select(Base, row.ShipmentNbr);
if(track != null){
SOFreightDetailExt invoiceExt = row.GetExtension<SOFreightDetailExt>();
if (invoiceExt != null){
invoiceExt.TrackNumber = track.TrackNumber;
}
}
}
}
#endregion
}
DAC Extension:
public class SOFreightDetailExt : PXCacheExtension<PX.Objects.SO.SOFreightDetail>
{
#region TrackNumber
public abstract class trackNumber : PX.Data.IBqlField
{
}
protected string _TrackNumber;
[PXString()]
[PXDefault()]
[PXUIField(DisplayName = "Tracking Number", IsReadOnly = true)]
public virtual string TrackNumber
{
get
{
return this._TrackNumber;
}
set
{
this._TrackNumber = value;
}
}
#endregion
}
I want all tracking numbers associated with the Shipment Nbr to be displayed in this field, right now it only shows one. This only will happen if there is multiple packages for one shipment number.
You need to loop on your records (PXSelect) in a foreach. You then need to add each string value to your tracknumber field. Something like this should work...
SOFreightDetailExt invoiceExt = row.GetExtension<SOFreightDetailExt>();
if(invoiceExt == null)
return;
foreach(SOPackageDetail track in PXSelect<SOPackageDetail, Where<SOPackageDetail.shipmentNbr, Equal<Required<SOFreightDetail.shipmentNbr>>>>.Select(Base, row.ShipmentNbr))
{
invoiceExt.TrackNumber = $"{invoiceExt.TrackNumber}, {track.TrackNumber}";
}
Also, there is no need for the PXConnectionScope. You can remove that.
I'm working on upgrading from 8.1 to 8.2 update 3. I understand that the search/indexing was changed and some code is obsolete or no longer works.
Unfortunately in one of our class projects there were some methods our sitecore partners had built for us that are no longer working due to obsolete code and now I need help updating that code. I've been able to narrow it down to just 2 files, with some simple code.
Here is the first set of code:
public partial class TagResults
{
/// <summary>
/// Searches against the Lucene index for pages given a specific tag
/// </summary>
/// <returns></returns>
public List<BasePage> GetPagesForTag(string Tag, int page, int pageSize, out int totalCount)
{
var tags = new List<BasePage>();
Index searchIndex = SearchManager.GetIndex(Constants.LuceneIndexes.Tags);
using (IndexSearchContext context = searchIndex.CreateSearchContext())
{
//The wildcard search allows us to pull back all items with the given tag
var query = new WildcardQuery(new Term(Constants.LuceneFields.Tags, Tag));
SearchHits hits = context.Search(query);
totalCount = hits.Length;
//Go through the results
SearchResultCollection results = hits.FetchResults(page * pageSize, pageSize);
foreach (SearchResult result in results)
{
var searchItem = result.GetObject<Item>();
Item currentDbItem = ItemUtility.GetItem(searchItem.ID);
//Store the item if it exists and is a descendant of the news listing
if (currentDbItem != null)
{
tags.Add(new BasePage(currentDbItem));
}
}
}
return tags.ToList();
}
public static bool IsItemCastable(Item sitecoreItem)
{
return sitecoreItem != null && !string.IsNullOrEmpty(sitecoreItem[FieldIds.IsTagResultsComponent]);
}
}
I think I have some of this changed correctly:
ISearchIndex searchIndex = ContentSearchManager.GetIndex(Constants.LuceneIndexes.tags);
using (IProviderSearchContext context = searchIndex.CreateSearchContent())
But then I get stuck on
SearchHits hits = context.Search(query);
totalCount = hits.Length;
//Go through the results
SearchResultCollection results = hits.FetchResults(page * pageSize, pageSize);
foreach (SearchResult result in results)
Now I'm asking a lot but I am learning. If someone could help me correct this, I would be really appreciative. I've been doing a lot of searching to try to figure out how to correct this but I feel like I'm missing something and I just need some help.
Thank you in advance.
I am a complete code noob and need help writing a test class for a trigger in Salesforce. Any help would be greatly appreciated.
Here is the trigger:
trigger UpdateWonAccounts on Opportunity(before Update) {
Set < Id > accountIds = new Set < Id > ();
//Collect End user Ids which has won Opportunities
for (Opportunity o : Trigger.new) {
if (o.isWon && o.EndUserAccountName__c != null) {
accountIds.add(o.EndUserAccountName__c);
}
}
List < Account > lstAccount = new List < Account > ();
//Iterate and collect all the end user records
for (Account a : [Select Id, Status__c From Account where Id IN : accountIds]) {
lstAccount.add(new Account(Id = a.Id, Status__c = true));
}
//If there are any accounts then update the records
if (!lstAccount.isEmpty()) {
update lstAccount;
}
}
Read An Introduction to Apex Code Test Methods and How To Write A Trigger Test.
Basically, you want to create a new testmethod that updates (inserts, deletes, undeletes, etc. depending on your trigger conditions) a record or sObject.
It looks somewhat like this:
public class myClass {
static testMethod void myTest() {
// Add test method logic to insert and update a new Opportunity here
}
}
I have a command that I've added to a "national" node in the Sitecore Editor. The command generates a list of the 50 state nodes beneath it. It then goes through the state nodes (1 at a time) and generates a list of local nodes under each state node. Within the lists of local nodes, I iterate through them and check if the new item exists - if it does not, I add (create) it as a child under the local node. Ultimately, there are nearly 300 local items that are being added during the course of this command.
Is there a more efficient way to do this (fast query to get the 300 local nodes into one list, then check if the item exists, and create it)? If so, I'm not sure how to do that...
I'm not sure what is the most costly part of the operation. Ultimately, I'm still doing up to 300 separate queries to check if it's there, followed by insert statements, so that may still take a while to run. If so, which setting in web config will increase the applicable "timeout" setting in Sitecore? The sample structure is as follows:
//Derive the template from the name of the item (page) that was passed in - this assumes that the template name and the item name are the same
Sitecore.Data.Database database = Sitecore.Data.Database.GetDatabase("master");
TemplateItem contentPageTemplate = database.SelectSingleItem("fast:/sitecore/Templates/User Defined/Home/Pages/Local Site/" + newPage);
Sitecore.Data.Items.Item[] stateNodes = null;
Sitecore.Data.Items.Item[] localNodes = null;
Item localHomePage = null;
Item newLocalPage = null;
int webBusinessID = 0;
string ID = "";
WebBusiness business;
//Get all of the immediate child nodes (state pages) under the "parent" node ("National Locations") - and put them into a list or array
stateNodes = database.SelectItems("fast:/sitecore/content/Home/National Locations/*");
for (int i = 0; i < stateNodes.Length; i++)
{
if (stateNodes[i].Children.Count > 0)
{
localNodes = database.SelectItems("fast:/sitecore/content/Home/National Locations/" + stateNodes[i].Fields["State Abbreviation"].ToString() + "/*");
}
else
{
//Do nothing
}
for (int j = 0; j < localNodes.Length; j++)
{
localHomePage = localNodes[j];
if (localHomePage.Publishing.IsPublishable(DateTime.Now, false) == true)
{
//If the new page does not exist, create it
if (localHomePage.Children[newPage] == null)
{
newLocalPage = localHomePage.Add(newPage, contentPageTemplate);
counter = counter + 1;
}
else
{
//Additional business logic
}
}
}
}
Unless I'm missing logic/code you don't have there, I think you can simply trim this down to one query to get to the local nodes by changing the XPath:
localNodes = database.SelectItems("fast:/sitecore/content/Home/National Locations/*/*");
The change is to get all immediate sub-items of the immediate sub-items of "National Locations"
So, I am setting the DataSource of my BindingSource to the DefaultViewManager of a DataSet that has a DataRelation. I then set my BindingSource as the UltraGrid's DataSource before applying a RowFilter to the the "SalesOrderSublines" DataView.
public void RefreshData()
{
var dataset = DataService.GetMillWorkOrders()
bindingSource1.DataSource = dataset.DefaultViewManager;
ultraGridSequences.SetDataBinding(bindingSource1, "", true, true);
var dvm = bindingSource1.DataSource as DataViewManager;
dvm.DataViewSettings["SalesOrderSublines"].RowFilter = "LINE_NO = 2;
}
public static DataSet GetMillWorkOrders()
{
DataSet ds = OracleHelper.ExecuteDataset(_connectionString, CommandType.StoredProcedure, SQL.GET_WORK_ORDERS);
ds.Tables[0].TableName = "WorkOrders";
ds.Tables[1].TableName = "SalesOrderSublines";
var dr = new DataRelation("WorkOrderSublines", ds.Tables["WorkOrders"].Columns["WORK_ORDER"], ds.Tables["SalesOrderSublines"].Columns["WORK_ORDER"]);
ds.Relations.Add(dr);
return ds;
}
Then, as the UltraGridRows are initializing I want to hide any parent row ("WorkOrders") that has no visible child rows ("WorkOrderSublines") because of my RowFilter.
private void ultraGridSequences_InitializeRow(object sender, Infragistics.Win.UltraWinGrid.InitializeRowEventArgs e)
{
if (e.Row.Band.Key != "WorkOrders") return;
e.Row.Hidden = e.Row.ChildBands["WorkOrderSublines"].Rows.VisibleRowCount == 0;
}
Although the RowFilter does work properly on the rows in the "WorkOrderSublines" band the VisibleRowCount of the band is still greater than zero and so the parent row is never hidden. My guess is that I want to look for something other than the VisibleRowCount of the ChildBand to determine if the top-level row should be hidden, but I'm stuck. Any help would be greatly appreciated. Thanks ahead of time.
Instead of relying on VisibleRowCount you could simply compare the count of child row filtered vs total count.
void ultraGridSequences_InitializeRow(object sender, Infragistics.Win.UltraWinGrid.InitializeRowEventArgs e)
{
if (e.Row.Band.Key != "WorkOrders") return;
var sublinesBand = e.Row.ChildBands["WorkOrderSublines"]
e.Row.Hidden = sublinesBand.Rows.Count(row => row.IsFilteredOut) ==
sublinesBand.Rows.Count();
}
Should be fine performance-wise so long as we're not talking huge amounts of records?
Using the Filtering within the Grid may be an option rather than using the filtering in the DataSource. The following resources have more details on implementing this:
http://forums.infragistics.com/forums/t/51892.aspx
http://devcenter.infragistics.com/Support/KnowledgeBaseArticle.aspx?ArticleID=7703