Good day
How do you limit users in Acumatica to only have access to certain Sales order Types ?
Thanks
This is older code, but you could try limiting according to Role. In this example, Guest Role users are limited to IN and TR OrderTypes:
[PXDBString(2, IsKey = true, IsFixed = true, InputMask = ">aa")]
[PXDefault(SOOrderTypeConstants.SalesOrder, typeof(SOSetup.defaultOrderType))]
[PXSelector(typeof(Search5<SOOrderType.orderType,
InnerJoin<SOOrderTypeOperation, On<SOOrderTypeOperation.orderType,
Equal<SOOrderType.orderType>, And<SOOrderTypeOperation.operation, Equal<SOOrderType.defaultOperation>>>,
LeftJoin<SOSetupApproval, On<SOOrderType.orderType, Equal<SOSetupApproval.orderType>>
, InnerJoin<Users, On<Current<AccessInfo.userName>, Equal<Users.username>>
, InnerJoin<UsersInRoles, On<Users.username, Equal<UsersInRoles.username>>
, InnerJoin<Roles, On<Roles.rolename, Equal<UsersInRoles.rolename>>>>>>>,
Where2<Where<Roles.guest, Equal<False>>,
Or<Where<SOOrderType.orderType, Equal<string_IN>,
Or<SOOrderType.orderType, Equal<string_TR>>>>>,
Aggregate<GroupBy<SOOrderType.orderType>>>))]
[PXRestrictor(typeof(Where<SOOrderTypeOperation.iNDocType, NotEqual<INTranType.transfer>,
Or<FeatureInstalled<FeaturesSet.warehouse>>>), ErrorMessages.ElementDoesntExist, typeof(SOOrderType.orderType))]
[PXRestrictor(typeof(Where<SOOrderType.requireAllocation, NotEqual<True>,
Or<AllocationAllowed>>), ErrorMessages.ElementDoesntExist, typeof(SOOrderType.orderType))]
[PXRestrictor(typeof(Where<SOOrderType.active, Equal<True>>), null)]
[PXUIField(DisplayName = "Order Type", Visibility = PXUIVisibility.SelectorVisible)]
[PX.Data.EP.PXFieldDescription]
protected virtual void SOOrder_OrderType_CacheAttached(PXCache sender) { }
Related
I am trying to make the PriceClassID required for Business Accounts when they are created. I initially did this by editing the DAC. This caused an issue where whenever an Employee was created, an error was displayed making creating an employee impossible.
Error: 'CPriceClassID' cannot be empty
I went back to the drawing board and decided to edit the attributes on the Graph which allowed me to create Employee records. However now when editing existing Vendors via the Business Accounts screen I get the same error. I can create and edit Vendors from the Vendors screen because it uses a different graph but I would still like to implement a more elegant solution
[PXDBString(10, IsUnicode = true)]
[PXSelector(typeof(AR.ARPriceClass.priceClassID))]
[PXUIField(DisplayName = "Price Class", Visibility = PXUIVisibility.Visible)]
[PXDefault()]
protected virtual void Location_CPriceClassID_CacheAttached(PXCache sender)
{
}
What is the best method to make the CPriceClassID field required on the Business Accounts screen that will still allow me to create Employees and Vendors without any errors?
You can use PXUIRequiredAttribute for achieving what you need.
Below is an example of how you can use it for making the field required only on the specific screen:
public class LocationExt : PXCacheExtension<PX.Objects.CR.Location>
{
public class BusinessAccountMaintScreen :Constant<string>
{
//"CR.30.30.00" is the page id of the Business Accounts screen
public BusinessAccountMaintScreen():base("CR.30.30.00")
{
}
}
#region UsrCustomField
[PXDBString(10, IsUnicode = true)]
[PXSelector(typeof(AR.ARPriceClass.priceClassID))]
[PXUIField(DisplayName = "Price Class", Visibility = PXUIVisibility.Visible)]
[PXDefault]
// Here we add checking for the current page so that this field will be required only on the Business Accounts screen
[PXUIRequired(typeof(Where<Current<AccessInfo.screenID>, Equal<BusinessAccountMaintScreen>>))]
public virtual String CPriceClassID {get;set;}
#endregion
}
In Numbering Sequences settings (CS201010), there is an option for manual numbering.
However, depending on the document type. There are instances where the reference number can be left blank. If it's blank, I'd want the auto numbering to kick in. Or something like call the NextNumber() function before saving the document. Is it possible ? How do I do that ?
At the moment, if I enforce the auto numbering. It doesn't allow me to type anything on the Reference number for example.
TIA
There are two ways: easy and little bit more complicated. Easy one will be attach to FieldDefaulting, and inside of that event check if that field is empty then assign some value into it.
Another way which better feet to Acumatica style is to implement your own AutoNumbering attribute and then apply that Autonumbering attribute to your DAC class. N.B. you can substitute Acumatica autonumbering attribute with yours with PXCacheExtension
below goes example of code with removing default autonumbering with implementing autonumbering via FieldDefaulting:
public class ARInvoiceEntryExt : PXGraphExtension<ARInvoiceEntry>
{
[PXDBString(15, InputMask = ">CCCCCCCCCCCCCCC", IsKey = true, IsUnicode = true)]
[PXDefault]
[PXUIField(DisplayName = "Reference Nbr.", TabOrder = 1, Visibility = PXUIVisibility.SelectorVisible)]
//[ARInvoiceType.RefNbr(typeof(Search2<ARRegisterAlias.refNbr, InnerJoinSingleTable<ARInvoice, On<ARInvoice.docType, Equal<ARRegisterAlias.docType>, And<ARInvoice.refNbr, Equal<ARRegisterAlias.refNbr>>>, InnerJoinSingleTable<Customer, On<ARRegisterAlias.customerID, Equal<Customer.bAccountID>>>>, Where<ARRegisterAlias.docType, Equal<Optional<ARInvoice.docType>>, And2<Where<ARRegisterAlias.origModule, Equal<BatchModule.moduleAR>, Or<ARRegisterAlias.released, Equal<True>>>, And<Match<Customer, Current<AccessInfo.userName>>>>>, OrderBy<Desc<ARRegisterAlias.refNbr>>>), Filterable = true, IsPrimaryViewCompatible = true)]
//[ARInvoiceType.Numbering]
//This is example of throwing away Acumatica autonumbering
//[ARInvoiceNbr]
[PXFieldDescription]
protected void ARInvoice_RefNbr_Cacheattached()
{
}
protected void ARInvoice_RefNbr_FieldDefaulting(PXCache sender, PXFieldDefaultingEventArgs e)
{
//here you can implement your way of initialization of this field
}
}
Or with attribute you can try something like this:
//somewhere in your code
public class RickAutonumberingAttribute : ARInvoiceNbrAttribute
{
//Here you'll need to play with implementation of your autonumbering
}
public class ARInvoiceEntryExt : PXGraphExtension<ARInvoiceEntry>
{
[PXDBString(15, InputMask = ">CCCCCCCCCCCCCCC", IsKey = true, IsUnicode = true)]
[PXDefault]
[PXUIField(DisplayName = "Reference Nbr.", TabOrder = 1, Visibility = PXUIVisibility.SelectorVisible)]
[ARInvoiceType.RefNbr(typeof(Search2<ARRegisterAlias.refNbr, InnerJoinSingleTable<ARInvoice, On<ARInvoice.docType, Equal<ARRegisterAlias.docType>, And<ARInvoice.refNbr, Equal<ARRegisterAlias.refNbr>>>, InnerJoinSingleTable<Customer, On<ARRegisterAlias.customerID, Equal<Customer.bAccountID>>>>, Where<ARRegisterAlias.docType, Equal<Optional<ARInvoice.docType>>, And2<Where<ARRegisterAlias.origModule, Equal<BatchModule.moduleAR>, Or<ARRegisterAlias.released, Equal<True>>>, And<Match<Customer, Current<AccessInfo.userName>>>>>, OrderBy<Desc<ARRegisterAlias.refNbr>>>), Filterable = true, IsPrimaryViewCompatible = true)]
//[ARInvoiceType.Numbering]
//This is example of throwing away Acumatica autonumbering
[RickAutonumberingAttribute]
[PXFieldDescription]
protected void ARInvoice_RefNbr_Cacheattached()
{
}
}
In Cash Sales (AR304000 screen) i want to set it's auto numbering sequence from invoice number sequence to payment number sequence.
i tried the following code but to no avail. saving new sales throws an error. see attached photo for the error.
here is my DAC code:
public class ARCashSaleExtension : PXCacheExtension<ARCashSale>
{
#region RefNumber
[PXDBString(15, IsKey = true, InputMask = ">CCCCCCCCCCCCCCC", IsUnicode = true, BqlField = typeof(**PX.Objects.AR.ARPayment.refNbr**))]
[PXDefault()]
[PXUIField(DisplayName = "Reference Nbr.", Visibility = PXUIVisibility.SelectorVisible)]
[ARPaymentType.RefNbr(typeof(Search2<ARCashSale.refNbr,
InnerJoinSingleTable<Customer, On<ARCashSale.customerID, Equal<Customer.bAccountID>>>,
Where<ARCashSale.docType, Equal<Current<ARCashSale.docType>>,
And2<Where<ARCashSale.origModule, NotEqual<BatchModule.moduleSO>, Or<ARCashSale.released, Equal<boolTrue>>>,
And<Match<Customer, Current<AccessInfo.userName>>>>>, OrderBy<Desc<ARCashSale.refNbr>>>), Filterable = true)]
[**ARPaymentType.Numbering()**]
[PXFieldDescription]
public String RefNbr
{
get;
set;
}
#endregion
}
I think you should use AutoNumberAttribute instead of ARPaymentType.Numbering attribute.
[AutoNumber(typeof(ARCashSale.docType), typeof(ARCashSale.docDate),
new string[] { CashSale, CashReturn },
new Type[] { typeof(ARSetup.paymentNumberingID), typeof(ARSetup.paymentNumberingID) })]
Besides, I can't see any reasons to use ARPaymentType.RefNbr attribute instead of ARCashSaleType.RefNbr attribute.
One more thing: from my point, it's better to use Cache_Attached on graph extension for rewriting attributes on one field instead of creating DAC extension.
Here is an example of Graph extension with CacheAttached:
public partial class ARCashSaleEntryExt : PXGraphExtension<ARCashSaleEntry>
{
[PXMergeAttributes(Method = MergeMethod.Merge)] // that attribute is here to keep all attributes of base field except the one that should be replaced.
[AutoNumber(typeof(ARCashSale.docType), typeof(ARCashSale.docDate),
new string[] { ARDocType.CashSale, ARDocType.CashReturn },
new Type[] { typeof(ARSetup.paymentNumberingID), typeof(ARSetup.paymentNumberingID) })]
public virtual void ARCashSale_RefNbr_CacheAttached(PXCache sender)
{
}
}
To learn more about cache_attached events see T200 training
I am trying to create a Field to store 'VendorID', in my own DAC.
First I tried using Acumatica attributes to show the selector, like the below
[VendorNonEmployeeActive(Visibility = PXUIVisibility.SelectorVisible, DescriptionField = typeof(Vendor.acctName), CacheGlobal = true, Filterable = true)]
AND
[POVendor(Visibility = PXUIVisibility.SelectorVisible, DescriptionField = typeof(Vendor.acctName), CacheGlobal = true, Filterable = true)]
AND other few attributes. but either it shows employee data or nothing. I even tried to write a selector of my own as below where BAccountRef is a class derived from BAccount.
[PXSelector(typeof(Search2<Vendor.bAccountID,
InnerJoin<BAccountRef, On<Vendor.bAccountID, Equal<BAccountRef.bAccountID>>>,
Where<Vendor.status, Equal<BAccountRef.status.active>,
And<Vendor.type, Equal<BAccountType.vendorType>>>>), new Type[] { typeof(BAccountRef.acctCD), typeof(BAccountRef.acctName) },
SubstituteKey = typeof(BAccountRef.acctCD))]
Unfortunately no luck, from the behaviour, it seems like the records are auto filtered to show employee info. I cant figure out how this is happening. How to make the selector show vendor info? How this is auto filtering the employees in this graph?
Most likely your BQL queries towards Vendor DAC are translated into SQL queries to EPEmployee table. This behavior is caused by the EPEmployee cache (and therefore the BAccount cache) initialized prior to Vendor cache.
Try using PX.Objects.AP.VendorAttribute together with the BAccountR DAC - use of BAccountR will break inheritance between the Vendor and BAccount' DACs and should be translated into SQL queries towardsBAccountandVendor` tables:
[Vendor(typeof(Search<BAccountR.bAccountID,
Where<BAccountR.type, Equal<BAccountType.companyType>,
Or<Vendor.type, NotEqual<BAccountType.employeeType>>>>),
Visibility = PXUIVisibility.SelectorVisible, CacheGlobal = true, Filterable = true)]
[PXRestrictor(typeof(Where<Vendor.status, IsNull,
Or<Vendor.status, Equal<BAccount.status.active>,
Or<Vendor.status, Equal<BAccount.status.oneTime>>>>),
AP.Messages.VendorIsInStatus, typeof(Vendor.status))]
Thanks All,
#Ruslan's answer helped to get the correct definition for the selector. When we use BAccountR or VendorR DAC's the SQL is not translating to EPEmployee and hence i am able to get the correct information.
[PXDimensionSelectorAttribute("VENDOR", typeof(Search<VendorR.bAccountID, Where<VendorR.type, Equal<BAccountType.vendorType>,
And<VendorR.status, Equal<BAccount.status.active>>>>), typeof(VendorR.acctCD), new Type[] { typeof(VendorR.acctCD), typeof(VendorR.acctName) })]
In one of my recent projects I've used the following in order to get VendorCD:
#region vendor
public abstract class vendor : PX.Data.IBqlField
{
}
protected string _Vendor;
[VendorRaw(typeof(Where<Vendor.vendorClassID, Equal<Current<VendorFilter.vendorClassID>>>),
DescriptionField = typeof(Vendor.acctName), DisplayName = "Vendor ID")]
[PXDefault("", PersistingCheck = PXPersistingCheck.Nothing)]
public virtual string Vendor
{
get
{
return this._Vendor;
}
set
{
this._Vendor = value;
}
}
#endregion
recently I had to add a Vendor Selector on the ExpenseClaimsDetails DAC, after trying several options, this is the one that worked for me:
[PXDBInt()]
[PXUIField(DisplayName = "Vendor", Enabled = true)]
[PXDimensionSelector("VENDOR", typeof(Search<VendorR.bAccountID, Where<VendorR.vStatus, Equal<VendorStatus.active>>>),
typeof(VendorR.acctCD),
new Type[] { typeof(VendorR.acctCD),
typeof(VendorR.acctName),
typeof(VendorR.vendorClassID),
typeof(VendorR.taxRegistrationID)},
Filterable = true,
SelectorMode = PXSelectorMode.TextModeSearch,
DescriptionField = typeof(VendorR.acctName))]
public int? UsrEVVendorID { get; set; }
public abstract class usrEVVendorID : PX.Data.BQL.BqlInt.Field<usrEVVendorID> { }
I'm trying to default the OrderType.POOrderType to POOrderType.DropShip. I've tried altering the attributes in the customization manager to the following:
[PXDBString(2, IsKey = true, IsFixed = true)]
[PXDefault(POOrderType.DropShip)]
[POOrderType.List()]
[PXUIField(DisplayName = "Type", Visibility = PXUIVisibility.SelectorVisible, Enabled = true)]
[PX.Data.EP.PXFieldDescription]
But upon insertion of a new record, it does nothing. I've also tried using the CacheAttached event in a graph extension of POOrderEntry as follows:
public class POOrderEntryExt : PXGraphExtension<POOrderEntry>
{
[PXDBString(2, IsKey = true, IsFixed = true)]
[PXDefault(POOrderType.DropShip)]
[POOrderType.List()]
[PXUIField(DisplayName = "Type", Visibility = PXUIVisibility.SelectorVisible, Enabled = true)]
[PX.Data.EP.PXFieldDescription]
protected virtual void POOrder_OrderType_CacheAttached(PXCache sender) { }
}
This also does NOT work.
I've finally tried using the RowInserting event as follows
protected virtual void POOrder_RowInserting(PXCache sender, PXRowInsertingEventArgs e)
{
POOrder poorder = (POOrder)e.Row;
if (poorder == null) return;
poorder.OrderType = POOrderType.DropShip;
}
This DOES default to DropShip, however, when I use the dropdown on the screen to change back to 'Normal', it empties all the fields, and the Type is also empty. If I select Normal again, then it displays the data in the fields correctly. I can't figure out what's going on here. I always have to select the Type twice to get anything to show. I can't see why the RowInserting event would cause this behavior...
There is POOrder_OrderType_FieldDefaulting event in the POOrderEntry, where default order type is set.
protected virtual void POOrder_OrderType_FieldDefaulting(PXCache sender, PXFieldDefaultingEventArgs e)
{
e.NewValue = POOrderType.RegularOrder;
}
It have 'higher priority' than PXDefault attribute (check T200 training for more information).
So you need to override this event handler.