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
Post a Comment