cancel
Showing results for 
Search instead for 
Did you mean: 

Document line update sometimes has no effect

Former Member
0 Kudos

Hello,

using DI API I'm updating sales orders, changing some field values in their lines.

Debugging I can see that the COM object for order lines (ord.Lines) gets correctly updated in the fields I set.

Also the final ord.Update() returns 0.

But when I check the order line on B1 client (or on the DB) I see that sometimes the old value is still there or sometimes is cleared.

This behaviour seems to be random.

I noticed that in B1 client, when you change an item, many other fields are changed automatically. A similar behaviour occurs via DI API, even for those fields that I change. For instance I change item code and quantity (setting to 2), but in SAP I see that item has changed and quantity has been reset to 1 (the default I guess).

Sometimes I also experienced this: I have 3 fields to change and I need 3 executions to finally change all of them, because they change one by one. It seems that you need to update the order as many times as the fields count to be changed.

I'm disoriented. Has anyone some clues?

Kind regards

Accepted Solutions (1)

Accepted Solutions (1)

pedro_magueija
Active Contributor
0 Kudos

Hi Mirco,

This works for me:


public void Start()

{

    var company = b1.Company;

    var application = b1.Application;

    IDocuments ord = (IDocuments)company.GetBusinessObject(BoObjectTypes.oOrders);

    //locate order

    int docEntry = 336;

    ord.GetByKey(docEntry);

    //locate the row

    ord.Lines.SetCurrentLine(0);

    PrintOrder(ord);

    //populate fields!

    ord.Lines.Delete();         

 

    ord.Lines.SetCurrentLine(0);

    ord.Lines.ItemCode = "A00001";         

    ord.Lines.UnitPrice = 150;

    ord.Lines.Quantity = 1;

    ord.Lines.LineTotal = 100;

    PrintOrder(ord);

    //commit data to B1

    int result = ord.Update();

    if (result != 0)

        Console.WriteLine(company.GetLastErrorDescription());

    ord.GetByKey(docEntry);

    PrintOrder(ord);

}

private void PrintOrder(IDocuments ord)

{

    Console.WriteLine($"Item: {ord.Lines.ItemCode}");

    Console.WriteLine($"Quantity: {ord.Lines.Quantity}");

    Console.WriteLine($"Unit Price: {ord.Lines.UnitPrice}");

    Console.WriteLine($"Total: {ord.Lines.LineTotal}");

    Console.WriteLine("----------------------------");

}

ps: output

Item: C00001

Quantity: 1

Unit Price: 84.56

Total: 84.56

----------------------------

Item: A00001

Quantity: 1

Unit Price: 150

Total: 100

----------------------------

Item: A00001

Quantity: 1

Unit Price: 150

Total: 100

----------------------------


Best regards,

Pedro Magueija


View Pedro Magueija's profile on LinkedIn

Message was edited by: Pedro Magueija

Former Member
0 Kudos

The solution of doing a ord.Lines.Delete() is not an option for me, because in this way I lose the LineNum (the new line will obtain a new LineNum), which could be already referenced by other objects in my environment.

...Unless you have a tip for keeping the same LineNum in the new line...

Thanks Pedro

pedro_magueija
Active Contributor
0 Kudos

Hi Mirco,

As a final alternative you can update the document twice.

This seems to work as well. And you keep your LineID.

But that is a temporary workaround. You should really report this to SAP.


Best regards,

Pedro Magueija


View Pedro Magueija's profile on LinkedIn

Johan_H
Active Contributor
0 Kudos

Hi Mirco,

You set the UnitPrice (Price Before Discount) and the LineTotal. UnitPrice is the price the system gets from the price list assigned to the BP.

Is it possible for you to set the Price (Price After Discount) instead, or if you only have the LineTotal, not to set any price property at all (so only the LineTotal) ?

Regards,

Johan

Former Member
0 Kudos

Hi Johan,

our solution needs that all this information must be set:

unit price

discount %

line total

because when the user prints a sales order all this information must be specified, for commercial purposes.

Thanks anyway!

Johan_H
Active Contributor
0 Kudos

Hi Mirco,

I understand, however, you can still use the Price property instead of UnitPrice. The Price property will override the UnitPrice, and is more reliable to calculate the discount percentage. So you would actual achieve the same thing as though a user would type in a different price in the SO in the client.

Regards,

Johan

Answers (3)

Answers (3)

Former Member
0 Kudos

I opened a ticket with SAP and it seems that this is an expected behaviour!...

It's a bit astonishing for me. We ended up following Pedro's suggestion: updating the order twice.

I hope that this behaviour will change soon.

Kind regards

pedro_magueija
Active Contributor
0 Kudos

Hi Mirco,

Thanks for the update. Sad that SAP is not willing to fix the issue. Unfortunately it's many times like that.

But you can always count on the community to come up with something .

Good luck.


Best regards,

Pedro Magueija


View Pedro Magueija's profile on LinkedIn

Johan_H
Active Contributor
0 Kudos

Before the last 5 years, when SAP was investing only the very bare minimum in B1 development, the sentence "It is not an error, it is by design" became a running joke at our company .

pedro_magueija
Active Contributor
0 Kudos

Hi Johan,

Same here. Same joke. I do acknowledge that SAP is different today, but there are still responses that don't make much sense (the one above being an example).

It's also the case that regarding the SDK, we are still secondary in "priority". And it also seems that they are focusing on developing things that weren't really needed (B1 Studio).

I'm sure that not everyone has this opinion (that's why it's an opinion), but it would be nice to "see" some sort of dedication from SAP to the actual needs of the developers and not just the "business" side.

What are your thoughts on this?

Cheers.


Best regards,

Pedro Magueija


View Pedro Magueija's profile on LinkedIn

Johan_H
Active Contributor
0 Kudos

Hi Pedro,

I have to agree with you on all points. They could at the very least bring (and keep) the SDK up to date with the client's functionality.

I suppose I am a bit of a cynic, but I guess that developing the SDK, is actually not really in SAP's (and SAP's Partner's) own best commercial interest. Already it is theoretically possible to build your own client, and use it with much cheaper licenses. And if they make the SDK too easy and reliable to use, too many customers could develop their own addons, or buy an addon from any IT company or free lance coder.

Anyway, SAP is understandably focused on growing its customer base for B1. I hope that they succeed so that B1 will no longer be the forgotten child in the SAP product family. Perhaps then they can spare a little more money for the SDK.

Regards,

Johan

pedro_magueija
Active Contributor
0 Kudos

If you run your code with a demo database do you get the same issue?


Best regards,

Pedro Magueija


View Pedro Magueija's profile on LinkedIn

Former Member
0 Kudos

Yes, I just tried and I get the same issue with a demo DB.

pedro_magueija
Active Contributor
0 Kudos

Hi Mirco,

Unfortunately I cannot offer more alternatives, except to upgrade to the latest PL and try again. You can also check if there is any SAP note for that PL regarding such an issue.

If you do find out what is causing it and resolve it, please do update this thread so we can all benefit.

Good luck.


Best regards,

Pedro Magueija


View Pedro Magueija's profile on LinkedIn

Former Member
0 Kudos

Hi Pedro,

I tried more tests. I can reproduce this issue

  • on
    • SAP Business One 9.1 (9.10.190) PL: 09  (32-bit)
    • SAP Business One 9.1 (9.10.170) PL: 07  (32-bit)
    • SAP Business One 9.2 (9.20.110) PL: 01  (32-bit)
  • also on a new blank DB

I also tried doing ord.Add() and the new order is created, with one line where unit price and line total are kept as I set them and discount percent is correctly calculated. The problem comes just when I do ord.Update().

So this issue can be reproduced everywhere by me. Could someone try to reproduce it following this simple steps?

  1. create a blank DB
  2. setup a period (2016)
  3. create a BP with code "C0001"
  4. create 2 items, just setting their codes to "ART1" and "ART2"
  5. create a sales order (which will have DocEntry 1) for BP "C0001", with one line with the item "ART1"
  6. create a new Visual Studio project named TestDocLineUpdate, with target platform x86 and reference to your SAPbobsCOM.dll in the DI API installed into the system, with this main file:
  7. 
    

    using SAPbobsCOM;

    using System;

    namespace TestDocLineUpdate

    {

        class Program

        {

            static void Main(string[] args)

            {

                int docEntry = 1;

                string newItemCode = "ART2";

                var oCompany = new Company();

                oCompany.UserName = FULLFILL;

                oCompany.Password = FULLFILL;

                oCompany.language = BoSuppLangs.ln_English;

                oCompany.Server = FULLFILL;

                oCompany.DbServerType = BoDataServerTypes.FULLFILL;

                oCompany.CompanyDB = FULLFILL;

                oCompany.UseTrusted = false;

                oCompany.DbUserName = FULLFILL;

                oCompany.DbPassword = FULLFILL;

                oCompany.LicenseServer = FULLFILL;

                //connect

                if (oCompany.Connect() != 0)

                {

                    Callback(oCompany.GetLastErrorCode() + " - " + oCompany.GetLastErrorDescription());

                    return;

                }

                IDocuments ord = (IDocuments)oCompany.GetBusinessObject(BoObjectTypes.oOrders);

                try

                {

                    //locate order

                    ord.GetByKey(docEntry);

                    //locate the row

                    ord.Lines.SetCurrentLine(0);

                    Callback("Before populate:");

                    Callback("ord.Lines.Currency = " + ord.Lines.Currency);

                    Callback("ord.Lines.UnitPrice = " + ord.Lines.UnitPrice);

                    Callback("ord.Lines.DiscountPercent = " + ord.Lines.DiscountPercent);

                    Callback("ord.Lines.LineTotal = " + ord.Lines.LineTotal);

                    //populate fields!

                    ord.Lines.ItemCode = newItemCode;

                    ord.Lines.Currency = "EUR";

                    ord.Lines.UnitPrice = 800;

                    ord.Lines.LineTotal = 308;

                    Callback("After populate:");

                    Callback("ord.Lines.Currency = " + ord.Lines.Currency);

                    Callback("ord.Lines.UnitPrice = " + ord.Lines.UnitPrice);

                    Callback("ord.Lines.DiscountPercent = " + ord.Lines.DiscountPercent);

                    Callback("ord.Lines.LineTotal = " + ord.Lines.LineTotal);

                    //commit data to B1

                    int result = ord.Update();

                    if (result != 0)

                        Callback(oCompany.GetLastErrorDescription());

                    Callback("After Update:");

                    Callback("ord.Lines.Currency = " + ord.Lines.Currency);

                    Callback("ord.Lines.UnitPrice = " + ord.Lines.UnitPrice);

                    Callback("ord.Lines.DiscountPercent = " + ord.Lines.DiscountPercent);

                    Callback("ord.Lines.LineTotal = " + ord.Lines.LineTotal);

                    ord.GetByKey(docEntry);

                    Callback("After Update and GetByKey:");

                    Callback("ord.Lines.Currency = " + ord.Lines.Currency);

                    Callback("ord.Lines.UnitPrice = " + ord.Lines.UnitPrice);

                    Callback("ord.Lines.DiscountPercent = " + ord.Lines.DiscountPercent);

                    Callback("ord.Lines.LineTotal = " + ord.Lines.LineTotal);

                }

                catch (Exception e)

                {

                    Callback(e.Message);

                }

                finally

                {

                    if (ord != null)

                    {

                        System.Runtime.InteropServices.Marshal.ReleaseComObject(ord);

                        GC.Collect();

                        GC.WaitForPendingFinalizers();

                        GC.Collect();

                    }

                    Console.ReadKey();

                }

            }

            private static void Callback(string msg)

            {

                Console.WriteLine(msg);

            }

        }

    }

  8. compile and run
  9. in SAP you will see that item and unit price has been updated, but line total and discount percent has not!

Is anyone able to reproduce this simple case?

Kind regards

pedro_magueija
Active Contributor
0 Kudos

Hi Mirco,

I was finally able to reproduce your issue.

There is some weird stuff going on. Here is what I did:


public void Start()

{

    var company = b1.Company;

    var application = b1.Application;

    IDocuments ord = (IDocuments)company.GetBusinessObject(BoObjectTypes.oOrders);

    //locate order

    int docEntry = 336;

    ord.GetByKey(docEntry);

    //locate the row

    ord.Lines.SetCurrentLine(0);

    PrintOrder(ord);

    //populate fields!

    ord.Lines.ItemCode = "A00001";

    ord.Lines.UnitPrice = 150;

    ord.Lines.Quantity = 1;

    ord.Lines.LineTotal = 100;

    PrintOrder(ord);

    //commit data to B1

    int result = ord.Update();

    if (result != 0)

        Console.WriteLine(company.GetLastErrorDescription());

    ord.GetByKey(docEntry);

    PrintOrder(ord);

}

private void PrintOrder(IDocuments ord)

{

    Console.WriteLine($"Item: {ord.Lines.ItemCode}");

    Console.WriteLine($"Quantity: {ord.Lines.Quantity}");

    Console.WriteLine($"Unit Price: {ord.Lines.UnitPrice}");

    Console.WriteLine($"Total: {ord.Lines.LineTotal}");

    Console.WriteLine("----------------------------");

}

The 336 docEntry is a newly created SO.

First run output:

Item: C00001

Quantity: 1

Unit Price: 84.56

Total: 84.56

----------------------------

Item: A00001

Quantity: 1

Unit Price: 150

Total: 100

----------------------------

Item: A00001

Quantity: 1

Unit Price: 150

Total: 150

----------------------------

Second run output:

Item: A00001

Quantity: 1

Unit Price: 150

Total: 150

----------------------------

Item: A00001

Quantity: 1

Unit Price: 150

Total: 100

----------------------------

Item: A00001

Quantity: 1

Unit Price: 150

Total: 100

----------------------------


Best regards,

Pedro Magueija


View Pedro Magueija's profile on LinkedIn

Former Member
0 Kudos

Hi Pedro,

I'm happy to know that you could reproduce the issue!

What should we do now? Ask SAP to solve it?

Kind regards

pedro_magueija
Active Contributor
0 Kudos

Hi Mirco,

I would definitely report it. In any case my post below is an alternative that you can use.

ps: sorry I did not see your other reply.

Yep, then you should create a ticket with SAP.

Please do update this thread once you get a response.

Cheers.


Best regards,

Pedro Magueija


View Pedro Magueija's profile on LinkedIn

Message was edited by: Pedro Magueija

pedro_magueija
Active Contributor
0 Kudos

Hi Mirco,

This should happen in the object itself. But when you update SAP will automatically apply its rules and calculations (discount calculation, taxes, etc...). That may in fact change some values in order to maintain the document integrity.

However this should be reproducible in the client itself, eg.:

Setting quantity one and the total to half the unit price, will result in 50% discount.

Can you give an example of the data in use, and the code in use?

This will help us help you.

Cheers.


Best regards,

Pedro Magueija


View Pedro Magueija's profile on LinkedIn

Former Member
0 Kudos

I managed to reproduce the issue also with this simplified code:


int docEntry = 1800;

IDocuments ord = (IDocuments)oCompany.GetBusinessObject(BoObjectTypes.oOrders);

try

{

    //locate order

    ord.GetByKey(docEntry);

    //locate the row

    ord.Lines.SetCurrentLine(0);

    Debug("Before populate:");

    Debug("ord.Lines.UnitPrice = " + ord.Lines.UnitPrice);

    Debug("ord.Lines.DiscountPercent = " + ord.Lines.DiscountPercent);

    Debug("ord.Lines.LineTotal = " + ord.Lines.LineTotal);

    //populate fields!

    ord.Lines.ItemCode = "OTHER_ITEM";

    ord.Lines.UnitPrice = 800;

    ord.Lines.LineTotal = 308;

    Callback("After populate:");

    Callback("ord.Lines.UnitPrice = " + ord.Lines.UnitPrice);

    Callback("ord.Lines.DiscountPercent = " + ord.Lines.DiscountPercent);

    Callback("ord.Lines.LineTotal = " + ord.Lines.LineTotal);

    //commit data to B1

    int result = ord.Update();

    if (result < 0)

        Callback(CommonsB1.oCompany.GetLastErrorDescription());

    Debug("After Update:");

    Debug("ord.Lines.UnitPrice = " + ord.Lines.UnitPrice);

    Debug("ord.Lines.DiscountPercent = " + ord.Lines.DiscountPercent);

    Debug("ord.Lines.LineTotal = " + ord.Lines.LineTotal);

    ord.GetByKey(docEntry);

    Debug("After Update and GetByKey:");

    Debug("ord.Lines.UnitPrice = " + ord.Lines.UnitPrice);

    Debug("ord.Lines.DiscountPercent = " + ord.Lines.DiscountPercent);

    Debug("ord.Lines.LineTotal = " + ord.Lines.LineTotal);

}

catch (Exception e)

{

    Debug(e.Message);

}

finally

{

    if (ord != null)

    {

        System.Runtime.InteropServices.Marshal.ReleaseComObject(ord);

        GC.Collect();

        GC.WaitForPendingFinalizers();

        GC.Collect();

    }

}

The starting situation is a sales order with just one line in it, with an item with code "AN_ITEM" and dafault values for the other line fields.

Normally this code should change the item in the order line, loading its defaults, but also setting unit price and line total and calculate the correct discount percent.

The output produced by Debug method is:


Before populate:

ord.Lines.UnitPrice = 0

ord.Lines.DiscountPercent = 0

ord.Lines.LineTotal = 0

After populate:

ord.Lines.UnitPrice = 800

ord.Lines.DiscountPercent = 0

ord.Lines.LineTotal = 308

After Update:

ord.Lines.UnitPrice = 800

ord.Lines.DiscountPercent = 0

ord.Lines.LineTotal = 308

After Update and GetByKey:

ord.Lines.UnitPrice = 800

ord.Lines.DiscountPercent = 0

ord.Lines.LineTotal = 800

while the final part should be:


ord.Lines.UnitPrice = 800

ord.Lines.DiscountPercent = 61.50

ord.Lines.LineTotal = 308

as it happens when Adding an order instead of Updating it.

pedro_magueija
Active Contributor
0 Kudos

Hi Mirco,

I haven't really tested your code but there is something puzzling here:

  1.   if (result < 0
  2.         Callback(CommonsB1.oCompany.GetLastErrorDescription()); 

Try the following if(result != 0) and see if you're getting an error code greater than 0.

Example:

10001090 - Posting period missing.


Best regards,

Pedro Magueija


View Pedro Magueija's profile on LinkedIn

Former Member
0 Kudos

Hi, I repost my previous post because I cannot edit it. I corrected Callback method with Debug method (it's just a log method).

Regarding your message, result is always 0 in my tests. Effectively the order gets updated and saved. The issue is somewhere else.

Could you reproduce the problem? Many thanks


I managed to reproduce the issue also with this simplified code:


int docEntry = 1800

IDocuments ord = (IDocuments)oCompany.GetBusinessObject(BoObjectTypes.oOrders);

try 

{

    //locate order 

    ord.GetByKey(docEntry);

    //locate the row 

    ord.Lines.SetCurrentLine(0); 

    Debug("Before populate:"); 

    Debug("ord.Lines.UnitPrice = " + ord.Lines.UnitPrice); 

    Debug("ord.Lines.DiscountPercent = " + ord.Lines.DiscountPercent); 

    Debug("ord.Lines.LineTotal = " + ord.Lines.LineTotal); 

    //populate fields! 

    ord.Lines.ItemCode = "OTHER_ITEM"; 

    ord.Lines.UnitPrice = 800; 

    ord.Lines.LineTotal = 308; 

    Debug("After populate:"); 

    Debug("ord.Lines.UnitPrice = " + ord.Lines.UnitPrice); 

    Debug("ord.Lines.DiscountPercent = " + ord.Lines.DiscountPercent); 

    Debug("ord.Lines.LineTotal = " + ord.Lines.LineTotal); 

    //commit data to B1 

    int result = ord.Update(); 

    if (result != 0

        Debug(CommonsB1.oCompany.GetLastErrorDescription());

    Debug("After Update:"); 

    Debug("ord.Lines.UnitPrice = " + ord.Lines.UnitPrice); 

    Debug("ord.Lines.DiscountPercent = " + ord.Lines.DiscountPercent); 

    Debug("ord.Lines.LineTotal = " + ord.Lines.LineTotal); 

    ord.GetByKey(docEntry);

    Debug("After Update and GetByKey:"); 

    Debug("ord.Lines.UnitPrice = " + ord.Lines.UnitPrice); 

    Debug("ord.Lines.DiscountPercent = " + ord.Lines.DiscountPercent); 

    Debug("ord.Lines.LineTotal = " + ord.Lines.LineTotal); 

}

catch (Exception e) 

{

    Debug(e.Message);

}

finally 

{

    if (ord != null

    {

        System.Runtime.InteropServices.Marshal.ReleaseComObject(ord);

        GC.Collect();

        GC.WaitForPendingFinalizers();

        GC.Collect();

    }

}

The starting situation is a sales order with just one line in it, with an item with code "AN_ITEM" and dafault values for the other line fields; prices are all empty.

Normally this code should change the item in the order line, loading its defaults, but also setting unit price and line total and calculate the correct discount percent.

The output produced by Debug method is:


Before populate:

ord.Lines.UnitPrice = 0

ord.Lines.DiscountPercent = 0

ord.Lines.LineTotal = 0

After populate:

ord.Lines.UnitPrice = 800

ord.Lines.DiscountPercent = 0

ord.Lines.LineTotal = 308

After Update:

ord.Lines.UnitPrice = 800

ord.Lines.DiscountPercent = 0

ord.Lines.LineTotal = 308

After Update and GetByKey:

ord.Lines.UnitPrice = 800

ord.Lines.DiscountPercent = 0

ord.Lines.LineTotal = 800

while the final part should be:


ord.Lines.UnitPrice = 800

ord.Lines.DiscountPercent = 61.50

ord.Lines.LineTotal = 308

as it happens when Adding an order instead of Updating it.

pedro_magueija
Active Contributor
0 Kudos

Hi Mirco,

Your code works just fine in my test. Are you sure you are looking at the right SO? DocEntry is 1800 but perhaps you meant DocNum 1800?

Is the business partner multi-currency?

What version of B1 (PL) are you using?


Best regards,

Pedro Magueija


View Pedro Magueija's profile on LinkedIn

pedro_magueija
Active Contributor
0 Kudos

Hi Mirco,

Note that if your Business Partner is multi-currency, you'll need to indicate the currency for the LineTotal to be updated.

E.g.:

Does not update line total for multi-currency BP


ord.Lines.ItemCode = "A00001";

ord.Lines.UnitPrice = 150;

ord.Lines.LineTotal = 100;

Does update line total for multi-currency BP


ord.Lines.ItemCode = "A00001";

ord.Lines.Currency = "CHF";

ord.Lines.UnitPrice = 150;

ord.Lines.LineTotal = 100;

In this case "CHF" is the local currency, and the SO for the BP is in USD so the end result is:

UnitPrice: 150 CHF

LineTotal: 100 USD

Cheers.


Best regards,

Pedro Magueija


View Pedro Magueija's profile on LinkedIn

Former Member
0 Kudos

Thanks Pedro,

in my test case the BP has "EUR" as Currency. How can I know if it is a "multi-currency BP"?

Anyway I tried setting Currency ("EUR") on the line, but nothing changes, LineTotal remains 800.

pedro_magueija
Active Contributor
0 Kudos

Hi Mirco,

In the BP Master Data you can check if All Currencies is selected:

What's the local system (your B1 system) default currency?


Best regards,

Pedro Magueija


View Pedro Magueija's profile on LinkedIn

Former Member
0 Kudos

Both local and system currencies are "EUR" and also this BP has "EUR" (not "All currencies").

Note that this issue seems to occure with any BP.

I forgot to tell you the B1 version: SAP Business One 9.1 (9.10.170) PL: 07  (32-bit).

pedro_magueija
Active Contributor
0 Kudos

Hi Mirco,

Then you BP is local currency, so your code should work as it does for me. One last thing, do you have any code in the SP_PostTransactionNotification stored procedure, that might interfere with updating the SO?


Best regards,

Pedro Magueija


View Pedro Magueija's profile on LinkedIn

pedro_magueija
Active Contributor
0 Kudos

Hi Mirco,

I'm actually assuming quantity is 1. Is it?


Best regards,

Pedro Magueija


View Pedro Magueija's profile on LinkedIn

Former Member
0 Kudos

There is code inside SBO_SP_TransactionNotification. It is for Beas addon, but there is no reference to ORDR or RDR1 tables.

Former Member
0 Kudos

Yes, Quantity is 1 before the Update and in my code it is not changed.

pedro_magueija
Active Contributor
0 Kudos

Running out of ideas here.

Does the Document Settings allow changes to existing orders?


Best regards,

Pedro Magueija


View Pedro Magueija's profile on LinkedIn

Former Member
0 Kudos

This flag is checked.