Skip to main content
Answer

Change the transaction description of invoices created with multiple installment credit terms (Build 2024.2)

  • November 21, 2025
  • 6 replies
  • 74 views

Is it possible to change the Transaction Description (ARTran.TranDesc) for the invoices created when using Credit Terms with the Multiple Installment Type?

Currently it generates the invoices with “Multiple Installment Split” as the description. Ideally, we’d like it to either copy the transaction description from the original invoice or not automatically post the invoice so that we have the opportunity to manually adjust the description (i.e. maybe we’d write 1st Installment/2nd Installment/etc., or Installment for Dec-2025/Installment for Jan-2026/etc.).

I reviewed the discussion on an earlier thread, but as that was a previous version I was asked to start a new thread. Change the transaction description of Invoices created with multiple installment credit terms | Community

 

Best answer by aleksandrsechin

​Hi @natwi 
Here is how you can implement the logic I described above using a low-code approach through the Customization Project Editor:


 Then, in the opened form, replace the code template with the following complete code snippet:

using PX.Data;
using PX.Data.BQL;
using PX.Data.BQL.Fluent;
using PX.Objects.AR;
using PX.Objects.CS;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Test
{
public class ARReleaseProcessExt : PXGraphExtension<PX.Objects.AR.ARReleaseProcess>
{
[PXOverride]
public virtual List<ARRegister> CreateInstallments(
PXResult<ARInvoice, PX.Objects.CM.Extensions.CurrencyInfo, Terms, Customer> res,
Func<PXResult<ARInvoice, PX.Objects.CM.Extensions.CurrencyInfo, Terms, Customer>,
List<ARRegister>> baseMethod)
{
var results = baseMethod(res);

var firstRegister = results.FirstOrDefault();
var firstInvoice = ARInvoice.PK.Find(Base, firstRegister.DocType, firstRegister.RefNbr);
var masterTran = new SelectFrom<ARTran>
.Where<ARTran.tranType.IsEqual<@P.AsString>
.And<ARTran.refNbr.IsEqual<@P.AsString>>>
.View(Base)
.SelectSingle(firstInvoice.DocType, firstInvoice.MasterRefNbr);

foreach (var register in results)
{
var installmentTran = new SelectFrom<ARTran>
.Where<ARTran.tranType.IsEqual<@P.AsString>
.And<ARTran.refNbr.IsEqual<@P.AsString>>>
.View(Base)
.SelectSingle(register.DocType, register.RefNbr);

installmentTran.TranDesc = masterTran.TranDesc;

Base.Caches[typeof(ARTran)].Update(installmentTran);
}

return results;
}
}
}

And do the same for this code snippet:

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

namespace Test
{
public class ARInvoiceEntry_Extension : PXGraphExtension<PX.Objects.AR.ARInvoiceEntry>
{
protected virtual void _(Events.RowSelected<ARInvoice> e)
{
if (!(e.Row is ARInvoice row)) return;

var cache = Base.Transactions.Cache;

if (row.Released.GetValueOrDefault())
{
Base.Transactions.Cache.AllowUpdate = true;
PXUIFieldAttribute.SetEnabled(cache, null, false);
PXUIFieldAttribute.SetEnabled<ARTran.tranDesc>(cache, null, true);
}
}
}
}

FYI: this code is based on version 25R2. If you are using a different version, you may encounter additional issues. If you are unable to publish your customization, feel free to share the Acumatica version you’re using along with the errors you’re getting — we’ll help adjust the code.
The code snippets above should generally work for you, but if anything doesn’t, we can correct the logic to achieve the result you need.

6 replies

Forum|alt.badge.img+3

Hi ​@natwi 

To override the transaction description, you can override the CreateInstallments method as follows:

public class ARReleaseProcessExt : PXGraphExtension<PX.Objects.AR.ARReleaseProcess>
{
[PXOverride]
public virtual List<ARRegister> CreateInstallments(
PXResult<ARInvoice, PX.Objects.CM.Extensions.CurrencyInfo, Terms, Customer> res,
Func<PXResult<ARInvoice, PX.Objects.CM.Extensions.CurrencyInfo, Terms, Customer>,
List<ARRegister>> baseMethod)
{
var results = baseMethod(res);

var firstRegister = results.FirstOrDefault();
var firstInvoice = ARInvoice.PK.Find(Base, firstRegister.DocType, firstRegister.RefNbr);
var masterTran = new SelectFrom<ARTran>
.Where<ARTran.tranType.IsEqual<@P.AsString>
.And<ARTran.refNbr.IsEqual<@P.AsString>>>
.View(Base)
.SelectSingle(firstInvoice.DocType, firstInvoice.MasterRefNbr);

foreach (var register in results)
{
var installmentTran = new SelectFrom<ARTran>
.Where<ARTran.tranType.IsEqual<@P.AsString>
.And<ARTran.refNbr.IsEqual<@P.AsString>>>
.View(Base)
.SelectSingle(register.DocType, register.RefNbr);

installmentTran.TranDesc = masterTran.TranDesc;

Base.Caches[typeof(ARTran)].Update(installmentTran);
}

return results;
}
}

Here you:

  • invoke the base method and get the results (the Installment ARRegisters you created);

  • select the master (original) transaction by the MasterRefNbr value;

  • set the installment transaction description using the master transaction.

As far as I have noticed, the Installment Invoices contain only one transaction (I didn’t dig deeper into the business logic), which is why I used SelectSingle to get the transaction. However, you can adjust the code if you need to handle additional cases.

Original Invoice
Installment

Additionally, if you want to allow users to manually adjust the description after the installments are generated, you can enable your field in the RowSelected event handler as follows:

public class ARInvoiceEntry_Extension : PXGraphExtension<PX.Objects.AR.ARInvoiceEntry>
{
protected virtual void _(Events.RowSelected<ARInvoice> e)
{
if (!(e.Row is ARInvoice row)) return;

var cache = Base.Transactions.Cache;

if (myCondition && row.Released.GetValueOrDefault())
{
Base.Transactions.Cache.AllowUpdate = true;
PXUIFieldAttribute.SetEnabled(cache, null, false);
PXUIFieldAttribute.SetEnabled<ARTran.tranDesc>(cache, null, true);
}
}
}

 


  • Author
  • Freshman I
  • November 24, 2025

Hi ​@natwi 

To override the transaction description, you can override the CreateInstallments method as follows:

public class ARReleaseProcessExt : PXGraphExtension<PX.Objects.AR.ARReleaseProcess>
{
[PXOverride]
public virtual List<ARRegister> CreateInstallments(
PXResult<ARInvoice, PX.Objects.CM.Extensions.CurrencyInfo, Terms, Customer> res,
Func<PXResult<ARInvoice, PX.Objects.CM.Extensions.CurrencyInfo, Terms, Customer>,
List<ARRegister>> baseMethod)
{
var results = baseMethod(res);

var firstRegister = results.FirstOrDefault();
var firstInvoice = ARInvoice.PK.Find(Base, firstRegister.DocType, firstRegister.RefNbr);
var masterTran = new SelectFrom<ARTran>
.Where<ARTran.tranType.IsEqual<@P.AsString>
.And<ARTran.refNbr.IsEqual<@P.AsString>>>
.View(Base)
.SelectSingle(firstInvoice.DocType, firstInvoice.MasterRefNbr);

foreach (var register in results)
{
var installmentTran = new SelectFrom<ARTran>
.Where<ARTran.tranType.IsEqual<@P.AsString>
.And<ARTran.refNbr.IsEqual<@P.AsString>>>
.View(Base)
.SelectSingle(register.DocType, register.RefNbr);

installmentTran.TranDesc = masterTran.TranDesc;

Base.Caches[typeof(ARTran)].Update(installmentTran);
}

return results;
}
}

 

Thanks ​@aleksandrsechin - I have a skills gap in that I am not sure how/where to override methods. I am comfortable with the code, but in Acumatica project customisations I have mostly only completed low/no code changes. If you could point me in the right direction for updating this please (or learning material if it’s not a simple answer), thank you.


Forum|alt.badge.img+3

​Hi @natwi 
Here is how you can implement the logic I described above using a low-code approach through the Customization Project Editor:


 Then, in the opened form, replace the code template with the following complete code snippet:

using PX.Data;
using PX.Data.BQL;
using PX.Data.BQL.Fluent;
using PX.Objects.AR;
using PX.Objects.CS;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Test
{
public class ARReleaseProcessExt : PXGraphExtension<PX.Objects.AR.ARReleaseProcess>
{
[PXOverride]
public virtual List<ARRegister> CreateInstallments(
PXResult<ARInvoice, PX.Objects.CM.Extensions.CurrencyInfo, Terms, Customer> res,
Func<PXResult<ARInvoice, PX.Objects.CM.Extensions.CurrencyInfo, Terms, Customer>,
List<ARRegister>> baseMethod)
{
var results = baseMethod(res);

var firstRegister = results.FirstOrDefault();
var firstInvoice = ARInvoice.PK.Find(Base, firstRegister.DocType, firstRegister.RefNbr);
var masterTran = new SelectFrom<ARTran>
.Where<ARTran.tranType.IsEqual<@P.AsString>
.And<ARTran.refNbr.IsEqual<@P.AsString>>>
.View(Base)
.SelectSingle(firstInvoice.DocType, firstInvoice.MasterRefNbr);

foreach (var register in results)
{
var installmentTran = new SelectFrom<ARTran>
.Where<ARTran.tranType.IsEqual<@P.AsString>
.And<ARTran.refNbr.IsEqual<@P.AsString>>>
.View(Base)
.SelectSingle(register.DocType, register.RefNbr);

installmentTran.TranDesc = masterTran.TranDesc;

Base.Caches[typeof(ARTran)].Update(installmentTran);
}

return results;
}
}
}

And do the same for this code snippet:

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

namespace Test
{
public class ARInvoiceEntry_Extension : PXGraphExtension<PX.Objects.AR.ARInvoiceEntry>
{
protected virtual void _(Events.RowSelected<ARInvoice> e)
{
if (!(e.Row is ARInvoice row)) return;

var cache = Base.Transactions.Cache;

if (row.Released.GetValueOrDefault())
{
Base.Transactions.Cache.AllowUpdate = true;
PXUIFieldAttribute.SetEnabled(cache, null, false);
PXUIFieldAttribute.SetEnabled<ARTran.tranDesc>(cache, null, true);
}
}
}
}

FYI: this code is based on version 25R2. If you are using a different version, you may encounter additional issues. If you are unable to publish your customization, feel free to share the Acumatica version you’re using along with the errors you’re getting — we’ll help adjust the code.
The code snippets above should generally work for you, but if anything doesn’t, we can correct the logic to achieve the result you need.


Forum|alt.badge.img
  • Jr Varsity III
  • December 2, 2025

Dovetailing on this, can this also be done for the intercompany transactions?

Currently the transaction description is “Balancing entry for: BRANCH” but the branch is the same branch that the transaction posts to.  It would be more helpful to people reviewing the general ledger transactions to know what branch that the balancing entry was from.  

These two descriptions should be swapped to be useful:

It is not helpful to see PRODWHOLE has a transaction that is a balancing entry for PRODWHOLE.  It would be more useful to the person reviewing the transaction to know that the branch PRODWHOLE has a balancing entry that came from PRODRETAIL. 


Forum|alt.badge.img+3

Hi ​@rena98 
Probably yes, but I think it would be better to create a separate topic for this issue with more detailed information, since it differs from the current one.


Forum|alt.badge.img
  • Jr Varsity III
  • December 3, 2025

Hi ​@rena98 
Probably yes, but I think it would be better to create a separate topic for this issue with more detailed information, since it differs from the current one.

I did, thanks!  Change the transaction description for intercompany balancing entries | Community