Acumatica - Extended graph children not showing when view - graph

Good Day Sir / Ma'am,
I have a question regarding extending graphs in Acumatica.
I have extended the SalesOrderEntry Graph with 2 custom views namely ReservationDetails and PropertyItems. Everything is running well except when I try to fetch a record, the details on my PropertyItems view are not populating.
EXTENDED GRAPH
public class SOOrderEntryExt : PXGraphExtension<SOOrderEntry>
{
#region Selects
public PXSelect<RECOReservationDetail,
Where<RECOReservationDetail.reservationNbr,
Equal<Current<SOOrder.orderNbr>>>> ReservationDetails;
public PXSelectJoin<InventoryItem,
LeftJoin<RECOReservationDetail, On<InventoryItem.inventoryID,
Equal<RECOReservationDetail.inventoryID>,
And<RECOReservationDetail.reservationNbr,
Equal<Current<SOOrder.orderNbr>>>>>,
Where<InventoryItem.inventoryID,
Equal<Current<RECOReservationDetail.inventoryID>>>> PropertyItems;
CUSTOM TABLE - ReservationDetail DAC
namespace RealEstate.DAC.CO
{
[Serializable]
public class RECOReservationDetail : IBqlTable
{
#region Reservation Nbr.
[PXDBString(15, IsKey = true)]
[PXUIField(DisplayName = "Reservation Nbr.")]
[PXParent(typeof(Select<SOOrder,
Where<SOOrder.orderNbr,
Equal<Current<RECOReservationDetail.reservationNbr>>>>))]
[PXDBDefault(typeof(SOOrder.orderNbr))]
public virtual string ReservationNbr { get; set; }
public abstract class reservationNbr : IBqlField { }
#endregion
#region Branch ID
[PXDBInt]
[PXSelector(typeof(Search<Branch.branchID>),
SubstituteKey = typeof(Branch.branchCD))]
[PXUIField(DisplayName = "Branch ID", Required = true)]
[PXDefault(typeof(AccessInfo.branchID), PersistingCheck = PXPersistingCheck.Nothing)]
public virtual int? BranchID { get; set; }
public abstract class branchID : IBqlField { }
#endregion
#region Inventory ID
[StockItem]
[PXUIField(DisplayName = "Inventory ID")]
public virtual int? InventoryID { get; set; }
public abstract class inventoryID : IBqlField { }
#endregion
Page - Image
The above image is the view when I'm trying to fetch an order from sales order. As you can tell, It populates the document details part except for the Features Group. I already put CommitChanges = True on the Inventory ID field so that it will fill in the necessary information for the features part, but sadly it doesn't fill in any data.
<px:PXSegmentMask ID="edInventoryID" runat="server" CommitChanges="True" DataField="InventoryID"></px:PXSegmentMask>
I tried debugging it, but the PropertyItems view always returns null value.
Thank you so much for the replies.
UPDATE - 10/05/2018
Full Page Link
Full Extended Graph Link
Full DAC Link

I think your main problem occurs because you re-implemented the Sales Order screen instead of extending it. While doing so you removed some important elements like the Document Details 'grid'.
If I just add your 2 Data Views to the original Sales Order screen without removing anything they appear to sync better. Notice it does pickup the Item description and item image properly (other blank fields is because I miss your custom DAC/Table):
To test this I extended original Sales Order instead of creating a new screen that is a copy of the orginal Sales Order. You likely removed too much of the original screen.

Related

Using Backlink feature of realm-dotnet in Xamarin.Forms App

My current employer is developing a mobile app using Xamarin.Forms and Asp.net mvc on the backend. I suggested to use realm in the mobile app. My manager want to see a POC(Proof of concept) app using realm with backlink feature before allowing it to be used in the app. I am working on the POC on GitHub . The documentation is very limiting and the GitHub repo of realm-dotnet don’t have good sample.
I completed the project. But unable to implement backlink. The sample app I have developed allow user to create assignees(employees) in the first page. The user can delete or edit the employees using context menu. When the user clicks on the employee name the app navigates to the ToDoListPage of that particular employee. Here the user can create ToDoItems. On this ToDoList page I want to show the ToDoItems that where assigned to that employee only.
The models were as follows:
public class Assignee : RealmObject
{
public Assignee()
{
ToDoItems = Enumerable.Empty<ToDoItem>().AsQueryable();
}
[PrimaryKey]
public string Id { get; set; } = Guid.NewGuid().ToString();
public string Name { get; set; }
public string Role { get; set; }
[Backlink(nameof(ToDoItem.Employee))]
public IQueryable<ToDoItem> ToDoItems { get; }
}
public class ToDoItem : RealmObject
{
[PrimaryKey]
public string Id { get; set; } = Guid.NewGuid().ToString();
public string Name { get; set; }
public string Description { get; set; }
public bool Done { get; set; }
public Assignee Employee { get; set; }
}
I am adding employee to each ToDo Item:
Item.Employee = Employee;
_realm.Add(Item);
Now I want to access the ToDoItems for the Employee:
Items = _realm.All<Assignee>().Where(x => x.Id == EmployeeId).FirstOrDefault().ToDoItems;
But this does not work. I will be grateful if someone can help me out by preferably writing code in my sample app or write the correct code in the reply.
Thank you
Firstly, Realm .NET doesn't currently support traversing properties (x.Employee.Id). Due to this, when I start the app and try to go to the ToDoListPage, the app crashes with the exception:
The left-hand side of the Equal operator must be a direct access to a persisted property in Realm
Realm supports object comparison, so we can fix this like so:
var employee = _realm.Find<Assignee>(EmployeeId);
Items = _realm.All<ToDoItem>().Where(x => x.Employee == employee);
Secondly, everything seemed fine in your code, so I dug a bit deeper and saw why it isn't working. The issue is that when we try to get all items with the code above, the EmployeeId parameter is null. Since the EmployeeId is being populated after the load logic has been triggered, we don't need to load the data in the ctor. So you can remove this code.
Finally, since you won't be loading the data in the ctor, and instead in the SetValues method, the UI needs to know, when the data has been updated, what exactly to redraw. Thus, you need to mark the collection to be Reactive too:
[Reactive]
public IEnumerable<ToDoItem> Items { get; set; }
Then, you need to change the SetValues method to use object comparison, instead of traversing:
async Task SetValues()
{
Employee = _realm.Find<Assignee>(EmployeeId);
Title = Employee.Name;
Items = _realm.All<ToDoItem>().Where(x => x.Employee == Employee);
}
To sum up - you don't need to try and load the data in the ctor, since you don't know when the EmployeeId will be set. You are already tracking when the property will change and inside the SetValues command you simply need to change the expression predicate.

Make a form field selection values dependent on another field value

I am editing the AP301000 screen, Bills and Adjustments, in a customization project.
I added two new fields to the form, which are both in the APRegisterExt class.
1. PONbr
2. ReceiptNbr
When a user selects a PO number, I want the ReceiptNbr selection values to be restricted to only the receipt records which have the same PO number.
I tried using a PXSelector attribute on ReceiptNbr, but because the PONumber is in an extension class, I cannot use Current<> to access this field.
Any ideas?
On your second CustomField's Selector attribute definition use Current<> statement for filtering, see below:
#region UsrCustomField1
[PXDBInt]
[PXUIField(DisplayName="CustomField1")]
[PXSelector(typeof(Search<DAC.Field>),
typeof(DAC.Field),
typeof(DAC.Field),
SubstituteKey= typeof(DAC.Field))]
public virtual int? UsrCustomField1 { get; set; }
public abstract class usrCustomField1 : IBqlField { }
#endregion
#region UsrCustomField2Dependent
[PXDBInt]
[PXUIField(DisplayName="CustomField2Dependent")]
[PXSelector(typeof(Search<DAC.Field, Where<DAC.Field, Equal<Current<UsrCustomField1>>>>),
typeof(DAC.Field),
typeof(DAC.Field),
SubstituteKey= typeof(DAC.Field))]
public virtual int? UsrCustomField2Dependent { get; set; }
public abstract class usrCustomField2Dependent : IBqlField { }
#endregion
Then on your ASPX file make sure you have added CommitChanges=True and AutoRefresh=true properties, see below:
<px:PXSelector runat="server" ID="CstPXSelector2" DataField="UsrCustomField1" CommitChanges="True" AutoRefresh="True" />
<px:PXSelector runat="server" ID="CstPXSelector1" DataField="UsrCustomField2Dependent" CommitChanges="True" AutoRefresh="True" />

How do I populate my model from a database entry?

I have set up a large form with lots of entries. It populates my model and then saves to the database. I also need to be able to pull this information out of the database, put it into the model, and populate a bunch of fields with it for review. How do I do this?
Using ASP.NET MVC 4 Razor.
var db = new TechProjPlansContext();
TechProjPlan model = new TechProjPlan();
I can set up my data context and model, but where do I go from here to populate the model with a data entry chosen by ID?
You can search by givenId and if found return result type of TechProjPlan otherwise null
var resultFound = db.TechProjPlans.Where(e=>e.Id = givenId).FirstOrDefault();
I strongly recommend following this tutorial step by step. From the tutorial to answer your question:
Write a Model class like:
public class Movie
{
public int ID { get; set; }
public string Title { get; set; }
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; }
public decimal Price { get; set; }
}
Add a DbSet to your Context class: (TechProjPlansContext in your project)
public class MovieDBContext : DbContext
{
public DbSet<Movie> Movies { get; set; }
}
Make sure you can connect to the database server, check your connectionStrings in your Web.config file.
As you wanted to filter only one Entity by using ID, you need a Controller class:
public ActionResult Details(int id = 0) // here id is set to 0 if it's null
{
Movie movie = db.Movies.Find(id);
if (movie == null)
{
return HttpNotFound();
}
return View(movie);
}
As you see, you'll be returning View(movie), that means you return Details page with the Entity (a movie) you got from the database. And have a View, that renders to actual HTML code the client will see. At the top of it, add the line:
#model MvcMovie.Models.Movie // (something TechProjPlans.Models.Movie in your project)
#Html.LabelFor(model => model.Title)
This will create a simple text showing the movie's title.
It's not logical to go deeper within an answer, so rest is up to you with that tutorial. Just keep in mind that the code above is only one example and you can use endless variations within each level for your situation.
You can right click on the directory Controllers, select Add New and select your Model class and Context class at the page. That will produce a Controller and Views (index, edit, delete, details, insert) tied to it which will be a good way to start your MVC study.

RavenDB and hierarchical documents

I am having difficulties solving this problem using RavenDB. I have these classes.
I excluded a lot of properties from them to keep the example simple.
public class Menu
{
public string Name { get; set; }
public List<NavigationNode> Nodes { get; set; }
}
public class NavigationNode
{
public string Text { get; set; }
public Guid? PageId { get; set; }
public string NodeType { get; set; }
public List<NavigationNode> Nodes { get; set; }
}
public class Page
{
public Guid PageId { get; set; }
public string Slug { get; set; }
}
So as you can see this is about rendering a navigation menu. Node lists are hierarchical and can go deep, in theory infinitely(of course in reality 2-4 sub levels only). At first i stored the Slug in the Node but realised that, what happens if the page Slug changes, changing all nodes when a page changes slug i would have to loop through all menus, climb down the hierarchy and find all those Slug values to change them, which does not sound like an optimal solution.
So i was thinking it should be possible to build an index that combines the Page Slug with rest of the data from the Node in a hierarchical structure.
I have been reading about Map Reduce, Multimap and recurse but i am not even sure where to start.
I found this http://ravendb.net/docs/2.0/client-api/querying/static-indexes/indexing-hierarchies
Here is a simple example i tried just to get something started, and i cannot even get that to work since i really don't understand the example on the page i linked to above.
public class NavigationIndex : AbstractIndexCreationTask<Menu>
{
public NavigationIndex()
{
Map = menus => from menu in menus
from node in Recurse(menu, x => x.Nodes)
select new
{
WhatIsThis = node // <- Why is this a collection?
};
}
}
According to the example node should not be a collection but an actual NavigationNode object.
Is it possible to achieve what i want in RavenDB and what am i doing wrong in the example?
Please feel free to ask anything you find confusing.
I apologize for the confusion. I'll try to explain it.
EDIT:
Changing PageId to string will not be a problem. I am using Guids since i need to be able to generate primary key ID:s before inserting. Anyway, what i want to Query for from the index is a hiearachical tree of navigation links where the Pages Slug is included. So i can recursively loop out a navigation menu on the website.
Answers to Matt Johnson's questions:
I want a output of a class you can see below
Page is a separate document
I am only going to query by Menu Name
public class NavigationIndexItem{
public string MenuName { get; set; }
public string Text { get; set; }
public string Slug { get; set; }
public string NodeType { get; set; }
public List ChildItems { get; set; }
}
Now when i see the above class i think i might a bit on the wrong path.
But anyway i will make some minor changes and thank you Matt for answering. However i am still running into same problem as before.
This row in your example: where node.PageId != null
node is not an instance of a specific NavigationNode but yet another collection so i cannot check the PageId property on it. I only get a list of LINQ extensions.
I'm making some assumptions of what you want. See my comments on the original question. But I think this is what you are after.
First - you need to change the id of the Page class to Id instead of PageId. This is so Raven will use your guid as part of its document id. Really you would be better off with string Ids, but this will still work.
Then you can do the following:
public class NavigationIndex : AbstractIndexCreationTask<Menu>
{
public NavigationIndex()
{
Map = menus => from menu in menus
from node in Recurse(menu, x => x.Nodes)
where node.PageId != null
let page = LoadDocument<Page>("pages/" + node.PageId)
select new
{
menu.Name,
node.Text,
node.PageId,
page.Slug
};
}
}
This uses the new LoadDocument feature of RavenDB 2.0, which is much more suitable than multi-map for your scenario.
Change it so it would be:
from node in Recurse(menu, x => x.Nodes.AsEnumerable())

Slim version of Large Object/Class

I have a product class which contains 11 public fields.
ProductId
ShortTitle
LongTitle
Description
Price
Length
Width
Depth
Material
Img
Colors
Pattern
The number of fields may grow with attributes for more specific product tyes. The description may contain a large amount of data.
I want to create a slim version of this product class that only contains the data needed. I'm only displaying 4 of the 12 fields when listing products on a category page. It seems like a waste to retrieve all of the data when most of it isn't being used.
I created a parent class of ProductListing that contains the 4 fields I need for the category page
ProductId
ShortTitle
Price
Img
Then created a class of Product that inherits from ProductListing containing all product data. It seems backwards as "ProductListing" is not a kind of "Product" but I just started reading about inheritance a few months ago so it's stil a little new to me.
Is there a better way to get a slim object so I'm not pulling data I don't need?
Is the solution I have in place fine how it is?
I personally do not favor inheritance for these kinds of problems because it can become confusing over time. Specifically, I try to avoid having two concrete classes in my inheritance hierarchy where one inherits from the other and both can be instantiated and used.
How about creating a ProductCoreDetail class that has the essential fields you need and aggregating it inside of the Product class. You can still expose the public fields by declaring them as public fields and proxying them to the nested ProductCoreDetail instance.
The benefit of this model is that any shared implementation code can be placed in ProductCoreDetail. Also, you can choose to define an additional interface IProductCoreDetail that both Product and ProductCoreDetail implement so that you can pass either instance to methods that just care about code information. I would also never exposed the aggregate instance publicly to consumer of Product.
Here's a code example:
// interface that allows functional polymorphism
public interface IProductCoreDetail
{
public int ProductId { get; set; }
public string ShortTitle { get; set; }
public decimal Price { get; set; }
public string Img { get; set; }
}
// class used for lightweight operations
public class ProductCoreDetail : IProductCoreDetail
{
// these would be implemented here..
public int ProductId { get; set; }
public string ShortTitle { get; set; }
public decimal Price { get; set; }
public string Img { get; set; }
// any additional methods needed...
}
public class Product : IProductCoreDetail
{
private readonly ProductCoreDetail m_CoreDetail;
public int ProductId { get { return m_CoreDetail.ProductId; } }
public string ShortTitle { get { return m_CoreDetail.ShortTitle; } }
public decimal Price { get { return m_CoreDetail.Price; } }
public string Img { get { return m_CoreDetail.Img; } }
// other fields...
public string LongTitle
public string Description
public int Length
public int Width
public int Depth
public int Material
public int Colors
public int Pattern
}
I agree with LBushkin that inheritence is the wrong approach here. Inheritence suggests that TypeB is a TypeA. In your case, the relationship is not quite the same. I used to create classes that were subsets of a large entity for things like search results, list box items, etc. But now with C# 3.5's anonymous type support and LINQ projections, I rarely need to do that anymore.
// C#
var results = from p in products
select new {
p.ProductId,
p.ShortTitle,
p.Price,
p.Img };
// VB.NET
Dim results = From p in products _
Select p.ProductId, p.ShortTitle, p.Price, p.Img
This creates an unnamed type "on-the-fly" that contains only the fields you specified. It is immutable so the fields cannot be changed via this "mini" class but it supports equality and comparison.
But when I do need to create a named type, I typically just create a separate class that has no relationship to the main class other than a lazy-loaded reference to the "full" version of the object.
I wouldn't use a separate class or inheritance.
For your slim version, why not just retrieve only the data you need, and leave the other fields empty? You might have two queries: one that fills all the fields, and another that only fills the slim fields. If you need to differentiate between the two, that's easy if one of the non-slim fields is NOT NULL in your DB; just check for null in the object.

Resources