/// <summary> /// Helper class to reverse project invoice voucher transactions and match those, which relates to customer /// </summary> class VKProjectInvoicePostingHelper { LedgerJournalTrans paymLedgerJournalTrans; /// <summary> /// Entry point to execute reversal and matching process /// </summary> /// <param name = "_projProposalJour">ProjProposalJour record</param> public void reverseTranasctions(ProjProposalJour _projProposalJour) { setPrefix("Invoice reversal process"); if (_projProposalJour && _projProposalJour.ProjInvoiceId) { ProjInvoiceJour projInvoiceJour = ProjInvoiceJour::find(_projProposalJour.ProjInvoiceId, _projProposalJour.InvoiceDate); LedgerJournalTable ledgerJournalTable = this.createJournal(projInvoiceJour); if (ledgerJournalTable) { info(strFmt("Reversing general journal %1", ledgerJournalTable.JournalNum)); this.postGeneralJournal(ledgerJournalTable); this.settleTransactions(projInvoiceJour, paymledgerJournalTrans); } } } /// <summary> /// Creates general journal based on project invoice voucher transactions /// </summary> /// <param name = "_projInvoiceJour">ProjInvoiceJour record</param> /// <returns>LedgerJournalTable record</returns> public LedgerJournalTable createJournal(ProjInvoiceJour _projInvoiceJour) { GeneralJournalEntry generalJournalEntry; GeneralJournalAccountEntry generalJournalAccountEntry; LedgerJournalTable ledgerJournalTable; LedgerJournalTrans ledgerJournalTrans; while select generalJournalEntry where generalJournalEntry.SubledgerVoucher == _projInvoiceJour.LedgerVoucher join generalJournalAccountEntry where generalJournalAccountEntry.GeneralJournalEntry == generalJournalEntry.RecId { if (!ledgerJournalTable) { ledgerJournalTable = this.createJournalHeader(_projInvoiceJour); } ledgerJournalTrans.clear(); ledgerJournalTrans.JournalNum = ledgerJournalTable.JournalNum; ledgerJournalTrans.TransDate = _projInvoiceJour.InvoiceDate; if (LedgerPostingType::CustBalance == generalJournalAccountEntry.PostingType) { ledgerJournalTrans.AccountType = LedgerJournalACType::Cust; ledgerJournalTrans.LedgerDimension = LedgerDynamicAccountHelper::getDynamicAccountFromAccountNumber(_projInvoiceJour.InvoiceAccount, ledgerJournalTrans.AccountType); ledgerJournalTrans.DefaultDimension = LedgerDimensionFacade::getDefaultDimensionFromLedgerDimension(generalJournalAccountEntry.LedgerDimension); } else { ledgerJournalTrans.AccountType = LedgerJournalACType::Ledger; ledgerJournalTrans.LedgerDimension = generalJournalAccountEntry.LedgerDimension; } if (LedgerPostingType::Tax == generalJournalAccountEntry.PostingType) { TaxTrans taxTrans; select firstonly taxTrans where taxTrans.Voucher == _projInvoiceJour.LedgerVoucher &&taxTrans.TransDate == generalJournalEntry.AccountingDate &&taxTrans.SourceCurrencyCode == generalJournalAccountEntry.TransactionCurrencyCode &&taxTrans.SourceTaxAmountCur == generalJournalAccountEntry.TransactionCurrencyAmount; if (taxTrans) { ledgerJournalTrans.TaxGroup = taxTrans.TaxGroup; ledgerJournalTrans.TaxItemGroup = taxTrans.TaxItemGroup; ledgerJournalTrans.TaxCode = taxTrans.TaxCode; } } //ledgerJournalTrans.OffsetAccountType = ledgerJournalTransOrig.OffsetAccountType; //ledgerJournalTrans.OffsetLedgerDimension = ledgerJournalTransOrig.OffsetLedgerDimension; //ledgerJournalTrans.OffsetDefaultDimension = ledgerJournalTransOrig.OffsetDefaultDimension; ledgerJournalTrans.CurrencyCode = _projInvoiceJour.CurrencyId; if (generalJournalAccountEntry.IsCredit) { ledgerJournalTrans.AmountCurDebit = abs(generalJournalAccountEntry.AccountingCurrencyAmount); } else { ledgerJournalTrans.AmountCurCredit = abs(generalJournalAccountEntry.AccountingCurrencyAmount); } //addition fields //ledgerJournalTrans.Approver = HcmWorker::userId2Worker(curuserid()); //ledgerJournalTrans.Approved = NoYes::Yes; ledgerJournalTrans.Txt = strFmt("Reverse invoice %1", _projInvoiceJour.ProjInvoiceId); ledgerJournalTrans.SkipBlockedForManualEntryCheck = true; ledgerJournalTrans.defaultRow(); ledgerJournalTrans.insert(); if (LedgerPostingType::CustBalance == generalJournalAccountEntry.PostingType) { paymledgerJournalTrans.data(ledgerJournalTrans); } } return ledgerJournalTable; } /// <summary> /// Creates general journal header /// </summary> /// <param name = "_projInvoiceJour">ProjInvoiceJour record</param> /// <returns>LedgerJournalTable record</returns> public LedgerJournalTable createJournalHeader(ProjInvoiceJour _projInvoiceJour) { ProjParameters projParameters = ProjParameters::find(); LedgerJournalTable ledgerJournalTable; if (!projParameters.VKJournalName) { throw Error("Please specify project sales invoice reversal general journal name"); } ledgerJournalTable.clear(); ledgerJournalTable.initValue(); ledgerJournalTable.JournalNum = JournalTableData::newTable(ledgerJournalTable).nextJournalId(); ledgerJournalTable.initFromLedgerJournalName(projParameters.VKJournalName); // journal description, should be after initFromLedgerJournalName ledgerJournalTable.Name = strFmt("Reverse invoice %1", _projInvoiceJour.ProjInvoiceId); ledgerJournalTable.CurrencyCode = _projInvoiceJour.CurrencyId; ledgerJournalTable.insert(); return ledgerJournalTable; } /// <summary> /// Posts general journal /// </summary> /// <param name = "_ledgerJournalTable">LedgerJournalTable record</param> void postGeneralJournal(LedgerJournalTable _ledgerJournalTable) { LedgerJournalCheckPost ledgerJournalCheckPost; ledgerJournalCheckPost = ledgerJournalCheckPost::newLedgerJournalTable(_ledgerJournalTable, NoYes::Yes); ledgerJournalCheckPost.runOperation(); //ledgerJournalCheckPost.run(); } /// <summary> /// Settles customer transactions /// </summary> /// <param name = "_projInvoiceJour">ProjInvoiceJour record</param> /// <param name = "_paymLedgerJournalTrans">LedgerJournalTrans record</param> void settleTransactions(ProjInvoiceJour _projInvoiceJour, LedgerJournalTrans _paymLedgerJournalTrans) { CustTable custTable = CustTable::find(_projInvoiceJour.InvoiceAccount); // find related transaciton LedgerJournalTrans paymLedgerJournalTransLoc; CustTransOpen invCustTransOpen, paymCustTransOpen; CustTrans invCustTrans, paymCustTrans; // Given the payment LedgerJournalTrans, find the related CustTrans which has CustTransOpen select firstonly paymLedgerJournalTransLoc where paymLedgerJournalTransLoc.RecId == _paymLedgerJournalTrans.RecId join paymCustTrans where paymCustTrans.Voucher == paymLedgerJournalTransLoc.Voucher && paymCustTrans.AccountNum == custTable.AccountNum && paymCustTrans.RecId == paymLedgerJournalTransLoc.CustTransId && paymCustTrans.TransType == LedgerTransType::GeneralJournal join paymCustTransOpen where paymCustTransOpen.RefRecId == paymCustTrans.RecId; // Find the related invoice to be settled against the payment journal in the query above select firstonly invCustTrans where invCustTrans.AccountNum == custTable.AccountNum && invCustTrans.Voucher == _projInvoiceJour.LedgerVoucher && invCustTrans.TransType == LedgerTransType::Project join invCustTransOpen where invCustTransOpen.RefRecId == invCustTrans.RecId; // Settlement SpecTransExecutionContext specTransExecutionContext = SpecTransExecutionContext::newFromSource(custTable); //SpecTransManager specTransManager = SpecTransManager::construct(specTransExecutionContext.parmSpecContext()); SpecTransManager specTransManager = SpecTransManager::newFromSpec(specTransExecutionContext.parmSpecContext()); Amount settleAmount = invCustTransOpen.AmountCur; //Prevent over settle if(settleAmount > (-paymCustTransOpen.AmountCur)) { settleAmount = (-paymCustTransOpen.AmountCur); } //Payment specTransManager.insert(paymCustTransOpen.DataAreaId, paymCustTransOpen.TableId, paymCustTransOpen.RecId, -settleAmount, paymCustTrans.CurrencyCode); //Invoice specTransManager.insert(invCustTransOpen.DataAreaId, invCustTransOpen.TableId, invCustTransOpen.RecId, settleAmount, invCustTrans.CurrencyCode); //Settle if(CustTrans::settleTransaction(specTransExecutionContext, CustTransSettleTransactionParameters::construct())) { info(strFmt("Settlement completed for Invoice %1, Journal reversal payment %2, Amount %3", _projInvoiceJour.ProjInvoiceId, _paymLedgerJournalTrans.JournalNum, settleAmount)); } else { throw Error("Settlement failed"); } } }
internal final class VKTest { /// <summary> /// Class entry point. The system will call this method when a designated menu /// is selected or when execution starts and this class is set as the startup class. /// </summary> /// <param name = "_args">The specified arguments.</param> public static void main(Args _args) { VKProjectInvoicePostingHelper projectInvoicePostingHelper = new VKProjectInvoicePostingHelper(); ProjProposalJour projProposalJour = ProjProposalJour::find('VK-000301'); ttsbegin; projectInvoicePostingHelper.reverseTranasctions(projProposalJour); ttscommit; info('done'); } }
DaxOnline.org is free platform that allows you to quickly store and reuse snippets, notes, articles related to Dynamics AX.
Authors are allowed to set their own AdSense units.
Join us.