Additional GS1 codes support in Acumatica - acumatica

We need to add support for GS1 Barcode Customer Part Number in the Purchases - Receive and Put Away screen, it is not supported by default and I can't a find a way to add it.
From looking at the source code, it seems like I need to override GS1Support property or the GetGS1ApplicationSteps() method on PX.Objects.PO.WMS.ReceivePutAway class but I can't find a way to to this. I tried to override using PXGraphExtension method:
public class ReceivePutAway_Extension : PXGraphExtension<ReceivePutAway>
{
}
but then I get the following error:
CS0311 The type 'PX.Objects.PO.WMS.ReceivePutAway' cannot be used as type parameter 'Graph' in the generic type or method 'PXGraphExtension'. There is no implicit reference conversion from 'PX.Objects.PO.WMS.ReceivePutAway' to 'PX.Data.PXGraph' class.
UPDATE:
After updating the extension class declaration as suggested, now the error is gone but I'm still unable to find a way to override GetGS1ApplicationSteps() method on the BLC extension class PX.Objects.PO.WMS.ReceivePutAway, .
Does anybody know how to make the override work for a class like this or maybe has good suggestion on how to add support for additional GS1 barcodes?

ReceivePutAway is not a Graph, therefore you cannot do a simple Graph Extension directly on it. ReceivePutAway inherits from WMSBase which is actually defined as a Graph Extension. This means that you need to end up with a second level graph extension.
If you need to customize ReceivePutAway, I would suggest to try the approach mentioned here:
https://help-2021r1.acumatica.com/(W(1))/Help?ScreenId=ShowWiki&pageid=c86fdae8-fef9-4490-aa57-3528d0fa172e
Refer to section 'Second-Level BLC Extension' in the above link. In your case, it might be something like this:
public class ExtensioReceivePutAway_Extension :
PXGraphExtension<ReceivePutAway, ReceivePutAwayHost>
{
}

Related

FakeItEasy in C# on a servicereference

I have a servicereference with a method I need to use in a test.
The servicereference class is defined as:
public class MyServiceReference : Clientbase<IMyServiceReference>, IMyServiceReference
{
public MyServiceReference()
{
}
..... methods is then defined
}
From my testmethod I have tried both
private MyServiceReference myServiceReferenceFake = A.Fake<MyServiceReference>();
// And
private MyServiceReference myServiceReference = new MyServiceReference();
For both of these is crashes in the constructor with the message:
System.InvalidOperationException: Could not find default endpoint element that references contract.
All I need is to have a callto definition from a method in that class.
How can this be solved?
I've no experience with Clientbase, which I assume to be a System.ServiceModel.ClientBase<TChannel>,but I can make some general comments.
Since you tried first to fake a MyServiceReference, I'll assume that you're not testing that class, and you want to use it as a collaborator for the system under test. In that case, your best bet is to try faking IMyServiceReference. interfaces are very easy to fake, since they don't bring along any behaviour or baggage like faking a class does.
If you feel you really need to fake a MyServiceReference, then we have to contend with the fact that FakeItEasy will eventually call MyServiceReference(), which will call ClientBase<IMyServiceReference>(), whose documentation says
Initializes a new instance of the ClientBase<TChannel> class using the default target endpoint from the application configuration file.
Based on the error you reported, I assume that the application configuration file is not found or does not include the configuration required to create a MyServiceReference. The fact that you get the same error when you just try to instantiate a MyServiceReference directly strengthens my belief.
So I think your paths forward are either to try faking IMyServiceReference or to provide the configuration that ClientBase<IMyServiceReference> needs.

How to access Obsolete variables in graph extension

I have field declared with obsolete in some other project, how i can access this field in my extended graph.
[Obsolete("Use AMShiftMst.shiftType", true)]
public abstract class shftDiff : IBqlField, IBqlOperand
{
protected shftDiff();
}
You cannot use this class shftDiff because the ObsoleteAttribute marks any usage as an error. The message in the obsolete call mentions the new object to use.
See ObsoleteAttribute(String, Boolean) here:
ObsoleteAttribute Class
However related to the product it looks like the message should indicate to use AMShiftMst.shftDiff and not AMShiftMst.shiftType as shiftType doesn't exist.
Using AMShiftMSt.shftDiff should solve your issue.

Overriding second level graph extension method in Acumatica

I need to work with the reusable business objects for Sales tax, discounts, etc. and need to override some of the methods in these graph extensions. For example I am starting with the Opportunities graph. I have a set of order totals that need to calculate into the overall products amount and in the past we just overrode the tax attribute on (I think) tax category. Anyhow I don't see how its possible to use the PXOverrideAttribute on a method from a second level graph extension.
Here is my example:
public class OpportunityMaintExtOne : PXGraphExtension<PX.Objects.CR.OpportunityMaint.SalesTax, PX.Objects.CR.OpportunityMaint>
{
[PXOverride]
public virtual void CalcDocTotals(object row, decimal CuryTaxTotal, decimal CuryInclTaxTotal, decimal CuryWhTaxTotal,
Action<object, decimal, decimal, decimal> del)
{
del?.Invoke(row, CuryTaxTotal, CuryInclTaxTotal, CuryWhTaxTotal);
var someOtherTotal = Base1.Documents.Cache.GetValueAsDecimal<CROpportunityExtension.aMCurySomeOtherTotal>(row);
if (someOtherTotal == 0)
{
return;
}
var curyDocTotal = someOtherTotal + Base1.Documents.Cache.GetValueAsDecimal<CROpportunity.curyProductsAmount>(row);
Base1.Documents.Cache.SetValue<CROpportunity.curyProductsAmount>(row, curyDocTotal);
}
}
What is going on inside of CalcDocTotals in my graph extension is not the focus. It is the fact that I cannot override the OpportunityMaint.SalesTax CalcDocTotals method as I could if the method was in the first level (Base) graph. The SalesTax graph extension has the method as protected but protected methods (if it was in the base graph) are overrideable using the PXOverrideAttribute if you make your method call public which is what I have done. I also tried using a declared delegate in place of the Action but same results (as I expected but wanted to confirm).
My question: Is it possible to override a second, third, etc. level graph extension method using the PXOverrideAttribute?
When I compile the code above and the page loads I get this error:
Method Void CalcDocTotals(System.Object, System.Decimal,
System.Decimal, System.Decimal,
System.Action`4[System.Object,System.Decimal,System.Decimal,System.Decimal])
in graph extension is marked as [PXOverride], but the original method
with such name has not been found in PXGraph
The ability to override extension methods from a higher level extension has been added in 2018R1 Update 4 (18.104.0023). This resolves my question/issue and allows for the code posted in my question to function as is.
You cannot override methods from Extension1 in Extension2 etc as far as I've been able to see in my years with Acumatica. My solution to the problem was thus : Create a helper graph with your basic methodology, create a field or property for it in whatever graph you wish to use it in (Preferably a Lazy initialized one), then in whatever project you must override the logic on, just reference your original project, and create an extension of your helper graph.

Xceed WPF PropertyGrid : decorating property with Category : compiler error

I have basically the same question as the one I asked here. Adding the using Xceed.Wpf.Toolkit.PropertyGrid.Attributes directive solved that.
This time, the compiler does not like [Category("Shipping")] decoration.
[Category("Shipping")]
public string ShipAddress { get; set; }
How can I deduce or determine what namespace needs to be included when I run into obstacles like this?
Here are the using directives I've included already:
using Xceed.Wpf.Toolkit.PropertyGrid;
using Xceed.Wpf.Toolkit.PropertyGrid.Editors;
using Xceed.Wpf.Toolkit.PropertyGrid.Commands;
using Xceed.Wpf.Toolkit.PropertyGrid.Converters;
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
The xaml is this:
<xctk:PropertyGrid AutoGenerateProperties="True" Name="XPG1" IsCategorized="True" />
I know this is an older question, but since it's unanswered I thought it would be helpful to provide one anyway. In this case you need the following using statement:
using System.ComponentModel;
In general, the best way to figure out what namespace or using statement you need is to look for the name of the attribute in the Object Browser under the Xceed namespace, and if you can't find it there, on Google.
One thing to remember - while it shows up as just [Category] in code, the actual name of the class will be CategoryAttribute.

Checking for an attribute on a destination property inside a custom AutoMapper TypeConverter

I have a custom type converter that converts UTC DateTime properties to a company's local time (talked about here: Globally apply value resolver with AutoMapper).
I'd now like to only have this converter do its thing if the property on the view model is tagged with a custom DisplayInLocalTime attribute.
Inside the type converter, if I implement the raw ITypeConvert<TSource, TDestination> interface, I can check if the destination view model property being converted has the attribute:
public class LocalizedDateTimeConverter : ITypeConverter<DateTime, DateTime>
{
public DateTime Convert(ResolutionContext context)
{
var shouldConvert = context.Parent.DestinationType
.GetProperty(context.MemberName)
.GetCustomAttributes(false)[0].GetType() == typeof(DisplayInLocalTimeAttribute);
if (shouldConvert) {
// rest of the conversion logic...
}
}
}
So this code works just fine (obviously there's more error checking and variables in there for readability).
My questions:
Is this the correct way to go about this? I haven't found anything Googling around or spelunking through the AutoMapper code base.
How would I unit test this? I can set the parent destination type on the ResolutionContext being passed in with a bit of funkiness, but can't set the member name as all implementors of IMemberAccessor are internal to AutoMapper. This, and the fact that it's super ugly to setup, makes me this isn't really supported or I'm going about it all wrong.
I'm using the latest TeamCity build of AutoMapper, BTW.
Don't unit test this, use an integration test. Just write a mapping test that actually calls AutoMapper, verifying that whatever use case this type converter is there to support works from the outside.
As a general rule, unit tests on extension points of someone else's API don't have as much value to me. Instead, I try to go through the front door and make sure that I've configured the extension point correctly as well.

Resources