Friday, November 15, 2024

Purchase cycle in D365 FO | Data Flow from PurchTable and PurchLine to Vendor Invoicing and Ledger Posting in Dynamics 365 Finance & Operations (D365 F&O)

This explanation outlines the data flow from the creation of a purchase order (PO) to vendor invoicing and final ledger posting. Key tables, processes, and roles are covered at each stage.

1. Purchase Order Creation

  • Purpose: Captures the initial details of the PO such as vendor, products, quantities, and expected prices.
  • Key Tables:
    • PurchTable: Contains header-level information about the PO (e.g., vendor, delivery date, PO status).
    • PurchLine: Stores line-level details like item ID, quantity, unit price, and delivery schedule.
  • Process:
    • A user creates a PO in D365 F&O, filling in the required details.
    • Data is saved to PurchTable (header) and PurchLine (lines).

2. Purchase Order Confirmation

  • Purpose: Confirms the order with the vendor and locks the order details for further processing.
  • Key Tables:
    • PurchTable: Updates the status to "Confirmed."
    • PurchLine: Retains line-item details, with the status reflecting "Confirmed."
  • Process:
    • When confirmed, the system creates a snapshot of the order, ensuring no changes are made without cancellation or amendment.

3. Product Receipt Posting

  • Purpose: Acknowledges the receipt of goods or services from the vendor.
  • Key Tables:
    • PurchTable: Updates the status to reflect "Received."
    • PurchLine: Captures received quantities against the line items.
    • VendPackingSlipJour: Stores packing slip header details for the receipt.
    • VendPackingSlipTrans: Stores packing slip line details.
  • Process:
    • Upon receipt, a packing slip is posted, associating the goods received with the PO.

4. Vendor Invoice Posting

  • Purpose: Records the vendor's invoice for the received goods or services.
  • Key Tables:
    • VendInvoiceJour: Stores invoice header details (e.g., invoice number, vendor, invoice date).
    • VendInvoiceTrans: Stores invoice line details corresponding to PO lines.
    • VendSettlement: Tracks settlements between the invoice and payments.
  • Process:
    • The system validates the invoice against the PO and receipt (three-way matching).
    • Discrepancies (if any) are flagged for resolution.
    • Invoice is posted, generating liability in the vendor ledger.

5. General Ledger Posting

  • Purpose: Posts financial transactions to the general ledger, reflecting vendor liabilities and expense accruals.
  • Key Tables:
    • LedgerJournalTable: Stores journal header information for invoice-related ledger postings.
    • LedgerJournalTrans: Contains journal line details, specifying accounts, amounts, and dimensions.
    • VendTrans: Updates vendor transactions with the invoiced amount.
  • Process:
    • Upon invoice posting, the system creates ledger entries:
      • Debit to expense or inventory accounts.
      • Credit to accounts payable (vendor liability).

6. Payment Processing

  • Purpose: Settles the vendor's outstanding invoice.
  • Key Tables:
    • VendTransOpen: Tracks open (unpaid) vendor transactions.
    • LedgerJournalTable: Contains payment journal headers.
    • LedgerJournalTrans: Stores payment journal lines.
    • BankTrans: Updates bank transactions for outgoing payments.
  • Process:
    • Payment is processed via bank or other methods, reducing the vendor liability.
    • Vendor transactions (VendTrans) and general ledger accounts are updated accordingly.

7. Reconciliation and Reporting

  • Purpose: Ensures all posted entries align with the organizational financial records.
  • Key Tables:
    • VendSettlement: Tracks settlements between invoices and payments.
    • GeneralJournalAccountEntry: Contains all detailed accounting entries related to the transactions.
    • VendInvoiceInfoLog: Stores log details for invoice postings.
  • Process:
    • Reports are generated for audit and reconciliation.
    • Any mismatches or errors are corrected through adjustments.

Summary of Key Tables and Their Roles

Table NamePurpose
PurchTableStores PO header information.
PurchLineStores PO line details.
VendPackingSlipJourTracks packing slip headers for product receipts.
VendPackingSlipTransTracks packing slip lines for product receipts.
VendInvoiceJourStores invoice headers.
VendInvoiceTransStores invoice lines.
LedgerJournalTableStores journal headers for financial postings.
LedgerJournalTransContains journal line details for ledger accounts.
VendTransTracks vendor ledger transactions.
VendSettlementTracks settlements of invoices and payments.
BankTransTracks bank transactions related to payments.
GeneralJournalAccountEntryContains detailed accounting entries for all financial transactions.

This structured flow ensures traceability and compliance with financial standards in D365 F&O.

Thursday, November 7, 2024

SSRS Reports using DP Contract UI Builder

Contract Class :


/// <summary>

/// Data Contract class for CustomerTransactions SSRS report

/// </summary>

/// <remarks>

/// This is the Data Contract class for the CustomerTransactions SSRS Report.

/// </remarks>

[

    DataContractAttribute,

    SysOperationContractProcessingAttribute(classStr(DIPL_CustTransUIBuilder))

]


public class DIPL_CustTransContract implements SysOperationValidatable

{

    TransDate   fromDate;

    TransDate   toDate;

    List        custAccount;

}


--------------------------------------------------------------------------------------------------------------------


/// <summary>

/// Gets or sets the value of the datacontract parameter CustAccount.

/// </summary>

/// <param name="_custAccount">

/// The new value of the datacontract parameter CustAccount.

/// </param>

/// <returns>

///  The current value of datacontract parameter CustAccount

/// </returns>

[

    DataMemberAttribute('CustAccount'),

    AifCollectionTypeAttribute('CustAccount', Types::String),

    SysOperationLabelAttribute(literalStr("CustAccount")),

    SysOperationDisplayOrderAttribute('3')

]

public List parmCustAccount(List _custAccount = custAccount)

{

    custAccount = _custAccount;


    return custAccount;

}


--------------------------------------------------------------------------------------------------------------------------


/// <summary>

/// Gets or sets the value of the datacontract parameter FromDate.

/// </summary>

/// <param name="_fromDate">

/// The new value of the datacontract parameter FromDate; optional.

/// </param>

/// <returns>

///  The current value of datacontract parameter FromDate

/// </returns>

[

    DataMemberAttribute('FromDate'),

    SysOperationLabelAttribute(literalstr("@SYS4083")),

    SysOperationHelpTextAttribute(literalstr("FromDate")),

    SysOperationGroupMemberAttribute('Date'),

    SysOperationDisplayOrderAttribute('1')

]

public TransDate parmFromDate(TransDate _fromDate = fromDate)

{

    fromDate = _fromDate;


    return fromDate;

}


------------------------------------------------------------------------------------------------------------------------


/// <summary>

/// Gets or sets the value of the datacontract parameter ToDate.

/// </summary>

/// <param name="_toDate">

/// The new value of the datacontract parameter ToDate; optional.

/// </param>

/// <returns>

///  The current value of datacontract parameter ToDate

/// </returns>

[

    DataMemberAttribute('ToDate'),

    SysOperationLabelAttribute(literalstr("@SYS8828")),

    SysOperationHelpTextAttribute(literalstr("ToDate")),

    SysOperationGroupMemberAttribute('Date'),

    SysOperationDisplayOrderAttribute('2')

]

public TransDate parmToDate(TransDate _toDate = toDate)

{

    toDate = _toDate;


    return toDate;

}


-------------------------------------------------------------------------------------------------------------------------


/// <summary>

///    Validates the SSRS report parameters.

/// </summary>

/// <returns>

///    true if successful; otherwise, false.

/// </returns>

public boolean validate()

{

    boolean ret = true;

    if (!fromDate)

    {

        fromDate = systemdateget();

    }


    if (!toDate)

    {

        toDate = systemdateget();

    }


    if (toDate < fromDate)

    {

        ret = checkFailed("@SYS16982");

    }


    return ret;

}


----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


UI Builder : Using it for Multiselect lookup


class DIPL_CustTransUIBuilder extends SysOperationAutomaticUIBuilder

{

    DIPL_CustTransContract              contract;

    DialogField                         dlgCustAccount;

    DialogField                         dialogFromdate;

    DialogField                         dialogTodate;

    SysLookupMultiSelectGrid            sysMultiGridCustAccount;

    SysLookupMultiSelectCtrl            sysMultiLookupCustAccount;

    container                           custAccountCon;


}

--------------------------------------------------------------------------------------------------------------------------


public void build()

{

    contract    = this.dataContractObject() as DIPL_CustTransContract;


    dialogFromdate  = this.addDialogField(methodStr(DIPL_CustTransContract, parmFromDate), contract);

    dialogTodate    = this.addDialogField(methodStr(DIPL_CustTransContract, parmToDate), contract);


}


--------------------------------------------------------------------------------------------------------------------------

private void CustAccountLookup(FormStringControl custAccountLookup)

{


    sysMultiGridCustAccount = SysLookupMultiSelectGrid::construct(custAccountLookup, custAccountLookup);

    sysMultiGridCustAccount.parmQuery(this.CustAccountQuery());

    sysMultiGridCustAccount.run();


    sysMultiGridCustAccount.setSelected();


}

--------------------------------------------------------------------------------------------------------------------------


private Query CustAccountQuery()


{


    Query                           query;

    QueryBuildDataSource            queryBuildDataSource;


    query = new Query();


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

    query.dataSourceTable(tablenum(CustTable)).addDataSource(tableNum(DirPartyTable));

    query.dataSourceTable(tablenum(DirPartyTable)).joinMode(JoinMode::InnerJoin);

    query.dataSourceTable(tablenum(DirPartyTable)).relations(true);

    query.dataSourceTable(tablenum(DirPartyTable)).addSelectionField(fieldNum(DirPartyTable,  Name));

    queryBuildDataSource.addSelectionField(fieldNum(CustTable,AccountNum));


    return query;


}


-------------------------------------------------------------------------------------------------------------------------

public  void getFromDialog()

{

    super();


    custAccountCon = sysMultiLookupCustAccount.getSelectedFieldValues();


    if (custAccountCon)

    {

        contract.parmCustAccount(con2List(custAccountCon));

    }


}

--------------------------------------------------------------------------------------------------------------------------

public void postBuild()

{


    super();


    contract = this.dataContractObject() as DIPL_CustTransContract;


}

--------------------------------------------------------------------------------------------------------------------------


public void postRun()

{


    dialog.dialogForm().formRun().controlMethodOverload(false);


    dlgCustAccount = this.addDialogField(methodStr(DIPL_CustTransContract, parmCustAccount), contract);

    dlgCustAccount.lookupButton(3);


    dlgCustAccount              = this.bindInfo().getDialogField(contract,methodStr(DIPL_CustTransContract, parmCustAccount));

    sysMultiLookupCustAccount   = SysLookupMultiSelectCtrl::constructWithQuery(this.dialog().formRun(), dlgCustAccount.control(), this.CustAccountQuery());


}

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


DP:


/// <summary>

///    The <c>DIPL_CustTransDP</c> class is the Report Data Provider class for the <c>CustTransaction</c> SSRS

///    report.

/// </summary>

[

    SRSReportParameterAttribute(classstr(DIPL_CustTransContract))

]

class DIPL_CustTransDP  extends   SRSReportDataProviderBase //SrsReportDataProviderPreProcess

{

    DIPLCustTransTmp                    diplCustTransTmp;

    CustTable                           custTable;

    DirPartyTable                       dirPartyTable;

    CustTrans                           custTrans;

    ProjTable                           projTable;

    ProjInvoiceJour                     projInvoiceJour;

    TaxTrans                            taxTrans;

    FromDate                            fromDate;

    ToDate                              toDate;


    DimensionAttributeLevelValueView    dimensionAttributeLevelValueView;

    DimensionAttributeValueSetItemView  dimensionAttributeValueSetItemView;

    DimensionAttribute                  dimensionAttribute;

    LedgerJournalTrans                  ledgerJournalTrans;


    #define.FromDate('FromDate')

    #define.ToDate('ToDate')


}

--------------------------------------------------------------------------------------------------------------------------

/// <summary>

/// Fetches the data from <c>DIPLCustTransTmp</c> temporary table.

/// </summary>

/// <returns>

/// The data from the <c>DIPLCustTransTmp</c> temporary table.

/// </returns>

[

    SRSReportDataSetAttribute('DIPLCustTransTmp')

]

public DIPLCustTransTmp getDIPLCustTransTmp()

{

    select diplCustTransTmp;

    return diplCustTransTmp;

}

--------------------------------------------------------------------------------------------------------------------------

public ExchRate getExchRateFind(CurrencyCode _currencyCode, TransDate _transDate)

{


    ExchangeRateHelper          exchangeRateHelper;

    CurrencyExchangeRate        exchangeRate1;

    CurrencyExchangeRate        exchangeRate;

    ;


    exchangeRateHelper  = ExchangeRateHelper::newExchangeDate(Ledger::current(), _currencyCode, _transDate);

    exchangeRate1       = exchangeRateHelper.getExchangeRate1();

    exchangeRate        = exchangeRateHelper.displayStoredExchangeRate(exchangeRate1);


    return exchangeRate;

}

--------------------------------------------------------------------------------------------------------------------------

/// <summary>

/// Inserts data into the temporary table.

/// </summary>

private void insertIntoTempTable()

{

    diplCustTransTmp.TransactionDate    = custTrans.TransDate;

    diplCustTransTmp.InvoiceDate           = projInvoiceJour.InvoiceDate;

    diplCustTransTmp.CustomerName     = custTable::find(custTrans.AccountNum).name();

    diplCustTransTmp.ProjectName         = ProjTable::find(dimensionAttributeValueSetItemView.DisplayValue).Name;

    diplCustTransTmp.Invoice                  = custTrans.Invoice;

    diplCustTransTmp.CurrencyCode       = custTrans.CurrencyCode;

    diplCustTransTmp.ExchangeRate       = this.getExchRateFind(custTrans.CurrencyCode,custTrans.TransDate);

    diplCustTransTmp.GrossAmount       = taxTrans.SourceBaseAmountCur;

    diplCustTransTmp.TaxAmount          = taxTrans.SourceTaxAmountCur;

    diplCustTransTmp.TaxCode               = taxTrans.TaxCode;

    diplCustTransTmp.AmountInCur       = custTrans.AmountCur;

    diplCustTransTmp.AmountInINR      = CustTrans.AmountMST;

    diplCustTransTmp.Description           = ledgerJournalTrans.Text;

    diplCustTransTmp.Voucher                = CustTrans.Voucher;

    diplCustTransTmp.TaxValue              = taxTrans.TaxValue; 


    diplCustTransTmp.insert();

}

--------------------------------------------------------------------------------------------------------------------------


/// <summary>

/// Processes the report business logic.

/// </summary>

[AifDocumentCreateAttribute, SysEntryPointAttribute(true)]

public void processReport()

{

    ListEnumerator                      custAccountListIterator;

    CustAccount                         custAccount;

    List                                parmCustAccount;

    List       list                 = new List(Types::String);

    DIPL_CustTransContract contract = this.parmDataContract() as DIPL_CustTransContract;

    fromDate                        = contract.parmFromDate();

    toDate                          = contract.parmToDate();

    parmCustAccount                 = contract.parmCustAccount();


    if (parmCustAccount != null)

    {

        custAccountListIterator = parmCustAccount.getEnumerator();


        while (custAccountListIterator.moveNext())

        {

            custAccount = custAccountListIterator.current();


            while select custTrans

                where custTrans.AccountNum              == custAccount

                    && custTrans.TransDate              >= fromDate

                    && custTrans.TransDate              <= toDate

            outer join projInvoiceJour

                    where ProjInvoiceJour.LedgerVoucher == CustTrans.Voucher

            outer join taxTrans

                    where TaxTrans.Voucher              == ProjInvoiceJour.LedgerVoucher

            {

                select firstOnly RecId,Name from dimensionAttribute

                    where DimensionAttribute.Name == "@SYS105167";


                select DimensionAttributeValueSet,DisplayValue,DimensionAttribute from dimensionAttributeValueSetItemView

                    where dimensionAttributeValueSetItemView.DimensionAttributeValueSet == custTrans.DefaultDimension

                        && dimensionAttributeValueSetItemView.DimensionAttribute        == dimensionAttribute.RecId;


                select firstOnly Text from ledgerJournalTrans

                    where ledgerJournalTrans.Voucher == custTrans.Voucher;


                this.insertIntoTempTable();

            }

        }

    }

}


https://daxingwitheshant.blogspot.com/2018/06/ssrs-reports-using-dp-contract-ui.html





Index and index hint

 http://daxingwitheshant.blogspot.com/2018/07/difference-between-index-and-index-hint.html

Adding multiple Query range in Dynamics 365 FO

Using OR:

QueryBuildRange qbr = SysQuery::findOrCreateRange(_qbds, fieldNum(HcmPerfJournal, Owner));

qbr.value(strFmt(‘(%1.%2 == %3) || (%1.%4 == %5)’,
_qbds.name(),
fieldStr(HcmPerfJournal, Owner), enum2int(HcmPerfManagerEmployee::Manager),
fieldStr(HcmPerfJournal, Share), enum2int(NoYes::Yes)));
qbr.status(RangeStatus::Hidden);

Using AND:

queryBuildRange = accessRightsListDataSource.addRange(fieldnum(DEL_AccessRightsList, RecId));
queryBuildRange.value(strfmt(‘((%1.%2==%3) && (%1.%4==%5))’,
accessRightsListDataSource.name(),
fieldstr(DEL_AccessRightsList, RecordType),
accessRecordType,
fieldstr(DEL_AccessRightsList, Id),
_securityKeyArray.value(i)));

Date Range:

queryBuildRange .value(SysQueryRangeUtil::dateRange(DateTimeUtil::date(DateTimeUtil::addDays(currentDateTime,relativeDaysFrom)), DateTimeUtil::date(DateTimeUtil::addDays(currentDateTime,relativeDaysTo)));

or

queryBuildRange.value(SysQuery::range(fromDate, toDate));

How to enable notifications for each and every check-in in Azure DevOps ADO

Go to Azure DevOps

Go to the project setting

Now go to notifications

Now click on the new subscription

a new pop-up will come, now click on Code(TFVC), select code is checked in 

click next

In the Deliver To select Custom email address

now in the address field, enter your email id

now in the filter criteria, field select server item

now in the operator select Under

now in value select your Repos path


TaDa !!!

how to run a batch job from code in d365 fo dynamics 365 finannace and operations

class LSAYTest extends SysOperationServiceController

{

    public static void main (Args _arg)

    {

        BatchHeader           batchHeader;

        BatchInfo             localBatchInfo;

        LSAvalaraapiController yourRunBaseBatchClass;

        SysRecurrenceData     sysRecurrenceData =

        SysRecurrence::defaultRecurrence();

        ;

        yourRunBaseBatchClass =

        LSAvalaraapiController::construct();


        //// retry 3 times

        //sysRecurrenceData =

        //SysRecurrence::setRecurrenceEndAfter(

        //                sysRecurrenceData, 3);

        //// retry after 1 minute

        //sysRecurrenceData =

        //SysRecurrence::setRecurrenceUnit(sysRecurrenceData,

        //                     SysRecurrenceUnit::Minute, 1);

    

        localBatchInfo = yourRunBaseBatchClass.batchinfo();

        //localBatchInfo.parmGroupId("YourBatchGroupId");

        batchHeader = batchHeader::construct();

        batchHeader.addTask(yourRunBaseBatchClass);

        //batchHeader.parmRecurrenceData(sysRecurrenceData);

        batchHeader.save();

    }


}

Basic SSRS Report to call from form current record

Controller


/// <summary>

/// RAF controller

/// </summary>

internal final class LSRafLabelController extends SrsReportRunController

{

    /// <summary>

    /// Main class of RAF lebel

    /// </summary>

    /// <param name = "_args">_args</param>

    public static void main(Args _args)

    {

        LSRafLabelController rafLabelController = new  LSRafLabelController();


        rafLabelController.parmReportName(ssrsReportStr(LSRAFLabel, Report));

        rafLabelController.parmDialogCaption("@LS_HISOL_GD:RAFLabel");

        rafLabelController.parmShowDialog(false);

        rafLabelController.parmArgs(_args);


        rafLabelController.startOperation();

    }


    /// <summary>

    /// prePromptModifyContract

    /// </summary>

    protected void prePromptModifyContract()

    {

        if(this.parmArgs())

        {

            LSRafLabelContract contract;

            ProdJournalProd prodJournalProd;

            contract = this.parmReportContract().parmRdpContract();


            prodJournalProd = this.parmArgs().record();

            contract.parmRecid(prodJournalProd.RecId);

        }


        super();

    }


}





Contract


/// <summary>

/// Contract class of RAF label

/// </summary>

[DataContractAttribute]

internal final class LSRafLabelContract

{

    RefRecid lineRecid;




    /// <summary>

    /// Parm contract

    /// </summary>

    /// <param name = "_recid">_recid</param>

    /// <returns>RefRecid</returns>

    [DataMemberAttribute('Recid')]

    public RefRecid parmRecid(RefRecid _recid = lineRecid)

    {

        lineRecid = _recid;

        return lineRecid;

    }


}





DP


/// <summary>

/// DP class for RAF report

/// </summary>

[SRSReportParameterAttribute(classStr(LSRafLabelContract))]

class LSRafLabelDP extends SRSReportDataProviderBase

{


    LSRafLabelTmp rafTmp;


   

    [SRSReportDataSetAttribute(tableStr(LSRafLabelTmp))]

    public LSRafLabelTmp getLSRafLabelTmp()

    {

        select rafTmp;

        return rafTmp;

    }


    /// <summary>

    /// Process report

    /// </summary>

    public void processReport()

    {


        ProdJournalProd prodJournalProd;

        InventDim       inventDim;

        LSRafLabelContract rafLabelContract;


        rafLabelContract = this.parmDataContract();


        select firstonly ItemId,QtyGood from prodJournalProd

            where prodJournalProd.RecId == rafLabelContract.parmRecid()

            join InventLocationId,inventBatchId,wMSLocationId from inventDim

            where prodJournalProd.InventDimId == inventDim.inventDimId;


        rafTmp.Warehouse        = inventDim.InventLocationId;

        rafTmp.ItemId           = prodJournalProd.ItemId;

        rafTmp.ProductName      = InventTable::find(prodJournalProd.ItemId).productName(SystemParameters::getSystemLanguageId());

        rafTmp.InventBatchId    = inventDim.inventBatchId;

        rafTmp.WMSLocationId    = inventDim.wMSLocationId;

        rafTmp.ManufacturingDate = InventBatch::find(inventDim.inventBatchId,prodJournalProd.ItemId).prodDate;

        rafTmp.Qty              = prodJournalProd.QtyGood;

        rafTmp.QtyBX            = this.convertedVal(prodJournalProd.ItemId,prodJournalProd.QtyGood,InventTableModule::find(prodJournalProd.ItemId,ModuleInventPurchSales::Invent).UnitId,'BX');

        rafTmp.ExpiryDate       =  InventBatch::find(inventDim.inventBatchId,prodJournalProd.ItemId).expDate;

       

        rafTmp.insert();

    }


    /// <summary>

    /// Converted value

    /// </summary>

    /// <param name = "_itemid">_itemid</param>

    /// <param name = "_qty">_qty</param>

    /// <param name = "_fromUnit">_fromUnit</param>

    /// <param name = "_toUnit">_toUnit</param>

    /// <returns>Qty</returns>

    public  Qty convertedVal(ItemId _itemid, Qty _qty, UnitOfMeasureSymbol _fromUnit, UnitOfMeasureSymbol _toUnit )

    {

        try

        {


            UnitOfMeasureConverter_Product unitConverter  = UnitOfMeasureConverter_Product::construct();

            unitConverter.parmProduct(InventTable::find(_itemid,true).Product);

            unitConverter.parmFromUnitOfMeasure(UnitOfMeasure::unitOfMeasureIdBySymbol(_fromUnit));

            unitConverter.parmToUnitOfMeasure(UnitOfMeasure::unitOfMeasureIdBySymbol(_toUnit));

            unitConverter.parmRoundAbsoluteValue(NoYes::No);

            unitConverter.parmApplyRounding(NoYes::No);

            return unitConverter.convertValue(_qty);

        }

        catch

        {

            warning("@DMF:DMFNoTimezone");


            return 0;

        }

    }


}

generate datetime d365 fo x++

 dateTime = DateTimeUtil::newDateTime(currentDate, 1);


All types of integration in d365 fo x++

https://community.dynamics.com/blogs/post/?postid=8f4aa6e2-8929-45e3-b794-43cba05e9523




https://learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/data-entities/integration-overview





https://learn.microsoft.com/en-us/dynamics365/guidance/techtalks/integrate-finance-operations-overview




record insert list

 





class testRecordInsertList

{

    public static void main(Args _args)

    {

        ProjInvoiceJour projInvoiceJour;

        RecordInsertList myTableTmpList;

        MyTable myTable;


        // Initiating the list with temp table buffer

        myTableTmpList = new RecordInsertList(tableNum(MyTable), false, false, false, false, false, myTable);


        while select InvoiceDate, InvoiceId from projInvoiceJour

            where projInvoiceJour.InvoiceDate >= _fromdate

               && projInvoiceJour.InvoiceDate <= _todate

        {

            myTable.InvDate = projInvoiceJour.InvoiceDate;

            myTable.Invoice = projInvoiceJour.InvoiceId;

            myTableTmpList.add(myTable);

        }

        myTableTmpList.insertDatabase();

    }

}


Credit note

In Dynamics 365 F&O, a credit note (also known as a credit memo) is a document issued to correct or reverse an invoice, often used when there has been an overcharge, incorrect items shipped, or a return of goods by the customer. It serves as a formal acknowledgment that a credit has been issued, reducing the amount the customer owes.


Example:

Let’s assume your company, Lifestyles, sells furniture, and you issued an invoice for 10 chairs at ₹5,000 each, totaling ₹50,000. However, the customer informs you that 2 of the chairs were damaged and have been returned. You agree to provide a credit for the 2 damaged chairs.


In this case, you would issue a credit note for the value of those 2 chairs (₹10,000). This reduces the customer’s outstanding balance from ₹50,000 to ₹40,000.


How it works in Dynamics 365 F&O:

1. Create a credit note: In the Accounts Receivable module, you create a credit note against the original sales invoice.

2. Post the credit note: Once posted, the system adjusts the customer’s balance, reflecting the reduction due to the returned or damaged goods.

3. Inventory adjustment (if applicable): If goods are returned, the inventory will be updated to reflect the increase in stock.


In some cases, credit notes can also be issued for discounts, price adjustments, or service-related issues.

Packing slip AR Accounts receivable

In Dynamics 365 F&O, a packing slip (also known as a delivery note) is a document that accompanies shipments of goods and serves as proof of delivery. It typically contains details about the items shipped, including quantities, descriptions, and shipment dates. In the context of sales orders or transfer orders, a packing slip is generated when the goods are physically shipped from the warehouse.

Key functions of a packing slip in Dynamics 365 F&O:
- Documentation of shipment: It outlines what has been sent to the customer or recipient, ensuring transparency.
- Inventory updates: Upon posting a packing slip, the system updates inventory records to reflect that the goods have left the warehouse.
- Legal and compliance: It can be used for legal and audit purposes, documenting the delivery of goods as part of the sales transaction.


A packing slip in Dynamics 365 F&O is primarily used in the Accounts Receivable (AR) module. It is associated with the sales process, where goods are shipped to customers. The packing slip confirms the physical delivery of goods to the customer and plays a role in sales order processing.

In contrast, Accounts Payable (AP) typically deals with vendor transactions, where you might encounter documents like purchase orders or vendor invoices but not packing slips directly, as it focuses on receiving goods rather than shipping them.

Production order

In Dynamics 365 F&O/SCM, a production order represents a task to manufacture a specific quantity of an item. It serves as the central hub for tracking and managing production activities, including the consumption of materials, labor, and machinery. The production order goes through multiple stages like creating, scheduling, releasing, starting, and reporting as finished, ensuring that the entire process from raw materials to finished goods is accurately recorded.


Steps in a Production Order:


1. Creation: A production order is created based on a sales order or demand forecast. It specifies the item to be produced, the quantity, and the due date.


2. Scheduling: This step involves assigning resources such as labor, machines, and tools to ensure the production timeline is feasible. The scheduling can be forward (starting as early as possible) or backward (working from the due date).


3. Release: When all materials and resources are available, the order is released, signaling the start of production. This allows material picking and production tasks to commence.


4. Production: During this phase, the raw materials are consumed, and work progresses on the production floor. Time and resource consumption are tracked, along with the status of the production.


5. Report as Finished: Once the production is completed, the items are reported as finished, and the produced quantity is moved to inventory.


6. Costing: Finally, the system calculates the cost of production based on material usage, labor, and overhead costs.



Use Case Scenario for Lifestyles:


At Lifestyles, you may create a production order for a batch of condoms. For example, if there is an order to produce 10,000 condoms of a specific type (e.g., lubricated), a production order will be generated specifying this quantity. The necessary materials, such as latex and lubricants, would be allocated. The scheduling ensures the availability of machines used for molding and quality checks. Once production is completed, the finished goods will be recorded in inventory, and the total cost of producing these condoms will be calculated, including materials, labor, and machine usage.


This process helps Lifestyles track production costs and ensure timely manufacturing to meet demand efficiently.

Transfer order

 what is a transfer order in D365 F&O/SCM. Explain in depth and use case scenario with example of lifestyles.


In Dynamics 365 Finance & Operations (D365 F&O)/Supply Chain Management (SCM), a Transfer Order is used to move inventory between different locations or warehouses within the same legal entity. It enables businesses to manage stock movements between plants, warehouses, or distribution centers while tracking the inventory's status during the transfer. Unlike purchase or sales orders, no external vendor or customer is involved; it's strictly internal.


In-depth Explanation:


1. Creation of Transfer Order: A transfer order is created when there is a need to transfer inventory from one warehouse to another. This process involves specifying the item, source warehouse, and destination warehouse, along with the quantity to be transferred.



2. Shipment Process: The inventory is then physically picked and shipped from the source warehouse. This step ensures that stock is deducted from the source warehouse's available inventory.



3. In-transit Status: During transit, the inventory is no longer available for use at either location. The system reflects this in-transit status, ensuring accurate stock management across locations.



4. Receiving Process: Once the goods arrive at the destination warehouse, they are received and added to the destination's available stock.



5. Accounting and Tracking: Throughout the process, D365 F&O records the inventory's journey, allowing for transparency and accountability.




Use Case for Lifestyles:


Imagine that Lifestyles has two warehouses, one in Bengaluru and another in Delhi. If the Bengaluru warehouse is running low on certain raw materials, and the Delhi warehouse has excess stock, a transfer order can be created in D365 F&O to transfer these materials from Delhi to Bengaluru. The transfer order tracks the entire movement—from picking the stock in Delhi, shipping it, and then receiving it in Bengaluru—ensuring that both locations have an accurate reflection of their inventories.


This helps Lifestyles maintain smooth production without interruptions caused by inventory shortages or

 delays in procurement.



Path :

Path for transfer order : https://lsdev0251da9102f61dad47devaos.axcloud.dynamics.com/?cmp=es80&mi=InventJournalTableTransfer

Inventory management > Journal entries > Items > Transfer






























----------------------------------------------------------------------------------------------------------------------------

Question: Is transfer journal and movement journal same ?

No, a Transfer Journal and a Movement Journal are not the same in Dynamics 365 Finance & Operations (D365 F&O). While both are used for internal inventory movements, they serve different purposes:

Transfer Journal:

  • The Transfer Journal is used for simple inventory transfers between different locations or warehouses within the same company. It directly adjusts the stock levels without the need for complex shipping or receiving processes.
  • Typically used when you don't need to track in-transit inventory, and the transfer is considered instant.

Movement Journal:

  • The Movement Journal is used to adjust the inventory within a single warehouse or location. It is commonly applied for movements that don't involve different warehouses, such as reclassifying stock from one bin to another within the same warehouse.
  • It can also be used to correct stock levels or manage inventory discrepancies.

Key Differences:

  • Transfer Journal involves moving stock between two different locations (warehouses or sites).
  • Movement Journal involves reclassifying or adjusting stock within the same warehouse or location.

Sales cycle in D365 FO | Data flow from SalesTable and SalesLine tables to customer invoicing and ledger posting

The data flow from SalesTable and SalesLine tables to customer invoicing and ledger posting in Dynamics 365 Finance & Operations (D365 F&O) involves several steps and multiple tables. Here's a comprehensive and accurate outline of the data flow, along with the names of the tables involved and the key processes:

1. Sales Order Creation

  • Tables Involved:
    • SalesTable: Stores header-level information of the sales order (e.g., order number, customer, dates).
    • SalesLine: Stores line-level details of the sales order (e.g., item numbers, quantity, price).
  • Process: Sales order entry.

2. Sales Order Confirmation

  • Tables Involved:
    • SalesTable (updated): Status is updated to "Confirmed."
    • SalesLine (updated): Status is updated to "Confirmed."
    • SalesParmTable: Stores parameter data for the sales order confirmation.
    • SalesParmLine: Stores line-level information for the confirmation.
  • Process: Sales order confirmation.

3. Packing Slip Posting

  • Tables Involved:
    • CustPackingSlipJour: Stores the header information for the packing slip (shipment).
    • CustPackingSlipTrans: Stores line-level details of the packing slip.
    • InventTrans: Tracks inventory transactions for the shipped items.
  • Process: Posting the packing slip (shipment) to indicate that goods have been shipped.

4. Invoice Posting

  • Tables Involved:
    • CustInvoiceJour: Stores the header information of the customer invoice.
    • CustInvoiceTrans: Stores line-level details of the customer invoice.
    • CustTrans: Tracks the customer transactions related to the invoice.
    • CustSettlement: Tracks settlement details of the invoice and payment.
    • CustPostInvoiceJour: Stores detailed posting information about the customer invoice.
    • CustTransOpen: Tracks open (outstanding) transactions, such as unpaid invoices.
    • LedgerJournalTrans: Records financial postings related to the invoice.
    • InventTrans (updated): Inventory is adjusted upon invoice posting.
  • Process: Customer invoicing.

5. Ledger Posting (Financial Integration)

  • Tables Involved:
    • LedgerJournalTable: Stores header information about the general ledger journals.
    • LedgerJournalTrans: Stores the actual journal entries related to the invoice (account postings for revenue, cost of goods sold, taxes, etc.).
    • CustTrans (updated): Customer transaction is recorded in financials.
    • VendTrans (if related to intercompany transactions): Tracks vendor transactions.
  • Process: Ledger postings for financial accounting purposes.

6. Payment and Settlement

  • Tables Involved:
    • CustTrans (updated): Updated when the payment is received.
    • CustSettlement (updated): Settlement between the invoice and payment.
    • CustTransOpen (updated): Closed once the payment is fully settled.
    • LedgerJournalTrans: Records journal entries for the payment and settlement.
  • Process: Customer payment and invoice settlement.

Summary of Key Tables:

  • Sales Order:
    • SalesTable, SalesLine
  • Order Confirmation:
    • SalesParmTable, SalesParmLine
  • Packing Slip Posting:
    • CustPackingSlipJour, CustPackingSlipTrans
  • Invoice Posting:
    • CustInvoiceJour, CustInvoiceTrans, CustTrans, CustPostInvoiceJour
  • Ledger Posting:
    • LedgerJournalTable, LedgerJournalTrans
  • Payment and Settlement:
    • CustTrans, CustSettlement, CustTransOpen

This is the typical flow of data from the sales order to invoicing and payment settlement in D365 F&O.

Data entitiy insert method COC

[ExtensionOf(tableStr(SalesOrderHeaderEntity))]

final class LSAYSalesOrderHeaderEntity_Extension

{

    public void insert()

    {


        next insert();

        

        if(LSParameters::find().FiscalDocumentSourceText == NoYes::Yes)

        {

            SalesTable      SalesTableLocal;

            SalesTable_BR   SalesTable_BRLocal;

            select firstonly SalesTableLocal

                where SalesTableLocal.SalesId == this.SalesOrderNumber;

            select firstonly SalesTable_BRLocal

                where SalesTable_BRLocal.SalesTable == SalesTableLocal.RecId;

            SalesTable_BR::getFiscalTextDocument(SalesTableLocal, SalesTable_BRLocal.SalesPurchOperationType_BR);

        }

    }


}

Find Current Exchange rate using X++ / Ax

/// <summary>

/// Global class used for generic methods.

/// added by santhosh 

/// </summary>

class LSGlobal

{

    public static real LSexchangeRate(

                                        CurrencyCode fromCurrency,

                                        CurrencyCode toCurrency,

                                        TransDate    transDate = today())

    {

        ExchangeRate                exchangeRate;

        ExchangeRateType            ExchangeRateType;

        ExchangeRateCurrencyPair    exchangeRateCurrencyPair;

        real                        exchRate;

    

        select firstonly exchangeRateCurrencyPair

            where exchangeRateCurrencyPair.ExchangeRateType == Ledger::find(Ledger::current()).DefaultExchangeRateType

            &&  exchangeRateCurrencyPair.FromCurrencyCode   == fromCurrency

            &&  exchangeRateCurrencyPair.ToCurrencyCode     == toCurrency;


        exchRate = exchangeRate::findByDate(exchangeRateCurrencyPair.RecId,transDate).ExchangeRate;

        return exchRate/100;

    }


}

SSRS report with query D365 fo dynamics query with records to include in report

DP CLASS

/// <summary>
/// RDP class for SCRF Export report
/// </summary>
[
    SRSReportQueryAttribute(queryStr(LSSCRFExportQuery))
]
public final class LSSCRFExportDP extends SRSReportDataProviderPreProcessTempDB
{
    LSSCRFExportReportTmp   scrfExportReportTmp;
    NoYes                   scrfEnhancementFeature;

    /// <summary>
    /// Method to get report data for LSSCRFExportReportTmp table
    /// </summary>
    /// <returns>LSSCRFExportReportTmp</returns>
    [SRSReportDataSetAttribute(tableStr(LSSCRFExportReportTmp))]
    public LSSCRFExportReportTmp getLSSCRFExportReportTmp()
    {
        select scrfExportReportTmp;
        return scrfExportReportTmp;
    }

    /// <summary>
    /// Method to process report data
    /// </summary>
    public void processReport()
    {
        Query                   query       = this.parmQuery();
        QueryRun                queryRun    = new QueryRun(query);
        LSSCRFMainTable         scrfMainTable;
        LSSCRFLine              scrfLine;
        LSSCRFFeatureLine       featureLine;

        scrfEnhancementFeature = LSEnableDisableFeaturesSetup::find(LSFeaturesList::SCRFEnhancement).Enabled;
        scrfExportReportTmp.setConnection(this.parmUserConnection());

        while (queryRun.next())
        {
            scrfMainTable   = queryRun.get(tableNum(LSSCRFMainTable));
            scrfLine        = queryRun.get(tableNum(LSSCRFLine));
            featureLine     = queryRun.get(tableNum(LSSCRFFeatureLine));

            this.insertData(scrfMainTable, scrfLine, featureLine);
        }
    }

    /// <summary>
    /// Method to insert report data into temp table
    /// </summary>
    /// <param name = "_scrfMainTable">_scrfMainTable</param>
    /// <param name = "_scrfLine">_scrfLine</param>
    /// <param name = "_featureLine">_featureLine</param>
    public void insertData(LSSCRFMainTable _scrfMainTable, LSSCRFLine _scrfLine, LSSCRFFeatureLine _featureLine)
    {
        LSSCRFPackagingLine primaryPackagingLine, secondaryPackagingLine, tertiaryPackagingLine, quarternaryPackagingLine;

        select firstonly primaryPackagingLine
            where primaryPackagingLine.LinePackagingType == LSLinePackagingType::Primary
            && primaryPackagingLine.FeatureLineRecId == _featureLine.RecId;

        select firstonly secondaryPackagingLine
            where secondaryPackagingLine.LinePackagingType == LSLinePackagingType::Secondary
            && secondaryPackagingLine.FeatureLineRecId == _featureLine.RecId;

        select firstonly tertiaryPackagingLine
            where tertiaryPackagingLine.LinePackagingType == LSLinePackagingType::Tertiary
            && tertiaryPackagingLine.FeatureLineRecId == _featureLine.RecId;

        select firstonly quarternaryPackagingLine
            where quarternaryPackagingLine.LinePackagingType == LSLinePackagingType::Quartenary
            && quarternaryPackagingLine.FeatureLineRecId == _featureLine.RecId;

        scrfExportReportTmp.clear();

        scrfExportReportTmp.SCRFId                                  = _scrfMainTable.SCRFId;
        scrfExportReportTmp.Description                             = _scrfMainTable.Description;
        scrfExportReportTmp.SCRFStatus                              = _scrfMainTable.SCRFStatus;
        scrfExportReportTmp.SCRFWorkflowStatus                      = _scrfMainTable.SCRFWorkflowStatus;
        scrfExportReportTmp.SubmittedBy                             = _scrfMainTable.SubmittedBy;
        scrfExportReportTmp.SubmittedDate                           = _scrfMainTable.SubmittedDate;
        scrfExportReportTmp.EffectiveDate                           = _scrfMainTable.EffectiveDate;
        scrfExportReportTmp.CreatedFor                              = _scrfMainTable.CreatedFor;
        scrfExportReportTmp.ReleaseNo                               = _scrfMainTable.ReleaseNo;
        // strmin() - Former type
        scrfExportReportTmp.ProductSubGroup                         = _scrfMainTable.ProductSubGroup;
        scrfExportReportTmp.ReasonForChange                         = _scrfMainTable.ReasonForChange;
        scrfExportReportTmp.HoldReason                              = _scrfMainTable.HoldReason;
        scrfExportReportTmp.Provisional                             = _scrfMainTable.Provisional;
        scrfExportReportTmp.CustAccount                             = _scrfMainTable.CustAccount;
        scrfExportReportTmp.CountryOfSaleMulti                      = _scrfMainTable.CountryOfSaleMulti;
        // strmin() - Machine
        scrfExportReportTmp.RegionCode                              = _scrfMainTable.RegionCode;
        scrfExportReportTmp.Standard                                = _scrfMainTable.Standard;
        scrfExportReportTmp.Standard2                               = _scrfMainTable.Standard2;
        scrfExportReportTmp.Standard3                               = _scrfMainTable.Standard3;
        scrfExportReportTmp.BatchSizeId                             = _scrfMainTable.BatchSizeId;
        [
            scrfExportReportTmp.PreprintCode,
            scrfExportReportTmp.BodySamplingCode,
            scrfExportReportTmp.ExtBodyLabName
        ]                                                           = this.getBodySampling(_scrfMainTable.SCRFId);
        scrfExportReportTmp.Thai501K                                = _scrfMainTable.Thai501K;
        scrfExportReportTmp.AdditionalTestReq                       = strRem('\'' + _scrfMainTable.AdditionalTestReq, '\'-');
            
        scrfExportReportTmp.ProductSelection                        = _scrfLine.ProductSelection;

        scrfExportReportTmp.FactoryProductCode                      = _featureLine.FactoryProductCode;
        scrfExportReportTmp.LatexType                               = _featureLine.LatexType;
        scrfExportReportTmp.Shape                                   = _featureLine.Shape;
        scrfExportReportTmp.Texture                                 = _featureLine.Texture;
        scrfExportReportTmp.ThicknessFeature                        = _featureLine.ThicknessFeature;
        scrfExportReportTmp.DimesionSpecification                   = _featureLine.DimesionSpecification;
        scrfExportReportTmp.Size                                    = _featureLine.Size;
        scrfExportReportTmp.Length                                  = _featureLine.Length;
        scrfExportReportTmp.Thickness                               = _featureLine.Thickness;
        scrfExportReportTmp.Width                                   = _featureLine.Width;
        scrfExportReportTmp.LubricantType                           = _featureLine.LubricantType;
        scrfExportReportTmp.LubricantQty                            = _featureLine.LubricantQty;
        scrfExportReportTmp.Color                                   = _featureLine.Color;
        scrfExportReportTmp.Flavour                                 = _featureLine.Flavour;
        scrfExportReportTmp.Masking                                 = _featureLine.Masking;
        scrfExportReportTmp.ExpiryDate                              = _featureLine.ExpiryDate;
        scrfExportReportTmp.FoilType                                = _featureLine.FoilType;

        scrfExportReportTmp.FilmType_Primary                        = primaryPackagingLine.FilmType;
        scrfExportReportTmp.PrintingOn_Primary                      = primaryPackagingLine.RecId ? enum2Str(primaryPackagingLine.PrintingOn) : '';
        scrfExportReportTmp.LotType_Primary                         = primaryPackagingLine.RecId ? enum2Str(primaryPackagingLine.LotType) : '';
        scrfExportReportTmp.ExpDateFormat_Primary                   = primaryPackagingLine.ExpDateFormat;
        scrfExportReportTmp.AdditionalPrinting_Primary              = primaryPackagingLine.AdditionalPrinting;
        scrfExportReportTmp.AdditionalPrintText_Primary             = primaryPackagingLine.AdditionalPrintText;
        scrfExportReportTmp.TopPk_Primary                           = primaryPackagingLine.TopPk;
        scrfExportReportTmp.BottomPk_Primary                        = primaryPackagingLine.BottomPk;
        scrfExportReportTmp.TopPk1_Primary                          = primaryPackagingLine.TopPk1;
        scrfExportReportTmp.BottomPk1_Primary                       = primaryPackagingLine.BottomPk1;
        scrfExportReportTmp.StripLength_Primary                     = primaryPackagingLine.StripLength;

        scrfExportReportTmp.PartialStripAllowed_Primary             = primaryPackagingLine.RecId ? enum2Str(primaryPackagingLine.PartialStripAllowed) : '';
        scrfExportReportTmp.AllowableStrips_Primary                 = strLRTrim(strReplace(primaryPackagingLine.AllowableStrips, 'Max. partial strip allowed', strMin()));
        scrfExportReportTmp.PartialStrips_Primary                   = primaryPackagingLine.RecId ? enum2Str(primaryPackagingLine.PartialStripsPacking) : '';
        scrfExportReportTmp.BulkStripsOrFullyPacked_Primary         = primaryPackagingLine.RecId ? enum2Str(primaryPackagingLine.BulkStripsOrFullyPacked) : '';
        scrfExportReportTmp.PackingInfo_Primary                     = primaryPackagingLine.PackingInfo;
        scrfExportReportTmp.AddPKNum_Primary                        = this.getAdditionalPkNum(primaryPackagingLine.RecId);
            
        scrfExportReportTmp.Type_Secondary                          = secondaryPackagingLine.Type;
        scrfExportReportTmp.PKNumber_Secondary                      = secondaryPackagingLine.PKNumber;
        scrfExportReportTmp.AddPkNum_Secondary                      = this.getAdditionalPkNum(secondaryPackagingLine.RecId);
        scrfExportReportTmp.CondomQtyIn2ndPack_Secondary            = secondaryPackagingLine.CondomQtyIn2ndPack;
        scrfExportReportTmp.PackingInfo_Secondary                   = secondaryPackagingLine.PackingInfo;
        scrfExportReportTmp.AdditionalPrintText_Secondary           = secondaryPackagingLine.AdditionalPrintText;

        scrfExportReportTmp.Type_Tertiary                           = tertiaryPackagingLine.Type;
        scrfExportReportTmp.PKNumber_Tertiary                       = tertiaryPackagingLine.PKNumber;
        scrfExportReportTmp.AddPkNum_Tertiary                       = this.getAdditionalPkNum(tertiaryPackagingLine.RecId);
        scrfExportReportTmp.CondomQtyIn3rdPack_Tertiary             = tertiaryPackagingLine.CondomQtyIn3rdPack;
        scrfExportReportTmp.PackingInfo_Tertiary                    = tertiaryPackagingLine.PackingInfo;
        scrfExportReportTmp.AdditionalPrintText_Tertiary            = tertiaryPackagingLine.AdditionalPrintText;

        scrfExportReportTmp.Type_Quarternary                        = quarternaryPackagingLine.Type;
        scrfExportReportTmp.PKNumber_Quarternary                    = quarternaryPackagingLine.PKNumber;
        scrfExportReportTmp.AddPkNum_Quarternary                    = this.getAdditionalPkNum(quarternaryPackagingLine.RecId);
        scrfExportReportTmp.CondomQtyInMasterCarton_Quarternary     = quarternaryPackagingLine.CondomQtyInMasterCarton;
        scrfExportReportTmp.PartialCartonAllowed_Quarternary        = quarternaryPackagingLine.RecId ? enum2Str(quarternaryPackagingLine.PartialCartonAllowed) : '';
        scrfExportReportTmp.PackingInfo_Quarternary                 = quarternaryPackagingLine.PackingInfo;

        scrfExportReportTmp.SCRFEnhancementFeature                  = scrfEnhancementFeature;
        scrfExportReportTmp.insert();
    }

    /// <summary>
    /// Method to get additional PK numbers
    /// </summary>
    /// <param name = "_recId">_recId</param>
    /// <returns>Additional PK numbers</returns>
    public str getAdditionalPkNum(RecId _recId)
    {
        LSSCRFPackAdditionalReq primaryAddReq;
        str                     addPKNum;

        while select PKNumber from primaryAddReq
            where primaryAddReq.LSSCRFPackagingLine == _recId && primaryAddReq.PKNumber
        {
            addPKNum += primaryAddReq.PKNumber + ',';
        }

        return addPKNum;
    }

    /// <summary>
    /// Method to get the body sampling data
    /// </summary>
    /// <param name = "_scrfId">_scrfId</param>
    /// <returns>Body sampling data</returns>
    public container getBodySampling(LSSCRFId _scrfId)
    {
        LSSCRFApprovalPreprintBodySampling  bodySampling;
        LSPreprintCode                      prePrintCode;
        LSBodySamplingCode                  bodySamplingCode;
        LSExtBodyLabName                    extBodyLabName;

        while select PreprintCode, BodySamplingCode, ExtBodyLabName from bodySampling
            where bodySampling.SCRFId == _scrfId
        {
            if(bodySampling.PreprintCode != strMin())
            {
                prePrintCode += bodySampling.PreprintCode + ',';
            }
            if(bodySampling.BodySamplingCode != strMin())
            {
                bodySamplingCode += bodySampling.BodySamplingCode + ',';
            }
            if(bodySampling.ExtBodyLabName != strMin())
            {
                extBodyLabName += bodySampling.ExtBodyLabName + ',';
            }
        }

        return [prePrintCode, bodySamplingCode, extBodyLabName];
    }

}


Controller

/// <summary>
/// Controller class for Export SCRF report
/// </summary>
public class LSSCRFExportReportController extends SrsReportRunController implements BatchRetryable
{
    /// <summary>
    /// Main method
    /// </summary>
    /// <param name = "_args">_args</param>
    public static void main(Args _args)
    {
        LSSCRFExportReportController controller = new LSSCRFExportReportController();

        controller.parmReportName(ssrsReportStr(LSSCRFExportReport, DesginV1));
        controller.parmArgs(_args);
        controller.startOperation();
    }

    public ClassDescription caption()
    {
        return "@LS_HISOL:ExportSCRFReport";
    }

    /// <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;
    }

}


Unified Experience dev d365 fo development server

https://devblogs.microsoft.com/powerplatform/the-public-preview-for-the-unified-experience-is-live/

Planned order in d365

What is Planned Transfer Orders in d365


In Dynamics 365 Finance and Operations (D365 F&O), Planned Transfer Orders are part of the Master Planning module, which is used to handle intercompany or intersite transfers of goods based on planned demand. Essentially, they represent a forecasted or planned movement of inventory between two different warehouses, sites, or legal entities within an organization.


Key Features of Planned Transfer Orders:

1. Demand-Driven: They are generated when there is a forecast or demand for a product at a particular location, but the inventory needs to be transferred from another location to meet that demand.

  

2. Generated by Master Planning: When Master Planning runs, it analyzes current stock levels, future demand, and supply, and it generates planned transfer orders if there’s a need to move inventory between different sites or warehouses.


3. Conversion to Transfer Orders: Planned transfer orders are not actual transactions. They are suggestions or plans that need to be reviewed and converted into actual transfer orders, which can then be processed for execution.


4. Optimization of Stock Levels: By using planned transfer orders, a company can ensure optimal stock levels across different locations, reducing the risk of stockouts in some locations while preventing overstock in others.


5. Lead Time Consideration: When creating planned transfer orders, D365 F&O takes into account lead times, transportation methods, and other logistical details to ensure that the stock will arrive in time to meet demand.


In short, Planned Transfer Orders help streamline internal logistics and stock movements across different locations within an organization, making sure that goods are in the right place at the right time.






Understanding the Planned Order Process in Dynamics 365 F&O

The process of handling Planned Orders in Dynamics 365 F&O starts with Master Planning and ends with the firming of the order. Let’s break down this process step by step:


1. Master Planning Setup

- Define planning parameters such as lead times, item coverage, safety stock, and replenishment rules (like make-to-order or make-to-stock).


2. Demand Forecasting and Supply Analysis

- Master planning runs based on sales orders, demand forecasts, or safety stock levels.

- The system analyzes the demand and supply requirements for the products.


3. Master Planning Run

- Execute Master Planning or Forecast Planning to create suggestions for fulfilling demands.

- The system generates Planned Orders for production, purchase, or transfer.


4. Review Planned Orders

- Users can review the Planned Production Orders, Planned Purchase Orders, or Planned Transfer Orders generated.

- The planner checks if the planned orders align with business needs and adjusts any quantities, dates, or other parameters if necessary.


5. Firming the Planned Order

- Once the planner is satisfied with the suggested orders, they firm the planned orders.

- Firming converts the planned order into an actionable order:

  - Planned Purchase Order → Purchase Order

  - Planned Production Order → Production Order

  - Planned Transfer Order → Transfer Order


6. Execution of Firmed Orders

- After firming, the purchase orders are sent to suppliers, production orders are sent to manufacturing, and transfer orders are processed for moving goods between warehouses.


7. Completion of Order

- The process ends when the firmed orders are completed (products are produced, purchased, or transferred as required).