Set default field value in Acumatica - acumatica

How can I set the default value of a date field in Acumatica to show as today? The field I am looking at is the Start Date field on the task entry screen CR306020.
Using version 5.00.2908

In its simplest form you can also use PXDefaultAttribute on your field using business date like so:
[PXDate]
[PXUIField(DisplayName = "From Date")]
[PXDefault(typeof(AccessInfo.businessDate))]
public virtual DateTime? FromDate;

You can use FieldDefaulting in graph. For example
public class CRTaskMaintExt: PXGraphExtension<CRTaskMaint>
{
protected virtual void DiscountDetail_StartDate_FieldDefaulting(PXCache sender, PXFieldDefaultingEventArgs e)
{
SO.DiscountDetail row = e.Row as SO.DiscountDetail;
if (row != null)
{
e.NewValue = DateTime.Now;
}
}
}

Related

Override Ship-To Contact & Address via UDF

I have a requirement on which the Ship-to Contact & Address in Shipments screen (for Transfer only) will be overridden by using the location of Customer selected from UDF.
The UDF that I have created
A piece of code that I used to test:
#region AddressLine1
[PXMergeAttributes(Method = MergeMethod.Merge)]
[PXDBScalar(typeof(Search2<SOAddress.addressLine1,
InnerJoin<SOShipment, On<SOAddress.customerID, Equal<SOShipment.customerID>>,
InnerJoin<BAccount, On<BAccount.bAccountID, Equal<SOShipment.customerID>>,
InnerJoin<SOShipmentKvExt, On<SOShipment.noteID, Equal<SOShipmentKvExt.recordID>>>>>,
Where<BAccount.acctCD, Equal<Current<SOShipmentKvExt.valueString>>>>))]
public string AddressLine1 { get; set; }
#endregion
Using the above code, the Address Line 1 field remains empty despite the customer in UDF being selected.
I would appreciate an easy-to-understand explanation since I'm fairly new in C#. Thanks!
Edit:
I managed to populate the Ship-to-Contact and Ship-to-Address fields by using the following code:
My DAC Extension:
public class SOShipmentExt : PXCacheExtension<PX.Objects.SO.SOShipment>
{
#region UsrCustomerID
[CustomerActive(DescriptionField = typeof(Customer.acctName))]
[PXUIField(DisplayName = "Customer ID")]
[PXDefault(PersistingCheck = PXPersistingCheck.Nothing)]
public virtual int? UsrCustomerID { get; set; }
public abstract class usrCustomerID : PX.Data.BQL.BqlInt.Field<usrCustomerID> { }
#endregion
#region UsrShipAddressID
[PXDBInt()]
[PXUIField(DisplayName = "Ship Address ID")]
public virtual Int32? UsrShipAddressID { get; set; }
public abstract class usrShipAddressID : PX.Data.BQL.BqlInt.Field<usrShipAddressID> { }
#endregion
#region UsrShipContactID
[PXDBInt()]
[PXUIField(DisplayName = "Ship Contact ID")]
public virtual Int32? UsrShipContactID { get; set; }
public abstract class usrShipContactID : PX.Data.BQL.BqlInt.Field<usrShipContactID> { }
#endregion
}
My Graph Extension:
public class SOShipmentEntryExt : PXGraphExtension<SOShipmentEntry>
{
#region Event Handlers
public virtual void SetShipAddressAndContact(SOShipment shipment, int? shipAddressID, int? shipContactID)
{
SOShipmentExt sOShipmentExt = shipment.GetExtension<SOShipmentExt>();
foreach (SOShipmentAddress address in Base.Shipping_Address.Select())
{
if (address.AddressID < 0)
{
Base.Shipping_Address.Delete(address);
}
}
foreach (SOShipmentContact contact in Base.Shipping_Contact.Select())
{
if (contact.ContactID < 0)
{
Base.Shipping_Contact.Delete(contact);
}
}
}
protected virtual void SOShipment_UsrCustomerID_FieldUpdated(PXCache sender, PXFieldUpdatedEventArgs e)
{
SOShipment row = (SOShipment)e.Row;
SOShipmentExt sOShipmentExt = row.GetExtension<SOShipmentExt>();
SOShipmentAddress sOShipment = SelectFrom<SOShipmentAddress>.Where<SOShipmentAddress.customerID.IsEqual<#P.AsInt>>.View.Select(this.Base, sOShipmentExt.UsrCustomerID);
SOShipmentContact sOShipmentContact = SelectFrom<SOShipmentContact>.Where<SOShipmentContact.customerID.IsEqual<#P.AsInt>>.View.Select(this.Base, sOShipmentExt.UsrCustomerID);
if (row != null && sOShipmentExt != null)
{
sOShipmentExt.UsrShipAddressID = sOShipment.AddressID;
sOShipmentExt.UsrShipContactID = sOShipmentContact.ContactID;
}
SetShipAddressAndContact(row, sOShipmentExt.UsrShipAddressID, sOShipmentExt.UsrShipContactID);
#endregion
}
The issues I’m facing now:
Once the document has been saved and I switched to another document, I am unable to access back the previous document that has been saved and it returns below errors:
ShipAddressID - Specified cast is not valid
ShipContactID - Specified cast is not valid
If the selected Customer ID doesn’t have any data in SOShipmentAddress or SOShipmentContact, then it won’t allow me to select the customer. Ideally, I should be able to select the customer and the fields should be auto populated with address details from Address table.
I would appreciate any help since I’m getting really close to solving this.
SOAddress is a table of addresses that are linked to SOs & Shipments. Since this data generally doesn't change very much, the idea is that records will be linked to multiple SOs and shipments. When an address is changed for a Customer, a new record is created in SOAddress. That way, historical data is preserved intact. Thus, records in the table should not be edited. So, rather than thinking about overwriting the address information in SOAddress, you should think about overwriting the ShipAddressID linked to the Shipment to either a new address you create or more likely an already existing one.

How to save a record with two fields disabled on the PM301000 screen

Good afternoon everyone,
I need your help, I want to record one or several records on the PM301000 Projects screen in the detail tab, Cost Budget.
When recording one or more records, two Mark for PO and Vendor ID fields must be disabled. When the condition of the Mark for PO field is equal to true.
I have used the RowPersisting event and it disables it but when I modify or leave the registry the fields are enabled again.
Please help me or tell me how I should do it, my code is as follows.
Thanks in advance.
namespace PX.Objects.PM
{
public class PMBudgetExt : PXCacheExtension<PX.Objects.PM.PMBudget>
{
#region UsrVendorID
[PXDBInt]
[PXUIField(DisplayName = "Vendor ID", Visibility = PXUIVisibility.Visible)]
[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) })]
public virtual int? UsrVendorID { get; set; }
public abstract class usrVendorID : PX.Data.BQL.BqlInt.Field<usrVendorID> { }
#endregion
#region UsrMarkforPO
[PXDBBool()]
[PXDefault(false)]
[PXUIField(DisplayName = "Mark for PO")]
public virtual bool? UsrMarkforPO { get; set; }
public abstract class usrMarkforPO : PX.Data.BQL.BqlBool.Field<usrMarkforPO> { }
#endregion
}
}
namespace PX.Objects.PM
{
public class ProjectEntry_Extension : PXGraphExtension<ProjectEntry>
{
#region Event Handlers
protected void PMCostBudget_RowPersisting(PXCache cache, PXRowPersistingEventArgs e)
{
PMCostBudget newRow = (PMCostBudget)e.Row;
if (newRow == null) return;
PMBudgetExt newRowE = PXCache<PMBudget>.GetExtension<PMBudgetExt>(newRow);
if (Base.CostBudget.Cache.AllowUpdate == true)
{
if (newRowE.UsrMarkforPO == true)
{
PXUIFieldAttribute.SetEnabled<PMBudgetExt.usrMarkforPO>(cache, newRow, false);
PXUIFieldAttribute.SetEnabled<PMBudgetExt.usrVendorID>(cache, newRow, false);
}
}
}
#endregion
}
}
RowPersisting event executes only on save event. Therefore it's not suited for setting the field states. You will get better results with RowSelected event which is executed everytime a record is selected to be displayed on screen. You should set the state on every callback whether it is enabled or disabled. Also, the event should be declared on the same DAC type you are using to set the field state so the cache object match.
public void PMBudget_RowSelected(PXCache sender, PXRowSelectedEventArgs e, PXRowSelected del)
{
if (del != null)
{
del(sender, e);
}
bool isFieldEnabled = [your_condition];
PXUIFieldAttribute.SetEnabled<PMBudget.field>(sender, e.Row, isFieldEnabled);
}

Detecting when an Invoice exceeds the PO amount

I have created a new APTran field called UsrPOTranAmt. I would like to populate it with the PO Line amount when the user either adds a PO or a PO Line to the invoice. Later I can compare the line transaction amount to the UsrPOTranAmt and determine if the user is paying more that the PO amount.
My initial thought was to detect when the PONbr field (PO Type, PO Number, and PO Line Number fields) was updated and then set the UsrPOTranAmt field to the same value as the CuryLineAmt or Amount field that was updated by the PO or PO Line selection. I have tried to detect the field_updated event with a warning message for PONbr and POLineNbr but neither approach has worked.
public class APInvoiceEntry_Extension : PXGraphExtension<APInvoiceEntry>
{
protected void APTran_PONbr_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e)
{
var row = (APTran)e.Row;
if (row.PONbr != null)
{
cache.RaiseExceptionHanding<APTran.PONbr>(row, row.PONbr,
new PXSetPropertyException("PO Line Number Changed", PXErrorLevel.Warning));
}
}
}
I do not receive the warning message so I don't expect that I can set the UsrPOTranAmt either with this event.
If you have not changed the default behavior of the Grid column of CommitChanges to True, it will not cause the postback and call the event. Give that a try.
The commitChanges is definitely required on a filed updated event, but here is the solution from ACM:
public class APTranExt : PXCacheExtension<PX.Objects.AP.APTran>
{
#region UsrPOTranAmt
[PXDecimal]
[PXUIField(DisplayName = "POTranAmt", Enabled = false)]
[PXDBScalar(typeof(Search<POLine.curyLineAmt,
Where<POLine.orderType, Equal<APTran.pOOrderType>,
And<POLine.orderNbr, Equal<APTran.pONbr>,
And<POLine.lineNbr, Equal<APTran.pOLineNbr>>>>>))]
public virtual Decimal? UsrPOTranAmt { get; set; }
public abstract class usrPOTranAmt : PX.Data.BQL.BqlDecimal.Field<usrPOTranAmt> { }
#endregion
}
public class APInvoiceEntry_Extension : PXGraphExtension<APInvoiceEntry>
{
#region Event Handlers
protected void APTran_RowUpdated(PXCache cache, PXRowUpdatedEventArgs e, PXRowUpdated InvokeBaseHandler)
{
if (InvokeBaseHandler != null)
InvokeBaseHandler(cache, e);
var row = (APTran)e.Row;
if(row != null && row.POOrderType != null && row.PONbr != null && row.POLineNbr != null)
{
POLine poline = PXSelect<POLine,
Where<POLine.orderType, Equal<Required<POLine.orderType>>,
And<POLine.orderNbr, Equal<Required<POLine.orderNbr>>,
And<POLine.lineNbr, Equal<Required<POLine.lineNbr>>>>>>.Select(Base, row.POOrderType, row.PONbr, row.POLineNbr);
if(poline != null)
{
cache.SetValue(row, "UsrPOTranAmt", poline.CuryLineAmt);
}
}
}
#endregion
}

Change label name of default fields

I want to show which user created Invoice, for this i have added default Acumatica field, but the label is showing as Created By, how can i change that label name to "Invoice Created By". Please have a look at below screenshot for field am referring to.
You could use PXUIFieldAttribute.SetDisplayName static method to change DAC field’s display name. This change will be applicable only for Sales Invoice Entry Graph (SO303000 screen)
public class SOInvoiceEntryPXDemoExt : PXGraphExtension<SOInvoiceEntry>
{
public override void Initialize()
{
PXUIFieldAttribute.SetDisplayName<ARInvoice.createdByID>(Base.Document.Cache, "Invoice Created By");
}
}
If you need display name changed for this field in all screens, you need to have DAC Extension as below:
With this, attributes specified in an extension DAC apply to DAC class in every Graph of the application unless a Graph replaces them with other attributes.
public class ARInvoicePXDemoExt : PXCacheExtension<ARInvoice>
{
[PXMergeAttributes(Method = MergeMethod.Append)]
[PXUIField(DisplayName = "Invoice Created By", Enabled = false, IsReadOnly = true)]
public virtual Guid? CreatedByID { get; set; }
}
You need to add CreatedByID field on screen SO303000
And set DisplayMode property to Text.
The 'CreatedByID' I believe is an audit field and therefore cannot easily change the ui of the additional data fields available through the control. The resolution I would suggest is a non database backed UI field that is populated during row selecting. Example can be found below :
public class SOOrderEntryExtension : PXGraphExtension<SOOrderEntry>
{
public virtual void SOOrder_RowSelecting(PXCache sender, PXRowSelectingEventArgs e)
{
SOOrder row = e.Row as SOOrder;
if(row != null)
{
SOOrderExtension rowExt = PXCache<SOOrder>.GetExtension<SOOrderExtension>(row);
Users user = PXSelectReadonly<Users, Where<Users.pKID, Equal<Required<Users.pKID>>>>.Select(this.Base, row.CreatedByID);
if(user != null)
{
rowExt.InvoiceCreatedBy = user.DisplayName;
}
}
}
}
public class SOOrderExtension : PXCacheExtension<SOOrder>
{
public abstract class invoiceCreatedBy : PX.Data.IBqlField
{
}
[PXString]
[PXUIField(DisplayName = "Invoice Created By")]
public virtual string InvoiceCreatedBy { get; set; }
}

How can I show QtyOnHand field(in IN402000) to the PO detail grid in PO301000

How can I show QtyOnHand in IN402000 to the PO 301000 detail grid?
The POLine DAC already has a "QtyAvail (Qty on Hand)" field. You would simply need to create a customization project, add the screen, navigate to the Grid: Transactions and add the Control for the field to the screen & publish.
If you need to add the field to PO Line and the Quantity Available from INItemStatus would suffice you could add it with:
using System;
using PX.Data;
using PX.Objects.PO;
using PX.Objects.IN;
public class POLine_Extension : PXCacheExtension<POLine> {
[PXDecimal]
[PXUIField(DisplayName = "Qty Avail", Enabled = false)]
[PXDBScalar(typeof(
Search<INSiteStatus.qtyAvail,
Where<INSiteStatus.inventoryID, Equal<POLine.inventoryID>,
And<INSiteStatus.siteID, Equal<POLine.siteID>>>>))]
public virtual decimal? QtyAvail { get; set; }
public abstract class qtyAvail : IBqlField {}
}
Then the PXDBScalar fields have their values set when the DAC is Selected. There's probably a better way this could be done, but to populate the field as lines are added & updated to the PO within a POOrderEntry graph extension, you could handle the FieldUpdated events for the InventoryID and SiteID to execute a function that retrieves the Qty Available using basically the same BQL and sets that value to the DAC extension field.
public class POOrderEntry_Extension : PXGraphExtension<POOrderEntry>
{
public virtual void POLine_InventoryID_FieldUpdated(PXCache sender, PXFieldUpdatedEventArgs e)
{
UpdateQtyAvailable(sender, e);
}
public virtual void POLine_SiteID_FieldUpdated(PXCache sender, PXFieldUpdatedEventArgs e)
{
UpdateQtyAvailable(sender, e);
}
private void UpdateQtyAvailable(PXCache sender, PXFieldUpdatedEventArgs e)
{
if (e.Row == null) return;
POLine row = (POLine)e.Row;
foreach(INSiteStatus siteStatus in PXSelect<INSiteStatus,
Where<INSiteStatus.inventoryID, Equal<Required<INSiteStatus.inventoryID>>,
And<INSiteStatus.siteID, Equal<Required<INSiteStatus.siteID>>>>>.Select(sender.Graph, row.InventoryID, row.SiteID))
{
sender.SetValueExt<POLine_Extension.qtyAvail>(row, siteStatus.QtyAvail);
}
}
}

Resources