bgmulinari / B1SLayer

A lightweight SAP Business One Service Layer client for .NET
MIT License
122 stars 42 forks source link

Patch Batch Request not remove items in a collection #47

Closed mruiz-GIEG closed 11 months ago

mruiz-GIEG commented 11 months ago

Hello, I am using slBatchRequests PATCH, to eliminate some elements from the collection, it does not give an error but it does not make the change and this that I specify the WithReplaceCollectionsOnPatch extension, it should be noted that only in the Batch I present the problem because in PatchStringAsync it works fine, but Since there are several changes, that's why I want it to go in Batch.

The code

var req1 = new SLBatchRequest( HttpMethod.Patch, "WHS1('BV-091')", "{\"WHS2Collection\": [{ \"LineId\":1,\"U_Usuario\": \"manager\",\"U_DesUsuario\":\"manager\" }]}") .WithReplaceCollectionsOnPatch() .WithReturnNoContent();

            HttpResponseMessage[] batchResult = await _serviceLayer                       
            .PostBatchAsync(req1);

thanks for the help, great library B1Slayer

bgmulinari commented 11 months ago

Hi, @mruiz-GIEG.

I did a quick test on the Items resource and I was not able to reproduce the issue. Here are my results:

The collection to be updated with a line removed: a1

My request:

var reqBody = new { ItemPreferredVendors = new[] { new { BPCode = "V10000" } } };

var req1 = new SLBatchRequest(HttpMethod.Patch, "Items('A00001')", reqBody)
    .WithReplaceCollectionsOnPatch()
    .WithReturnNoContent(); // not really necessary as PATCH requests don't return any content

HttpResponseMessage[] batchResult = await serviceLayer.PostBatchAsync(req1); // 204 response

The collection after the request above was made (line successfully removed): a2

Do you observe the same issue on other resources as well?

mruiz-GIEG commented 11 months ago

Not only do I have a problem with Batch, but PatchStringAsync works great, no way am I going to have to make several calls to the server, I'll tell you about any news, thanks

bgmulinari commented 11 months ago

@mruiz-GIEG, try sending the batch request through Postman (like shown here) and see if works. Remember to use the same parameters (B1S-ReplaceCollectionsOnPatch=true in the request header).

If you get the same issue, then I guess it could be a Service Layer bug and not something related to B1SLayer.

mruiz-GIEG commented 11 months ago

Hello @bgmulinari , good morning, I proceeded with the tests, I attached the screens, first I did a get to see how many records there are, then I did the batch successfully and then I did a get again and the element collection was successfully updated.

Note: It is a master data type user table.

Batch code:

--batch_36522ad7-fc75-4b56-8c71-56071383e77c Content-Type: application/http Content-Transfer-Encoding:binary

PATCH /b1s/v1/WHS1('BV-091')

{"WHS2Collection": [ {
"LineId": 4, "U_Usuario": "manager", "U_DesUsuario": "manager" } ] }

--batch_36522ad7-fc75-4b56-8c71-56071383e77c--

Get batch Headers Get Next
bgmulinari commented 11 months ago

@mruiz-GIEG, I see that you put your B1S-ReplaceCollectionsOnPatch=true header in the main request, that's not what B1SLayer does. The header is put in the inner request inside your batch request body.

Can you test it again like this?

image

--25f775be-0f5a-4bb0-bbd4-0b239a9b5eff
Content-Type: multipart/mixed; boundary="changeset_a02032b8-d3eb-4d8b-94b2-f5d72a467577"

--changeset_a02032b8-d3eb-4d8b-94b2-f5d72a467577
Content-Type: application/http; msgtype=request
content-transfer-encoding: binary

PATCH /b1s/v1/Items('A00001') HTTP/1.1
Host: 192.168.18.2:50000
B1S-ReplaceCollectionsOnPatch: true
Prefer: return-no-content
Content-Type: application/json; charset=utf-8

{"ItemPreferredVendors":[{"BPCode":"V10000"}]}
--changeset_a02032b8-d3eb-4d8b-94b2-f5d72a467577--

--25f775be-0f5a-4bb0-bbd4-0b239a9b5eff--
mruiz-GIEG commented 11 months ago

I tried with the code provided from postam, and it works correctly, I batch successfully and update the values, then I modify it for my user table and it gives ok without errors, but it does not update the data collection, unless I add in the header B1S-ReplaceCollectionsOnPatch to true, then I can come to the conclusion that if the sap system table works fine from B1SLayer, the batch does it satisfactorily including the ReplaceCollectionsOnPatch in each request, but if it is the user table it must go in the global header otherwise the request does not update the collection.

I attach the code: Code with system tables: --25f775be-0f5a-4bb0-bbd4-0b239a9b5eff Content-Type: multipart/mixed; boundary="changeset_a02032b8-d3eb-4d8b-94b2-f5d72a467577"

--changeset_a02032b8-d3eb-4d8b-94b2-f5d72a467577 Content-Type: application/http; msgtype=request content-transfer-encoding: binary

PATCH /b1s/v1/Items('AF02-000087') HTTP/1.1 Host: 192.168.0.243:50000 B1S-ReplaceCollectionsOnPatch: true Prefer: return-no-content Content-Type: application/json; charset=utf-8

{"ItemPreferredVendors":[{"BPCode":"V10000"}]} --changeset_a02032b8-d3eb-4d8b-94b2-f5d72a467577--

--25f775be-0f5a-4bb0-bbd4-0b239a9b5eff--

Code with user tables: --changeset_a02032b8-d3eb-4d8b-94b2-f5d72a467577 Content-Type: application/http; msgtype=request content-transfer-encoding: binary

PATCH /b1s/v1/WHS1('BV-091') HTTP/1.1 Host: 192.168.0.243:50000 B1S-ReplaceCollectionsOnPatch: true Prefer: return-no-content Content-Type: application/json; charset=utf-8

{"WHS2Collection": [ {
"LineId": 4, "U_Usuario": "manager", "U_DesUsuario": "manager" } ] } --changeset_a02032b8-d3eb-4d8b-94b2-f5d72a467577--

Get Headers batch Get Next
mruiz-GIEG commented 11 months ago
Get Next
bgmulinari commented 11 months ago

@mruiz-GIEG, I tested it again with an UDO this time (master data type) and it still worked as expected, both on Postman and on B1SLayer. Are you able to test it in a different SAP environment to check if you get a different result?

GET request before PATCH: image

PATCH request within a batch:

string reqBody = "{\"UDOTestLinesCollection\":[{\"Code\":\"UDO_Record1\",\"U_LineDesc\":\"Line1\",\"LineId\":1}]}";
var req1 = new SLBatchRequest(HttpMethod.Patch, "UDOTest('UDO_Record1')", reqBody).WithReplaceCollectionsOnPatch();
HttpResponseMessage[] batchResult = await serviceLayer.PostBatchAsync(req1);

PATCH request above captured in Fiddler Classic (monitoring tool):

--40a099f9-0f2d-4a20-bc15-820b07bb6a91
Content-Type: multipart/mixed; boundary="changeset_8dc20042-49fe-43f9-b476-92a724a05408"

--changeset_8dc20042-49fe-43f9-b476-92a724a05408
Content-Type: application/http; msgtype=request
content-transfer-encoding: binary

PATCH /b1s/v1/UDOTest('UDO_Record1') HTTP/1.1
Host: 192.168.18.2:50000
B1S-ReplaceCollectionsOnPatch: true
Content-Type: application/json; charset=utf-8

{"UDOTestLinesCollection":[{"Code":"UDO_Record1","U_LineDesc":"Line1","LineId":1}]}
--changeset_8dc20042-49fe-43f9-b476-92a724a05408--

--40a099f9-0f2d-4a20-bc15-820b07bb6a91--

GET request after PATCH (line successfully removed): image

mruiz-GIEG commented 11 months ago

I tried with another udo that I have but with the same result, excuse my ignorance, modify the B1SLayer library, and add B1S-ReplaceCollectionsOnPatch in the general request and it works fine for me, I ask if I leave it like this, that can impact me in something negative, or It will be a version issue, the one I have is Sap Bussiones One 9.2 PL:08 (64 bits), I would not want to be modifying the library because when there is an update I would not like to lose the changes I make, what version of sap do you have.

bgmulinari commented 11 months ago

@mruiz-GIEG, that version was released quite a while ago, so it's very much possible this is an issue that was fixed in later releases. I'm on version 10.0 FP2208.

Can you try one last test? Try changing your Service Layer URL in your SLConnection instance from /b1s/v1 to /b1s/v2. This will use OData v4 and could result in a different outcome.

Remember that when using OData v4, the content ID is mandatory and it needs to be specified in your SLBatchRequest instances.

var req1 = new SLBatchRequest(
    HttpMethod.Patch,
    "WHS1('BV-091')",
    "{"WHS2Collection": [{ "LineId":1,"U_Usuario": "manager","U_DesUsuario":"manager" }]}",
    1) // Content-ID
    .WithReplaceCollectionsOnPatch();
bgmulinari commented 11 months ago

@mruiz-GIEG, were you able to perform the test?

mruiz-GIEG commented 11 months ago

@bgmulinari , Good morning, yes, I did the tests without success, we are evaluating how to migrate to version 10 next year, thank you very much.

bgmulinari commented 11 months ago

That's unfortunate, but the upgrade to version 10 is definitely a good decision.

In case you want to keep using the library without modifying it yourself, you could use the workaround below. Just keep in mind this will add the header to every batch request, so you might want to improve the logic here.

serviceLayer.BeforeCall(call =>
{
    if (call.Request.Verb == HttpMethod.Post && call.Request.Url.Path.Contains("$batch"))
    {
        call.Request.Headers.Add("B1S-ReplaceCollectionsOnPatch", "true");
    }
});
mruiz-GIEG commented 11 months ago

@bgmulinari , Excellent news with Version 1.3.2, the problem has been solved, thank you very much.