(To be clear, not recommending you deploy the library with your solution just so you can create sales orders, I'm suggesting you look at the code to see how they do it).
That would have been handy but i'm working on nav 2009.
As the previous post suggested, I'm following the code found in the code unit for creating a sales order from a sales quotes. But the issue now is the roll back thing. I can't do a full rollback if my sales order routine are scattered into many code units because of the COMMIT called by Navy after a transaction...
Do NOT create sales order like in the test unit framework! If you read the documentation about it, it states that the test unit framework does only create the data necessary for a certain test, therfore you can not be sure you get a proper order. I would recommend look at productive code if you don't know how to do create certain data in NAV.
The PRE-CONDITIONS step:
2.Create only data (records and fields in the records) that is needed for the test.
a.Setup data should be created using direct assignments only (":="). Using VALIDATEs and other C/AL procedures to set up data may go through unnecessary paths unrelated to the test.
b.Avoid using any functions or triggers in the production code, as that results in "usually" doing more than what the unit test requires. For example, in a case where items need to be sold from inventory, the items may be added by two approaches:
Avoid
Making a posting through item journals
Prefer
Create item ledger entries directly
c.It may not be necessary to fill in all primary key fields, as they may not be relevant to the test. For example, in a test that checks the OnValidate trigger on the Location Code field of the Sales Line table, it may not be necessary to put in the Document No. field.
d.Because of the above reasons, the use of libraries to create business data should be limited, as they tend to make "complete" business entities. Instead, use LOCAL helper functions to promote reuse of code. As an example, some unit tests may only need (as part of their setup data) an Item record, with the Base Unit of Measure field filled in. Although the base unit of measure for any item should always have Qty. per Unit of Measure set to 1, this requirement may be irrelevant in case of such unit tests.
LOCAL PROCEDURE CreateItemWithBaseUOM@1(VAR Item@1000 : Record 27);
VAR
ItemUnitOfMeasure@1001 : Record 5404;
BEGIN
Item.INIT;
Item.INSERT;
ItemUnitOfMeasure.Code := 'NewCode';
ItemUnitOfMeasure.INSERT;
Item."Base Unit of Measure" := ItemUnitOfMeasure.Code;
Item.MODIFY;
END;
e.Improving the performance:
A.Database changes should be limited to only INSERTs. MODIFY calls should be avoided. This limits the number of database calls and speeds up the test. For example, in order to create an item with a base unit of measure:
Avoid
The helper function to create an item record in the previous example.
Prefer
LOCAL PROCEDURE CreateItemWithBaseUOM@1(VAR Item@1000 : Record 27);
VAR
ItemUnitOfMeasure@1001 : Record 5404;
BEGIN
Item.INIT;
ItemUnitOfMeasure.Code := 'NewCode';
ItemUnitOfMeasure.INSERT;
Item."Base Unit of Measure" := ItemUnitOfMeasure.Code;
Item.INSERT;
END;
B.Taking the approach of minimal data creation, calls to INSERT(TRUE) should be avoided. Plain INSERTs should be used as in the above example.
C.In case record variables are to be passed to helper functions, it is recommended to pass them as VARs even though the records themselves are not going to be altered. This is faster than passing the record variables as
values.
Nobody said anything about using the exact code from the unit tests. The unit tests are an excellent way to learn what logic needs to be employed to achieve a certain result. The actual code may be of limited use depending on how the test is implemented, but it beats scrolling through a ton of system code to figure out the minimum required fields and/or the logic of an operation.
In addition to being invaluable for doing regression testing on customizations, the unit test framework can also be a great learning tool for people trying to figure NAV out.
Worst advice I have seen, as the OP is looking for a simple example to create as Sales Order not a unit test, they should be using example code that is complete and uses standard validation routines only ](*,)
Avoid
Making a posting through item journals
Prefer
Create item ledger entries directly
How could you unit test say "Item Application" without using the posting routines, these will create many needed database records, insert an 'item ledger entry' directly would be no good, as you have lost all the validation and supporting data for a true unit test?
In my own personal opinion, developers should never Create item ledger entries directly (Item Ledgers have 'Value Entries', "Ledger Entry Dimensions" as well), it takes less time to populate and post a journal than write the code, and validation makes sure all support data including dimensions and tables are in place, this will reduce the chances of errors later when posting.
As the OP wants to create Sales Orders, all they need to do is to create a manual order write down the fields they populate, then do the same in code.
Looking at the code in the sample code function, not a good example for a novice, there is no validation for 'NewCode', nothing to check that 'NewCode' is in the "Unit of Measure" table.
Confusion is caused here between "Item Unit of Measure" and "Unit of Measure" both are required for the Item record, the "Item No." is not populated in example [-X !
Table 5404 "Item Unit of Measure" Fields: 1 Item No. Code 20
2 Code Code 10
3 Qty. per Unit of Measure Decimal
7300 Length Decimal
7301 Width Decimal
7302 Height Decimal
7303 Cubage Decimal
7304 Weight Decimal
I would suggest never to 'hard code' not even for testing, if you do add a check in code, like this!
UOM = Table 204 "Unit of Measure"
IF NOT UOM.GET('EACH')THEN BEGIN
UOM.INIT;
UOM.Code := 'EACH';
UOM.Description := 'Each';
UOM.INSERT;
END;
This would then be the structure of the sample code
//Init the item clear the "No." field
Item.INIT; //The "No." field will retain the last value and error on insert
Item."No." := ''; //So clear the "No." field to stop the error
Item.INSERT(TRUE); //Run trigger code to set the item "No."
ItemUnitOfMeasure.INIT;
ItemUnitOfMeasure."Item No.":= Item."No.";
ItemUnitOfMeasure.Code := UOM.Code;
ItemUnitOfMeasure."Qty. per Unit of Measure" := 1;
ItemUnitOfMeasure.INSERT;
Item."Base Unit of Measure" := ItemUnitOfMeasure.Code;
Item.MODIFY;
Nobody said anything about using the exact code from the unit tests. The unit tests are an excellent way to learn what logic needs to be employed to achieve a certain result. The actual code may be of limited use depending on how the test is implemented, but it beats scrolling through a ton of system code to figure out the minimum required fields and/or the logic of an operation.
In addition to being invaluable for doing regression testing on customizations, the unit test framework can also be a great learning tool for people trying to figure NAV out.
Well but this is the second time i read answers to questions like "how i can i make this in nav" and the answer is have a look at the test framework.
I think if you recommand this you have to warn the people about the limitations of that code in the test framework. Since these are realy basic questions you have to assume you answer to a beginner so therefore i think it is definitly recommended to tell the whole story...
I found the solution to the rollback problem which is simply handling the whole called codeunit as such:
IF NOT Codeunit.RUN THEN...
This way it will suppress the error message as well as doing a full Rollback to the previous state.
However, my Sales Order creation routine needs to write to a LOG table which I DON'T want to be affected by the rollback
in case of an error. Is there a way to COMMIT an "isolate" transaction (e.g. while inserting a log line to a table) ?
Comments
(To be clear, not recommending you deploy the library with your solution just so you can create sales orders, I'm suggesting you look at the code to see how they do it).
As the previous post suggested, I'm following the code found in the code unit for creating a sales order from a sales quotes. But the issue now is the roll back thing. I can't do a full rollback if my sales order routine are scattered into many code units because of the COMMIT called by Navy after a transaction...
Here the best practices http://blogs.msdn.com/b/nav/archive/2012/12/03/writing-unit-tests-in-c-al.aspx?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+MicrosoftDynamicsNavTeamBlog+%28Microsoft+Dynamics+NAV+Team+Blog%29
In addition to being invaluable for doing regression testing on customizations, the unit test framework can also be a great learning tool for people trying to figure NAV out.
How could you unit test say "Item Application" without using the posting routines, these will create many needed database records, insert an 'item ledger entry' directly would be no good, as you have lost all the validation and supporting data for a true unit test?
In my own personal opinion, developers should never Create item ledger entries directly (Item Ledgers have 'Value Entries', "Ledger Entry Dimensions" as well), it takes less time to populate and post a journal than write the code, and validation makes sure all support data including dimensions and tables are in place, this will reduce the chances of errors later when posting.
As the OP wants to create Sales Orders, all they need to do is to create a manual order write down the fields they populate, then do the same in code.
Example:
Looking at the code in the sample code function, not a good example for a novice, there is no validation for 'NewCode', nothing to check that 'NewCode' is in the "Unit of Measure" table.
Confusion is caused here between "Item Unit of Measure" and "Unit of Measure" both are required for the Item record, the "Item No." is not populated in example [-X !
Table 5404 "Item Unit of Measure" Fields:
1 Item No. Code 20
2 Code Code 10
3 Qty. per Unit of Measure Decimal
7300 Length Decimal
7301 Width Decimal
7302 Height Decimal
7303 Cubage Decimal
7304 Weight Decimal
I would suggest never to 'hard code' not even for testing, if you do add a check in code, like this!
UOM = Table 204 "Unit of Measure"
This would then be the structure of the sample code
HTH
David
Mobile: +44(0)7854 842801
Email: david.cox@adeptris.com
Twitter: https://twitter.com/Adeptris
Website: http://www.adeptris.com
Well but this is the second time i read answers to questions like "how i can i make this in nav" and the answer is have a look at the test framework.
I think if you recommand this you have to warn the people about the limitations of that code in the test framework. Since these are realy basic questions you have to assume you answer to a beginner so therefore i think it is definitly recommended to tell the whole story...
just my 2 cents...
@David Cox: :thumbsup: I totaly agree with you.
Thanks for the help. I appreciate it.
I found the solution to the rollback problem which is simply handling the whole called codeunit as such:
IF NOT Codeunit.RUN THEN...
This way it will suppress the error message as well as doing a full Rollback to the previous state.
However, my Sales Order creation routine needs to write to a LOG table which I DON'T want to be affected by the rollback
in case of an error. Is there a way to COMMIT an "isolate" transaction (e.g. while inserting a log line to a table) ?
David