Override BQL used for PXProjection on SOShipmentPlan - acumatica

I have a need to override the Select statement being used for the SOShipmentPlan PXProjection/DAC, namely, removing the
And <INPlanType.isFixed, Equal<boolFalse>
condition.
I can override all of the CreateShipment() logic and bring in any other necessary routines into an SOShipmentEntry_Extension class, to the point where I finally can use my own version of a SOShipmentPlan class, but that all seems needlessly complex when all I want to do is override the select for the PXProjection attribute. Overriding CreateShipment() and supporting routines also seems like a quick way to get in trouble come time for upgrades.
So, is there an easy way to override the PXProjection's BQL, or am I stuck overriding all kinds of code?
UPDATE 1
Based on a link provided below (stackoverflow.com/a/41540659/7376238), I feel like I'm close. Here's the block of code I end up with:
namespace PX.Objects.SO
{
public class SOShipmentEntry_Extension : PXGraphExtension<SOShipmentEntry>
{
#region Event Handlers
#endregion
[Serializable]
[PXProjection(typeof(Select2<SOOrder,
InnerJoin<SOOrderType, On<SOOrder.FK.OrderType>,
InnerJoin<INItemPlan, On<INItemPlan.refNoteID, Equal<SOOrder.noteID>>,
InnerJoin<INPlanType, On<INItemPlan.FK.PlanType>>>>,
Where<INItemPlan.hold, Equal<boolFalse>,
And<INItemPlan.planQty, Greater<decimal0>,
And<INPlanType.isDemand, Equal<boolTrue>,
And<INPlanType.isForDate, Equal<boolTrue>,
And<Where<INItemPlan.fixedSource, IsNull,
Or<INItemPlan.fixedSource, NotEqual<INReplenishmentSource.transfer>>>>>>>>>))]
[PXSubstitute()]
public partial class SOShipmentPlanCst : SOShipmentPlan
{
int x = 0;
}
}
But it doesn't seem to work. Not sure of where I'm supposed to put the code. I've tried putting the class definition inside and outside of public class SOShipmentEntry_Extension : PXGraphExtension<SOShipmentEntry> class (currently inside the extension class as shown). No luck either way.

THIS ANSWER DIDN'T WORK
Fair warning... I have not done this to a PXProjection before, so you'll have to see if this works. The nature of extensions tends to allow overriding views by simply redefining them. I have not done this myself with a projection, but I suspect it will be similar. Give it a try and see if you get the desired results. All I can say about testing it is that "it compiled" when I added to my project and removed the INItemPLanType.isFixed condition.
public class SOShipmentEntry_Extension : PXGraphExtension<SOShipmentEntry>
{
[PXProjection(typeof(Select2<SOOrder,
InnerJoin<SOOrderType, On<SOOrder.FK.OrderType>,
InnerJoin<INItemPlan, On<INItemPlan.refNoteID, Equal<SOOrder.noteID>>,
InnerJoin<INPlanType, On<INItemPlan.FK.PlanType>>>>,
Where<INItemPlan.hold, Equal<boolFalse>,
And<INItemPlan.planQty, Greater<decimal0>,
And<INPlanType.isDemand, Equal<boolTrue>,
And<INPlanType.isForDate, Equal<boolTrue>,
And<Where<INItemPlan.fixedSource, IsNull, Or<INItemPlan.fixedSource, NotEqual<INReplenishmentSource.transfer>>>>>>>>>))]
public partial class SOShipmentPlan : IBqlTable { }
}

Related

graph extension is marked as [PXOverride], but the original method with such name has not been found in PXGraph

I'm needing to adjust some of the field attributes for the Location.VCashAccountID field on the Vendors screen - AP303000. When I put the code below into a customization DLL, it compiles fine and there are not apparent issues on the screen. However, when I try to publish the customization project with the DLL included, I get an error.
Code:
public class VendorMaintDefLocationExtExt : PXGraphExtension<VendorMaint.DefLocationExt,
VendorMaint>
{
public void _(Events.CacheAttached<PX.Objects.CR.Standalone.Location.vCashAccountID> e) { }
}
Error:
"Method Boolean DoValidateAddresses(PX.Objects.CR.Extensions.ValidateAddressesDelegate) in graph extension is marked as [PXOverride], but the original method with such name has not been found in PXGraph"
What am I missing?
TIA!
The following implementation will override the vCashAccount attribute on AP303000
public class AAVendorMaintDefLocationExtExtension : PXGraphExtension<DefLocationExt, DefContactAddressExt, VendorMaint>
{
[PXMergeAttributes(Method = MergeMethod.Merge)]
[PXUIField(DisplayName = "I am override")]
public void _(Events.CacheAttached<PX.Objects.CR.Standalone.Location.vCashAccountID> e) { }
}
You will also require the following references
using PX.Data;
using PX.Objects.AP;
using static PX.Objects.AP.VendorMaint;
The result can be seen in the snip below
The main difficulty in this task was the multitude of graph extensions utilized by the page. Though it's a beneficial design to encapsulate functionality it can be finnicky to determine which order they should be declared in a new extension.
You're graph extension extends VendorMaint.DefLocationExt which contains DoValidateAddresses. Try just extending VendorMaint.

PostSharp - Applying aspect to mscorlib but prohibit modifying calls in my own class

My aspect:
[Serializable]
class DumbLogger : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
Log.Print("Entry: ") + args.Method.Name;
args.FlowBehavior = FlowBehavior.Continue;
}
}
This is what i am using to modify the calls in mscorlib AND trying to exclude them from being modified in my class called LOG
[assembly: MY_PROJECT.DumbLogger(
AttributeTargetTypes = "MY_PROJECT.Log",
AttributeExclude = true,
AttributePriority = 1)]
[assembly: MY_PROJECT.DumbLogger(
AttributeTargetAssemblies = "mscorlib",
AttributePriority = 2)]
But.. This doesnt do the trick because if i look at my LOG class with ILspy decompiler i can see method calls to any class # mscorlib.dll being modified for example:
<>z__Aspects.<System.Object.ToString>b__v(text)
The reason i wanna do this is because when i enter the method Log.Print it will generate a stackoverflow exception and will infinitely call itself.
I am already aware of maybe excluding certain namespaces and classes like string from mscorlib but i have my reasons to do it the way i described.
PostSharp Aspects in general are applied to declarations (assemblies, types, methods, parameters, fields, etc.). When you are applying an MethodLevelAspect (base class of OnMethodBoundaryAspect) on an external method, PostSharp transforms the call site (call instruction in IL), but still thinks of the aspect as being on the declaration itself.
There is currently no way to filter by call site and it would require a different kind of aspect and/or advices. Therefore your AttributeExclude=true specifying attribute on the assembly does not have any effect as it says that the aspect should not be applied on Log type, which it is not.
The common technique that solves exactly this case is to use a ThreadStatic variable to break the recursion cycle as the following code demonstrates:
[Serializable]
class DumbLogger : OnMethodBoundaryAspect
{
[ThreadStatic] private static bool logging;
public override void OnEntry(MethodExecutionArgs args)
{
if (logging)
return;
try
{
logging = true;
Log.Print("Entry: " + args.Method.Name);
args.FlowBehavior = FlowBehavior.Continue;
}
finally
{
logging = false;
}
}
}
Please also note that MethodInterception and OnMethodBoundary aspects are the only aspect that work on external assemblies.

Xamarin Forms - CustomObject, XAML Initialization, Setter not called, DependencyProperty, I'm lost?

I have a problem and I searched a solution about it. Lucky, I red lot of post about it but I'm lost with the explaination I found. The initale problem is coming from a personal project about the polyline of the Xamarin.Forms.Map where the initialization is realized by a binding from the XAML part..
Let me be clear by an example :
I have an object CustomMap.cs which inherit from Xamarin.Forms.Map (This file is in the PCL part -> CustomControl/CustomMap.cs)
public class CustomMap : Map, INotifyPropertyChanged
{
public static readonly BindableProperty PolylineAddressPointsProperty =
BindableProperty.Create(nameof(PolylineAddressPoints), typeof(List<string>), typeof(CustomMap), null);
public List<string> PolylineAddressPoints
{
get { return (List<string>)GetValue(PolylineAddressPointsProperty); }
set
{
SetValue(PolylineAddressPointsProperty, value);
this.GeneratePolylineCoordinatesInner();
}
}
// ...
}
So the Xaml part of the page, where the control is called, looks like that:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:control="clr-namespace:MapPolylineProject.CustomControl;assembly=MapPolylineProject"
x:Class="MapPolylineProject.Page.MainPage">
<ContentPage.Content>
<control:CustomMap x:Name="MapTest" PolylineAddressPoints="{Binding AddressPointList}"
VerticalOptions="Fill" HorizontalOptions="Fill"/>
</ContentPage.Content>
</ContentPage>
The Csharp part:
public partial class MainPage : ContentPage
{
public List<string> AddressPointList { get; set; }
public MainPage()
{
base.BindingContext = this;
AddressPointList = new List<string>()
{
"72230 Ruaudin, France",
"72100 Le Mans, France",
"77500 Chelles, France"
};
InitializeComponent();
//MapTest.PolylineAddressPoints = AddressPointList;
}
}
So, everything is fine if I edit the PolylineAddressPoints from the object instance (if the commented part isnt' commented..), but if I init the value from the XAML (from the InitializeComponent();), it doesn't work, the SetValue, in the Set {}, isn't called..
I then searched on the web about it and get something about the Dependency Properties? or something like that. So I tried some solutions but, from WPF, so some methods, such as DependencyProperty.Register();. So yeah, I can't find the way to solve my problem..
I also though about something, if DependencyProperty.Register(); would exists in Xamarin.Forms, then it means I would have to do it for each values? Because, if every value has to be set by a XAML binding logic, it would not work, I would have to register every value, doesn't it?
I'm sorry if I'm not clear, but I'm so lost about this problem.. Please, do not hesitate to ask for more details, thank in advance !
I finaly got a solution just over here => Ignore the Binding initialization
Copy paste from Stackoverflow. This following answer was given by Stephane Delcroix, thank to him !
There are multiple questions in this:
Why is the property setter never called when using Xaml ?
Am I properly defining my BindableProperty ?
Why is my binding failing ?
Let me answer them in a different order.
Am I properly defining my BindableProperty ?
The BindableProperty declaration is right, but could be improved by using an IList<string>:
public static readonly BindableProperty PolylineAddressPointsProperty =
BindableProperty.Create(nameof(PolylineAddressPoints), typeof(IList<string>), typeof(CustomMap), null);
but the property accessor is wrong, and should only contains this:
public IList<string> PolylineAddressPoints
{
get { return (IList<string>)GetValue(PolylineAddressPointsProperty); }
set { SetValue(PolylineAddressPointsProperty, value); }
}
I'll tell you why while answering the next question. But you want to invoke a method when the property has changed. In order to do that, you have to reference a propertyChanged delegate to CreateBindableProperty, like this:
public static readonly BindableProperty PolylineAddressPointsProperty =
BindableProperty.Create(nameof(PolylineAddressPoints), typeof(IList<string>), typeof(CustomMap), null,
propertyChanged: OnPolyLineAddressPointsPropertyChanged);
And you have to declare that method too:
static void OnPolyLineAddressPointsPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
((CustomMap)bindable).OnPolyLineAddressPointsPropertyChanged((IList<string>)oldValue, (IList<string>)newValue);
}
void OnPolyLineAddressPointsPropertyChanged(IList<string> oldValue, IList<string> newValue)
{
GeneratePolylineCoordinatesInner();
}
Why is the property setter never called when using Xaml ?
The property, and the property accessors, are only meant to be invoked when accessing the property by code. C# code.
When setting a property with a BindablePrperty backing store from Xaml, the property accessors are bypassed and SetValue() is used directly.
When defining a Binding, both from code or from Xaml, property accessors are again bypassed and SetValue() is used when the property needs to be modified. And when SetValue() is invoked, the propertyChanged delegate is executed after the property has changed (to be complete here, propertyChanging is invoked before the property change).
You might wonder why bother defining the property if the bindable property is only used by xaml, or used in the context of Binding. Well, I said the property accessors weren't invoked, but they are used in the context of Xaml and XamlC:
a [TypeConverter] attribute can be defined on the property, and will be used
with XamlC on, the property signature can be used to infer, at compile time, the Type of the BindableProperty.
So it's a good habit to always declare property accessors for public BindableProperties. ALWAYS.
Why is my binding failing ?
As you're using CustomMap as bot View and ViewModel (I won't tell the Mvvm Police), doing this in your constructor should be enough:
BindingContext = this; //no need to prefix it with base.
As you're doing it already, your Binding should work once you've modified the BindableProperty declaration in the way I explained earlier.

Calling one specific overriden method in all derived classes

Consider the following code:
// ======== Abstract class ========
public abstract class Creatures {
public abstract void loseEnergy();
public void execute()
{
loseEnergy();
}
}
// ======== Animals ========
public class Animals : Creatures
{
public override void loseEnergy(){}
}
public class Birds : Animals
{
public override void loseEnergy(){}
}
// ======== Human ========
public class Human : Creatures
{
public override void loseEnergy(){}
}
public class Male : Human
{
public override void loseEnergy(){}
}
public class Female : Human
{
public override void loseEnergy(){}
}
[ This code was based on the code by Jayson suggested here: "Base class methods calling derived class methods ?" ]
In the given code example, I would like to have the runtime executing EACH derived class object's certain method, in this case, which is 'loseEnergy()', however, I could not find the solution.
How do I approach this problem?
What can be useful to know or to try.. in order to solve this issue?
Your help is very much appreciated!
Thank you!
Kind regards,
Segara
P.S. Some search I have done so far:
"How to call overriden methods in all derived classes"
"Collection of derived classes that have generic base class"
"How to call derived function using base class object"
"Call method of the derived class through reflection possible or no"
EDIT:
I decided to stick to the idea I had before which is to have some list that would contain the objects of the classes that have 'loseEnergy()' method. Having such list I will be able to call every object's method 'loseEnergy()', which is what I wanted.
Question can be closed.
Thank you.
I didn't really understand your problem but anyway i can try to give you some means to use abstract classes :
If you use a abstract method, you SHOULD override it in a subclasses (like a method declared in an interface)
If you want that all inherited class use a same method, you can implement it in the abstract class ; all subclasses will use the method you implements if you don't override it, you've have to not declare it in the subclasses (extends < ABS_CLASS > is good enough)
If you want use a method of the abstract class which is override in the sub class you can use the keyword super .
I hope it will help you.
if you mean that you want the calls: female.loseEnergy() -> human.loseEnergy() -> creature.loseEnergy(), call the base method in the first line of the overriden one
public class Female : Human
{
public override void loseEnergy()
{
base.loseEnergy();
// do stuff
}
}
In the Greenfoot environment that you mention in the post above, the act() method is called only on actors which have been added into the "world". Internally, this adds them into a list. The simulation process iterates through the list and calls act() on each object in turn. Objects that are not "in the world" are not known to the system and so do not have their act method called. There is no magic here going on here.
If you wanted similar behaviour but without manually adding objects into a list, you could possibly have the base class constructor add new objects into a global list. I don't know C# so I don't know precisely how to do this, but I cannot imagine it would be difficult.

Is there a way to show partial class name in the testrunner for resharper?

I have created a set of tests that I have grouped together by using a partial class. Is there a way to get the partial name to show up in the test runner? What I have is something like
File 1:
public partial class MyWrapperClass
{
[TestClass]
public class This_is_a_descriptive_scenario {
[TestMethod]
public void This_is_a_descriptive_scenario_outcome() { ... }
}
}
File 2:
public partial class MyWrapperClass
{
[TestClass]
public class This_is_a_descriptive_scenario2 {
[TestMethod]
public void This_is_a_descriptive_scenario2_outcome() { ... }
}
}
When running tests like that in the builtin test runner in Visual studio I can see the result as: MyWrapperClass+This_is_a_descriptive_test, if I have added the class column to the test result. But when you run the test in resharper's testrunne they are grouped by project and/or namespace and the class name, but I can't see that the tests are part of a partial class anywhere. Is that possible?
I don't think this is supported. Although it might be possible to extend it. I can point you in the right direction if you're willing to go down that path.
The easiest solution would be to use namespaces for grouping instead of partial classes.
Hope this helps
Miguel
The name of a partial class is the same in either file... No, there's nothing that currently groups tests by test file name.

Resources