hljs.configure({cssSelector: "code"}); hljs.highlightAll();

Friday, July 28, 2023

X++ to get addresses,GST Numbers,state code,HSN/SAC codes from Tax information of customer invoice journal in D365FO

 X++ to get addresses,GST Numbers,state code,HSN/SAC codes from Tax information of customer invoice journal in D365FO

TaxDocumentRowTransaction           taxDocumentRowTransaction;
TaxDocumentRowTransaction_IN        taxDocumentRowTransaction_IN;
TransTaxInformationHelper           transTaxInformationHelper;
TransTaxInformation                 transTaxInformation, transTaxInformationItem;
LogisticsPostalAddress              logisticsPostalAddress, supplierPostalAddress;
LogisticsAddressState               logisticsAddressState, supplierState;
CustInvoiceTrans					CustInvoiceTrans;
		
select taxDocumentRowTransaction
	where taxDocumentRowTransaction.voucher  == ""
		&& taxDocumentRowTransaction.Source == TaxModuleType::SalesInvoice
	join taxDocumentRowTransaction_IN
	where taxDocumentRowTransaction_IN.TaxDocumentRowTransactionRecId == taxDocumentRowTransaction.RecId;

//Retrieving address of a sales invoice journal(Customer tax information address from transaction level)
	
logisticsPostalAddress = LogisticsPostalAddress::findRecId(taxDocumentRowTransaction.PartyPostalAddress);
logisticsAddressState = LogisticsAddressState::find(logisticsPostalAddress.CountryRegionId, logisticsPostalAddress.State);

//Retrieving address of a sales invoice journal (company address from the transaction level)

supplierPostalAddress  = LogisticsPostalAddress::findRecId(taxDocumentRowTransaction.CompanyPostalAddress);
supplierState          = LogisticsAddressState::find(supplierPostalAddress.CountryRegionId, supplierPostalAddress.State);

select firstonly CustInvoiceTrans
	where CustInvoiceTrans.ParentRecId == custInvoiceJour.RecId;
	
// To get all the details from Tax Information at a Transaction level
transTaxInformationHelper = TransTaxInformationHelper::newHelper();
transTaxInformation       = transTaxInformationHelper.getTransTaxInformation(tableNum(CustInvoiceTrans), custInvoiceTransLoc.RecId);

// To get the Company address from tax information.
LogisticsLocationEntity::location2PostalAddress(transTaxInformation.CompanyLocation, DateTimeUtil::getSystemDateTime(), true).Address;
LogisticsLocationEntity::location2PostalAddress(transTaxInformation.CustomerLocation, DateTimeUtil::getSystemDateTime(), true).City;
LogisticsLocationEntity::location2PostalAddress(transTaxInformation.CustomerLocation, DateTimeUtil::getSystemDateTime(), true).ZipCode;

// Customer tax information address
LogisticsLocationEntity::location2PostalAddress(transTaxInformation.CustomerLocation, DateTimeUtil::getSystemDateTime(), true).Address;

// To Find HSN/SAC Code
HSNCodeTable_IN::find(transTaxInformation.HSNCodeTable).Code;
ServiceAccountingCodeTable_IN::find(transTaxInformation.ServiceAccountingCodeTable).SAC;

//Warehouse address
inventLocationLogisticsLocation inventLocationLogisticsLocation;
logisticsLocation 				logisticsLocation;
LogisticsPostalAddress  		logisticsPostalAddress;

InventLocation inventFromLocation = InventLocation::find('warehouse');
Select firstOnly inventLocationLogisticsLocation
	where inventLocationLogisticsLocation.InventLocation == inventFromLocation.RecId
		&& inventLocationLogisticsLocation.IsPrimary == 1;
		
if (inventLocationLogisticsLocation)
{
	select firstOnly logisticsLocation
		where logisticsLocation.RecId == InventLocationLogisticsLocation.Location;
}
logisticsPostalAddress = logisticsPostalAddress::findByLocation(logisticsLocation.recid);
info(LogisticsPostalAddress.Address);

// Replace '\n' with null in address
TextBuffer textBuffer = new TextBuffer();
textBuffer.setText(Address);
textBuffer.Replace('\n','');

info(textBuffer.getText());

//Get GSTIn Numbers
TaxRegistrationNumbers_IN taxRegistrationNumbers_IN;
TaxInformation_IN         taxInformation_IN;

select taxRegistrationNumbers_IN
	join taxInformation_IN
	where taxInformation_IN.GSTIN == taxRegistrationNumbers_IN.RecId
		&& taxInformation_IN.RecID == transTaxInformation.CustomerTaxInformation;
		
Info(taxRegistrationNumbers_IN.RegistrationNumber);

//Company GSTIN

TaxRegistrationNumbers_IN::find(transTaxInformation.GSTIN).RegistrationNumber;

Keep Learning!!

Tuesday, July 18, 2023

Custom service in D365FO

 Recently, I've got an requirement to send the vendor payments from D365FO to third party system. For that I have created custom service and exposed it to external application.

Steps to create custom service.

Step 1. Create a contract class for request.

Whenever third party system accessing our custom service they will provide invoice number as input. Based on the input will be sending the payment data against it.
Class CSVendTransRequestContract
{
    private   InvoiceID         InvoiceId;
    
    [DataMember("Invoice number")]
    public InvoiceId parmInvoiceNumber(InvoiceId _value = InvoiceId)
    {
        InvoiceId = _value;
        return InvoiceId;
    }
}

Step 2. Create another contract class for Response.

Response for our CS would be below columns form response contract class.



[DataContractAttribute,Newtonsoft.Json.JsonObject(IsReference = false)]
class CSVendTransResponseContract
{
    private   Voucher         paymentVoucher;
    private   Date            Pdate;
    private   Amount          amount,tdsAmount;
    private   str             number;
    private   str             paymentReference;

    [DataMember("Payment voucher")]
    public Voucher parmPaymentVoucher(Voucher _value = paymentVoucher)
    {
        paymentVoucher = _value;
        return paymentVoucher;
    }
    [DataMember("Date")]
    public date parmDate(date _value = Pdate)
    {
        Pdate = _value;

        return Pdate;
    }
    [DataMember("Amount")]
    public Amount parmAmount(Amount _value = amount)
    {
        amount = _value;
        return Amount;
    }
    [DataMember("TDS Amount")]
    public Amount parmTDSAmount(Amount _value = tdsAmount)
    {
        tdsAmount = _value;
        return tdsAmount;
    }
    [DataMember("Payment reference")]
    public Name parmPaymentReference(Name _value = paymentReference)
    {
        paymentReference = _value;
        return paymentReference;
    }
}

Step 3: Create a service class to run the business logic and return the response.

class CSVendTransService
{
    [AifCollectionType('return', Types::Class, classStr(CSVendTransResponseContract))]
    public  List SendResponse(CSVendTransRequestContract _invoices)
{ VendTrans vendTrans; VendSettlement vendSettlement; List resultSet = new List(Types::Class); while select SettleAmountMST,OffsetTransVoucher,TransDate from vendSettlement join PaymReference from vendTrans where vendTrans.recid == vendSettlement.TransRecId && vendTrans.AccountNum == vendSettlement.AccountNum && vendTrans.DataAreaId == vendSettlement.TransCompany && vendTrans.Invoice == _invoices.
parmInvoiceNumber( && vendTrans.TransType == LedgerTransType::Purch { CSVendTransResponseContract responseContract = new CSVendTransResponseContract(); responseContract.parmPaymentVoucher(vendSettlement.OffsetTransVoucher); responseContract.parmAmount(vendSettlement.SettleAmountMST); responseContract.parmDate(vendSettlement.TransDate); responseContract.parmTDSAmount(VendTrans_W::findByVendTrans(vendTrans.RecId).TDSAmount_IN); responseContract.parmPaymentReference(LedgerJournalTrans::find(vendtransLoc.JournalNum,vendtransLoc.Voucher,false).PaymReference); resultSet.addEnd(responseContract); } } return resultSet; }


Step 4: Create a service and open its properties and assign the service class Name (CSVendTransService). Refer below image





Next step is to create service operation and give a name and assign method name(SendResponse) in properties as below image.





Step 5 : Create a Service Group 
Right click on service group, create service and in its properties select the service created in step 4.

Refer below image.



Custom service is completed. Now lets test this custom service in Postman.

URL :

 https://xxxxx.sandbox.operations.dynamics.com/api/services/service group name/service name/service operation name

Sample request JSON

{
	_invoices :
	{
		"Invoice number" :"Test"
	}
}
Note : If you want to send the list of invoices in request body. in request contract create parm method which returns list.
 We have to create new contract class and parm method which returns list.

Sample JSON for List of invoices
{
	_invoices : [
	        {
		        "Invoice number" :"Test"
	        }
        ]
}
[DataContractAttribute] 
public class CSVendTransInvoicesListRequest
{
    private List    Invoices;

    [DataMemberAttribute('Contract'),
    DataCollection(Types::Class, classStr(CSVendTransResponseContract)),
    AifCollectionTypeAttribute('_contractClass', Types::Class, classStr(CSVendTransResponseContract)),
    AifCollectionTypeAttribute('return', Types::Class, classStr(CSVendTransResponseContract))]
    public List parmInvoices(List _contractClass = Invoices)
    {
        Invoices = _contractClass;
        return Invoices;
    }
}

Retrieving the list values in service class method.
class CSVendTransService
{
    [AifCollectionType('return', Types::Class, classStr(CSVendTransResponseContract))]
    public  List SendResponse(CSVendTransInvoicesListRequest _invoices)
    {
		list invoices  = _invoices.Parminvoices();
		listEnumerator enumerator = invoices.getEnumerator();
		while(enumerator.MoveNext())
		{
			CSVendTransRequestContract  contract = new CSVendTransRequestContract();
			contract = enumerator.current();
			
			// DO your operation
		}
	}
}

Keep Learning!!

Wednesday, July 5, 2023

Export DMF Package Using logic apps

Export DMF Package Using logic apps

Step 1: Create a  Http request is received and Build the request body with parameters.

Definition Group Id and Package name  is Data Project Name.


Step 2: Create a new step and select Fin & Ops trigger as below image. After that select the environment and make the connection.

Step 3: Create a Until Trigger and within until trigger create Delay trigger and Fin and Ops Execute action trigger.

Fin & Ops DMF action is DataManagementDefinitionGroups-GetExecutionSummaryStatus.

In until Trigger write below expression.

@or(equals(body('Execute_action_3')?['value'], 'Succeeded'),equals(body('Execute_action_3')?['value'], 'PartiallySucceeded'),equals(body('Execute_action_3')?['value'], 'Failed')).

This step returns the execution Id.

Step 4: Create a fin & Ops execution action trigger and input for this step is Execution id from the previous step.

The DMF Action is 

DataManagementDefinitionGroups-GetExportedFileUrl which returns the file url that is exported in FO.

Step 5: Create a HTTP GET and Response triggers.

HTTP GET >> Input is File URL from Previous step and response is content of the file.



You can add additional triggers to save this file in Blob or SFTP.

Final Flow:



Keep Learning!!



Tuesday, July 4, 2023

To open a particular report in a specific language in D365FO Using X++

To open a particular report in a specific language in D365FO, you will need to create the labels for that language. The labels contain the translated text for different elements of the report, such as field labels, column headers, and other user interface elements.  

By parameterizing the language ID and maintaining it in the report contract, you can dynamically set the language at runtime and generate the report in the desired language without hardcoding the value.

In my case it is Hardcoded.

Write below code in controller class Main method.

  public static void main(Args _args)
  {
   LanguageSpecificContract    contract;
   LanguagespecificController  controller;       	
   controller = new LanguagespecificController();
   controller.parmReportName(ssrsReportStr(LanguageSpecificReport, Report));       
    controller.parmReportContract().parmRdlContract().parmLabelLanguageId("fr-FR");// To open a report in specific language.
   contract = controller.parmReportContract().parmRdpContract() as LanguageSpecificContract;
controller.parmArgs(_args); controller.parmShowDialog(false); controller.startOperation(); }

Keep Learning!!