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()
{
}
}
Related
I have a requirement to create a opportunity like screen and I do not know how to implement the auto generating the document number for newly created document
I am looking forward someone to help me on this issue.
The following steps I have used and I have attached the code for review. I am getting error while saving and not generating the number
I have create a numbering sequence for Memo In document
I have created a DAC for Sequence number setup
region MemoInOrderId
public abstract class memoInOrderId : PX.Data.IBqlField
{
}
protected string _MemoInOrderId;
[PXDBString(10, IsUnicode = true)]
[PXDefault("MEMOIN")]
[PXSelector(typeof(Numbering.numberingID),
DescriptionField = typeof(Numbering.descr))]
[PXUIField(DisplayName = "Memo In Order Nbr")]
public virtual string MemoInOrderId
{
get
{
return this._MemoInOrderId;
}
set
{
this._MemoInOrderId = value;
}
}
#endregion
I have added Auto Generation Sequence number to MemoIn DAC
`
#region OrderNbr
public abstract class orderNbr : PX.Data.IBqlField
{
}
[PXDBString(10, IsUnicode = true, IsKey = true, InputMask = ">CCCCCCCCCCCCCCC")]
[PXUIField(DisplayName = "Order Nbr", Visibility = PXUIVisibility.SelectorVisible)]
[AutoNumber(typeof(MemoSetUp.memoInOrderId), typeof(AccessInfo.businessDate))]
[PXSelector(typeof(MemoIN.orderNbr),
new Type[]
{
typeof(MemoIN.orderNbr),
typeof(MemoIN.orderDate),
typeof(MemoIN.vendorId)
})]
public virtual string OrderNbr { get; set; }
#endregion
In the configuration Screen I have selected numbering sequence used for memo in document
While saving the Memo In document I am getting the following error
I have noticed the Order number is not initialized to "NEW" and it is showing "SELECT"
I have gone through CASetup , CMSetup , ARSetup DAC code and not able to figure out the difference.
If we want to use a numbering sequence it is very straight forward in Acumatica. You should have a setup/preferences field somewhere that defines which numbering sequence you will use for your document number field.
Here is an example of a setup field using a selector to pick a numbering sequence:
// Setup field indicating which numbering sequence to use.
public abstract class myNumberingID : PX.Data.IBqlField
{
}
protected String _MyNumberingID;
[PXDBString(10, IsUnicode = true)]
[PXSelector(typeof(Numbering.numberingID), DescriptionField = typeof(Numbering.descr))]
[PXUIField(DisplayName = "My Numbering Sequence")]
public virtual String MyNumberingID
{
get
{
return this._MyNumberingID;
}
set
{
this._MyNumberingID = value;
}
}
Next, in your document number field you will use the AutoNumberAttribute to define the field as a consumer of a numbering sequence. Below is an example of a number field using the defined number sequence configured in the setup table above (Assumes "MyNumberingID" exists in DAC/Table "MySetup").
// Field using the numbering sequence...
public abstract class myNumberField : PX.Data.IBqlField
{
}
protected String _MyNumberField;
[PXDBString(15, IsUnicode = true, IsKey = true, InputMask = ">CCCCCCCCCCCCCCC")]
[PXUIField(DisplayName = "My Number", Visibility = PXUIVisibility.SelectorVisible)]
[AutoNumber(typeof (MySetup.myNumberingID), typeof (AccessInfo.businessDate))]
[PXDefault]
public virtual String MyNumberField
{
get
{
return this._MyNumberField;
}
set
{
this._MyNumberField = value;
}
}
Edit: Make sure in the graph building the documents to include a PXSetup view to the setup table.
Now when you insert and persist a new record on the DAC that contains your number field, the next numbering sequence value will be used (unless the numbering sequence is configured for manual numbering then the user must provide a value).
For a more complex configuration when there are multiple numbering sequences used based on specific conditions/field values, you can look at PX.Objects.IN.INRegister.RefNbr for an example. Look at INDocType.Numbering and how it changes the numbering sequence based on INRegister.docType (shown below). Another example would be sales order order types related to the sales order document.
public class NumberingAttribute : AutoNumberAttribute
{
public NumberingAttribute()
: base(typeof(INRegister.docType), typeof(INRegister.tranDate),
new string[] { Issue, Receipt, Transfer, Adjustment, Production, Change, Disassembly },
new Type[] { typeof(INSetup.issueNumberingID), typeof(INSetup.receiptNumberingID), typeof(INSetup.receiptNumberingID), typeof(INSetup.adjustmentNumberingID), typeof(INSetup.kitAssemblyNumberingID), typeof(INSetup.kitAssemblyNumberingID), typeof(INSetup.kitAssemblyNumberingID) }) { ; }
}
I want to hide or update a field on the UI based on conditions of another field.
For example, if I have a field called Color:
[PXUIField(DisplayName="Color")]
[PXStringList("Red,Blue,Other")]
[PXDefault("Red")]
And text field for comments only shown when "Other" is selected, how is this accomplished?
The requested behavior can either be accomplished either with a series of event handlers or with a bunch of attributes. You can find several examples on how to subscribe to the RowSelected and FieldUpdated events in the T200 training course, available at Acumatica University and Acumatica Open University
Going with field attributes is a more convenient and way easier option for your particular scenario. I would recommend setting CommitChanges to True for the drop-down, so the Comments field is cleared and disabled/enabled immediately after the user updates Color. Also, it's very to have your Color declared after Comments, so the framework will process Comments field first and always clear the current Comments value after the Color field got updated.
public class Other : Constant<string>
{
public Other() : base("Other") { }
}
public abstract class comments : IBqlField { }
[PXDBString(255, IsUnicode = true)]
[PXUIField(DisplayName = "Comments")]
[PXUIEnabled(typeof(Where<color, Equal<Other>>))]
[PXFormula(typeof(Default<color>))]
[PXDefault(PersistingCheck = PXPersistingCheck.Nothing)]
public string Comments { get; set; }
public abstract class color : IBqlField { }
[PXDBString(10, IsUnicode = true)]
[PXUIField(DisplayName = "Color")]
[PXStringList("Red,Blue,Other")]
[PXDefault("Red")]
public string Color { get; set; }
The only way to conditionally hide/show editor on a form is though the RowSelected event handler:
public void YourDAC_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
YourDAC row = e.Row as YourDAC;
if (row == null) return;
PXUIFieldAttribute.SetVisible<YourDAC.comments>(sender, row, row.Color == "Other");
}
I believe, in the T200 training course, there are several examples on the PXUIFieldAttribute.SetVisible method.
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.