Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Connection to Dynamics 365Business Central #103

Open
mbasboll opened this issue Jan 14, 2021 · 17 comments
Open

Connection to Dynamics 365Business Central #103

mbasboll opened this issue Jan 14, 2021 · 17 comments
Labels
enhancement New feature or request question Further information is requested

Comments

@mbasboll
Copy link

mbasboll commented Jan 14, 2021

Hello David,

I have been playing around with using your library to generate the code to interface with Dynamics 365 Business Central api. This is looking very promising so far and I am able to retrieve all of the entity sets. For example I can retrieve all of the PurchaseInvoice entries for a specific company in Business Central by specifying a baseUrl of:

https://api.businesscentral.dynamics.com/v2.0/environmentname/Sandbox/api/v2.0/companies(comanyid)/

then calling: client.purchaseInvoices().toList()

However when I try to get a specific invoice by executing: client.purchaseInvoices("3681423d-eed6-4a6a-a612-fffc5562cb60").get() i run into this error:

com.github.davidmoten.odata.client.ClientException: responseCode=404 from url=https://api.businesscentral.dynamics.com/v2.0/environmentname/Sandbox/api/v2.0/companies(companyid)/purchaseInvoices/3681423d-eed6-4a6a-a612-fffc5562cb60, expectedResponseCode in [200, 200], message=
{"error":{"code":"BadRequest_NotFound","message":"The request URI is not valid. Since the segment 'purchaseInvoices' refers to a collection, this must be the last segment in the request URI or it must be followed by an function or action that can be bound to it otherwise all intermediate segments must refer to a single resource. CorrelationId: 4d419359-ae9b-41b4-928b-1781d99acb36."}}

As far as I can tell, the problem seems to be in the url. The resulting url from the call is:

https://api.businesscentral.dynamics.com/v2.0/environmentname/Sandbox/api/v2.0/companies(companyid)/purchaseInvoices/3681423d-eed6-4a6a-a612-fffc5562cb60

But the Business Central api is expecting a function call like this:

https://api.businesscentral.dynamics.com/v2.0//Sandbox/api/v2.0/companies(companyid)/purchaseInvoices(3681423d-eed6-4a6a-a612-fffc5562cb60)

Any chance you can point me in the direction of where I might be going wrong?

Many thanks,

Morten

@davidmoten
Copy link
Owner

Can you post the service metadata? I need to clarify what is a function and what is not. Can you also show me how you built your client? The other Microsoft services use this option;

You may want PathStyle.IDENTIFIERS_IN_ROUND_BRACKETS.

@mbasboll
Copy link
Author

I have attached the metadata file here. Looks reasonable that I might need to change to PathStyle.IDENTIFIERS_IN_ROUND_BRACKETS

Can I just make the change in: odata-client/odata-client-microsoft-client-builder/src/main/java/com/github/davidmoten/microsoft/client/builder/MicrosoftClientBuilder.java

Line 520 in b3b46c8

I would be happy to show you how I built my client but I am new to github so I am not quite sure how I can share it.

Many thanks for your help so far.

microsoft-nav-metadata.txt

@davidmoten
Copy link
Owner

By all means give it a shot. If required I can make that configurable publicly in the client builder.

@mbasboll
Copy link
Author

Things look very good! A made the change from:

Path basePath = new Path(baseUrl, PathStyle.IDENTIFIERS_AS_SEGMENTS);
to
Path basePath = new Path(baseUrl, PathStyle.IDENTIFIERS_IN_ROUND_BRACKETS);

My preliminary testing has been successful and I have not encountered any issues. I think it would be very helpful if this was configurable.

Thanks again for this.

@davidmoten
Copy link
Owner

I've added support in MicrosoftClientBuilder in PR #106 which has been merged. Let me know if it suits and I'll build the next release.

@mbasboll
Copy link
Author

mbasboll commented Feb 9, 2021

David,

Yes, this is excellent! I am now able to build my client with the new option:

private MicrosoftClientBuilder createBuilder() {
Creator creator = context -> {
try {
return b.serviceCls.getConstructor(Context.class).newInstance(context);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | NoSuchMethodException | SecurityException e) {
throw new ClientException(e);
}
};
return MicrosoftClientBuilder //
.baseUrl(b.baseUrl.get()) //
.creator(creator) //
.addSchema(SchemaInfo.INSTANCE) //
.pathStyle(PathStyle.IDENTIFIERS_IN_ROUND_BRACKETS) //
.build();
}

Many thanks for this,

Morten

@davidmoten
Copy link
Owner

Good to hear! I'll build the next release with that change shortly.

@tibona
Copy link

tibona commented Feb 17, 2021

Good to hear! I'll build the next release with that change shortly.

Hi David.

I would like to ask when this fix will be released and available via Maven Central?

@davidmoten
Copy link
Owner

Sorry, got distracted. Release 0.1.51 is on Maven Central now with the discussed enhancement.

@davidmoten davidmoten added the enhancement New feature or request label Feb 17, 2021
@mbasboll
Copy link
Author

Hello David,

Updated to 0.1.51 and things are looking good. I am able to do gets(), posts(), and deletes() on purchase invoice documents in Business Central. Just running into the following error in RequestHelpler.java, trying to do a patch() to update a purchase invoice:

com.github.davidmoten.odata.client.ClientException: responseCode=400 from url=https://api.businesscentral.dynamics.com/v2.0//Sandbox/ODataV4/Company('PML')/PurchaseInvoice(Document_Type%3D'Invoice'%2CNo%3D'IPI-0561282'), expectedResponseCode in [200, 299], message=
{"error":{"code":"BadRequest_InvalidToken","message":"Could not validate the client concurrency token required by the service. Please provide a valid token in the client request. CorrelationId: 41403538-77d3-4eed-ac4a-84b730dc6310."}}
at com.github.davidmoten.odata.client.internal.RequestHelper.checkResponseCode(RequestHelper.java:88)
at com.github.davidmoten.odata.client.internal.RequestHelper.checkResponseCode(RequestHelper.java:94)
at com.github.davidmoten.odata.client.internal.RequestHelper.patchOrPut(RequestHelper.java:257)
at com.github.davidmoten.odata.client.internal.RequestHelper.patch(RequestHelper.java:196)
at com.github.davidmoten.odata.client.EntityRequest.patch(EntityRequest.java:33)
at com.github.davidmoten.odata.client.EntityRequestOptionsBuilder.patch(EntityRequestOptionsBuilder.java:94)
at com.github.davidmoten.odata.client.EntityRequest.patch(EntityRequest.java:49)

Looks like it could be an authentication issue in my code but I noticed some TODO statements in your code. Can you tell me if the patch function is working?

Many thanks,

Morten

@mbasboll
Copy link
Author

David,

Would you know how I could use your library to perform deep inserts in Business Central? I have successfully posted the following json payload in postman to https://api.businesscentral.dynamics.com/v2.0/[environment id]/sandbox/api/v2.0/companies([company id])/purchaseInvoices

{
"number": "1234",
"vendorNumber": "VEN123",
"purchaseInvoiceLines": [
{
"itemId": "bfc03c90-2fe0-47fc-9f51-a4d2c605944c",
"description": "Some custom material",
"quantity": 5
},
{
"itemId": "bfc03c90-2fe0-47fc-9f51-a4d2c605944c",
"description": "Some more custom material",
"quantity": 10
}
]
}

I don't see how I am able to create the purchaseInvoiceLines json array with the PurchaseInvoice.builder() function generated from the metadata (metadata file attached)

I am able to generate the invoice by doing individual posts for the PurchaseInvoice and PurchaseInvoiceLine but would like to combine it into a single post.

microsoft_NAV_metadata.txt

@davidmoten
Copy link
Owner

Sorry @mbasboll I missed this (or read it quickly and forgot to get back to it!), feel free to nag me about stuff. I'll have a look.

@davidmoten
Copy link
Owner

I generated from your metadata and I'd expect the exchange to go like this:

PurchaseInvoice x = nav.companies().purchaseInvoices().post(PurchaseInvoice.builder()....build());
nav.companies().purchaseInvoices(x.getId().get()).purchaseInvoiceLines().post(list);

Of course we aren't able to pass a list.

You know I assume that you can use custom requests to do this with the client as a workaround but I'll add an issue to be able to add a a list of items for the post (and I'll check the OData spec in that regard).

@mbasboll
Copy link
Author

mbasboll commented May 2, 2021

Thanks for taking a look at this. Having the ability to add a list of items in a post would be great. In the meantime, I will take a look at using custom requests.

@davidmoten
Copy link
Owner

davidmoten commented May 3, 2021

@mbasboll I assume that the purchaseInvoice, purchaseInvoiceLine entityTypes in the metadata were created by you? If so then what you can do to allow addition of purchaseInvoiceLines to the purchaseInvoice builder is declare a purchaseInvoiceLine as a ComplexType not an EntityType. That way it will effectively be an embedded collection inside a PurchaseInvoice. Of course if you want to edit one PurchaseInvoiceLine then you need to replace the collection in the PurchaseInvoice but that might be ok?

@mbasboll
Copy link
Author

mbasboll commented May 3, 2021

I have not created any of the entityTypes. All of the entityTypes in the metadata are straight from Microsoft. The metadata file is directly from v2.0 of the Business Central API:
https://api.businesscentral.dynamics.com/v2.0/environmentid/sandbox/api/v2.0/$metadata

I have successfully tested creating a purchase invoice using postman. Below is a sample url and json body. As you can see this has two collection levels (purchaseInvoiceLines and dimensionSetLines)

Would Microsoft be doing something outside of the odata standard to accomplish this?

Sample post url:
https://api.businesscentral.dynamics.com/v2.0/environmentid/sandbox/api/v2.0/companies(companyid)/purchaseInvoices

json body:
{
"number": "127",
"vendorNumber": "SHOMAK",
"purchaseInvoiceLines": [
{
"itemId": "bfc03c90-2fe0-47fc-9f51-a4d2c605944c",
"description": "Some custom material",
"quantity": 5,
"dimensionSetLines": [
{
"code": "DIVISION",
"valueCode": "RES"
},
{
"code": "REGION",
"valueCode": "CAL"
},
{
"code": "LINEOFB",
"valueCode": "DI"
},
{
"code": "BUSALL",
"valueCode": "PRO"
}
]
},
{
"itemId": "bfc03c90-2fe0-47fc-9f51-a4d2c605944c",
"description": "Some more custom material",
"quantity": 10,
"dimensionSetLines": [
{
"code": "DIVISION",
"valueCode": "RES"
},
{
"code": "REGION",
"valueCode": "CAL"
},
{
"code": "LINEOFB",
"valueCode": "DI"
},
{
"code": "BUSALL",
"valueCode": "PRO"
}
]
}
]
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants