Dynamics Navision 2017 - Insert Sales Order using Web Services - web-services

We have Navision Dynamics 2017 which has Sales Orders exposed as a SOAP web service. Technically, I am supposed to be able to create sales orders via this web service.
We also have another system built in C# .NET that has staff sales orders that need to go into Navision. This ordering system has all the information like customer, item, quantity, price etc to be able to create a valid order in Navision.
Can someone tell me how I can call the service and create a sales header and Line from the staff sales orders system into Navision..
Preferably a walk through tutorial would be ideal. I've searched and can't seem to find one that I can follow

The classic 'goto' for NAV services was always the following blog post, albeit it's an example for PHP. Take into account changes are required in NAV to be able to interact with the service (Hint: Activate NTLM):
https://blogs.msdn.microsoft.com/freddyk/2010/01/19/connecting-to-nav-web-services-from-php/
There is now an updated version by the same autor, complementing the original post:
https://blogs.msdn.microsoft.com/freddyk/2016/11/06/connecting-to-nav-web-services-from-php-take-2/
Example for C#:
https://blogs.msdn.microsoft.com/freddyk/2010/01/19/connecting-to-nav-web-services-from-c-using-web-reference/
Example for completing a Sales Order:
https://blogs.msdn.microsoft.com/freddyk/2009/11/17/extending-page-web-services-and-creating-a-sales-order-again/

I googled it for you. Is for Nav 2013, but it is all the same in 2017.
https://community.dynamics.com/nav/b/ishwarsblogspot/archive/2016/09/26/register-and-consume-codeunit-as-a-web-service-in-nav-2013-r2

Here's what I did in the rest API that I developed with .NET Core 5, I created 2 pages (one for sales header and one for sales lines) and one code-unit for invoking calculate discount action on NAV.
[Route("order")]
[HttpPost]
private async Task<dynamic> createOrder(orderDTO request)
{
var systemService = this.OrderServiceProvider.GetProxy();
List<OrderServiceReference.Sales_Quote_Line> lineList = new List<OrderServiceReference.Sales_Quote_Line>();
foreach (OrderLine orderLine in request.Sales_Quote_Line)
{
Sales_Quote_Line line = new Sales_Quote_Line()
{
Type = OrderServiceReference.Type.Item,
TypeSpecified = true,
No = orderLine.No,
Quantity = orderLine.Quantity,
QuantitySpecified = true
};
lineList.Add(line);
}
var task = await systemService.CreateAsync(new OrderServiceReference.Create()
{
Dis_SQ = new Dis_SQ()
{
Salesperson_Code = request.Salesperson_Code,
Sell_to_Customer_No = request.Sell_to_Customer_No,
Order_Date = new DateTime(),
SalesLines = lineList.ToArray()
}
});
var salesQuotes = task.Dis_SQ;
// var systemService2 = new DiscountServiceReference.Dis_Discount_Cal_PortClient();
var calculateSystemWebService = this.CalculateDiscountServiceProvider.GetProxy();
await calculateSystemWebService.CalcOffersSHAsync(new CalcOffersSH()
{
Body = new CalcOffersSHBody()
{
pDocNo = salesQuotes.No,
pDocType = 0
}
});
// get sales lines
var systemService1 = this.OrderLinesServiceProvider.GetProxy();
var task1 = await systemService1.ReadMultipleAsync(new SalesOrderServiceReference.ReadMultiple()
{
filter = new HHT_SO_Filter[]
{
new HHT_SO_Filter()
{
Criteria = salesQuotes.No,
Field = HHT_SO_Fields.Document_No
}
},
bookmarkKey = "",
setSize = 200
});
return new
{
sales_header = task.Dis_SQ,
sales_line = task1.ReadMultiple_Result1
};
}
If you need any more help comment below.

Related

Web API Controller Unit testing multiple test issue

I have create a web API am have developed some unit tests for it. In one of my controllers I pass in a variable of a Id which runs a stored procedure and returns a list of data with the matching data. Here is one of my unit tests:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Web.Http.Results;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using WebApi.Controllers;
using WebApi.Models;
namespace UnitTestProject1
{
[TestClass]
public class ProductContollerTests
{
// Unit Test Description: Tests to check the number of returned items with the BrandId = 1 matches the number of Products In testProducts
[TestMethod]
public void GetProducts_ShouldRetrunCorrectProducts()
{
var testProducts = GetTestProducts();
var controller = new ProductsController(testProducts);
var result = controller.GetProducts(1) as List<Product>;
Assert.AreEqual(testProducts.Count, result.Count);
}
private List<Product> GetTestProducts()
{
var testProducts = new List<Product>
{
new Product { BrandId = 1, ProductId = 1, ProductName = "Home" },
new Product { BrandId = 1, ProductId = 2, ProductName = "Motor" },
new Product { BrandId = 1, ProductId = 3, ProductName = "Travel" },
new Product { BrandId = 1, ProductId = 4, ProductName = "Van" },
new Product { BrandId = 1, ProductId = 5, ProductName = "Commercial" }
};
return testProducts;
}
}
}
Current this is passing because I am count the data that is returned and compared to see if it is equal to the data in the list testproducts. Currently this is a unit test for when the brand id is equal to 1. But what happens if I wanted to test for when brand id is equal to 2.
I can add a new product to the list testProducts but this then cause the first test to fails as I am counting the elements in list testProducts so when i add another product e.g.
new Product { BrandId = 2, ProductId = 6, ProductName = "Creditor" }
There are more values in testProducts than the data being returned from my API. Is there a way in which i could add it so that i only count the elements which have a brandId of one so that i could add other tests or will i have to always create a new testproducts List when testing something different.
you are telling this controller to work with a list of five products and then when you call the get method with an ID of 1, which you are not even using by the way, you verify that you get 5 products back.
It's a pointless test, you're not testing anything. I am not even mentioning that you're instantiating a web api controller with a list of items for some strange reason.
Instead, here's what I would do:
I would create a list of items, for real, in an actual database, then call the get brand endpoint and verify that I get back what I should. This would be an integration test which tells you that multiple endpoints are working.
Unit testing is about functionality, changing some data somehow, following a clearly definable method, with clear inputs and outputs.
I would also move away from this idea of instantiating controllers to call methods inside them, instead create proper layers and test those. This is like building a modern API in a webforms way.

Rally Web Services API: How do I get the URL link of the user story? (getDetailUrl() method)

Please be patient and Do Not flag this as duplicate: Using the Rally REST API, how can I get the non-API (website) URL for a user story?
I want to be able to generate a link for the user story.
Something like this: https://rally1.rallydev.com/#/-/detail/userstory/*********
As opposed to this: https://rally1.rallydev.com/slm/webservice/v2.0/hierarchicalrequirement/88502329352
The link will be integrated into another application for the managers to see the user story.
I did read about the getDetailUrl() method, but in my case I am creating the user stories by parsing email and linking that to a notification service in Slack.
I am aware of the formattedID and (_ref), but I would have to query for it again, and I am creating batches of userstories through a loop. I need the actual web site link to the user story.
Here is my sample code:
public void CreateUserStory(string workspace, string project, string userstoryName){
//authenticate with Rally
this.EnsureRallyIsAuthenticated();
//DynamicJsonObject for HierarchicalRequirement
DynamicJsonObject toCreate = new DynamicJsonObject();
toCreate[RallyConstant.WorkSpace] = workspace;
toCreate[RallyConstant.Project] = project;
toCreate[RallyConstant.Name] = userstoryName;
try
{
//Create the User Story Here
CreateResult createUserStory = _api.Create(RallyConstant.HierarchicalRequirement, toCreate);
Console.WriteLine("Created Userstory: " + "URL LINK GOES HERE");
}
catch (WebException e)
{
Console.WriteLine(e.Message);
}
}
We don't have a method in the .NET toolkit for doing this, but it's easy to create.
The format is this:
https://rally1.rallydev.com/#/detail/<type>/<objectid>
Just fill in the type (hierarchicalrequirement turns into userstory, but all the others are the same as the wsapi type) and the objectid from the object you just created.
var parameters = new NameValueCollection();
parameters["fetch"] = "FormattedID";
var toCreate = new DynamicJsonObject();
var createResult = restApi.create("hierarchicalrequirement", toCreate, parameters);
var type = Ref.getTypeFromRef(createResult.Reference);
var objectID = Ref.getOidFromRef(createResult.Reference);
var formattedID = createResult.Object["FormattedID"];
And you can specify fetch fields to be returned on the created object so you don't have to re-query for it.

Unit testing with Effort - Adding records with identity off

I am using using Effort (for EF4) to do some unit tests.
var ctx= Effort.ObjectContextFactory.CreateTransient<TheContext>(Shared.Connection);
ctx.companies.AddObject(new company() { ID = 100, name = "Agent", is_agent = true });
ctx.SaveChanges(System.Data.Objects.SaveOptions.DetectChangesBeforeSave);
The ID column in the company is an identity field. After executing the above query, it turns out the ID value is 1 instead of 100. Is there any way to control Identity_insert while using Effort
This is just to add the solution on this thread. #MrBlueSky add the archieved links of the solution on the comments above. But, DbConfiguration which is used on the link, does not exists anymore on the latest Effort. The solution still exists on Effort.EF6 [version="1.3.0"]. And you can use the method SetIdentityFields on EffortConnection.DbManager to turn on or off the identity fields
if (Effort.DbConnectionFactory.CreateTransient() is EffortConnection connection)
{
connection.Open();
connection.DbManager.SetIdentityFields(false);
connection.DbManager.ClearMigrationHistory();
connection.Close();
}
Turning on
// Add data with explicitly set id
Person initPerson = new Person { Id = 5, FirstName = "John", LastName = "Doe" };
dataInitContext.People.Add(initPerson);
dataInitContext.SaveChanges();
Assert.AreEqual(5, initPerson.Id);
// Enable identity field
connection.Open();
connection.DbManager.SetIdentityFields(true);
connection.Close();

Meteor regex find() far slower than in MongoDB console

I've been researching A LOT for past 2 weeks and can't pinpoint the exact reason of my Meteor app returning results too slow.
Currently I have only a single collection in my Mongo database with around 2,00,000 documents. And to search I am using Meteor subscriptions on the basis of a given keyword. Here is my query:
db.collection.find({$or:[
{title:{$regex:".*java.*", $options:"i"}},
{company:{$regex:".*java.*", $options:"i"}}
]})
When I run above query in mongo shell, the results are returned instantly. But when I use it in Meteor client, the results take almost 40 seconds to return from server. Here is my meteor client code:
Template.testing.onCreated(function () {
var instance = this;
// initialize the reactive variables
instance.loaded = new ReactiveVar(0);
instance.limit = new ReactiveVar(20);
instance.autorun(function () {
// get the limit
var limit = instance.limit.get();
var keyword = Router.current().params.query.k;
var searchByLocation = Router.current().params.query.l;
var startDate = Session.get("startDate");
var endDate = Session.get("endDate");
// subscribe to the posts publication
var subscription = instance.subscribe('sub_testing', limit,keyword,searchByLocation,startDate,endDate);
// if subscription is ready, set limit to newLimit
$('#searchbutton').val('Searching');
if (subscription.ready()) {
$('#searchbutton').val('Search');
instance.loaded.set(limit);
} else {
console.log("> Subscription is not ready yet. \n\n");
}
});
instance.testing = function() {
return Collection.find({}, {sort:{id:-1},limit: instance.loaded.get()});
}
And here is my meteor server code:
Meteor.publish('sub_testing', function(limit,keyword,searchByLocation,startDate,endDate) {
Meteor._sleepForMs(200);
var pat = ".*" + keyword + ".*";
var pat2 = ".*" + searchByLocation + ".*";
return Jobstesting.find({$or:[{title:{$regex: pat, $options:"i"}}, { company:{$regex:pat,$options:"i"}},{ description:{$regex:pat,$options:"i"}},{location:{$regex:pat2,$options:"i"}},{country:{$regex:pat2,$options:"i"}}],$and:[{date_posted: { $gte : endDate, $lt: startDate }},{sort:{date_posted:-1},limit: limit,skip: limit});
});
One point I'd also like to mention here that I use "Load More" pagination and by default the limit parameter gets 20 records. On each "Load More" click, I increment the limit parameter by 20 so on first click it is 20, on second click 40 and so on...
Any help where I'm going wrong would be appreciated.
But when I use it in Meteor client, the results take almost 40 seconds to return from server.
You may be misunderstanding how Meteor is accessing your data.
Queries run on the client are processed on the client.
Meteor.publish - Makes data available on the server
Meteor.subscribe - Downloads that data from the server to the client.
Collection.find - Looks through the data on the client.
If you think the Meteor side is slow, you should time it server side (print time before/after) and file a bug.
If you're implementing a pager, you might try a meteor method instead, or
a pager package.

EXM subscribe to list C#

I'm working on converting my old Sitecore (< 8) code to work with Sitecore EXM. I'm having a hard time adding users to Recipient Lists from code. The answers in this post: Sitecore 8 EXM add a contact to list from listmanager don't answer my questions completely, and since I cannot comment, I've decided to start a new topic.
My first problem is that my EcmFactory.GetDefaultFactory().Bl.RecipientCollectionRepository.GetEditableRecipientCollection(recipientListId) gives a compilation error on the RecipientCollectionRepository, it says it does not exist. So I've used slightly different code. My code now, is as follows:
var contactRepository = new ContactRepository();
var contactName = this.Email.Text;
var contact = contactRepository.LoadContactReadOnly(contactName);
contact = contactRepository.CreateContact(Sitecore.Data.ID.NewID);
contact.Identifiers.AuthenticationLevel = Sitecore.Analytics.Model.AuthenticationLevel.None;
contact.System.Classification = 0;
contact.ContactSaveMode = ContactSaveMode.AlwaysSave;
contact.Identifiers.Identifier = contactName;
contact.System.OverrideClassification = 0;
contact.System.Value = 0;
contact.System.VisitCount = 0;
var contactPreferences = contact.GetFacet<IContactPreferences>("Preferences");
contactPreferences.Language = "nl-NL";
var contactEmailAddresses = contact.GetFacet<IContactEmailAddresses>("Emails");
contactEmailAddresses.Entries.Create("test").SmtpAddress = this.Email.Text;
contactEmailAddresses.Preferred = "test";
var contactPersonalInfo = contact.GetFacet<IContactPersonalInfo>("Personal");
contactPersonalInfo.FirstName = contactName;
contactPersonalInfo.Surname = "recipient";
if (recipientList != null)
{
var xdbContact = new XdbContactId(contact.ContactId);
if (!recipientList.Contains(xdbContact, true).Value)
{
recipientList.AddRecipient(xdbContact);
}
contactRepository.SaveContact(contact, new ContactSaveOptions(true, null));
}
So the recipientList is found, and the first time I add a contact to it, it increases the "Recipients" to 1 (checked using the /sitecore/system/List Manager/All Lists/E-mail Campaign Manager/Custom/RecipientList).
I also have a message which has this Opt-in recipient list, but when I check that message, it says it will be sent to 0 subscribers.
Any thoughts on this?
See this article listing known issues in Sitecore EXM:
https://kb.sitecore.net/articles/149565
"The recipient list shows "0" total recipients after recipients have been subscribed to the list. (62217)"
I got around this in a sandbox environment by adding a simple list (from csv, one contact) to the message. This upped the total recipient count from 0 to 1 which allows the message to be activated. All recipients in the composite list were sent a message.
Do you have a distributed environment? If so the RecipientCollectionRepository will not work as it is only available on a Content Management server. You could try using the ClientApi:
ClientApi.UpdateSubscriptions(RecipientId recipientId, string[] listsToSubscribe, string[] listsToUnsubscribe, string managerRootId, bool confirmSubscription)
and just add the id of the list you want to subscribe people to in the first string array.
Just a quick note with this option, listToUnsubscribe does not actually remove a contact from a list. You are meant to pass through the ID of the opt out list. This basically excludes them from any future emails. One draw back is that you will no longer be able to resubscribe them.
If this does not work for you you will need to create your own API between your CD server and your CM server where the CM server uses the recipientCollectionRepository to subscribe and unsubscribe