web
You’re offline. This is a read only version of the page.
close
Skip to main content

Announcements

No record found.

News and Announcements icon
Community site session details

Community site session details

Session Id :
Finance | Project Operations, Human Resources, ...
Active Discussion

How to create sales order by SysOperation framework using x++ code in D365 F&O

(0) ShareShare
ReportReport
Posted on by 5
As you know that sales order is the most important and useful feature of Dynamic-365 F&O and many developers have requirement to create sales order through x code. in this blog i will share the complete step by step process with x code. But before starting you should need to know the complete cycle of creating sales order.

1- Create Sales order 

2- Confirm Sales order 

3- Create Picking List 

4- Register picking list 

5- Create Picking Slip 

6- Invoiced Sales order 

So let’s get started, 

first, you need to create the following three classes for Sys Operation. 

SOSysOperationsController // SO Sales Order 

SOSysOperationsContract 

SOSysOperationsService 

 Then finally create Display Menu Item to open Parameter form. 

step-1 : create a class with the following name and extends from SysOperationServiceController or copy paste the following code. 

class SOSysOperationsController extends SysOperationServiceController 

{ 

 protected void new() 

 { 

     super(classStr(SOSysOperationsService), methodStr(SOSysOperationsService, process),

                                                                         SysOperationExecutionMode::Synchronous); 

 } 

 public static SOSysOperationsController construct(SysOperationExecutionMode _executionMode =

                                                                                              SysOperationExecutionMode::Synchronous) 

 {

 SOSysOperationsController controller = new SOSysOperationsController(); 

 controller.parmExecutionMode(_executionMode); 

 return controller; 

 } 

 public static void main(Args _args) 

 { 

     SOSysOperationsController controller;  

     controller = SOSysOperationsController::construct(); 

     controller.parmArgs(_args); 

 controller.startOperation(); 

 } 

} 

step-2 : create another class for Contract to show pop-form and paste the following code 

class SOSysOperationsContract 

{ 

 CustAccount custAccount; 

 ItemId itemId; 

 InventLocationId inventLocationId; //warehouse; 

 InventSiteId inventSiteId; //Site 

 [DataMemberAttribute("custAccount"), AifCollectionTypeAttribute("_custAccount", Types::String)] public CustAccount parmCustAccount(CustAccount _custAccount = custAccount) 

 { 

 custAccount = _custAccount; return custAccount;

 } 

 [DataMemberAttribute("ItemId"), AifCollectionTypeAttribute("_ItemId", Types::String)] 

 public ItemId parmItemId(ItemId _itemId = itemId) 

 {

 itemId = _itemId; return itemId; 

 } 

 [DataMemberAttribute("inventLocationId"), AifCollectionTypeAttribute("_inventLocationId", Types::String)] 

 public InventLocationId parmInventLocationId(InventLocationId _inventLocationId = inventLocationId) 

 {

 inventLocationId = _inventLocationId; return inventLocationId; 

 } 

 [DataMemberAttribute("InventSiteId"), AifCollectionTypeAttribute("_InventSiteId", Types::String)]

 public InventSiteId parmInventSiteId(InventSiteId _InventSiteId = InventSiteId) 

 {

 InventSiteId = _InventSiteId; 

 return InventSiteId; 

 }

 } 

step-3 : create one more class for Services which is used for logic business copy and paste the following code. 

class SOSysOperationsService extends SysOperationServiceBase 

{ 

 SalesTable salesTable; 

 SalesLine salesLine; 

 SalesFormLetter salesFormLetter; 

 SalesFormLetter_PickingList pickingList; 

 InventDim inventDim; 

 WMSPickingRouteID pickingRouteId; 

 NumberSeq numberSeq; 

 CustPackingSlipJour custPackingSlipJour; 

 SalesId salesId; 

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

 CustInvoiceJour custInvoiceJour; 

 InventTable inventTable; 

 CustTable custTable; 

 CustAccount custAccount; 

 str warehouse; 

 str site;

 ItemId itemId; 

 public void process(SOSysOperationsContract _contract) 

 {

 custAccount =_contract.parmCustAccount(); 

 itemId = _contract.parmitemId(); 

 site = _contract.parmInventSiteId(); 

 warehouse = _contract.parmInventLocationId();

 ttsbegin; salesTable.clear();

 numberSeq = NumberSeq::newGetNum(SalesParameters::numRefSalesId()); 

 numberSeq.used();

 salesTable.SalesId = numberSeq.num(); 

 salesId = salesTable.SalesId; 

 salesTable.initValue(); ///custAccount = "US-001";

 if(CustTable::find(custAccount)) 

 { 

 salesTable.CustAccount = custAccount; 

 } 

 else 

 { 

 info(strFmt("Customer account %1 doesn't exist.", custAccount)); 

 }

 salesTable.initFromCustTable(); 

 if(InventLocation::find(warehouse).InventLocationId != "") 

 { 

 salesTable.InventSiteId = InventLocation::find(warehouse).InventSiteId; 

 salesTable.InventLocationId = inventlocation::find(warehouse).InventLocationId; 

 } 

 salesTable.insert();

 inventTable.clear(); 

 inventDim.clear(); 

 salesLine.clear();

 select * from inventTable where inventTable.itemId == itemId; //"1000";

 salesLine.clear(); 

 salesLine.SalesId = salesId; 

 salesLine.ItemId = inventTable.ItemId; 

 salesLine.itemIdChanged(); 

 salesLine.initFromInventTable(InventTable::find(salesLine.ItemId));

 if(Inventlocation::find(warehouse).InventLocationId != "") 

 {

 inventdim.InventSiteId = InventLocation::find(warehouse).InventSiteId; 

 inventdim.InventLocationId = Inventlocation::find(warehouse).InventLocationId; 

 } 

 salesLine.InventDimId = InventdIm::findOrCreate(inventDim).inventDimId;

 salesLine.createLine(NoYes::Yes, // Validate 

 NoYes::Yes, // initFromSalesTable 

 NoYes::No, // initFromInventTable 

 NoYes::Yes, // calcInventQty

 NoYes::Yes, // searchMarkup 

 NoYes::Yes); //

 salesLine.SalesPrice = 250; 

 salesLine.SalesQty = 3; 

 salesLine.LineDisc = 25;

 salesLine.RemainSalesPhysical = salesLine.SalesQty;

 salesLine.QtyOrdered = salesLine.calcQtyOrdered(); 

 salesLine.RemainInventPhysical = salesLine.QtyOrdered;

 salesLine.LineAmount= salesLine.calcLineAmount(); 

 salesLine.update(); 

 ttscommit; 

 info(strFmt("Sales order '%1' has been created", salesTable.SalesId));



 ////////CreateSOConfirmed //////// 

 ttsBegin; salesTable = SalesTable::find(salesId);

 salesFormLetter = SalesFormLetter::construct(DocumentStatus::Confirmation);

 salesFormLetter.update(salesTable, systemDateGet(), SalesUpdate::All, AccountOrder::None, false, false);

 ttsCommit; 

 info(strFmt("Sales order '%1' has been Confirmed", salesTable.SalesId));



 //////// CreateSOPickingList////////

 ttsBegin; salesTable = SalesTable::find(salesId); 

 if (salesTable && salesTable.SalesStatus == SalesStatus::Backorder) 

 {

 salesFormLetter = SalesFormLetter::construct(DocumentStatus::PackingSlip); salesFormLetter.update(salesTable,systemDateGet(),SalesUpdate::PackingSlip,AccountOrder::one, NoYes::No, NoYes::No, NoYes::No); 

 if (salesFormLetter.parmJournalRecord().TableId == tableNum(custPackingSlipJour)) 

 {

 custPackingSlipJour = salesFormLetter.parmJournalRecord(); 

 info(strFmt('Packing Slip :%1 successfully created for Sales Order :%2', custPackingSlipJour.PackingSlipId, custPackingSlipJour.SalesId)); 

 }

 } 

 else

 { 

 info(strFmt('%1 does not exsists in the system !', salesId)); 

 } 

 ttscommit; 

 ////////Picking List Register//////// 

 ttsBegin; 

 select pickingRouteID from WMSPickingRoute where WMSPickingRoute.customer ==custAccount; 

        pickingRouteId = WMSPickingRoute.pickingRouteID;

        if(pickingRouteId)

        {

            list.addEnd(WMSPickingRoute.pickingRouteID);

            WMSPickingRoute::finishMulti(list.pack());

            info(strFmt("Picking List Register with pickingRouteID: %1",pickingRouteId));

        }

        else

        {

            info(strFmt('%1 does not exsists in the system !', pickingRouteId));

        }

        ttsCommit;



 /////// CreateSOPickingSlip //////// 

 ttsBegin; salesTable = salesTable::find(salesId); ///replace '001011' your sales order number 

 salesFormLetter = SalesFormLetter_PickingList::newPickingList();

 salesFormLetter.transDate(systemDateGet());

 salesFormLetter.update(salesTable, systemdateget(), SalesUpdate::All, AccountOrder::None, NoYes::No, NoYes::No);

 ttsCommit; 

 info(strFmt("Sales order '%1' Picking List created", salesTable.SalesId)); 



 ////////Invoicing the sales order//////// 

 ttsBegin;

 try 

 { 

 salesTable = SalesTable::find(salesId); 

 if (salesTable && salesTable.SalesStatus == SalesStatus::Delivered) 

 { 

 salesFormLetter = SalesFormLetter::construct(DocumentStatus::Invoice); 

 salesFormLetter.update(salesTable, systemDateGet(), SalesUpdate::All, AccountOrder::None, NoYes::No, NoYes::No, NoYes::No, NoYes::Yes); 

 if (salesFormLetter.parmJournalRecord().TableId == tableNum(CustInvoiceJour)) 

 { 

 custInvoiceJour = salesFormLetter.parmJournalRecord(); 

 info(strFmt('Invoice for Sales Order: %1 has been posted, Invoice: %2', custInvoiceJour.SalesId, custInvoiceJour.InvoiceId)); 

 }

 } 

 else 

 {

 info(strFmt('%1 does not exsists or not in delivered state.', salesId)); 

 } 

 } 

 catch (Exception::Error) 

 {

 info(strFmt('Failed to post Sales order invoice for %1.', salesId)); 

 } 

 ttscommit; 

 } 

} 

  • huijij Profile Picture
    19,811 on at

    Thanks for your sharing.

  • Suggested answer
    Deepak Agarwal Profile Picture
    8,624 on at

    Thanks for sharing this, it will be more helpful if you put them in proper formatting. Use rich formatting for the same.  

  • Rafiullah Afridi Profile Picture
    5 on at

  • Martin Dráb Profile Picture
    239,022 Most Valuable Professional on at

    Please don't confuse discussion forums with a blogging platform. Blog posts don't belong here.

    Also, if you want to ask questions here, learn how to do it. For example, use Insert > Code (in the rich formatting view) to paste source code. It'll make code much easier to read than your post above.

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Introducing the 2026 Season 1 community Super Users

Congratulations to our 2026 Super Stars!

Congratulations to our 2025 Community Spotlights

Thanks to all of our 2025 Community Spotlight stars!

Leaderboard > Finance | Project Operations, Human Resources, AX, GP, SL

#1
Giorgio Bonacorsi Profile Picture

Giorgio Bonacorsi 613

#2
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 455 Super User 2026 Season 1

#3
Syed Haris Shah Profile Picture

Syed Haris Shah 292 Super User 2026 Season 1

Last 30 days Overall leaderboard

Product updates

Dynamics 365 release plans