Default [PXDBInt] data field to Null value? - acumatica

How can I have a numeric field allow and default to a Null / unspecified value?
When I add the control for this field to the screen it always defaults to "0" on new entities...
[PXDBInt]
[PXDefault(TypeCode.DBNull, "", PersistingCheck=PXPersistingCheck.Nothing)]
[PXUIField(DisplayName="Nullable Int")]

The issue here appears to be whether the field is in a Form area or Grid table. In a Grid a null-value is rendered as an empty cell and persists as null if left empty. However, when in a Form area a null value is rendered with "0". If the value is changed attempting to then change it back to empty/null results in a zero value persisting to the database.
The solution I found was when creating the control instead of using a PXNumberEdit type field, changing it to a PXTextEdit field and setting the TextMode property to "Number" gave the desired effect. Null values would render as empty and are distinguished from actual zero values.

There is AllowNull attribute in px:PXNumberEdit control.
In this implementation you do not even need to add the PXDefault attribute to your field.
I added MinValue = 1, MaxValue = 999999 in c# code and DisplayFormat="n0" MaxLength="6" in .aspx because of my task, it should work without this.
<px:PXNumberEdit runat="server" ID="edUsrCapacity" DataField="UsrCapacity"
DisplayFormat="n0" MaxLength="6" AllowNull="True" />
[PXDBInt(MinValue = 1, MaxValue = 999999)]
[PXUIField(DisplayName = Messages.FsEquipment.Capacity)]
public virtual int? UsrCapacity
{
get;
set;
}
public abstract class usrCapacity : BqlInt.Field<usrCapacity>
{
}

The default value for all fields is null unless you force a value with PXDefault.
If you remove the [PXDefault] attribute it will automatically default to null.
Make sure your value is defined as a int? and not int as well. the "?" denotes it as "nullable"
For example:
#region CurrentConfigRevision
public abstract class currentConfigRevision : PX.Data.IBqlField
{
}
protected int? _CurrentConfigRevision;
[PXDBInt]
[PXUIField(DisplayName="Current Revision")]
public virtual int? CurrentConfigRevision
{
get
{
return this._CurrentConfigRevision;
}
set
{
this._CurrentConfigRevision = value;
}
}
#endregion
This will always have a null value unless the user specifies in the interface (or it's set via code)

Related

How to Refresh PXDBScalar

I have added an unbound field to the ARInvoice DAC and set a PXDBScalar attribute. The problem I'm having is that the PXDBScalar attribute doesn't seem to update the field value when other fields post back or if I hit the Save button on screen AR301000. I have to click on the Refresh button on the browser in order to get the field to update. How can I update the unbound field, that has the PXDBScalar attribute, whenever there is a post back on the page?
Here's what the unbound field looks like:
#region UsrBranchOrg
[PXInt]
[PXUIField(DisplayName = "Branch Org")]
[PXDefault(0)]
[PXDBScalar(typeof(Search<Branch.organizationID, Where<Branch.branchID, Equal<PX.Objects.AR.ARRegister.branchID>>>))]
public virtual Int32? UsrBranchOrg { get; set; }
public abstract class usrBranchOrg : PX.Data.BQL.BqlInt.Field<usrBranchOrg> { }
#endregion
TIA!
The definition of ARInvoice inherits from ARRegister.
public partial class ARInvoice : ARRegister, IInvoice, ICreatePaymentDocument
The ARInvoice.BranchID field is defined as:
public new abstract class branchID : PX.Data.BQL.BqlInt.Field<branchID> { }
/// <summary>
/// The identifier of the <see cref="Branch">branch</see> to which the document belongs.
/// </summary>
/// <value>
/// Corresponds to the <see cref="Branch.BranchID"/> field.
/// </value>
[Branch(typeof(AccessInfo.branchID), IsDetail = false, TabOrder = 0)]
[PXFormula(typeof(Switch<
Case<Where<PendingValue<ARInvoice.branchID>, IsPending>, Null,
Case<Where<ARInvoice.customerLocationID, IsNotNull,
And<Selector<ARInvoice.customerLocationID, Location.cBranchID>, IsNotNull>>,
Selector<ARInvoice.customerLocationID, Location.cBranchID>,
Case<Where<Current2<ARInvoice.branchID>, IsNotNull>,
Current2<ARInvoice.branchID>>>>,
Current<AccessInfo.branchID>>))]
public override Int32? BranchID
{
get
{
return this._BranchID;
}
set
{
this._BranchID = value;
}
}
#endregion
What this means is that the Branch ID is set via formula (and not stored in the database) when you change the customer location on the ARInvoice. All that said, you are looking up the branch from an ARRegister object instead of the ARInvoice record itself.
Does it work if you simply change the Search to:
[PXDBScalar(typeof(Search<Branch.organizationID,
Where<Branch.branchID, Equal<branchID>>>))]
In this case, it will pull branchID from the current DAC (ARInvoice). When you reference other DAC's as you have, often you have to include Current<> or .FromCurrent, depending on whether using BQL or FBQL, respectively. <- in all honesty, not 100% sure if "Current" would apply to ARRegister in this case, but I'd still change the reference to point directly to ARInvoice.
Assuming branchID defaulted properly on ARInvoice, and there is no reason it should not, then referencing it should change the Organization ID selected when you commit a change to CustomerLocationID on the ARInvoice which subsequently changes (via PXForumla) the BranchID on the ARInvoice.

Acumatica how to make a Custom Branch field not mandatory or be able to select branch from a lookup

I'm facing the following issue:
I have created a user field "UsrBranch".
Using the Branch lookup from the SO Financial Settings, I'm able to select and save into my new "UsrBranch" field, but it makes the field mandatory, even when I set the field as "Required = false".
Example 1:
[PXUIField(DisplayName = "Branch")]
[Branch(typeof(Coalesce<Search<Location.cBranchID,
Where<Location.bAccountID, Equal<Current<SOOrder.customerID>>,
And<Location.locationID, Equal<Current<SOOrder.customerLocationID>>>>>,
Search<Branch.branchID, Where<Branch.branchID,
Equal<Current<AccessInfo.branchID>>>>>), Required = false)]
public virtual Int32? UsrBranch { get; set; }
public abstract class usrBranch : PX.Data.BQL.BqlString.Field<usrBranch> { }
If I change the lookup to a PXSelector it displays the Branches, but I'm not able to select any.
Example 2:
[PXUIField(DisplayName = "Branch")]
[PXSelector(typeof(Branch.branchID),
SubstituteKey = typeof(Branch.branchCD))]
public virtual Int32? UsrBranch { get; set; }
public abstract class usrBranch : PX.Data.BQL.BqlString.Field<usrBranch> { }
Any Help will be gratefully appreciated.
The "Required" Property controls whether or not the star will show up on the field in the UI. The "PersistingCheck" property on the PXDefaultAttribute controls whether or not a value is mandatory.
The constructor of the BranchAttribute adds a PXDefaultAttribute to the field, and the default value for the "PersistingCheck" property is PXPersistingCheck.Null. This disallows the field from being null when saved. Since BranchAttribute derives from the AcctSubAttribute/PXAggregateAttribute you can set the "PersistingCheck" property on the BranchAttribute and it will set the "PersistingCheck" property on the added PXDefaultAttribute. To make it so the field can be null, set the "PersistingCheck" property to PXPersistingCheck.Nothing on the BranchAttribute:
[Branch(typeof(Coalesce<
Search<Location.cBranchID,
Where<Location.bAccountID, Equal<Current<SOOrder.customerID>>,
And<Location.locationID, Equal<Current<SOOrder.customerLocationID>>>>>,
Search<Branch.branchID,
Where<Branch.branchID, Equal<Current<AccessInfo.branchID>>>>>), PersistingCheck = PXPersistingCheck.Nothing)]
public virtual int? UsrBranch { get; set; }
Additionally, there is a PXUIFieldAttribute on the BranchAttribute so adding another one onto the field is redundant.

PXTimeSpanLong(Format = TimeSpanFormatType.????) not giving correct output/input

Good day
I am currently using [PXDBTimeSpan] but I am limited to only 24 Hours.
I need is to be able to set an Hour value above 100Hours.
example: 126:11 (HHH:mm ; one hundred and twenty-six hours.)
I have looked into [PXTimeSpanLong()] where i tested:
*Format = TimeSpanFormatType.LongHoursMinutes
*I tried using an inputmask
* tried using just PXTimeSpanLong and setting the Time mode to true.
I looked on the wiki for more info on TimeSpanFormatType but the enum types have not been documented.
Side note: I am using Acumatica ERP to create this field
Acumatica pages uses days hours minutes format when bound to a DateTime field so you would have to follow that pattern with this data type:
<px:PXMaskEdit ID="edTimeReaction" runat="server" DataField="TimeReaction"
InputMask="### d\ays ## hrs ## mins" EmptyChar="0" Text="0" />
On screen it looks like this:
To get the desired format you would have to choose a different data type like String which will accept any text format. You then add the field as a MaskEdit field editor control and apply the desired InputMask.
Adding MaskEdit control:
Setting the MaskEdit InputMask properties:
String data type will allow saving any arbitrary format like 3 digits:
We have used PXDBTimeSpanLong with the LongHoursMinutes format. Actually we have fields where the format is selectable via a setup. LongHoursMinutes should work in your case as long as you use PXMaskEdit for your page.
On the INT field for your DAC:
[PXDBTimeSpanLong(Format = TimeSpanFormatType.LongHoursMinutes)]
Then on the page for your field:
<px:PXMaskEdit ID="edMyTimeField" runat="server" DataField="MyTimeField" />
Example showing the PXDBTimeSpanLong field on the left and the same value using a simple PXInt unbound field on the right to show the DB value:
The full dac fields used from the example:
#region MyTimeField
public abstract class myTimeField : PX.Data.BQL.BqlInt.Field<myTimeField> { }
protected Int32? _MyTimeField;
[PXDBTimeSpanLong(Format = TimeSpanFormatType.LongHoursMinutes)]
[PXDefault(TypeCode.Int32, "0")]
[PXUIField(DisplayName = "LongHoursMinutesField")]
public virtual Int32? MyTimeField
{
get
{
return this._MyTimeField;
}
set
{
this._MyTimeField = value;
}
}
#endregion
#region MyTimeFieldDB
[PXInt]
[PXUIField(DisplayName = "DB Value")]
public virtual Int32? MyTimeFieldDB
{
get
{
return this._MyTimeField;
}
}
#endregion

PXFormula not updating

I've created a new custom bound field UsrMatchCode for the BAccount DAC. My goal is to create a field which I can query from a web service call to identify "potential" duplicate customer records. My plan is to concatenate the following into a single 9-character calculated field:
First 5 Characters of Address.PostalCode
First 2 Characters of Address.AddressLine1
First 2 Characters of Contact.FullName
But before I can get this far, I'm stuck getting the value of the PXFormula to display when updating/saving existing records. Strangely, it does output a value for new records. See screenshot.
I've reduced the PXFormula to using constants only to rule out other fields causing the problem.
public class BAccountExt : PXCacheExtension<PX.Objects.CR.BAccount>
{
private class index1 : Constant<int>
{
public index1() : base(0) { }
}
private class length5 : Constant<int>
{
public length5() : base(5) { }
}
private class testString : Constant<string>
{
public testString() : base("123456789") { }
}
#region UsrMatchCode
public abstract class usrMatchCode : IBqlField { }
[PXDBString(9)]
[PXUIField(DisplayName = "Match Code", Enabled = false)]
[PXFormula(typeof(Substring<testString, index1, length5>))]
public virtual string UsrMatchCode { get; set; }
#endregion
}
I feel like I'm missing something obvious, but I can't work it out.
I avoid using PXFormula and PXDBxxx types at the same time.
The PXDBxxx attribute tells the framework you want to persist the field value to DB and reload it's value from DB while PXFormula tells the framework the string value needs to be computed from the formula. The two approach appear incompatible because it's not clear cut whether the value will be coming from DB or from formula after the record has been persisted to DB. Other attributes like PXDefault are more suited for PXDBxxx types because it will only run at initialisation.
I would recommend either to use PXFormula with the unbound PXString type or to use PXDefault instead of PXFormula for initialisation of PXDBString.

Adding custom selector to a grid

I am having an issue with adding a selector for a custom field to a grid. I am having a lot of issues and I am a bit lost.
We need to add a selector to the "Documents to Apply" tab on the AR302000 screen (Finance -> Accounts Recievable -> Payments and Applications). This selector would be based off of a custom field we added to ARRegister.
public abstract class usrUploadDocNbr : IBqlField { }
[PXDBString(15)]
[PXUIField(DisplayName = Messages.UploadDocNbr)]
public virtual string UsrUploadDocNbr { get; set; }
I did not decorate this with the PXSelector tag since we use this field as with a textbox most of the time. From there, I added it to the AR302000 grid mentioned above, but the field was always disabled.When I looked at the fields available to add to the grid, there is ARInvoice__UsrUploadDocNbr and ARRegisterAlias__UsrUploadDocNbr. This kind of makes sense to me,but only a little bit.
When I tried to use either one of those fields, the row in the grid would always be read-only. From here, I figured I would try to add the field to ARAdj since this was the type of many of the fields in the grid. I added the following code:
public abstract class usrUploadDocNbr : IBqlField, IBqlOperand { }
[PXDBString(BqlField =typeof(ArRegisterExt.usrUploadDocNbr))]
[PXUIField(DisplayName = Messages.UploadBatchNbr, Enabled = true)]
[PXSelector(typeof(ARRegister.refNbr),
typeof(ARAdjust.ARInvoice.refNbr),
typeof(ARAdjust.ARInvoice.docDate),
typeof(ArRegisterExt.usrUploadDocNbr),
typeof(ARAdjust.ARInvoice.finPeriodID),
typeof(ARAdjust.ARInvoice.customerID),
typeof(ARRegister.customerLocationID),
typeof(PX.Objects.AR.Standalone.ARRegister.curyID),
typeof(ARRegister.curyOrigDocAmt),
typeof(ARRegister.curyDocBal),
typeof(PX.Objects.AR.Standalone.ARRegister.status),
typeof(ARAdjust.ARInvoice.dueDate),
typeof(ARAdjust.ARInvoice.invoiceNbr),
typeof(PX.Objects.AR.Standalone.ARRegister.docDesc),
SubstituteKey = typeof(ArRegisterExt.usrUploadDocNbr))]
public virtual string UsrUploadDocNbr { get; set; }
When I added this field, the selector worked, sort of. I was able to have the selector window open, but all the column names were the type name rather than the annotated name (as an example, usrUploadDocNbr rather than "Upload Doc. Nbr.").
But another issue popped up - the Refernce Nbr selector no longer works. We added the UsrUploadDocNbr to the Reference Nbr selector. The code is as follows:
[PXMergeAttributes(Method = MergeMethod.Append)]
[PXCustomizeSelectorColumns(
typeof(ARAdjust.ARInvoice.refNbr),
typeof(ARAdjust.ARInvoice.docDate),
typeof(ArRegisterExt.usrUploadDocNbr),
typeof(ARAdjust.ARInvoice.finPeriodID),
typeof(ARAdjust.ARInvoice.customerID),
typeof(ARRegister.customerLocationID),
typeof(PX.Objects.AR.Standalone.ARRegister.curyID),
typeof(ARRegister.curyOrigDocAmt),
typeof(ARRegister.curyDocBal),
typeof(PX.Objects.AR.Standalone.ARRegister.status),
typeof(ARAdjust.ARInvoice.dueDate),
typeof(ARAdjust.ARInvoice.invoiceNbr),
typeof(PX.Objects.AR.Standalone.ARRegister.docDesc))]
public virtual string AdjdRefNbr { get; set; }
The error that pops up reads (it does display the same thing twice in a single modal):
Invalid column name 'UsrUploadDocNbr'
Invalid column name 'UsrUploadDocNbr'
And at this point I am pretty lost. I am sure I am doing many things wrong, just not sure what it is.
First:
You should give typeof(Search<DAC.FIELD>) to the PXSelector as first parameter.
So change this line
[PXSelector(typeof(ARRegister.refNbr),
To
[PXSelector(typeof(Search<ARRegister.refNbr>),
Second:
Message
Invalid column name 'UsrUploadDocNbr'
mostly is being shown(if the field is decorated with PXDB... like attribute) when you have not created the field in the Database's Table.

Resources