Skip to main content
Question

Auto Post Check and Payment doesn't generate Project Transaction

  • 16 February 2024
  • 3 replies
  • 39 views

Forum|alt.badge.img

I do customization on Release of Check and Payment with the goal:

  • When the exchange of currency change, the amount of gain (or loss) will be link to an account
    • Gain mean: the additional revenue which come from the rate of currency → link to account 635
    • Loss mean: the money we loss because of rate of currency → link to account 515
  • This amount of money will be tracked in Project information

For example: I have a Check and Payment Record as following: The cross rate is 26.000 (which is higher than the exchange currency in Bill and Adjustment)

  1. Then release this one will generate a GL transaction as following:
     

    Note: there is a row for Account 635 which include information from APBill and APPayment → this is what I customize

  2. Post GL Transaction: As a result, there is a Project Transactions generated 
     

  3. This cost will be tracked in Project Cost Budget
     

     

However, When I turn on Auto Post on Release, There is no Project Transaction being generated. It leads to the cost isn’t statistical in Project cost budget.

 

Here is the code of my customization

using PX.Common;
using PX.Data;
using PX.Objects.GL;
using System.Collections;

namespace PX.Objects.AP
{
    // Acuminator disable once PX1016 ExtensionDoesNotDeclareIsActiveMethod extension should be constantly active
    public class APPaymentEntry_Extension : PXGraphExtension<APPaymentEntry>
    {
        #region Event Handlers
        protected class ProcessBatch : IPrefetchable
        {
            private Batch _Batch;
            public Batch Batch
            {
                get
                {
                    return _Batch;
                }
            }
            public ProcessBatch(Batch batch)
            {
                _Batch = batch;
            }
            void IPrefetchable.Prefetch()
            {
            }
        }
        protected class ProcessTran : IPrefetchable
        {
            private GLTran _Tran;
            public GLTran Tran
            {
                get
                {
                    return _Tran;
                }
            }
            private int? _SubID;
            private int? _ProjectID;
            private int? _TaskID;
            public int? SubID
            {
                get
                {
                    return _SubID;
                }
            }
            public int? ProjectID
            {
                get
                {
                    return _ProjectID;
                }
            }
            public int? TaskID
            {
                get
                {
                    return _TaskID;
                }
            }
            public ProcessTran(GLTran tran, int? subID, int? projectID, int? taskID)
            {
                _Tran = tran;
                _SubID = subID;
                _ProjectID = projectID;
                _TaskID = taskID;
            }
            void IPrefetchable.Prefetch()
            {
            }
        }

        private void PopulateFromAPTran(PXCache cache, PXRowPersistingEventArgs args, bool storeInSlot = false)
        {
            var tran = (GLTran)args.Row;
            if (tran == null || args.Operation != PXDBOperation.Insert || tran.Module != BatchModule.AP) return;
            if (storeInSlot)
            {
                PXContext.SetSlot<ProcessTran>(new ProcessTran(tran, tran.SubID, tran.ProjectID, tran.TaskID));
            }
            else
            {
                ProcessTran processTran = PXContext.GetSlot<ProcessTran>();
                if (processTran != null && tran == processTran.Tran)
                {
                    tran.SubID = processTran.SubID;
                    tran.ProjectID = processTran.ProjectID;
                    tran.TaskID = processTran.TaskID;
                }
            }
            var account = (Account)PXSelectorAttribute.Select<GLTran.accountID>(cache, tran);
            //Account account = PXSelect<Account, Where<Account.accountID, Equal<Required<Account.accountID>>>>.Select(Base, tran.AccountID);
            // if account is null or Account isn't 635, 515 -> Skip handling.
            if (account == null || (account.AccountClassID != "515" && account.AccountClassID != "635")) return;
            var currentSub = (Sub)PXSelectorAttribute.Select<GLTran.subID>(cache, tran);
            //Sub currentSub = PXSelect<Sub, Where<Sub.subID, Equal<Required<Sub.subID>>>>.Select(Base, tran.SubID);
            if (currentSub == null || currentSub.SubCD != "000000000000") return;
            // populate SubID from Bill and Adjustment to GLTran
            // find index of GLTran Gain and Lost
            var docOrder = 0;
            var secondGainAndLostClassID = account.AccountClassID == "515" ? "635" : "515";
            Account secondGainAndLostAcc = PXSelect<Account, Where<Account.accountClassID, Equal<Required<Account.accountClassID>>>>.Select(Base, secondGainAndLostClassID);
            if (secondGainAndLostAcc != null)
            {
                PXResultset<GLTran> glTranGainAndLost = PXSelect<GLTran,
                                    Where<GLTran.batchNbr, Equal<Required<GLTran.batchNbr>>,
                                        And<GLTran.lineNbr, NotEqual<Required<GLTran.lineNbr>>, And<Where<GLTran.accountID, Equal<Required<GLTran.accountID>>,
                                                Or<GLTran.accountID, Equal<Required<GLTran.accountID>>>>>>>>
                                    .Select(Base, tran.BatchNbr, tran.LineNbr, account.AccountID, secondGainAndLostAcc.AccountID);
                docOrder = glTranGainAndLost.Count;
            }
            else
            {
                PXResultset<GLTran> glTranGainAndLost = PXSelect<GLTran,
                                    Where<GLTran.batchNbr, Equal<Required<GLTran.batchNbr>>,
                                        And<GLTran.accountID, Equal<Required<GLTran.accountID>>>>>
                                    .Select(Base, tran.BatchNbr, account.AccountID);
                docOrder = glTranGainAndLost.Count;
            }

            // Get list Bill and Adjustment
            PXResultset<APAdjust> documentLines = PXSelect<APAdjust, Where<APAdjust.adjgRefNbr, Equal<Required<APPayment.refNbr>>>>.Select(Base, tran.RefNbr);
            if (documentLines.Count <= docOrder) return;
            APAdjust docLine = documentLines[docOrder];
            //get first row of detail tab
            APTran firstLine = PXSelect<APTran, Where<APTran.refNbr, Equal<Required<APTran.refNbr>>>, OrderBy<Asc<APTran.lineNbr>>>.Select(Base, docLine.AdjdRefNbr);
            if (firstLine == null) return;
            if (!firstLine.SubID.HasValue && !firstLine.ProjectID.HasValue && !firstLine.TaskID.HasValue) return;
            if (firstLine.SubID.HasValue)
            {
                // get sub CD of APTran
                var orgSub = (Sub)PXSelectorAttribute.Select<APTran.subID>(cache, firstLine);
                //Sub orgSub = PXSelect<Sub, Where<Sub.subID, Equal<Required<Sub.subID>>>>.Select(Base, firstLine.SubID);
                if (orgSub != null)
                {
                    // find Sub by SubCD
                    var newSubCD = orgSub.SubCD.Substring(0, orgSub.SubCD.Length - "CC22".Length) + "CC22";
                    Sub newSub = PXSelect<Sub, Where<Sub.subCD, Equal<Required<Sub.subCD>>>>.Select(Base, newSubCD);
                    if (newSub == null)
                    {
                        // newSubCD doesn't exist yet. Set SubCD to TranDesc temporary so that it could be created in RowPersisting event handler
                        Sub sub = new Sub
                        {
                            SubCD = newSubCD
                        };
                        PXCache<Sub> subCache = new PXCache<Sub>(Base);
                        sub = subCache.Insert(sub) as Sub;
                        Base.Caches[typeof(Sub)].PersistInserted(sub);
                        if (sub != null)
                        {
                            tran.SubID = sub.SubID;
                            tran.OrigSubID = sub.SubID;
                        }
                    }
                    else
                    {
                        // newSubCD exist. Add link to Tran
                        tran.SubID = newSub.SubID;
                        tran.OrigSubID = newSub.SubID;
                    }
                    if (firstLine.ProjectID.HasValue)
                    {
                        tran.ProjectID = firstLine.ProjectID;
                    }
                    if (firstLine.TaskID.HasValue)
                    {
                        tran.TaskID = firstLine.TaskID;
                    }
                }
            }

            cache.Update(tran);
        }

        public PXAction<APPayment> release;
        [PXUIField(DisplayName = "Release", MapEnableRights = PXCacheRights.Update, MapViewRights = PXCacheRights.Update)]
        [PXProcessButton]
        public IEnumerable Release(PXAdapter adapter)
        {
            PXGraph.InstanceCreated.AddHandler<JournalEntry>((graph) =>
            {
                //graph.RowInserting.AddHandler<GLTran>((cache, args) =>
                //{
                //    PopulateFromAPTran(cache, args, true);
                //});
                graph.RowPersisting.AddHandler<GLTran>((cache, args) =>
                {
                    PopulateFromAPTran(cache, args);
                });
            });
            PXGraph.InstanceCreated.AddHandler<JournalEntry>((graph) =>
            {
                graph.RowInserting.AddHandler<Batch>((cache, args) =>
                {
                    PXContext.SetSlot<ProcessBatch>(null);
                });
            });
            PXGraph.InstanceCreated.AddHandler<JournalEntry>((graph) =>
            {
                graph.RowPersisted.AddHandler<Batch>((cache, args) =>
                {
                    if (args.TranStatus == PXTranStatus.Completed)
                    {
                        PXContext.SetSlot<ProcessBatch>(
                        new ProcessBatch((Batch)args.Row));
                    }
                });
            });
            return Base.release.Press(adapter);
        }

        #endregion
    }
}

 

Thank you in advance,

Khoi

3 replies

Laura02
Captain II
Forum|alt.badge.img+19
  • Captain II
  • 3135 replies
  • February 16, 2024

Hello,

Does the Currency Gain or Loss account have an Account Group connected in Finance → Chart of Accounts screen?

Ability to add Project to a transaction is controlled by Account Group

Laura


Forum|alt.badge.img
  • Author
  • Jr Varsity II
  • 85 replies
  • February 23, 2024

hello @Laura02,

Yes, it connected to a certain Account Group.

 

 


Chris Hackett
Community Manager
Forum|alt.badge.img
  • Acumatica Community Manager
  • 2654 replies
  • April 1, 2024

Hi @mrthanhkhoi were you able to find a solution? Thank you!


Reply


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings