Copying multiple records with multiple keys

Greetings all, admitted newbie here slogging through creating my first set of extensions in BC.

I created a couple of tables to calculate commissions and need to move data from one to the other when an invoice is created from an order. The 2 tables are “Order Commissions” and “Invoice Commissions” Both files have the same setup with 2 field keys (Order No/Seq and InvoiceNo/Seq) I have the logic all figured out on taking 1 Order Commissions record, changing the order number to Invoice Number, and inserting the record into the Invoice Commissions table. Invoice commissions table has 2 extra fields, #7 for storing invoiced amount, and #8 for Commission calculated.

So the issue at hand is an order might have more than 1 order commissions record. I’ve been experimenting with "Order Commission.findset(false, false) as a record reference expression, but I only seem to hit 1 record. How can I get this code to loop through multiple records in the Order Commissions table?

Code shown below:

local procedure InsertCommissionsIntoInvoice(SalesLine: Record “Sales Line”; var SalesInvLine: Record “Sales Invoice Line”; SalesInvHeader: Record “Sales Invoice Header”)
var
OrderComm: RecordRef;
OrderCommFieldRef: FieldRef;
InvComm: RecordRef;
InvCommFieldRef: FieldRef;
Ord: Text;
Inv: Text;
Seq: Integer;
Sales: code[2];
Rate: Integer;
Orderpct: Integer;
trip: Text[11];
SalesAmount: Decimal;
InvoiceAmount: Decimal;
Commission: Decimal;
OrderCommKey: text;

begin

with SalesLine do begin
//if Invoice Commission Line ! already exists
//copy sales Commission line to Invoice Commission Line
//Calculate Invoice Amount
//Calculate Commnission, add to Invoice Commission Line

OrderComm.open(database::“Order Commissions”);
OrderCommFieldRef := OrderComm.field(1);
OrderCommFieldRef.SetRange(Salesline.“Document No.”);
//OrderComm.FindSet(false, false);
if Ordercomm.findset(false, false) then begin
repeat
//Order Commission record(s) exists, read data & assign to variables
OrderCommFieldRef := OrderComm.field(2);
Seq := OrderCommFieldRef.Value;
OrderCommFieldRef := OrderComm.field(3);
Sales := OrderCommFieldRef.Value;
OrderCommFieldRef := OrderComm.field(4);
Rate := OrderCommFieldRef.Value;
OrderCommFieldRef := OrderComm.field(5);
Orderpct := OrderCommFieldRef.Value;
OrderCommFieldRef := OrderComm.field(6);
trip := OrderCommFieldRef.Value;

InvComm.open(database::“Invoice Commissions”);
InvCommFieldRef := InvComm.field(1);
InvCommFieldRef.SetRange(SalesInvHeader.“No.”);

if InvComm.find(’=’) then //Commission has already been calculated for previous lines. Add the current line
begin
InvCommFieldRef := invcomm.field(7); //read “Amount Calculated Against” from found record
SalesAmount := InvCommFieldRef.value;
SalesAmount := SalesAmount + SalesInvLine.Amount;
InvCommFieldRef.value := SalesAmount; // Set new value back to “Invoice Commissions”
InvCommFieldRef := InvComm.field(8);
Commission := SalesAmount * (Rate / 100) * (Orderpct / 100);
InvCommFieldRef.value := Commission;
InvComm.Modify;

end else begin
//insert new Invoice Commission Record
InvComm.init;
InvCommFieldRef.value := SalesInvHeader.“No.”;
InvCommFieldRef := InvComm.field(2);
InvCommFieldRef.value := Seq;
InvCommFieldRef := InvComm.field(3);
InvCommFieldRef.value := Sales;
InvCommFieldRef := InvComm.field(4);
InvCommFieldRef.value := Rate;
InvCommFieldRef := InvComm.field(5);
InvCommFieldRef.value := Orderpct;
InvCommFieldRef := InvComm.field(6);
InvCommFieldRef.value := trip;
InvCommFieldRef := InvComm.field(7);
InvoiceAmount := SalesInvLine.Amount;
InvCommFieldRef.value := SalesInvLine.Amount;
SalesAmount := SalesInvLine.Amount;
InvCommFieldRef := InvComm.field(8);
Commission := (InvoiceAmount * (Rate / 100) * (Orderpct / 100));
InvCommFieldRef.value := Commission;
InvComm.insert;
end;
until OrderComm.next = 0;
end;
end;
end;

May I ask, possible, a stupid question like WHY do you do all these stuff SO complex? Do you want to play with RecordRec and FieldRef?

And to understand how many records do you select just change temporary the //OrderComm.FindSet(false, false); to “message(format(OrderComm.Count)));” and then debug all ftuff

LOL, because I’m just discovering how to do any of this. It would be great to stumble on the most efficient way to do things right off the bat, right?

Funny you should comment right now. I figured out I should use SetFilter instead of SetRange. Works like a charm EXCEPT now I’m getting database errors as I try to overwrite the existing records. Some other logical issue to deal with. Tomorrow. It’s getting late and my brain is fried for today!

It absolutely makes no sense at all to use RecordRef and FieldRef and I hope that what you are developing is purely for “fun learning” and not an actual development request from a customer.

Unless you have a very good reason to do it like this… then this is the most stupid way of doing it (sorry, i know i am rude) Secondly RecordRef and FieldRef are very slow compared and should only be used in very special situations.

What part of ‘newbie’ did you not understand? Good lord, I’m a beginner at this with NO training at all and I got this far. Is it the most efficient way to do this? Obviously not, but I don’t know a better way. So thank you for your advice, but I am asking for help. If you have a suggestion, I would appreciate it if you shared. If not, feel free to ignore the pleadings of a beginner.

BTW, I am not in this for a ‘customer’. I am a customer. I’m doing this for my team because my MSP’s programmer took another job and they are short handed. I’m trying to make a go live deadline and I’m doing my best.

If you have gotten No training at all - then stop yourself! You can easily make more damage than good. There’s a reason why people get training, and do this for a living.

What you are doing is something that others has done for more than a decade, and I would strongly suggest that you find someone that knows BC and Development - What you do in days/week this person will be able to do in a few hours/days - making your deadline easier to reach, and with the right solution. But if it has nothing to do with “reaching a deadline” - Be my guest, and continue your work.

Having said that - forget about RecordRef and FieldRef this is ONLY for VERY experienced developers.

I you want to work with a table /record then use that record in your code!

Change your OrderComm to a tablerelation as “Order Commision” like you did with the Sales Lines.

Take a look at e.g. Table 18 Customer, Table 36 Sales Header og 37 Sales Line.

Hi GTOGuy64,

Please check out the e-books on development, I am also not a pro developer, but have some basic knowledge and for past 3 months, I am working as a one man bad, where I do everything regarding the NAV for an end-user and I am reading ebooks that help me to write the code…

I have a subscription and reading this book

https://subscription.packtpub.com/book/application-development/9781789137798 -admin, please do not bank me for posting the link to the paid service:)

I am sure you can find e-book and code as you read.

Thank you

BR Damjan

Thank you very much. I was going to buy that book a few weeks ago, but for whatever reason I hesitated. Now I’m glad! I’m starting my trial on packtpub today.

BTW, in my defense I have been an IT pro, developing a bunch of minor apps using antique technology - RPG and the like. A lot of the concepts of OOP aren’t natural to me. Am I being wise moving forward on my own? Maybe not. But I have successfully modified several tables and pages, created a few triggers that work fine, and am learning every day. I am a one man shop in a 50 person organization, and it isn’t technically even my job. I am responsible for the day to day operation, on top of watching and maintaining our It infrastructure and moving to a new ERP platform. I’m a busy guy.

We fully understand that you are a busy guy.(ofcource).

You are trying to do something that is really not within your current range of knowledge, and therefore you are spending a lot of time.

I, myself knows a something about cars and repairing - but I would never spend 10-20 hours of fixing my car if someone else can do it in matter of 1 or 2 hours - unless I do it for fun.

Your time is probably better spent in doing something that you are an expert in and if you really want to do BC development - go get a training class - what you learn in a week wil save you months of googling/reading time - trust me I’ve been there myself.

If you don’t know much about BC then take a look at www.usedynamics.com and/or at youtube where you will find more than 350 videos.

Here is also an free online course from Microsoft:

https://community.dynamics.com/365/b/learningcurriculum/posts/81222-application-foundation-in-dynamics-365-business-central

Here is how to start it after the download: https://community.dynamics.com/365/b/learningcurriculum/posts/how-to-run-a-downloaded-course

I think people should support newbies more. There is a lack of information on Business Central for Developers compared to other Programming Languages / Systems.

Imagine a world where you can learn BC online without paying a fortune for workshops in countries someone may not afford to travel to.

Thank you.

I should point out that my question is flawed and I didn’t realize it. Both tables I am talking about have a single key, but both of the keys are 2 fields: Order No/Seq and Invoice No/Seq. I have attached my procedure to an event that passes both of the numbers to my function. The gist of the issue is:

How do you read a record from one file, swap the order number for the invoice number, and write that record to another file?

Two cents from here. There are plenti of options of learning BC and there’s a HUGE support of newbies. Just take a look around this site, and see how many questions and qualified answers that users are getting totally for free.

It is not true that there is a lack of information on Business Central - If you look at Microsoft alone ( https://docs.microsoft.com/en-us/dynamics365/business-central/ ) then there are more than several weeks of information to go through. Websites that I have mentioned earlier usedynamics.com, youtube.com and more gives you litterly DAYS of information about BC - And you don’t even have to be a Microsoft Partner to get than information - and you get it totally for free.

Having said all that, NOTHING beats training, and making training material, videos, blogs costs money and someone has to pay for that. So If you do not want to pay for it - be my guest, but you are missing out a lot. Just ask around and they will tell you the very same as I do. IT is hard to learn to read if you don’t have a teacher…

You can gett a record by using the function GET just like

Customer.GET(“10000”); //# where the primarykey is Customer no. 10000

Customer.MODIFY(TRUE); //# You can save a modified record using this command. The parameter TRUE executes the code in the MODIFY-trigger

Customer.VALIDATE(Name,“A new Customer Name”); //# You add a new value to a field using Table.VALIDATE(FIELD,NEW_VALUE);

If a primary key of a table consist of more than one field then you can do two things either use the GET function or a FIND/FINDSET/FINDFIRST/FINDLAST

example:

SalesHeader.GET(“Document type”::Order,“1000”); //# OR

SalsesHeader.RESET;

SalesHeader.SETRANGE(“Document Type”,“Document Type”::Order);

SalesHeader.SETRANGE(“Document No.”,“1000”);

SalesHeader.FINDFIRST;

In order to get it to work make sure that you shorten the folder name if you unpack to your desktop. Secondly you probably have to use the new Edge browser - Firefox and Chrome seems to have problems.

Pleace notice that big parts of the material is old as the product has evolved very much after the release of the material (both the Spring and Fall release have been changing a lot).

Awesome! I had to switch over to a different language for another project (VBA inside Excel anyone?) I will look at this on Monday and see if it is my salvation. Thank you.

Working solution posted below. It turns out I asked the question incorrectly. I was trying to setrange on my target file, when all I needed to do was initialize the record and assign values to the key fields. Duh.

Thanks for the help, and the smacking around about doing things the hard was. I come from a procedural background, where you have to expressly open and close files, etc. This OOP stuff is smarter than that!

local procedure InsertCommissionsIntoInvoice(SalesLine: Record “Sales Line”; var SalesInvLine: Record “Sales Invoice Line”; SalesInvHeader: Record “Sales Invoice Header”)
var
OrderCommRec: record “Order Commissions”;
InvoiceCommRec: record “Invoice Commissions”;
Ord: Text;
Inv: Text;
Seq: Integer;
Sales: code[2];
Rate: Integer;
Orderpct: Integer;
trip: Text[11];
SalesAmount: Decimal;
InvoiceAmount: Decimal;
Commission: Decimal;

begin

with SalesLine do begin
//if Invoice Commission Line ! already exists
//copy sales Commission line to Invoice Commission Line
//Calculate Invoice Amount
//Calculate Commnission, add to Invoice Commission Line

OrderCommRec.Reset();
OrderCommRec.SetRange(“Sales Order Number”, SalesLine.“Document No.”);
if OrderCommRec.findset(false, false) then
repeat
//Order Commission record(s) exists, read data & assign to variables

Seq := OrderCommRec.Seq;
Sales := OrderCommRec.“Salesman No.”;
Rate := OrderCommRec.“Commission Pct”;
Orderpct := OrderCommRec.“Order Pct”;
trip := OrderCommRec.“Trip Number”;

InvoiceCommRec.Init();
InvoiceCommRec.“Invoice Number” := SalesInvHeader.“No.”;
InvoiceCommRec.Seq := Seq;

if InvoiceCommRec.find(’=’) then //Commission has already been calculated for previous lines. Add the current line
begin

SalesAmount := InvoiceCommRec.“Amount Calc Against”;
SalesAmount := SalesAmount + SalesInvLine.Amount;
InvoiceCommRec.“Amount Calc Against” := SalesAmount; // Set new value back to “Invoice Commissions”
Commission := SalesAmount * (Rate / 100) * (Orderpct / 100);
InvoiceCommRec.“Calculated Commission” := Commission;
InvoiceCommRec.Modify;

end else begin
//insert new Invoice Commission Record
InvoiceCommRec.init;
InvoiceCommRec.“Invoice Number” := SalesInvHeader.“No.”;
InvoiceCommRec.Seq := Seq;
InvoiceCommRec.“Salesman No.” := Sales;
InvoiceCommRec.“Commission Pct” := Rate;
InvoiceCommRec.“Order Pct” := Orderpct;
InvoiceCommRec.“Trip Number” := trip;
InvoiceAmount := SalesInvLine.Amount;
InvoiceCommRec.“Amount Calc Against” := SalesInvLine.Amount;
SalesAmount := SalesInvLine.Amount;
Commission := (InvoiceAmount * (Rate / 100) * (Orderpct / 100));
InvoiceCommRec.“Calculated Commission” := Commission;
InvoiceCommRec.Insert();
end;

until OrderCommRec.next = 0;
end;
end;