If you want to create custom Attribute for autonumbering field you need:
- Create Setup page for configuring autonumbering field or maybe you can use existing
- Create Attribute which you'll add to your entity
- Add attribute to field that you need increment
Create Setup page for configuration autonumbering field
Setup.cs like this:
[System.SerializableAttribute()]
[PXPrimaryGraph(typeof(CurrencyMaint))]
[PXCacheName("Your company Preferences")]
public class Setup : PX.Data.IBqlTable
{
#region DocumentRefNbr
public abstract class documentRefNbr : PX.Data.IBqlField
{
}
protected string _DocumentRefNbr;
[PXDBString(15, IsUnicode = true)]
[PXDefault("00010")]
[PXUIField(DisplayName = "Document Last Ref. Number")]
public virtual string DocumentLastDocNbr
{
get
{
return this._DocumentRefNbr;
}
set
{
this._DocumentRefNbr = value;
}
}
#endregion
#region ReturnDocRefNbr
public abstract class returnLastDocNbr : PX.Data.IBqlField
{
}
protected string _ReturnLastDocRefNbr;
[PXDBString(15, IsUnicode = true)]
[PXDefault("00010")]
[PXUIField(DisplayName = "Return Documnet Ref. Number")]
public virtual string ReturnLastDocNbr
{
get
{
return this._ReturnLastDocRefNbr;
}
set
{
this._ReturnLastDocRefNbr = value;
}
}
#endregion
#region AutoNumbering
public abstract class autoNumbering : PX.Data.IBqlField
{
}
protected bool? _AutoNumbering;
[PXDBBool()]
[PXDefault(true, PersistingCheck = PXPersistingCheck.Nothing)]
[PXUIField(DisplayName = "Auto Numbering")]
public virtual bool? AutoNumbering
{
get
{
return this._AutoNumbering;
}
set
{
this._AutoNumbering = value;
}
}
#endregion
}
We create 3 fields:
- DocumentLastDocNbr - for setting start position to numbering;
- ReturnLastDocNbr - for get last number from db
- AutoNumbering bool field for setting auto or manual numbering
Next, create graph SetupMaint for Setup page:
public class SetupMaint : PXGraph<SetupMaint>
{
public PXSave<Setup> Save;
public PXCancel<Setup> Cancel;
public PXSelect<Setup> LastNumbers;
}
Next, create view, page YC101000:
<%@ Page Language="C#" MasterPageFile="~/MasterPages/FormView.master" AutoEventWireup="true" ValidateRequest="false" CodeFile="YC101000.aspx.cs" Inherits="Page_YC101000" Title="Untitled Page" %>
<%@ MasterType VirtualPath="~/MasterPages/FormView.master" %>
<asp:Content ID="cont1" ContentPlaceHolderID="phDS" Runat="Server">
<px:PXDataSource ID="ds" runat="server" Visible="True" Width="100%" TypeName="CurrencyApplication.SetupMaint" PrimaryView="LastNumbers">
</px:PXDataSource>
</asp:Content>
<asp:Content ID="cont2" ContentPlaceHolderID="phF" Runat="Server">
<px:PXFormView ID="form" runat="server" DataSourceID="ds" Style="z-index: 100" Width="100%" DataMember="LastNumbers" TabIndex="800">
<Template>
<px:PXLayoutRule runat="server" StartRow="True" ControlSize="SM" LabelsWidth="SM"/>
<px:PXTextEdit ID="edLastDocNbr" runat="server" DataField="DocumentLastDocNbr">
</px:PXTextEdit>
<px:PXTextEdit ID="edReturnLastDocNbr" runat="server" DataField="ReturnLastDocNbr">
</px:PXTextEdit>
<px:PXCheckBox ID="edAutoNumbering" runat="server" AlignLeft="True" DataField="AutoNumbering" Text="Auto Numbering">
</px:PXCheckBox>
</Template>
<AutoSize Container="Window" Enabled="True" MinHeight="200" />
</px:PXFormView>
</asp:Content>
Create Attribute
After it, you can create attribute:
public class AutoNumberAttribute : PXEventSubscriberAttribute,
IPXFieldDefaultingSubscriber, IPXFieldVerifyingSubscriber,
IPXRowPersistingSubscriber, IPXRowPersistedSubscriber
{
public const string NewValue = "";
private bool _AutoNumbering;
private Type _AutoNumberingField;
private BqlCommand _LastNumberCommand;
public virtual Type LastNumberField { get; private set; }
public static void SetLastNumberField<Field>(PXCache sender, object row, Type lastNumberField)
where Field : IBqlField
{
foreach (PXEventSubscriberAttribute attribute in sender.GetAttributes<Field>(row))
{
if (attribute is AutoNumberAttribute)
{
AutoNumberAttribute attr = (AutoNumberAttribute)attribute;
attr.LastNumberField = lastNumberField;
attr.CreateLastNumberCommand();
}
}
}
public AutoNumberAttribute(Type autoNumbering)
{
if (autoNumbering != null &&
(typeof(IBqlSearch).IsAssignableFrom(autoNumbering) ||
typeof(IBqlField).IsAssignableFrom(autoNumbering) && autoNumbering.IsNested))
{
_AutoNumberingField = autoNumbering;
}
else
{
throw new PXArgumentException("autoNumbering");
}
}
public AutoNumberAttribute(Type autoNumbering, Type lastNumberField)
: this(autoNumbering)
{
LastNumberField = lastNumberField;
CreateLastNumberCommand();
}
private void CreateLastNumberCommand()
{
_LastNumberCommand = null;
if (LastNumberField != null)
{
if (typeof(IBqlSearch).IsAssignableFrom(LastNumberField))
_LastNumberCommand = BqlCommand.CreateInstance(LastNumberField);
else if (typeof(IBqlField).IsAssignableFrom(LastNumberField) && LastNumberField.IsNested)
_LastNumberCommand = BqlCommand.CreateInstance(typeof(Search<>), LastNumberField);
}
if (_LastNumberCommand == null) throw new PXArgumentException("lastNumberField");
}
public override void CacheAttached(PXCache sender)
{
BqlCommand command = null;
Type autoNumberingField = null;
if (typeof(IBqlSearch).IsAssignableFrom(_AutoNumberingField))
{
command = BqlCommand.CreateInstance(_AutoNumberingField);
autoNumberingField = ((IBqlSearch)command).GetField();
}
else
{
command = BqlCommand.CreateInstance(typeof(Search<>), _AutoNumberingField);
autoNumberingField = _AutoNumberingField;
}
PXView view = new PXView(sender.Graph, true, command);
object row = view.SelectSingle();
if (row != null)
{
_AutoNumbering = (bool)view.Cache.GetValue(row, autoNumberingField.Name);
}
}
public virtual void FieldDefaulting(PXCache sender, PXFieldDefaultingEventArgs e)
{
if (_AutoNumbering)
{
e.NewValue = NewValue;
}
}
public virtual void FieldVerifying(PXCache sender, PXFieldVerifyingEventArgs e)
{
if (_AutoNumbering && PXSelectorAttribute.Select(sender, e.Row, _FieldName, e.NewValue) == null)
{
e.NewValue = NewValue;
}
}
protected virtual string GetNewNumber(PXCache sender, Type setupType)
{
if (_LastNumberCommand == null)
CreateLastNumberCommand();
PXView view = new PXView(sender.Graph, false, _LastNumberCommand);
object row = view.SelectSingle();
if (row == null) return null;
long number;
string lastNumber = (string)view.Cache.GetValue(row, LastNumberField.Name);
number = Int64.Parse(lastNumber);
number = number + 3;
lastNumber = "0000" + Convert.ToString(number);
view.Cache.SetValue(row, LastNumberField.Name, lastNumber);
PXCache setupCache = sender.Graph.Caches[setupType];
setupCache.Update(row);
setupCache.PersistUpdated(row);
return lastNumber;
}
public virtual void RowPersisting(PXCache sender, PXRowPersistingEventArgs e)
{
if ((e.Operation & PXDBOperation.Command) == PXDBOperation.Insert)
{
Type setupType = BqlCommand.GetItemType(_AutoNumberingField);
string lastNumber = GetNewNumber(sender, setupType);
if (lastNumber != null)
{
sender.SetValue(e.Row, _FieldOrdinal, lastNumber);
}
}
}
public virtual void RowPersisted(PXCache sender, PXRowPersistedEventArgs e)
{
if ((e.Operation & PXDBOperation.Command) == PXDBOperation.Insert &&
e.TranStatus == PXTranStatus.Aborted)
{
sender.SetValue(e.Row, _FieldOrdinal, NewValue);
Type setupType = BqlCommand.GetItemType(_AutoNumberingField);
sender.Graph.Caches[setupType].Clear();
}
}
}
Pay attention that for correct work you must implement interfaces, and ovveride standart methods(RowPersisting.... etc, all that need)
Main function for generating new walue is GetNewNumber; New walue will be bigger on 3;
Ok, here we described method -
SetLastNumberField()
This method we call from graph before when we click save data to database in event RowPersisting:
Add attribute to field that you need increment;
public class CurrencyMaint : PXGraph<CurrencyMaint, UsrCurrency>
{
public PXFilter<ExchangeDateFilter> Filter;
public PXSelect<UsrCurrency, Where<UsrCurrency.currencyExchangeDate, Equal<Current<ExchangeDateFilter.exchangeDate>>>> Currencies;
public PXSetup<Setup> AutoNumSetup;
public CurrencyMaint()
{
Setup setup = AutoNumSetup.Current;
}
protected virtual void UsrCurrency_RowPersisting(PXCache sender, PXRowPersistingEventArgs e)
{
UsrCurrency doc = (UsrCurrency)e.Row;
if (sender.GetStatus(doc) == PXEntryStatus.Inserted)
{
AutoNumberAttribute.SetLastNumberField<UsrCurrency.extRefNbr>(
sender, doc,
typeof(Setup.returnLastDocNbr));
}
}
}
So for example I have DAC class and field ExtRefNbr I want to set autonumber attrbute, to do this try: [AutoNumber(typeof(Setup.autoNumbering))]
Of course don`t forget to create aspx page :)
[System.SerializableAttribute()]
public class UsrCurrency : PX.Data.IBqlTable
{
public abstract class extRefNbr : PX.Data.IBqlField
{
}
protected string _ExtRefNbr;
[PXDBString(40, IsUnicode = true, InputMask = ">CCCCCCCCCCCCCCC")]
[PXDefault("00000000")]
[PXUIField(DisplayName = "Document Ref.")]
[AutoNumber(typeof(Setup.autoNumbering))]
public virtual string ExtRefNbr
{
get
{
return this._ExtRefNbr;
}
set
{
this._ExtRefNbr = value;
}
}
#region CurrencyID
#endregion
#region CurrencyName
#endregion
#region CurrencyRate
#endregion
#region CurrencyCC
#endregion
}
And after configure Setup page:
And try to add new rows, and test autonumber:
Enjoy the result )