Hi Guys
I have been trying to insert a batch of records (quotes copied to orders) using a codeunit and see if anyone can help. This is just a proof of concept and if it works I want to import an excel file to a user table and run similar code to create orders. In a nutshell, what I want is the system to continue after the error, and if possible write errors to a user table. So below is the code pattern I think I require:
if Item.findset repeat
if MyCodeUnit.run(Item) then begin
WriteLog( GETLASTERRORTEXT);
end;
until Item.next = 0;
Now with my code below I don't know how to pass a parameter (sales header) to the code unit. The first code unit should run the second code unit per each header record. Sales line loop is designed to fail for some records as a test.
Code that purposely fails if more than one line on sales quote:
codeunit 50020 U_LastError
{
trigger OnRun()
var
SalesQuote: Record "Sales Header";
begin
SalesQuote.Reset();
SalesQuote.SetRange(Status, SalesQuote.Status::Open);
SalesQuote.Setrange("Document Type", SalesQuote."Document Type"::Quote);
if SalesQuote.FindSet(true) then
repeat
if CreateOrderCodeUnit.Run() then //need to pass SalesQuote as parameter?
message('Message %1', GetLastErrorText());
Commit();
until SalesQuote.Next() = 0;
end;
var
CreateOrderCodeUnit: Codeunit U_CreateSalesOrderTest;
SalesQuote: Record "Sales Header";
}
codeunit 50013 U_CreateSalesOrderTest
{
var
SalesHeader: Record "Sales Header";
SalesLine: Record "Sales Line";
SalesQuoteHeader: Record "Sales Header";
SalesQuoteLine: record "Sales Line";
NextLineNo: Integer;
trigger OnRun()
begin
CreateSO(SalesQuoteHeader);
end;
procedure CreateSO(var SalesQuoteHeader: Record "Sales Header")
Begin
Clear(SalesHeader);
SalesHeader.Init;
SalesHeader.VALIDATE("Document Type", SalesHeader."Document Type"::Order);
SalesHeader.Validate("No. Series", 'S-ORD2');
// insert the new record into the table
SalesHeader.validate("Sell-to Customer No.", SalesQuoteHeader."Sell-to Customer No.");
SalesHeader.Validate("External Document No.", SalesQuoteHeader."External Document No.");
SalesHeader.Validate("Requested Delivery Date", SalesQuoteHeader."Requested Delivery Date");
SalesHeader.INSERT(TRUE);
SalesQuoteLine.Reset();
SalesQuoteLine.SetRange("Document Type", SalesQuoteLine."Document Type"::Quote);
SalesQuoteLine.SetRange("Document No.", SalesQuoteHeader."No.");
if SalesQuoteLine.FindSet() then begin
NextLineNo := 0;
if SalesLine.Findfirst() then
repeat
Clear(SalesLine);
salesLine.Init();
SalesLine."Document No." := SalesHeader."No.";
SalesLine."Document Type" := SalesHeader."Document Type";
nextLineNo := nextLineNo + 10000;
salesLine."Line No." := nextLineNo;
SalesLine.Validate(Type, SalesQuoteLine.Type);
SalesLine.validate("No.", SalesQuoteLine."No.");
SalesLine.Validate(Description, SalesQuoteLine.Description);
SalesLine.validate(Quantity, SalesQuoteLine.Quantity);
SalesLine.INSERT(true);
NextLineNo := 0;//TEST ONLY to FAIL with duplicate line no
until SalesQuoteLine.Next() = 0;
end;
end;
}
0
Comments
Ok I looked at how base app sales-post batch job is coded and modified my code. Now it run through all records and import valid ones. Problem is I get a pop up "OnAfterValidate Your Ref" when I try to write back something to failed record - in this case failed Sales Quote. I think it is standard practis to mark records as success for failure. Here's the latest code:
codeunit 50020 U_CreateSalesOrderBatch
{
trigger OnRun()
begin
CreateSalesOrderBatch();
end;
var
local procedure CreateSalesOrderBatch()
var
SalesReceivablesSetup: Record "Sales & Receivables Setup";
SalesHeader: Record "Sales Header";
ErrorMessageManagement: Codeunit "Error Message Management";
begin
LockTimeout(false);
SalesHeader.SetRange("Document type", SalesHeader."Document Type"::Quote);
if SalesHeader.FindSet() then
repeat
if NOT Codeunit.Run(Codeunit::U_CreateSalesOrder, SalesHeader) then begin
SalesHeader.Validate("Your Reference", 'Error Test');
SalesHeader.Modify(True);
Commit();
ErrorMessageManagement.LogLastError();
Commit();
end
until SalesHeader.Next() = 0;
end;
}
codeunit 50013 U_CreateSalesOrder
{
TableNo = "Sales Header";
trigger OnRun()
begin
CreateSo(Rec);
end;
procedure CreateSO(var SalesQuoteHeader: Record "Sales Header")
var
SalesHeader: Record "Sales Header";
SalesLine: Record "Sales Line";
SalesQuoteLine: record "Sales Line";
NextLineNo: Integer;
Begin
Clear(SalesHeader);
SalesHeader.Init;
SalesHeader.VALIDATE("Document Type", SalesHeader."Document Type"::Order);
SalesHeader.Validate("No. Series", 'S-ORD');
SalesHeader.validate("Sell-to Customer No.", SalesQuoteHeader."Sell-to Customer No.");
SalesHeader.Validate("External Document No.", SalesQuoteHeader."External Document No.");
SalesHeader.Validate("Requested Delivery Date", SalesQuoteHeader."Requested Delivery Date");
SalesHeader.INSERT(TRUE);
SalesQuoteLine.Reset();
SalesQuoteLine.SetRange("Document Type", SalesQuoteLine."Document Type"::Quote);
SalesQuoteLine.SetRange("Document No.", SalesQuoteHeader."No.");
if SalesQuoteLine.FindSet() then begin
NextLineNo := 0;
if SalesLine.Findfirst() then
repeat
Clear(SalesLine);
salesLine.Init();
SalesLine."Document No." := SalesHeader."No.";
SalesLine."Document Type" := SalesHeader."Document Type";
nextLineNo := nextLineNo + 10000;
salesLine."Line No." := nextLineNo;
SalesLine.Validate(Type, SalesQuoteLine.Type);
SalesLine.validate("No.", SalesQuoteLine."No.");
SalesLine.Validate(Description, SalesQuoteLine.Description);
SalesLine.validate(Quantity, SalesQuoteLine.Quantity);
SalesLine.INSERT(true);
NextLineNo := 0;//TEST ONLY to FAIL with duplicate line no
until SalesQuoteLine.Next() = 0;
end;
end;
}