Data allocation error in the CreateSalesPrice method - acumatica

Situation:
I have to asign price per subitem on both the Vendor Price Worksheets screen and Vendor Prices screen.
When the release button is pressed in Vendor Price Worksheets, the records in the APPriceWorksheetDetail table have to be created in the APVendorPrice table, Obviously I have to assign the SubItemID field value of the APPriceWorksheetDetail table to the UsrSubItemID field of the APVendorPrice table.
Notes:
It was not necessary to create the SubItemID field in Vendor Price Worksheets grid because it already existed in Details dataview.
I created the SubItemID field in Vendor Prices grid because it didn't exist in Records dataview.
This is my Vendor Price Worksheets screen
This is my Vendor Prices screen
This is my APVendorPriceExtensions DAC
using PX.Data;
using PX.Objects.AP;
using PX.Objects.CM;
using PX.Objects.IN;
using PX.Objects.CS;
using PX.Objects;
using System.Collections.Generic;
using System;
namespace PX.Objects.AP
{
public class APVendorPriceExt : PXCacheExtension<PX.Objects.AP.APVendorPrice>
{
#region UsrSubItemID
[PXDefault(typeof(Search<InventoryItem.defaultSubItemID,
Where<InventoryItem.inventoryID, Equal<Current<APVendorPrice.inventoryID>>,
And<InventoryItem.defaultSubItemOnEntry, Equal<boolTrue>>>>),
PersistingCheck = PXPersistingCheck.Nothing)]
[PXFormula(typeof(Default<APVendorPrice.inventoryID>))]
[SubItem(typeof(APVendorPrice.inventoryID))]
public virtual int? UsrSubItemID { get; set; }
public abstract class usrSubItemID : PX.Data.BQL.BqlInt.Field<usrSubItemID> { }
#endregion
}
}
I found the method that assigns the values in APPriceWorkSheetMain graph, the method is called CreateSalesPrice, I'm trying to override that method putting my custom UsrSubItemID field but I get the following error: "CS0117: 'APVendorPrice' does not contain a definition for 'UsrSubItemID'".
This is my APPriceWorkSheetMain_Extension
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using PX.Common;
using PX.Data;
using PX.Objects.Common;
using PX.Objects.Common.Extensions;
using PX.Objects.CS;
using PX.Objects.CM;
using PX.Objects.IN;
using PX.Objects.GL;
using PX.Api;
using PX.Objects;
using PX.Objects.AP;
namespace PX.Objects.AP
{
public class APPriceWorksheetMaint_Extension : PXGraphExtension<APPriceWorksheetMaint>
{
#region Event Handlers
public delegate APVendorPrice CreateSalesPriceDelegate(APPriceWorksheetDetail priceLine, Nullable<Boolean> isPromotional, Nullable<DateTime> effectiveDate, Nullable<DateTime> expirationDate);
[PXOverride]
public APVendorPrice CreateSalesPrice(APPriceWorksheetDetail priceLine, Nullable<Boolean> isPromotional, Nullable<DateTime> effectiveDate, Nullable<DateTime> expirationDate, CreateSalesPriceDelegate baseMethod)
{
APVendorPrice newSalesPrice = new APVendorPrice
{
VendorID = priceLine.VendorID,
InventoryID = priceLine.InventoryID,
UsrSubItemID = priceLine.SubItemID,
SiteID = priceLine.SiteID,
UOM = priceLine.UOM,
BreakQty = priceLine.BreakQty,
SalesPrice = priceLine.PendingPrice,
CuryID = priceLine.CuryID,
IsPromotionalPrice = isPromotional,
EffectiveDate = effectiveDate,
ExpirationDate = expirationDate,
};
return newSalesPrice;
}
#endregion
}
}
Any advice for this?

Did you try using the following approach? (updating through the extension DAC):
APVendorPrice newSalesPrice = new APVendorPrice
{
VendorID = priceLine.VendorID,
InventoryID = priceLine.InventoryID,
SiteID = priceLine.SiteID,
UOM = priceLine.UOM,
BreakQty = priceLine.BreakQty,
SalesPrice = priceLine.PendingPrice,
CuryID = priceLine.CuryID,
IsPromotionalPrice = isPromotional,
EffectiveDate = effectiveDate,
ExpirationDate = expirationDate,
};
var vendorPriceExt = PXCache<APVendorPrice>.GetExtension<APVendorPriceExt>(newSalesPrice);
vendorPriceExt.UsrSubItemID = priceLine.SubItemID;
return newSalesPrice;

Related

How to get DAC record from Note Table

Does anyone have a code snippet on how to go from RefNoteId => DAC when I dont know what dac type the note is attached to?
I have made it this far (row.RefNoteID is what I am starting from)
Note note = PXSelect<Note, Where<Note.noteID, Equal<Required<Note.noteID>>>>.Select(this, row.RefNoteID);
Type recordType = Type.GetType(note.EntityType);
PXCache recordCache = Caches[recordType];
How can I now do a PXSelect<recordType, Where<recodType.noteID, Equal<Required<recordType.noteID>>>>.Select(GRAPH) ? The recordType could be any DAC in the system that has a noteID.
Thanks
The below code works for me and it is based on the way Acumatica gets the record inside the PXRefNoteSelectorAttribute.PrimaryRow_RowPersisted.
The problem with this approach is that this will work for Header entities like SOOrder, INRegister, SOInvoice, SOShipment, and others. But for "detail" entities like SOLine, INTran, and others this approach will work only if that corresponding record has some Note related to Text/File. Acumatica is adding records corresponding to their NoteID into the Note table only if that detail records have some Note/Text. My best guess is that this is done in order to avoid over-spamming the Note table.
using PX.Data;
using PX.Objects.SO;
using System;
using System.Collections;
using System.Linq;
using System.Web.Compilation;
namespace SearchByNoteID
{
// Acuminator disable once PX1016 ExtensionDoesNotDeclareIsActiveMethod extension should be constantly active
public class SOOrderEntryExt : PXGraphExtension<SOOrderEntry>
{
public PXAction<SOOrder> searchByNoteID;
[PXUIField(DisplayName ="Search by Note ID")]
[PXButton(CommitChanges = true)]
public virtual IEnumerable SearchByNoteID(PXAdapter adapter)
{
var order = adapter.Get<SOOrder>().FirstOrDefault();
if(order!=null)
{
//
//...
//
Guid? noteID = GetNoteID();
object record = GetRecordByNoteID(noteID);
//
//... do whatever you want with the record
//
}
return adapter.Get();
}
protected object GetRecordByNoteID(Guid? noteID)
{
var type = GetEntityType(this.Base, noteID);
if(type==null) return null;
object entityRow = new EntityHelper(this.Base).GetEntityRow(type, noteID);
return entityRow;
}
protected Type GetEntityType(PXGraph graph, Guid? noteID)
{
if (noteID == null)
{
return null;
}
Note note = PXSelectBase<Note, PXSelect<Note, Where<Note.noteID, Equal<Required<Note.noteID>>>>.Config>.SelectWindowed(graph, 0, 1, new object[]
{
noteID
});
if (note == null || string.IsNullOrEmpty(note.EntityType))
{
return null;
}
return PXBuildManager.GetType(note.EntityType, false);
}
}
}

Acumatica Vendor ID segment key different to BIZZACCOUNT segment length

I want to know if it's possible to setup Vendor ID segment keys with a less number of characters than the BiZAccounts..
For example I have created branch Keys like USBRANCH1 but now I want to create Vendor ID like V001 but not give the user possibility to enter more than 4 characters?
I'm not sure why BIZaccount is tied to vendors, customers, employees in terms of segment keys as this reduces flexibility and changing key length and type
Thanks
You can do the following to achieve that:
1. Create your own Segmented Key like below:
Create Cache Extension to the Vendor's DAC to change Default VENDOR Segmented Key which is inherited from BIZACCTto yours MYVENDOR like below:
using PX.Data;
using PX.Data.EP;
using PX.Objects.AP;
using PX.Objects.CR;
using PX.Objects.GL;
using System;
namespace ClassLibrary1.DAC
{
public class VendorExt:PXCacheExtension<Vendor>
{
[MyVendorRaw(IsKey = true)]
[PXDefault]
[PXFieldDescription]
public virtual string AcctCD { get; set; }
}
[PXDBString(30, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Vendor", Visibility = PXUIVisibility.Visible)]
public sealed class MyVendorRawAttribute : AcctSubAttribute
{
public MyVendorRawAttribute() : this(null)
{
}
public MyVendorRawAttribute(Type where)
{
Type type = BqlCommand.Compose(new Type[]
{
typeof(Search2<, , >),
typeof(Vendor.acctCD),
typeof(LeftJoin<Contact, On<Contact.bAccountID, Equal<Vendor.bAccountID>, And<Contact.contactID, Equal<Vendor.defContactID>>>, LeftJoin<Address, On<Address.bAccountID, Equal<Vendor.bAccountID>, And<Address.addressID, Equal<Vendor.defAddressID>>>>>),
(where == null) ? typeof(Where<Match<Current<AccessInfo.userName>>>) : BqlCommand.Compose(new Type[]
{
typeof(Where2<, >),
typeof(Where<Match<Current<AccessInfo.userName>>>),
typeof(And<>),
where
})
});
PXDimensionSelectorAttribute pxdimensionSelectorAttribute;
this._Attributes.Add(pxdimensionSelectorAttribute = new PXDimensionSelectorAttribute("MYVENDOR", type, typeof(Vendor.acctCD), new Type[]
{
typeof(Vendor.acctCD),
typeof(Vendor.acctName),
typeof(Vendor.vendorClassID),
typeof(Vendor.status),
typeof(Contact.phone1),
typeof(Address.city),
typeof(Address.countryID)
}));
pxdimensionSelectorAttribute.DescriptionField = typeof(Vendor.acctName);
this._SelAttrIndex = this._Attributes.Count - 1;
this.Filterable = true;
((PXDimensionSelectorAttribute)this._Attributes[this._SelAttrIndex]).CacheGlobal = true;
}
public const string DimensionName = "MYVENDOR";
}
}
After this Vendor CD will work with 4 length. But as you can see on the screenshot below there will be some issues with the existing records. So I recommend you to do this only in case if the system has not existing Vendors.
Also after doing this I assume you to check all the pages which use Vendor for correct working.

Custom Selector not refreshing when placed in Grid

I have a custom Selector created using PXCustomSelectorAttribute class, I am not able to do AutoRefresh as this option is not available. Can anyone tell me how to Autorefresh the custom selector.
Below is an example how to create a CustomSelector and set it to AutoRefresh mode.
using PX.Objects.SO;
using PX.Objects.AR;
using PX.Data;
using System.Collections;
namespace TestLib
{
public class SOOrderExt : PXCacheExtension<SOOrder>
{
#region UsrTestField
[PXDBString]
[PXUIField(DisplayName = "TestField")]
[CustomerPriceClass()]
public virtual string UsrTestField { get; set; }
public abstract class usrTestField:IBqlField { }
#endregion
}
public class CustomerPriceClassAttribute : PXCustomSelectorAttribute
{
public CustomerPriceClassAttribute()
: base(typeof(ARPriceClass.priceClassID))
{
this.DescriptionField = typeof(ARPriceClass.description);
}
protected virtual IEnumerable GetRecords()
{
ARPriceClass epc = new ARPriceClass();
epc.PriceClassID = ARPriceClass.EmptyPriceClass;
epc.Description = PX.Objects.AR.Messages.BasePriceClassDescription;
yield return epc;
foreach (ARPriceClass pc in PXSelect<ARPriceClass>.
Select(this._Graph))
{
yield return pc;
}
}
}
}
After this you need to add the field to the UI from Layout Editor and set the AutoRefresh property in the Ext Properties section to True. See the screen-shot below.
UPDATE:
In case of Grid you need to add you will need to add Control in the Levels of the Grid like is shown on the screenshot below:
After adding the control you will see the Field Editor (3) for that field.
In the properties of the Field Editor the AutoRefresh is available and you can set it to True:

Automatically calculating and adding Landedcost

I need to add a LandedCost in PO Receipt screen (PO302000) based on a fix percentage (which I can include as a custom field in PO Preferences). It should be automatically added by the time PO Receipt is released. Which event should be the best approach to trigger and add LandedCost?
Is that when user uncheck OnHold checkbox?
Or, User clicks on Release button? If yes then can I extend release action?
The method that releases the POReceipts is static we cannot override it.
However, we can override the places where this static method is being called. It is called in two places: 1) on the release Action of POReceiptEntry(graph) and 2) on the constructor of the POReleaseReceipt(graph) that sets the process delegate.
1) On the POReceiptEntry, you can extend this graph to first do your Custom code and then call base release method.
public class POReceiptEntry_Extension:PXGraphExtension<POReceiptEntry>
{
public PXSetup<POSetup> posetup;
#region Event Handlers
public PXAction<POReceipt> release;
[PXUIField(DisplayName = Messages.Release, MapEnableRights = PXCacheRights.Update, MapViewRights = PXCacheRights.Update)]
[PXProcessButton]
public virtual void Release()
{
//retrieve value from Custom field added on PO Preferences screen
//POSetup setup = posetup.Current;
//POSetupExt setupExt = setup.GetExtension<POSetupExt>();
LandedCostTran landedCost = Base.landedCostTrans.Insert();
landedCost.LandedCostCodeID = "YOURLANDEDCOSTCODE";
landedCost.InvoiceNbr = "YOURINVOICENUMBER";
landedCost.CuryLCAmount = 2; //Formula here using setupExt.UsrFieldPercentange
Base.landedCostTrans.Update(landedCost);
Base.release.Press();
}
#endregion
}
2) On the POReleaseReceipt graph, since the process delegate is set on the constructor of this graph, you can extend this graph and override Initialize() method to set your custom process delegate.
Your custom process delegate will have your custom code and then call base method.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Text;
using PX.Common;
using PX.Data;
using PX.Objects.CS;
using PX.Objects.IN;
using PX.Objects.AP;
using PX.Objects.PO;
using PX.Objects.GL;
using PX.Objects.CM;
using PX.Objects;
namespace PX.Objects.PO
{
public class POReleaseReceipt_Extension:PXGraphExtension<POReleaseReceipt>
{
public override void Initialize()
{
//Gets Process Delegate
var processDelegate = (PXProcessingBase<POReceipt>.ProcessListDelegate)Base.Orders.GetProcessDelegate();
//Change the process delegate that was created by the framework by your custom one.
Base.Orders.SetProcessDelegate(delegate (List<POReceipt> orders) { POReceiptsProc(orders, processDelegate); });
}
public static void POReceiptsProc(List<POReceipt> orders, PXProcessingBase<POReceipt>.ProcessListDelegate processDelegate)
{
//Execute your custom code here
//create POReceiptEntry graph, Loop through the orders, Access your Custom field, Add LandedCost
PXTrace.WriteInformation("Start Process execution");
POReceiptEntry graph = PXGraph.CreateInstance<POReceiptEntry>();
........
//Call the base action
if (processDelegate != null)
processDelegate(orders);
}
}
}

Create Button Under Actions To Redirect To Report In Acumatica

I am trying to add an option under Actions in Acumatica on the Checks & Payment screen AP302000. See below what I am trying to achieve:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization;
using PX.Common;
using PX.Data;
using PX.Objects.CM;
using PX.Objects.CA;
using PX.Objects.CS;
using PX.Objects.GL;
using PX.Objects.CR;
using PX.Objects;
using PX.Objects.AP;
namespace PX.Objects.AP
{
public class APPaymentEntry_Extension:PXGraphExtension<APPaymentEntry>
{
#region Event Handlers
public PXAction<APPayment> ShowURL;
[PXUIField(DisplayName = "Print Remittance")]
[PXButton]
protected virtual void showURL()
{
APPayment doc = Document.Current;
if (doc.RefNbr != null) {
throw new PXReportRequiredException(doc.RefNbr, "AP991000", null);
}
}
#endregion
}
}
This is however telling me that there is no definition and no extension method for 'APPayment'. Can someone please walk me through how to achieve what I am trying to do?
Note that the report has only 1 parameter (RefNbr)
Thanks,
G
To Add a new Action in existing Actions Menu, you should override the Initialize() method and use AddMenuAction.
public class APPaymentEntry_Extension : PXGraphExtension<APPaymentEntry>
{
public override void Initialize()
{
Base.action.AddMenuAction(ShowURL);
}
public PXAction<APPayment> ShowURL;
[PXUIField(DisplayName = "Print Remittance")]
[PXButton]
protected virtual void showURL()
{
APPayment doc = Base.Document.Current;
if (doc.RefNbr != null)
{
throw new PXReportRequiredException(doc, "AP991000", null);
}
}
}
Document.Current should be accessed as Base.Document.Current in Extensions. You need to pass the DAC as first parameter in PXReportRequiredException if DAC has the appropriate parameter value. Alternatively, you can build parameters and pass it to PXReportRedirectException.
Dictionary<string, string> parameters = new Dictionary<string, string>();
parameters["ParameterName1"] = <Parameter Value>;
...
throw new PXReportRequiredException(parameters, <reportID>, "Report")

Resources