Wednesday, February 14, 2024

Code to create the Invoice approval in D365 f&o

 My requirement is to create invoice approvals for the posted invoice register lines which were available in find voucher of invoice approval.

AP>Invoice approval>Create journal>Find voucher.


I need to create two journals with the details present in image.

class VendInvoiceApprovalAutomationService extends SysOperationServiceBase

{

   public void processRecords()

   {

       QueryRun                queryRun = this.query();

       LedgerJournalTrans      ledgerJournalTrans;

       LedgerJournalTable      ledgerJournalTable;

 

       while(queryRun.next())

       {

           ledgerJournalTrans = queryRun.get(tableNum(LedgerJournalTrans));

 

           try

           {

               ttsbegin;

               this.createHeader(ledgerJournalTable);

               if (ledgerJournalTable.RecId && ledgerJournalTrans.RecId)

               {

                   this.createApprovalLines(ledgerJournalTrans,ledgerJournalTable);

                   Info(strFmt("Vendor approval journal created -%1",ledgerJournalTable.JournalNum));

               }

               else

               {

                   throw error("Record not found.");

               }

               ttscommit;

           }

           catch

           {

               continue;

           }

       }

   }

 

   public void createApprovalLines(LedgerJournalTrans _ledgerJournalTrans,LedgerJournalTable _ledgerJournalTable)

   {

       LedgerJournalTrans                  ledgerJournalTrans,ledgerJournalTransLoc,ledgerJournalTransNew;

       RefRecId                            ledgerJournalTransRecId = 0;

       ledgerJournalTransRecId = _ledgerJournalTrans.RecId;

 

       LedgerJournalEngine_VendApprove  ledgerJournalEngine = LedgerJournalEngine::construct(LedgerJournalType::Approval);

       LedgerJournalEngine_Server::addVoucher(_ledgerJournalTable,LedgerJournalTrans::findRecId(ledgerJournalTransRecId,false));

 

       select ledgerJournalTransLoc where ledgerJournalTransLoc.RecId == ledgerJournalTransRecId;

       select firstonly ledgerJournalTrans

           where ledgerJournalTrans.JournalNum == _ledgerJournalTable.JournalNum;

 

       ledgerJournalEngine.newJournalActive(_ledgerJournalTable);

       ledgerJournalEngine.preCreate(ledgerJournalTrans);

       ledgerJournalEngine.active(ledgerJournalTransLoc);

 

       ledgerJournalTransNew.initValue();

 

       ledgerJournalTransNew.VendTransId = ledgerJournalTransLoc.VendTransId;

       ledgerJournalTransNew.AccountType = ledgerJournalTransLoc.AccountType;

       ledgerJournalTransNew.JournalNum  = _ledgerJournalTable.JournalNum;

       ledgerJournalEngine.initValue(ledgerJournalTransNew);

       ledgerJournalTransNew.setDefaultAccount(true, ledgerJournalTransLoc.parmAccount());

       ledgerJournalTransNew.LineNum = LedgerJournalTrans::firstLineNum(_ledgerJournalTable.JournalNum) - 1;

       if (ledgerJournalTransNew.LineNum == 0)

       {

           ledgerJournalTransNew.LineNum = -1;

       }

       ledgerJournalTransNew.CurrencyCode = ledgerJournalTransLoc.CurrencyCode;

       ledgerJournalEngine.preWrite(ledgerJournalTransNew);

       ledgerJournalEngine.preWriteUpdateDefaultDimension(ledgerJournalTransNew);

       ledgerJournalTransNew.insert();

       ledgerJournalEngine.write(ledgerJournalTransNew);

       

   }

 

   public void createHeader(LedgerJournalTable      ledgerJournalTable)

   {

       LedgerJournalName  ledgerJournalName;

 

       select firstonly ledgerJournalName

           where ledgerJournalName.JournalType == LedgerJournalType::Approval;

       if (!ledgerJournalName)

       {

           throw Error ("Journal Name does not exists in the system.");

       }

       ledgerJournalTable.clear();

       ledgerJournalTable.initValue();

       ledgerJournalTable.initFromLedgerJournalName(ledgerJournalName.JournalName);

       ledgerJournalTable.JournalNum  = JournalTableData::newTable(ledgerJournalTable).nextJournalId();

       ledgerJournalTable.JournalType = LedgerJournalType::Approval;

       ledgerJournalTable.insert();

   }

 

   public QueryRun query()

   {

       QueryBuildDataSource qbds;

       QueryBuildRange qbr;

       LedgerJournalId vendInvoicePoolJournalNum = LedgerJournalTable::findVendorInvoicePool().JournalNum;

       Query query = new Query();

       qbds = query.addDataSource(tablenum(LedgerJournalTrans));

 

       qbr = qbds.addRange(fieldnum(LedgerJournalTrans, JournalNum ));

       qbr.value(queryValue(vendInvoicePoolJournalNum));

 

       qbr = qbds.addRange(fieldnum(LedgerJournalTrans, AccountType));

       qbr.value(queryValue(LedgerJournalACType::Vend));

 

       qbr = qbds.addRange(fieldnum(LedgerJournalTrans, Approved));

       qbr.value(queryValue(NoYes::No));

 

       qbds = qbds.addDataSource(tablenum(LedgerJournalTransAccountView));

       qbds.addLink(fieldnum(LedgerJournalTrans, RecId), fieldnum(LedgerJournalTransAccountView, RecId1));

       qbds.joinMode(JoinMode::ExistsJoin);

       qbds.fetchMode(QueryFetchMode::One2One);

 

       qbds = qbds.addDataSource(tablenum(VendTrans));

       qbds.joinMode(JoinMode::ExistsJoin);

       qbds.fetchMode(0);

 

       qbds.addLink(fieldnum(LedgerJournalTransAccountView, AccountNum), fieldnum(VendTrans, AccountNum));

       qbds.addLink(fieldnum(LedgerJournalTransAccountView, Voucher), fieldnum(VendTrans, Voucher));

       qbds.addLink(fieldnum(LedgerJournalTransAccountView, TransDate), fieldnum(VendTrans, TransDate));

       qbds.addLink(fieldnum(LedgerJournalTransAccountView, Invoice), fieldnum(VendTrans, Invoice));

 

       qbr = qbds.addRange(fieldnum(VendTrans, Arrival));

       qbr.value(queryValue(NoYes::Yes));

 

       qbr = qbds.addRange(fieldnum(VendTrans, JournalNum));

       qbr.value(queryValue(vendInvoicePoolJournalNum));

       

       QueryRun  qr = new QueryRun(query);

 

       return qr;

   }

}

.....................................................

Output :




Sunday, January 7, 2024

Generate Payment Advice Report for selected record in D365F&O X++

 Accounts Payable>Vendor Payment Journal>Lines>Print>Payment Advice

The standard report is generating for all the line records automatically, Our requirement is to generate the report for only selected record.

[ExtensionOf(classStr(BankPaymAdvicePaymentQueryGenerator))]

internal final class DaxBankPaymAdvicePaymentQueryGenerator_Extension

{

   public QueryRun getPaymentLineQueryRun(BankPaymAdviceContract _bankPaymAdviceContract)

   {

       Query query ;

       QueryRun    queryRun;

       queryRun = next getPaymentLineQueryRun(_bankPaymAdviceContract);

       query = queryRun.query();

       query.dataSourceTable(tableNum(LedgerJournalTrans)).addRange(fieldNum(LedgerJournalTrans, RecId)).value(queryValue(_bankPaymAdviceContract.parmLedgerJournalTransRecId()));

       return queryRun;

   }

}

.............................

[ExtensionOf(classStr(BankPaymAdviceUIBuilder))]

internal final class DaxBankPaymAdviceUIBuilder_Extension

{

   private DialogField dialogRecid;

   public void postRun()

   {

       next postRun();

 

       LedgerJournalTrans ledgerJournalTrans;

       BankPaymAdviceContract contract = this.dataContractObject();

       if (this.controller().parmArgs() && this.controller().parmArgs().record())

       {

           ledgerJournalTrans = this.controller().parmArgs().record() as LedgerJournalTrans;

       }

       contract.parmLedgerJournalTransRecId(ledgerJournalTrans.RecId);

   }

}

.................................

Output :






Thursday, January 4, 2024

Remove marked for settlement open transactions through X++ code

 AP>Invoices>Invoice Journal>Lines>Settele Transcations



View Marked Transcations.





Other Way:

http://daxdude.blogspot.com/2013/02/remove-marked-for-settlement-open.html



Thursday, December 7, 2023

Code to update data for custom fields in SubBillScheduleLine lines which are created from milestone allocation in D365 f&o X++

[Extensionof(tableStr(SubBillScheduleLine))]

internal final class DaxSubBillScheduleLine_Extension

{

   public void recreateMilestoneSubItems(SubBillMilestoneAllocationHeader _milestoneAllocationHeader)

   {

       SubBillScheduleLine milestoneSubLine;

       SubBillMilestoneAllocationLine  allocationLine;

       while select allocationLine

           where allocationLine.SubBillSchedLineRecId == _milestoneAllocationHeader.SubBillSchedLineRecId

       {

           select forupdate milestoneSubLine

               where milestoneSubLine.RecId == allocationLine.SubBillSchedLineRecId;

           ttsbegin;

           milestoneSubLine.DaxEnum = DaxEnum::Advanced; //custom field

           milestoneSubLine.update();

           ttscommit;

       }

       next recreateMilestoneSubItems(_milestoneAllocationHeader);

   }

   public void insert()

   {

       SubBillScheduleLine milestoneSubLine;

       select milestoneSubLine

           where milestoneSubLine.SubBillMilestoneHeaderRecId == this.SubBillMilestoneHeaderRecId;

       this.DaxStatus = milestoneSubLine.DaxStatus; //custom field

       next insert();

   }

}

..............

Subsription billing > All Billing Schedules

Create a header and line and click on Milestone Allocation.




Lines from milestone will be created in SubBillScheduleLines. And custom fields will be updated.







Monday, November 27, 2023

Code to Populate Custom field data from PurchTable to VendInvoiceJour in D365 f&o X++

[ExtensionOf(tableStr(VendInvoiceJour))]

public final class DaxVendInvoiceJour_Extension

{

   public void insert()

   {

       PurchTable      purchTable = PurchTable::find(this.PurchId);

       this.Dax_Remarks = purchTable.Dax_Remarks;

       next insert();

   }

}

...............

OtherWay:

[ExtensionOf(classStr(FormletterService))]

 internal final class DaxFormLetterServiceClass_Extension

 {

    protected void processJournal(Printout _printout)

    {

         VendInvoiceJour         vendInvoiceJourlocal;

         PurchTable              purchTable;

         next processJournal(_printout);

        select forupdate vendInvoiceJourlocal 

            join purchTable

                where vendInvoiceJourlocal.ParmId == parmId

                && vendInvoiceJourlocal.purchId == purchTable.purchId;

        ttsbegin;

        vendInvoiceJourlocal.Dax_Remarks = purchTable.Dax_Remarks; // custom field

        vendInvoiceJourlocal.update();

        ttscommit;

     }

 }

.........................

Other Way :

[ExtensionOf(classStr(PurchFormLetter_Invoice))]

internal final class DaxPurchFormLetter_Invoice_Extension

{

   protected void runRemainUpdates()

   {

       VendInvoiceJour     vendInvoiceJour;

       PurchTable          purchTable;

       str parmid = this.parmId();

       next runRemainUpdates();

       select forupdate vendInvoiceJour

           where vendInvoiceJour.ParmId == parmid;

       purchTable = PurchTable::find(vendInvoiceJour.PurchId);

       ttsbegin;

       vendInvoiceJour.Dax_Remarks = purchTable.Dax_Remarks;

       vendInvoiceJour.update();

       ttscommit;

   }

}

Output :


    





How to make grid empty based on conditions in D365 f&o X++

 I have grid with purchline datasource.

If the location is empty . Then grid should be empty.(no records in gird)

If the location has some range. then range should be applied on grid.


 QueryBuildDataSource            qbdspurch;

 QueryBuildRange                       qbr;

if(this.daxlocation)

{

                 qbdspurch = this.query().dataSourceTable(tableNum(PurchLine));

                    qbr = qbdspurch.addRange(fieldNum(PurchLine, daxlocation));

                    qbr.value(this.daxlocation);

}

else

{

                     qbdspurch = this.query().dataSourceTable(tableNum(PurchLine));

                    qbr = qbdspurch.addRange(fieldNum(PurchLine, PurchId));

                    qbr.value(SysQuery::valueEmptyString()); //makes grid empty

}

reference blog:

https://daxingwitheshant.blogspot.com/2015/04/how-to-filter-gird-based-on-given-input.html

Monday, November 6, 2023

Code to create a Simple BatchJob with Records to include filter in D365F&O X++

/// <summary>

/// The <c>MCRFTCEventProcessBatch</c> class handles processing FTC events in batch.

/// </summary>

class MyBatchJobBatch extends RunBaseBatch implements BatchRetryable

{

   // Packed variables

   int                 dummy;

   // Dialog fields

   QueryRun                            projectQueryRun;

 

   #define.CurrentVersion(2)

   #localmacro.CurrentList

       dummy,

       startDate,

       endDate

   #endmacro

   /// <summary>

   /// Adds the <c>SalesID</c> to the dialog box

   /// allowing the user to run a batch over the selected

   /// <c>SalesID</c>.

   /// </summary>

   /// <returns>

   /// The dialog box box.

   /// </returns>

   public Object dialog()

   {

       DialogRunbase               dialog; 

       //Setup the dialog

       dialog = super();

       dialog.caption("Simple Batch Job");

       return dialog;

   }

   /// <summary>

   /// Retrieves the user entered values from dialog form.

   /// </summary>

   /// <returns>

   /// true if the values are retrieved successfully; otherwise, false.

   /// </returns>

   public boolean getFromDialog()

   {

       boolean ret;

       ret = super();

       return ret;

   }

   protected void initQuery()

   {

       QueryBuildDataSource qbds;

       Query                query = new Query();

 

       query.allowCrossCompany(true);

       qbds = query.addDataSource(tableNum(CustTable));

       projectQueryRun = new QueryRun(query);

   }

   protected void new()

   {

       super();

       this.initQuery();

   }

   public container pack()

   {

       return [#CurrentVersion, #CurrentList];

   }

   boolean prompt()

   {

       return super();

   }

   public QueryRun queryRun()

   {

       return projectQueryRun;

   }

   public boolean showQueryValues()

   {

       return true;

   }

   public boolean unpack(container packedClass)

   {

       Version version = runbase::getVersion(packedClass);

       switch (version)

       {

           case #CurrentVersion:

               [version, #CurrentList] = packedClass;

               break;

           default:

               return false;

       }

       return true;

   }

    public static MCRFTCEventProcessBatch construct()

   {

       return new MCRFTCEventProcessBatch();

   }

   public static ClassDescription description()

   {

       return "Simple Batch Job";

   }

   public static void main(Args args)

   {

       MyBatchJobBatch myBatchJobBatch = new myBatchJobBatch();

       myBatchJobBatch.parmInBatch(false);

 

       if (myBatchJobBatch.prompt())

           myBatchJobBatch.runOperation();

   }

 

   /// <summary>

   /// Describes whether the class is designed for execution in a new session.

   /// </summary>

   /// <returns>

   /// false.

   /// </returns>

   protected boolean canRunInNewSession()

   {

       return false;

   }

   /// <summary>

   /// Specifies if the batch task is retryable for transient exceptions or not.

   /// </summary>

   /// <returns>

   /// If true is returned, the batch task is retryable, otherwise it is not.

   /// </returns>

   [Hookable(false)]

   final boolean isRetryable()

   {

       return true;

   }

}

Output :