Skip to main content
Question

Display Custom fields on Revenue Budget Tab (Project Screen)

  • October 28, 2025
  • 0 replies
  • 29 views

Hello 

I am new here and currently looking for feedback on my approach:
Scenario: When a user pays the invoice.
Fig a: Invoice Screen:



Ask: On the Revenue Budget tab under the project, , I need to display the following  through a user-defined field.

 

 

  • Display “Total Units Paid” : reflecting the quantity for which invoice payment has been received from the customer.
  • Display “Total Amount Paid” : representing the corresponding total value.
  • Display “Difference in Units” ( Budgeted – Paid) : showing the variance between total billed units and total paid units.

I would appreciate if someone could provide feedback on my approach as I am bit lost.


DAC:

using PX.Data;
using PX.Objects.AR;

namespace PX.Objects.PM
{

//Total Units Paid

        #region UsrUnitsPaid
        [PXString(50)]
        [PXUIField(DisplayName = "Units Paid")]
        public  string UsrUnitsPaid{ get; set; }
        public abstract class usrUnitsPaid: PX.Data.BQL.BqlString.Field<usrUnitsPaid> { }
        #endregion 

//Total Amount Paid

        #region UsrAmtPaid
        [PXString(50)]
        [PXUIField(DisplayName = "Amount Paid")]
        public  string UsrAmtPaid{ get; set; }
        public abstract class usrAmtPaid: PX.Data.BQL.BqlString.Field<usrAmtPaid> { }
        #endregion 

//Difference in Units

        #region UsrPendingUnits
        [PXString(50)]
        [PXUIField(DisplayName = "Out Standing Units")]
        public  string UsrPendingUnits{ get; set; }
        public abstract class usrPendingUnits: PX.Data.BQL.BqlString.Field<usrPendingUnits> { }
        #endregion 

}

 

Observation: I see invoice method in exisiitng Invoice in base class code

        public virtual IEnumerable invoices()
        {
            var manualInvoiceSelect = new PXSelectReadonly2<ARInvoice,
                LeftJoin<PMBillingRecord, On<ARInvoice.docType, Equal<PMBillingRecord.aRDocType>, And<ARInvoice.refNbr, Equal<PMBillingRecord.aRRefNbr>>>,
                LeftJoin<PMProforma, On<ARInvoice.docType, Equal<PMProforma.aRInvoiceDocType>, And<ARInvoice.refNbr, Equal<PMProforma.aRInvoiceRefNbr>>>>>,
                Where<PMBillingRecord.recordID, IsNull, And<ARInvoice.projectID, Equal<Current<PMProject.contractID>>>>>(this);

            var manualResult = manualInvoiceSelect.Select();

            if (manualResult.Count == 0)
            {
                var view = new PXView(this, false, Invoices.View.BqlSelect);
                var startRow = PXView.StartRow;
                int totalRows = 0;

                var list = view.Select(PXView.Currents, PXView.Parameters, PXView.Searches, PXView.SortColumns, PXView.Descendings, PXView.Filters,
                                       ref startRow, PXView.MaximumRows, ref totalRows);

                PXView.StartRow = 0;

                return list;
            }
            else
            {
                HashSet<string> added = new HashSet<string>();

                var autoInvoicesSelect = new PXSelectReadonly2<PMBillingRecord,
                    LeftJoin<PMProforma, On<PMProforma.refNbr, Equal<PMBillingRecord.proformaRefNbr>, And<PMProforma.corrected, Equal<False>>>,
                    LeftJoin<ARInvoice, On<ARInvoice.docType, Equal<PMBillingRecord.aRDocType>, And<ARInvoice.refNbr, Equal<PMBillingRecord.aRRefNbr>>>>>,
                    Where<PMBillingRecord.projectID, Equal<Current<PMProject.contractID>>>>(this);

                PXResultset<PMBillingRecord> rs = autoInvoicesSelect.Select();

                List<PXResult<PMBillingRecord, PMProforma, ARInvoice>> list = new List<PXResult<PMBillingRecord, PMProforma, ARInvoice>>(rs.Count + manualResult.Count);
                foreach (PXResult<PMBillingRecord, PMProforma, ARInvoice> record in rs)
                {
                    ARInvoice invoice = record;
                    if (!string.IsNullOrEmpty(invoice.RefNbr))
                    {
                        added.Add(string.Format("{0}.{1}", invoice.DocType, invoice.RefNbr));
                    }

                    list.Add(record);
                }

                int cx = -1;
                foreach (PXResult<ARInvoice, PMBillingRecord, PMProforma> record in manualResult)
                {
                    var ar = (ARInvoice)record;
                    var br = (PMBillingRecord)record;
                    var proforma = (PMProforma)record;
                    var hasProforma = !string.IsNullOrEmpty(proforma?.RefNbr)
                        && br.ARDocType == ar.DocType
                        && br.ARRefNbr == ar.RefNbr
                        && proforma?.Corrected != true;

                    if (added.Contains(string.Format("{0}.{1}", ar.DocType, ar.RefNbr)))
                        continue;

                    if (string.IsNullOrEmpty(br.ARDocType))
                    {
                        br.ARDocType = ar.DocType;
                        br.ARRefNbr = ar.RefNbr;
                        br.RecordID = cx--;
                        br.BillingTag = "P";
                        br.ProjectID = ar.ProjectID;
                    }

                    if (hasProforma)
                    {
                        br.ProformaRefNbr = proforma.RefNbr;
                    }

                    list.Add(new PXResult<PMBillingRecord, PMProforma, ARInvoice>(
                        br,
                        hasProforma ? proforma : new PMProforma(),
                        ar));
                }

                var order = 0;
                var isDirty = Invoices.Cache.IsDirty;
                foreach (var item in list)
                {
                    var record = (PMBillingRecord)item;
                    record.SortOrder = ++order;

                    Invoices.Cache.SetStatus(record, PXEntryStatus.Held);
                }
                Invoices.Cache.IsDirty = isDirty;
                return list;
            }
        }


Question :

I want to know if we can use, the above base method and find a way to query the Invoice.

Graph Extension:
namespace PX.Objects.PM
{
    public class ProjectEntryExtension : PXGraphExtension<ProjectEntry>
    {

        public delegate IEnumerable InvoicesDelegate();

        [PXOverride]
        public virtual IEnumerable invoices(InvoicesDelegate baseMethod)
        {
            var invoiceList = baseMethod();
            foreach (PXResult<ARInvoice> record in invoiceList)
            {
                  //assign the values to custom DAC

            }

   }
}
Looking for feedback on the correct approach