Customization on Sales invoice Report in D365 F&O

 We have a requirement to create a new design and show some new fields in the sales invoice report. 


So for that we need to consider the below steps :- 


1) Controller class than extends standard class and create alogic.

2) Create a print management class to call the new design.

3) Extension of DP class to write a logic.

4) Report design.

====================================================================

1) Controller class : - 

/// <summary>

/// Extension of the controller class to call the custom design of report "MMSSalesInvoice.report" for MMS legal entity.

/// </summary>

class MMSSalesInvoiceController extends SalesInvoiceController

{


  

    public static MMSSalesInvoiceController construct()

        {

            return new MMSSalesInvoiceController();

        }


        public static void main(Args _args)

        {

            SrsReportRunController formLetterController = MMSSalesInvoiceController::construct();

            MMSSalesInvoiceController controller = formLetterController;

         

            if(curExt() == "MMS")

            {

                controller.parmReportName(ssrsReportStr(MMSSalesInvoice, Report));

                

            }

            else if(curExt() == "PP01")

            {

                controller.parmReportName(ssrsReportStr(PPSalesInvoice, Report));

                

            }

            else

            {

                controller.parmReportName(ssrsReportStr(SalesInvoice, Report));

            }

                

            controller.parmArgs(_args);

            formLetterController.parmShowDialog(false);

            controller.startOperation();

        }


    /// <summary>

    ///    Initializes the form letter report.

    /// </summary>

    protected void initFormLetterReport()

    {

        formLetterReport = FormLetterReport::construct(PrintMgmtDocumentType::SalesOrderInvoice);

        formLetterReport.parmPrintType(PrintCopyOriginal::OriginalPrint);

        formLetterReport.parmReportRun().parmCheckScreenOutput(true);


        super();

    }


    /// <summary>

    /// Loads and iterates through print settings for the specified record.

    /// </summary>

    /// <remarks>Method overload added for extensibility.</remarks>

    protected void outputReports()

    {

        super();

    }


}

=====================================================================

2) Print management event handler :- 


/// <summary>

/// Add the custom report for the sales invoice i.e "MMSSalesInvoice.Report" in the prient management setting.

/// </summary>

class MMSPrintMgtDocTypeHandlersExt

{

    [SubscribesTo(classstr(PrintMgmtDocType), delegatestr(PrintMgmtDocType, getDefaultReportFormatDelegate))]

    public static void getDefaultReportFormatDelegate(PrintMgmtDocumentType _docType, EventHandlerResult _result)

    {

        switch (_docType)

        {

            // Sales invoice report.

            case PrintMgmtDocumentType::SalesOrderInvoice:

                if(curExt()=='MMS')

                    _result.result(ssrsReportStr(MMSSalesInvoice, Report));


                else if(curExt()=='PP01')

                    _result.result(ssrsReportStr(PPSalesInvoice, Report));

                   


                else

                    _result.result(ssrsReportStr(SalesInvoice, Report));

               break;


            //PO Confirmation report.

            case PrintMgmtDocumentType::PurchaseOrderRequisition:

                _result.result(ssrsReportStr(MMSPurchPurchaseOrder,Report));

                break;

           

        }

    }


}

=======================================================================

3) Dp class extends


/// <summary>

/// Extension of the sales "SalesInvoiceDP" class to fill the data in the temp table.

/// </summary>

[ExtensionOf(classstr(SalesInvoiceDP))]

final class MMSSalesInvoiceDP_Extension

{

    

    

    protected void populateSalesInvoiceTmp( CustInvoiceJour _custInvoiceJour,

                                            CustInvoiceTrans _custInvoiceTrans,

                                            TaxSpec _taxSpec,

                                            CustPaymSchedLine _custPaymSchedLine,

                                            CustTrans _prepaymentCustTrans,

                                            TaxTrans _prepaymentTaxTrans )

    {

        next populateSalesInvoiceTmp( _custInvoiceJour,

                                     _custInvoiceTrans,

                                     _taxSpec,

                                     _custPaymSchedLine,

                                     _prepaymentCustTrans,

                                     _prepaymentTaxTrans);


        SalesInvoiceTmp         salesInvoiceTmp = this.parmSalesInvoiceTmp();

        SalesLine               salesLine       = _custInvoiceTrans.salesLine(), salesLineLoc;

        amount                  LineDiscount, exchangeAmount, totalAmount;

        currencyCode            salesTableCurrencyCode = SalesTable::find(salesLine.SalesId).CurrencyCode;

        CurrencyExchangeRate    exchRate;


       

        salesInvoiceTmp.MMSProductDes  = salesLine.Name;

        salesInvoiceTmp.MMSDiscPercent = SalesTable::find(salesLine.SalesId).DiscPercent;

        salesInvoiceTmp.MMSAmountInWords = this.AmountToWords(_custInvoiceJour.InvoiceAmount);


        if(curExt() =="PP01")

        {


            LineDiscount = salesLine.SalesQty * salesLine.SalesPrice;


            salesInvoiceTmp.MMSDiscAmount = (LineDiscount * SalesTable::find(salesLine.SalesId).DiscPercent) / 100;


            if(salesLine.LineDisc)

            {

                salesInvoiceTmp.MMSDiscAmount = salesLine.LineDisc;

            }


            else  if(salesLine.LinePercent)

            {

                salesInvoiceTmp.MMSDiscAmount = (LineDiscount * salesLine.LinePercent) / 100 ;

            }


            salesInvoiceTmp. LineAmount = salesLine.SalesQty * salesLine.SalesPrice;


            salesInvoiceTmp.LineAmountInclTax = salesInvoiceTmp. LineAmount - salesInvoiceTmp.MMSDiscAmount; //_custInvoiceTrans.LineAmount + _custInvoiceTrans.LineAmountTax - salesInvoiceTmp.MMSDiscAmount;

           

            salesInvoiceTmp.MMSTaxAmount = Tax::calcTaxAmount(salesLine.TaxGroup, salesLine.TaxItemGroup, Systemdateget(), salesLine.CurrencyCode, salesInvoiceTmp.LineAmountInclTax, TaxModuleType::Sales);


           

            LineDiscount = 0.00;

        }


        this.parmSalesInvoiceTmp(salesInvoiceTmp);

    }


    /// <summary>

    /// Processes the report business logic.

    /// </summary>

    /// <remarks>

    /// This method provides the ability to write the report business logic and will be called by the SSRS

    /// at runtime. The method will compute data and populate the data tables that will be returned to the

    /// SSRS. Note that this is a framework class. Customizing this class can cause problems with future

    /// upgrades to the software.

    /// </remarks>

    public void processReport()

    {

        next processReport();


        amount                  Totaldiscount, TotaltaxAmount,TotalLineAmount, finalTotal, exchangeAmount;

        CurrencyExchangeRate    exchRate, totalExchangeValue;

        SalesInvoiceTmp         salesInvoiceTmp = this.parmSalesInvoiceTmp();

        SalesInvoiceTmp         salesInvoiceTmpLoc = salesInvoiceTmp;


        if(curExt() =="PP01")

        {

            Totaldiscount   = 0.00;

            TotaltaxAmount  = 0.00;

            finalTotal      = 0.00;

            exchRate        = 0.00;

            exchangeAmount  = 0.00;


            select sum(MMSDiscAmount), sum(LineAmount) from salesInvoiceTmp;

            {

                Totaldiscount   = salesInvoiceTmp.MMSDiscAmount;

               // TotaltaxAmount  = salesInvoiceTmp.MMSTaxAmount;

                TotalLineAmount = salesInvoiceTmp.LineAmount;

            }


            select forupdate salesInvoiceTmpLoc;// where salesInvoiceTmpLoc.recid == salesInvoiceTmp.RecId;

            {

                ttsbegin;


                finalTotal = TotalLineAmount + salesInvoiceTmp.SumTax + salesInvoiceTmp.SumMarkup - Totaldiscount;


                salesInvoiceTmpLoc.MMSAmountInWords = HSPurchPurchaseOrder_EventHandler::numeralsToTxt(finalTotal);


                if(salesInvoiceTmpLoc.CustInvoiceJourCurrencyCode != "AED")

                {

                

                    exchRate = this.getExchRate(ExchangeRateType::findByName("Default"), salesInvoiceTmpLoc.CustInvoiceJourCurrencyCode, "AED", salesInvoiceTmpLoc.CustInvoiceJourDueDate);


                    if(exchRate > 0.00)

                    {

                        exchangeAmount = (finalTotal)  * exchRate;


                        salesInvoiceTmp.MMSAmountInWordsExchange = HSPurchPurchaseOrder_EventHandler::numeralsToTxt(exchangeAmount);

                        salesInvoiceTmp.MMSTotalAmountExchange = exchangeAmount;

                    }

                    else

                    {

                        salesInvoiceTmp.MMSAmountInWordsExchange =  HSPurchPurchaseOrder_EventHandler::numeralsToTxt(finalTotal);

                        salesInvoiceTmp.MMSTotalAmountExchange = finalTotal;

                    }


                        salesInvoiceTmp.MMSTotalExchangeRateValue = decRound(salesInvoiceTmp.SumTax * exchRate, 2);

                    salesInvoiceTmp.MMSExchangeRate = exchRate;

                }


                salesInvoiceTmpLoc.update();

                ttscommit;;

           

            }

        }


    }


    public SalesInvoiceTmp parmSalesInvoiceTmp(SalesInvoiceTmp _salesInvoiceTmp = salesInvoiceTmp)

    {

        this.salesInvoiceTmp = _salesInvoiceTmp;

        return this.salesInvoiceTmp;

    }


    /// <summary>

    /// Method used to convert the value in the amount to words helpfull for the amount to display in SSRS report.

    /// </summary>

    public Description255 AmountToWords(AmountCur _invoiceAmount)

    {

        Amount amount;

        Description amount2Str;

        amount = _invoiceAmount;


        if (amount > 0)

        {

            amount = real2int(round(amount , 1));

        }

        else

        {

            amount = real2int(round(-(amount) , 1));

        }

        amount2Str = Global::numeralsToTxt(amount);

        amount2Str = subStr(amount2Str,5,strLen(amount2Str)-4);

        amount2Str = subStr(amount2Str,strLen(amount2Str)-10,- strLen(amount2Str));

        amount2Str = str2Capital(amount2Str) + 'only.';


        return amount2Str;

    }


    /// <summary>

    /// Gets exchange rates from the <c>ExchangeRateType</c> value.

    /// </summary>

    /// <param name="_exchangeRateType">

    /// The target <c>ExchangeRateType</c> value.

    /// </param>

    /// <param name="_fromCurrency">

    /// The currency to convert from.

    /// </param>

    /// <param name="_toCurrency">

    /// The currency to convert to.

    /// </param>

    /// <param name="_transDate">

    /// The transaction date.

    /// </param>

    /// <returns>

    /// The exchange rate based on given criteria.

    /// </returns>

    public CurrencyExchangeRate getExchRate(ExchangeRateType _exchangeRateType, CurrencyCode _fromCurrency, CurrencyCode _toCurrency, TransDate _transDate)

    {

        ExchangeRateCurrencyPair    exchangeRateCurrencyPair;

        ExchangeRate                exchangeRate;

        TransDate                   validFromDate;

        CurrencyExchangeRate        exchRate;

        CurrencyExchangeRate        variableExchangeRate;


        validFromDate = mkDate(1, mthOfYr(_transDate), year(_transDate));


        select firstonly RecId from exchangeRateCurrencyPair

        where exchangeRateCurrencyPair.FromCurrencyCode    == _fromCurrency

            && exchangeRateCurrencyPair.ToCurrencyCode     == _toCurrency

            && exchangeRateCurrencyPair.ExchangeRateType   == _exchangeRateType.RecId;


        if (exchangeRateCurrencyPair.RecId)

        {

            select firstonly

            //select an exchange rate that is valid between the month start date of the transDate and the transDate

            validtimestate(validFromDate, _transDate)

            exchangeRate

            where exchangeRate.ExchangeRateCurrencyPair == exchangeRateCurrencyPair.RecId

                // ValidFrom date needs to be between the month start date of the transDate and the transDate

            && exchangeRate.ValidFrom >= validFromDate

                && exchangeRate.ValidFrom <= _transDate

                //ValidTo date needs to be greater or equal to transDate

            && exchangeRate.ValidTo >= _transDate;


            exchRate = exchangeRate.ExchangeRate / 100;


            if(exchRate == 0.00)

            {

                select firstonly validtimestate(_transDate) ExchangeRate

                  from exchangeRate

                   where exchangeRate.ExchangeRateCurrencyPair == exchangeRateCurrencyPair.RecId;


                 exchRate = exchangeRate.ExchangeRate / 100;


                // Since the caller asked for the rate in terms of From > To, it must be the reciprocal

                // in order to be accurate.

              //  exchRate = ExchangeRateCalculation::calculateReciprocalExchangeRate(exchangeRate.ExchangeRate);

            }

        }


        return exchRate;

    }


}

=======================================================================



Comments

Popular posts from this blog

75) COC - Create a coc of the table modified method

46) D365 FO: SHAREPOINT FILE UPLOAD USING X++