Sum values of detail rows (in extension) and put it in header (in extension) - customization

Acumatica 2021 R1 - Customizations
I am using PXFormula to multiply a qty and cost to create a new extension field in the details of Physical Inventory Review (although I would think the specific screen wouldn’t matter.) That part is working fine. However, I then want to sum that new column’s values into a new extension field in the header. I can't get that part to work.
Here is the relevant detail code:
using PX.Data;
using System;
namespace PX.Objects.IN
{
public class INPIDetailExt : PXCacheExtension<PX.Objects.IN.INPIDetail>
{
#region UsrExtBookCost
[PXDecimal]
[PXUIField(DisplayName="Ext. Book Cost")]
[PXFormula(typeof(Mult<INPIDetail.bookQty, INPIDetail.unitCost>),
typeof(SumCalc<INPIHeaderExt.usrTotalBookCost>))]
public virtual Decimal? UsrExtBookCost { get; set; }
public abstract class usrExtBookCost : PX.Data.BQL.BqlDecimal.Field<usrExtBookCost> { }
#endregion
}
}
Here’s the header code:
using PX.Data;
using System;
namespace PX.Objects.IN
{
public class INPIHeaderExt : PXCacheExtension<PX.Objects.IN.INPIHeader>
{
#region UsrTotalBookCost
[PXDecimal]
[PXUIField(DisplayName="Total Book Cost")]
public virtual Decimal? UsrTotalBookCost { get; set; }
public abstract class usrTotalBookCost : PX.Data.BQL.BqlDecimal.Field<usrTotalBookCost> { }
#endregion
}
}
I feel it has something to do with the fact that these are extensions and that somehow the PXParent that is called in INPIDetail does not cover these extension.
Any suggestions would be appreciated.

By any chance are you calling the PXFormulaAttribute.CalcAggregate in the row selected event of the INPIHeader. This should force the SumCalc to recalculate and update your value
PXFormulaAttribute.CalcAggregate<INPIDetailExt.usrExtBookCost>(DetailView.Cache, e.Row);

Related

How to act on a class with ml.net?

I have a public class with a couple of public methods. The class may also have public properties that indicate the state. The methods may have parameters. Perhaps a return value. Perhaps some of them are defined as asynchronous.
Lets say the class represents an interface to control a game.
Maybe the class have methods such as move left, move right, jump, fire, etc.
Example:
public class Game
{
public int Ammo { get; private set; }
public void Fire() { /* ... */ }
public void Jump() { /* ... */ }
public void MoveRight() { /* ... */ }
public void MoveLeft() { /* ... */ }
// more methods
}
I would like to use ml.net to act on the class, to play the the game.
How would I do this?
As far as I can tell, you want to build an 'artificial intelligence' that would apply 'control inputs' to the given system (like your Game class), and learn to 'play the game'.
This appears to match very closely to the definition of Reinforcement learning. As you can see from the Wikipedia article, there exist numerous approaches to reinforcement learning, so the problem as you stated it right now is not well-defined enough to have only one solution.
As also mentioned in the comments, ML.NET doesn't currently support any reinforcement learning scenarios. This will probably change in the future, especially if there is enough public interest in them.
You can use the Command pattern in conjunction with ML.NET to solve your problem. The Command pattern essentially generates the sequence of commands that are then executed by a Command Interpreter in the traditional sense of architecture patterns.
We use the Command pattern to generate the game play training data as follows:
Create a class called GameState.
public class GameState
{
public enum GameAction
{
Fire,
Jump,
MoveRight,
MoveLeft,
...
}
public GameState Current { get; set; }
public GameAction NextAction { get; set; }
public GameOutcome Outcome { get; set; }
public string Descriptor {
get {
// returns a string that succinctly and uniquely
// describes the current game state
}
}
}
and define a GameOutcome class:
public class GameOutcome
{
public int GameID { get; set; }
public enum OutcomeState
{
Win,
Loss,
Tie,
Unfinished
}
public OutcomeState Outcome { get; set; }
}
If you can generate GameState sequences from actual game play as training data, then you can create a predictor (essentially a MultiClassClassifier) using ML.NET that takes the GameState.Descriptor, GameState.Outcome.OutcomeState and GameState.NextAction with the Descriptor and OutcomeState as features and NextAction as the predicted label.
In live (automated play), you initialize the gamestate and then predict the next action setting an OutcomeState of 'Win' and using the ML classifier to predict the learnt next action.
The trick lies in encapsulating a rich and succinct game state description that takes into account the history of steps followed to get to the current game state and the projected future outcome of the game (from a large number of historical game plays).

Sitecore WFFM custom save action not called

I have created a custom save action in WFFM. After updating the save action to have the correct assembly and fully qualified class name I added the save action to a form and attempted to submit. The form submits and presents the thank you message however the issue is that in the class being invoked the execute method of the save action is never called. I am not sure why this is the case any thoughts?
Here is my custom save action and a link to a picture of how I have configured it.
WFFM type
using Sitecore.WFFM.Abstractions.Actions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sitecore.Data;
using Sitecore.WFFM.Abstractions.Shared;
using Sitecore.WFFM.Actions.Base;
using Sitecore.Form.Submit;
namespace Core.Forms {
public class CustomSaveAction: ISaveAction {
//custom parameters
public string SharepointUrl { get; set; }
public string ListId { get; set; }
public string MappedFields { get; set; }
public ID ActionID { get; set; }
public ActionType ActionType
{
get
{
return ActionType.Save;
}
}
public ActionState QueryState(ActionQueryContext queryContext) {
return ActionState.Enabled;
}
public string UniqueKey { get; set; }
public void Execute(ID formId, AdaptedResultList adaptedFields, ActionCallContext actionCallContext = null, params object[] data) {
throw new NotImplementedException();
}
}
}
So I was testing in chrome and getting frustrated so asked another dev on my team to do a build on his machine and see what happened. Low and behold the break point hit. I tried deleting my local copy and repulling from source control and was still running into the same issue. Upon getting frustrated switching browsers somehow managed to make it work. I am guessing that there is something that chrome is caching that it shouldn't be but either way this is what fixed it for me.
Could you update the Execute method and use something like:
public void Execute(ID formid, AdaptedResultList fields, params object[] data)
{
Assert.ArgumentNotNull(fields, "fields");
// Your code here
}

EF6 Code First: How can I centralize content for separate sections of my site?

I want to store all our site's content in one central Content table but relate it to each section of the site. Something like:
Content (for the actual content byte[] and basic info all sections use)
ResearchArticleContent (basically has the related ContentId from the content table and extra cols for info specific to ResearchArticles)
ResearchArticle
ExecutiveContent (basically has the related ContentID from Content table and extra cols for specific data for Executives)
Executive
...and so on.
I'm having trouble understanding the whole code first approach as it pertains to ForeignKeys and InverseProperties. That's the real issue.
So, say I have these two classes as an example:
public class Content
{
[Key]
public int ContentId { get; set; }
public int ContentType { get; set; }
public byte[] ContentBytes { get; set; }
public DateTime AddedDate { get; set; }
[**`InverseProperty or ForeignKey???`**("ResearchArticleContent")]
public virtual ResearchArticleContent ResearchArticleContent { get; set; }
}
and:
public class ResearchArticleContent
{
[Key]
public int ResearchArticleContentId { get; set; }
[ForeignKey("ContentId")]
public virtual Content Content {get;set;}
public int ResearchArticleId { get; set; }
[ForeignKey("ResearchArticleId")]
public virtual ResearchArticle RelatedArticle { get; set; }
}
Where do I put the ForeignKeys / InverseProperties to relate these correctly. Because ideally, I will have Executivecontent, ResearchArticlecontent and so on for each section of the site. (I am following the precedent already laid out in a Data-First prj that I am mimicking so this is the way I have do this, fyi.)
Entity framework requires a type identifier field when you store compound objects in a single table; however, you can get around this pretty easily using views. To use views, create a single content table and a > base < class. Do not apply the TableAttribute data annotation to the base class. All other data annotations are fine.
public class ContentBase
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ContentId { get; set; }
public string Content { get; set; }
...
}
Then, you can create derived classes that more closely represent the content and apply the TableAttribute data annotation to those. For example,
[Table("ResearchArticleView")]
public class ResearchArticle : ContentBase
{
...you can add more properties here that are included in the view...
...and not necessarily the underlying table, like from a joined table...
...or just use the class as is, so that you have a better name...
}
To use this, set up a view called ResearchArticleView that includes the columns in the base class, as well as any computed or joined columns you want, then add a DbSet to your context that represents the view.
I recommend having content tables for each type of content and then use the method I've described for derived types for each content type. For example, create a base for research articles and a base for execute content. Because, when your database gets big and full of content, having one monolithic content table may cause you backup and optimization issues.

Getting an Internal Link with Glass.Mapper

I've got an Internal Link set up in Sitecore, and I'm trying to map the field using Glass.Mapper, but it just keeps coming back empty, and I'm not sure what I'm doing wrong.
The template in Sitecore is pretty simple:
The Source of the link is set to a folder that only allows content based on the 'System' template to be created.
In my code, I have an object set up:
namespace Playground.GlassObjects
{
public partial class Status
{
public virtual string Description { get; set; }
public virtual string StatusCode { get; set; }
public virtual Glass.Mapper.Sc.Fields.Link System { get; set; }
}
}
Which is being used basically like this:
public void DoStuff(Sitecore.Data.Items.Item item)
{
var status = item.GlassCast<Status>();
this.DoOtherStuff(status);
}
What I'm running into is glassObj.Description, and glassObj.StatusCode are being wired up exactly like I want/expect, but glassObj.System is not.
Can anyone tell me what I'm doing wrong here? I'm at a loss right now, with all the magic that's going on behind the scenes.
The Glass.Mapper.Sc.Fields.Link class is designed to work with the General Link field. The internal link field stores values as paths e.g /sitecore/content/home/events. This means it isn't compatible with the Link class.
Instead you should map it to another class you have created.
public partial class Status
{
public virtual string Description { get; set; }
public virtual string StatusCode { get; set; }
public virtual MySystem System { get; set; }
}
public class MySystem{
public virtual string Url { get; set; }
public virtual string MyField { get; set; }
}
Fast forward to 2022 Internal Link field seems to be working with Glassmapper without any extra effort. All you have to do is add Internal Link case to GlassGenerator.tt file on the project where you will generate the template.
This will ensure your model will have Link field like this:
[SitecoreField(FieldId = "{D2CF138A-0A1C-4766-B250-F56E9458B624}")]
Link InternalLinkField{ get; set; }
It will have some info populated and most of the other properties will be null. The ones that will help you are:
Url (full path to the internal link item)
TargetId (ID of the internal link item)
Here are the available properties:
There is an alternative to that, you can get the link from fields like this:
yourGlassItem.Item.Fields["InternalLinkFieldName"]
You will get the entire Internal link Item. You can use Value or InheritedValue property to get the path of the linked item.

Need to Seriazlize List<object>, but FXCop complains "Do not expose generic lists"

I have an object that I need to serialize. The object contains several properties, including a List. FXCop is complaining that I should not expose generic lists, and I get that, however, due to the fact that I can't specify an interface based property on an object that I want serialized I'm not sure where to turn next.
Any thoughts?
BTW, I'm using XMLSerialization, but that's not a requirement.
I took FxCop's suggestion and wrapped my list in a Collection. This blew some of my code out of the water, but a after a few adjustments I was up and running again.
Here's some code showing before and after:
Before:
public class PersistentDataView
{
public string Title { get; set; }
private List<object> Inputs { get; set;}
}
After:
public class PersistentDataView
{
private List<object> _inputs;
public string Title { get; set; }
public Collection<object> Inputs
{
get
{
if (_inputs == null)
_inputs = new List<object>();
//Wrap the private field into a collection.
return new Collection<object>(_inputs);
}
}
}