Hi,
I would like to extend the standard sales Credit Memo API V2.
I already found a usefull Tutorial by Kauffman online. And I'm able to add custom fields that work.
But when I try to expand the credit memo lines they just stay empty.
deep inserting a line doesn't work either.
Header:
page 50106 "T - Sales Credit Memos"
{
APIVersion = 'v2.0';
EntityCaption = 'Sales Credit Memo';
EntitySetCaption = 'Sales Credit Memos';
ChangeTrackingAllowed = true;
DelayedInsert = true;
EntityName = 'salesCreditMemo';
EntitySetName = 'salesCreditMemos';
ODataKeyFields = SystemId;
PageType = API;
SourceTable = "Sales Cr. Memo Entity Buffer";
Extensible = false;
APIPublisher = 'test';
APIGroup = 'crMemo';
layout
{
area(content)
{
repeater(Group)
{
field(id; rec.SystemId)
{
Caption = 'Id';
Editable = false;
trigger OnValidate()
begin
RegisterFieldSet(Rec.FieldNo(SystemId));
end;
}
field(number; rec."No.")
{
Caption = 'No.';
Editable = false;
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("No."));
end;
}
field(externalDocumentNumber; rec."External Document No.")
{
Caption = 'External Document No.';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("External Document No."))
end;
}
field(creditMemoDate; rec."Document Date")
{
Caption = 'Credit Memo Date';
trigger OnValidate()
begin
DocumentDateVar := rec."Document Date";
DocumentDateSet := true;
RegisterFieldSet(rec.FieldNo("Document Date"));
end;
}
field(postingDate; rec."Posting Date")
{
Caption = 'Posting Date';
trigger OnValidate()
begin
PostingDateVar := rec."Posting Date";
PostingDateSet := true;
RegisterFieldSet(rec.FieldNo("Posting Date"));
end;
}
field(dueDate; rec."Due Date")
{
Caption = 'Due Date';
trigger OnValidate()
begin
DueDateVar := rec."Due Date";
DueDateSet := true;
RegisterFieldSet(rec.FieldNo("Due Date"));
end;
}
field(customerId; rec."Customer Id")
{
Caption = 'Customer Id';
trigger OnValidate()
begin
if not SellToCustomer.GetBySystemId(rec."Customer Id") then
Error(CouldNotFindSellToCustomerErr);
rec."Sell-to Customer No." := SellToCustomer."No.";
RegisterFieldSet(rec.FieldNo("Customer Id"));
RegisterFieldSet(rec.FieldNo("Sell-to Customer No."));
end;
}
field(customerNumber; rec."Sell-to Customer No.")
{
Caption = 'Customer No.';
trigger OnValidate()
begin
if SellToCustomer."No." <> '' then begin
if SellToCustomer."No." <> rec."Sell-to Customer No." then
Error(SellToCustomerValuesDontMatchErr);
exit;
end;
if not SellToCustomer.Get(rec."Sell-to Customer No.") then
Error(CouldNotFindSellToCustomerErr);
rec."Customer Id" := SellToCustomer.SystemId;
RegisterFieldSet(rec.FieldNo("Customer Id"));
RegisterFieldSet(rec.FieldNo("Sell-to Customer No."));
end;
}
field(customerName; rec."Sell-to Customer Name")
{
Caption = 'Customer Name';
Editable = false;
}
field(billToName; rec."Bill-to Name")
{
Caption = 'Bill-To Name';
Editable = false;
}
field(billToCustomerId; rec."Bill-to Customer Id")
{
Caption = 'Bill-To Customer Id';
trigger OnValidate()
begin
if not BillToCustomer.GetBySystemId(rec."Bill-to Customer Id") then
Error(CouldNotFindBillToCustomerErr);
rec."Bill-to Customer No." := BillToCustomer."No.";
RegisterFieldSet(rec.FieldNo("Bill-to Customer Id"));
RegisterFieldSet(rec.FieldNo("Bill-to Customer No."));
end;
}
field(billToCustomerNumber; rec."Bill-to Customer No.")
{
Caption = 'Bill-To Customer No.';
trigger OnValidate()
begin
if BillToCustomer."No." <> '' then begin
if BillToCustomer."No." <> rec."Bill-to Customer No." then
Error(BillToCustomerValuesDontMatchErr);
exit;
end;
if not BillToCustomer.Get(rec."Bill-to Customer No.") then
Error(CouldNotFindBillToCustomerErr);
rec."Bill-to Customer Id" := BillToCustomer.SystemId;
RegisterFieldSet(rec.FieldNo("Bill-to Customer Id"));
RegisterFieldSet(rec.FieldNo("Bill-to Customer No."));
end;
}
field(sellToAddressLine1; rec."Sell-to Address")
{
Caption = 'Sell-to Address Line 1';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Sell-to Address"));
end;
}
field(sellToAddressLine2; rec."Sell-to Address 2")
{
Caption = 'Sell-to Address Line 2';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Sell-to Address 2"));
end;
}
field(sellToCity; rec."Sell-to City")
{
Caption = 'Sell-to City';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Sell-to City"));
end;
}
field(sellToCountry; rec."Sell-to Country/Region Code")
{
Caption = 'Sell-to Country/Region Code';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Sell-to Country/Region Code"));
end;
}
field(sellToState; rec."Sell-to County")
{
Caption = 'Sell-to State';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Sell-to County"));
end;
}
field(sellToPostCode; rec."Sell-to Post Code")
{
Caption = 'Sell-to Post Code';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Sell-to Post Code"));
end;
}
field(billToAddressLine1; rec."Bill-to Address")
{
Caption = 'Bill-to Address Line 1';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Bill-to Address"));
end;
}
field(billToAddressLine2; rec."Bill-to Address 2")
{
Caption = 'Bill-to Address Line 2';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Bill-to Address 2"));
end;
}
field(billToCity; rec."Bill-to City")
{
Caption = 'Bill-to City';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Bill-to City"));
end;
}
field(billToCountry; rec."Bill-to Country/Region Code")
{
Caption = 'Bill-to Country/Region Code';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Bill-to Country/Region Code"));
end;
}
field(billToState; rec."Bill-to County")
{
Caption = 'Bill-to State';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Bill-to County"));
end;
}
field(billToPostCode; rec."Bill-to Post Code")
{
Caption = 'Bill-to Post Code';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Bill-to Post Code"));
end;
}
field(shortcutDimension1Code; rec."Shortcut Dimension 1 Code")
{
Caption = 'Shortcut Dimension 1 Code';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Shortcut Dimension 1 Code"));
end;
}
field(shortcutDimension2Code; rec."Shortcut Dimension 2 Code")
{
Caption = 'Shortcut Dimension 2 Code';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Shortcut Dimension 2 Code"));
end;
}
field(currencyId; rec."Currency Id")
{
Caption = 'Currency Id';
trigger OnValidate()
begin
if rec."Currency Id" = BlankGUID then
rec."Currency Code" := ''
else begin
if not Currency.GetBySystemId(rec."Currency Id") then
Error(CurrencyIdDoesNotMatchACurrencyErr);
rec."Currency Code" := Currency.Code;
end;
RegisterFieldSet(rec.FieldNo("Currency Id"));
RegisterFieldSet(rec.FieldNo("Currency Code"));
end;
}
field(currencyCode; CurrencyCodeTxt)
{
Caption = 'Currency Code';
trigger OnValidate()
begin
rec."Currency Code" :=
GraphMgtGeneralTools.TranslateCurrencyCodeToNAVCurrencyCode(
LCYCurrencyCode, COPYSTR(CurrencyCodeTxt, 1, MAXSTRLEN(LCYCurrencyCode)));
if Currency.Code <> '' then begin
if Currency.Code <> rec."Currency Code" then
Error(CurrencyValuesDontMatchErr);
exit;
end;
if rec."Currency Code" = '' then
rec."Currency Id" := BlankGUID
else begin
if not Currency.Get(rec."Currency Code") then
Error(CurrencyCodeDoesNotMatchACurrencyErr);
rec."Currency Id" := Currency.SystemId;
end;
RegisterFieldSet(rec.FieldNo("Currency Id"));
RegisterFieldSet(rec.FieldNo("Currency Code"));
end;
}
field(paymentTermsId; rec."Payment Terms Id")
{
Caption = 'Payment Terms Id';
trigger OnValidate()
begin
if rec."Payment Terms Id" = BlankGUID then
rec."Payment Terms Code" := ''
else begin
if not PaymentTerms.GetBySystemId(rec."Payment Terms Id") then
Error(PaymentTermsIdDoesNotMatchAPaymentTermsErr);
rec."Payment Terms Code" := PaymentTerms.Code;
end;
RegisterFieldSet(rec.FieldNo("Payment Terms Id"));
RegisterFieldSet(rec.FieldNo("Payment Terms Code"));
end;
}
field(shipmentMethodId; rec."Shipment Method Id")
{
Caption = 'Shipment Method Id';
trigger OnValidate()
begin
if rec."Shipment Method Id" = BlankGUID then
rec."Shipment Method Code" := ''
else begin
if not ShipmentMethod.GetBySystemId(rec."Shipment Method Id") then
Error(ShipmentMethodIdDoesNotMatchAShipmentMethodErr);
rec."Shipment Method Code" := ShipmentMethod.Code;
end;
RegisterFieldSet(rec.FieldNo("Shipment Method Id"));
RegisterFieldSet(rec.FieldNo("Shipment Method Code"));
end;
}
field(salesperson; rec."Salesperson Code")
{
Caption = 'Salesperson';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Salesperson Code"));
end;
}
field(pricesIncludeTax; rec."Prices Including VAT")
{
Caption = 'Prices Include Tax';
Editable = false;
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Prices Including VAT"));
end;
}
part(dimensionSetLines; "T - Dimension Set Lines")
{
Caption = 'Dimension Set Lines';
EntityName = 'dimensionSetLine';
EntitySetName = 'dimensionSetLines';
SubPageLink = "Parent Id" = Field(SystemId), "Parent Type" = const("Sales Credit Memo");
}
part(salesCreditMemoLines; "T - Sales Credit Mem Lines")
{
Caption = 'Lines';
EntityName = 'salesCreditMemoLine';
EntitySetName = 'salesCreditMemoLines';
SubPageLink = "Document Id" = Field(SystemId);
}
field(discountAmount; rec."Invoice Discount Amount")
{
Caption = 'discountAmount';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Invoice Discount Amount"));
DiscountAmountSet := true;
InvoiceDiscountAmount := rec."Invoice Discount Amount";
end;
}
field(discountAppliedBeforeTax; rec."Discount Applied Before Tax")
{
Caption = 'Discount Applied Before Tax';
Editable = false;
}
field(totalAmountExcludingTax; rec.Amount)
{
Caption = 'Total Amount Excluding Tax';
Editable = false;
}
field(totalTaxAmount; rec."Total Tax Amount")
{
Caption = 'Total Tax Amount';
Editable = false;
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Total Tax Amount"));
end;
}
field(totalAmountIncludingTax; rec."Amount Including VAT")
{
Caption = 'Total Amount Including Tax';
Editable = false;
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Amount Including VAT"));
end;
}
field(status; rec.Status)
{
Caption = 'Status';
Editable = false;
}
field(lastModifiedDateTime; rec.SystemModifiedAt)
{
Caption = 'Last Modified Date';
Editable = false;
}
field(invoiceId; SalesInvoiceId)
{
Caption = 'InvoiceId';
trigger OnValidate()
var
SalesInvoiceHeader: Record "Sales Invoice Header";
SalesInvoiceAggregator: Codeunit "Sales Invoice Aggregator";
EmptyGuid: Guid;
begin
if SalesInvoiceId = EmptyGuid then begin
rec."Applies-to Doc. Type" := rec."Applies-to Doc. Type"::" ";
Clear(rec."Applies-to Doc. No.");
Clear(InvoiceNo);
RegisterFieldSet(rec.FieldNo("Applies-to Doc. Type"));
RegisterFieldSet(rec.FieldNo("Applies-to Doc. No."));
exit;
end;
if not SalesInvoiceAggregator.GetSalesInvoiceHeaderFromId(SalesInvoiceId, SalesInvoiceHeader) then
Error(InvoiceIdDoesNotMatchAnInvoiceErr);
rec."Applies-to Doc. Type" := rec."Applies-to Doc. Type"::Invoice;
rec."Applies-to Doc. No." := SalesInvoiceHeader."No.";
InvoiceNo := rec."Applies-to Doc. No.";
RegisterFieldSet(rec.FieldNo("Applies-to Doc. Type"));
RegisterFieldSet(rec.FieldNo("Applies-to Doc. No."));
end;
}
field(invoiceNumber; rec."Applies-to Doc. No.")
{
Caption = 'Invoice No.';
trigger OnValidate()
begin
if InvoiceNo <> '' then begin
if rec."Applies-to Doc. No." <> InvoiceNo then
Error(InvoiceValuesDontMatchErr);
exit;
end;
rec."Applies-to Doc. Type" := rec."Applies-to Doc. Type"::Invoice;
RegisterFieldSet(rec.FieldNo("Applies-to Doc. Type"));
RegisterFieldSet(rec.FieldNo("Applies-to Doc. No."));
end;
}
field(phoneNumber; rec."Sell-to Phone No.")
{
Caption = 'Phone No.';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Sell-to Phone No."));
end;
}
field(email; rec."Sell-to E-Mail")
{
Caption = 'Email';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Sell-to E-Mail"));
end;
}
field(customerReturnReasonId; rec."Reason Code Id")
{
Caption = 'Customer Return Reason Id';
trigger OnValidate()
begin
if rec."Reason Code Id" = BlankGUID then
rec."Reason Code" := ''
else begin
if not ReasonCode.GetBySystemId(rec."Reason Code Id") then
Error(ReasonCodeIdDoesNotMatchAReasonCodeErr);
rec."Reason Code" := ReasonCode.Code;
end;
RegisterFieldSet(rec.FieldNo("Reason Code Id"));
RegisterFieldSet(rec.FieldNo("Reason Code"));
end;
}
part(attachments; "APIV2 - Attachments")
{
Caption = 'Attachments';
EntityName = 'attachment';
EntitySetName = 'attachments';
SubPageLink = "Document Id" = Field(SystemId), "Document Type" = const("Sales Credit Memo");
}
}
}
}
actions
{
}
trigger OnAfterGetRecord()
begin
SetCalculatedFields();
if not rec.Posted then
if HasWritePermissionForDraft then
GraphMgtSalCrMemoBuf.RedistributeCreditMemoDiscounts(Rec);
end;
trigger OnDeleteRecord(): Boolean
begin
GraphMgtSalCrMemoBuf.PropagateOnDelete(Rec);
exit(false);
end;
trigger OnInsertRecord(BelowxRec: Boolean): Boolean
begin
CheckSellToCustomerSpecified();
GraphMgtSalCrMemoBuf.PropagateOnInsert(Rec, TempFieldBuffer);
SetDates();
UpdateDiscount();
SetCalculatedFields();
exit(false);
end;
trigger OnModifyRecord(): Boolean
begin
if xRec.SystemId <> rec.SystemId then
Error(CannotChangeIDErr);
GraphMgtSalCrMemoBuf.PropagateOnModify(Rec, TempFieldBuffer);
UpdateDiscount();
SetCalculatedFields();
exit(false);
end;
trigger OnNewRecord(BelowxRec: Boolean)
begin
ClearCalculatedFields();
end;
trigger OnOpenPage()
begin
SetPemissionsFilters();
end;
var
TempFieldBuffer: Record "Field Buffer" temporary;
SellToCustomer: Record "Customer";
BillToCustomer: Record "Customer";
Currency: Record "Currency";
PaymentTerms: Record "Payment Terms";
ShipmentMethod: Record "Shipment Method";
ReasonCode: Record "Reason Code";
GraphMgtSalCrMemoBuf: Codeunit "Graph Mgt - Sal. Cr. Memo Buf.";
GraphMgtGeneralTools: Codeunit "Graph Mgt - General Tools";
LCYCurrencyCode: Code[10];
CurrencyCodeTxt: Text;
CannotChangeIDErr: Label 'The "id" cannot be changed.', Comment = 'id is a field name and should not be translated.';
CouldNotFindSellToCustomerErr: Label 'The sell-to customer cannot be found.';
CouldNotFindBillToCustomerErr: Label 'The bill-to customer cannot be found.';
SellToCustomerNotProvidedErr: Label 'A "customerNumber" or a "customerId" must be provided.', Comment = 'customerNumber and customerId are field names and should not be translated.';
SellToCustomerValuesDontMatchErr: Label 'The sell-to customer values do not match to a specific Customer.';
BillToCustomerValuesDontMatchErr: Label 'The bill-to customer values do not match to a specific Customer.';
PermissionFilterFormatTxt: Label '<>%1&<>%2', Locked = true;
PermissionCrMemoFilterformatTxt: Label '<>%1&<>%2&<>%3&<>%4', Locked = true;
DiscountAmountSet: Boolean;
InvoiceDiscountAmount: Decimal;
SalesInvoiceId: Guid;
InvoiceNo: Code[20];
InvoiceValuesDontMatchErr: Label 'The "invoiceId" and "invoiceNumber" do not match to a specific Invoice.', Comment = 'invoiceId and invoiceNumber are field names and should not be translated.';
InvoiceIdDoesNotMatchAnInvoiceErr: Label 'The "invoiceId" does not match to an Invoice.', Comment = 'invoiceId is a field name and should not be translated.';
CurrencyValuesDontMatchErr: Label 'The currency values do not match to a specific Currency.';
CurrencyIdDoesNotMatchACurrencyErr: Label 'The "currencyId" does not match to a Currency.', Comment = 'currencyId is a field name and should not be translated.';
CurrencyCodeDoesNotMatchACurrencyErr: Label 'The "currencyCode" does not match to a Currency.', Comment = 'currencyCode is a field name and should not be translated.';
PaymentTermsIdDoesNotMatchAPaymentTermsErr: Label 'The "paymentTermsId" does not match to a Payment Terms.', Comment = 'paymentTermsId is a field name and should not be translated.';
ShipmentMethodIdDoesNotMatchAShipmentMethodErr: Label 'The "shipmentMethodId" does not match to a Shipment Method.', Comment = 'shipmentMethodId is a field name and should not be translated.';
PostedCreditMemoActionErr: Label 'The action can be applied to a posted credit memo only.';
DraftCreditMemoActionErr: Label 'The action can be applied to a draft credit memo only.';
CannotFindCreditMemoErr: Label 'The credit memo cannot be found.';
CancelingCreditMemoFailedInvoiceCreatedAndPostedErr: Label 'Canceling the credit memo failed because of the following error: \\%1\\An invoice is posted.', Comment = '%1 - arbitrary text (an error message)';
CancelingCreditMemoFailedInvoiceCreatedButNotPostedErr: Label 'Canceling the credit memo failed because of the following error: \\%1\\An invoice is created but not posted.', Comment = '%1 - arbitrary text (an error message)';
CancelingCreditMemoFailedNothingCreatedErr: Label 'Canceling the credit memo failed because of the following error: \\%1.', Comment = '%1 - arbitrary text (an error message)';
AlreadyCancelledErr: Label 'The credit memo cannot be cancelled because it has already been canceled.';
NoLineErr: Label 'Please add at least one line item to the credit memo.';
ReasonCodeIdDoesNotMatchAReasonCodeErr: Label 'The "customerReturnReasonId" does not match to a Reason Code.', Comment = 'customerReturnReasonCodeId is a field name and should not be translated.';
BlankGUID: Guid;
DocumentDateSet: Boolean;
DocumentDateVar: Date;
PostingDateSet: Boolean;
PostingDateVar: Date;
DueDateSet: Boolean;
DueDateVar: Date;
HasWritePermissionForDraft: Boolean;
local procedure SetCalculatedFields()
begin
Rec.LoadFields("Applies-to Doc. Type", "Currency Code");
SetInvoiceId();
CurrencyCodeTxt := GraphMgtGeneralTools.TranslateNAVCurrencyCodeToCurrencyCode(LCYCurrencyCode, rec."Currency Code");
end;
local procedure ClearCalculatedFields()
begin
Clear(SalesInvoiceId);
Clear(InvoiceNo);
Clear(InvoiceDiscountAmount);
Clear(DiscountAmountSet);
TempFieldBuffer.DeleteAll();
end;
local procedure RegisterFieldSet(FieldNo: Integer)
var
LastOrderNo: Integer;
begin
LastOrderNo := 1;
if TempFieldBuffer.FindLast() then
LastOrderNo := TempFieldBuffer.Order 1;
Clear(TempFieldBuffer);
TempFieldBuffer.Order := LastOrderNo;
TempFieldBuffer."Table ID" := Database::"Sales Cr. Memo Entity Buffer";
TempFieldBuffer."Field ID" := FieldNo;
TempFieldBuffer.Insert();
end;
local procedure CheckSellToCustomerSpecified()
begin
if (rec."Sell-to Customer No." = '') and
(rec."Customer Id" = BlankGUID)
then
Error(SellToCustomerNotProvidedErr);
end;
local procedure SetInvoiceId()
var
SalesInvoiceHeader: Record "Sales Invoice Header";
SalesInvoiceAggregator: Codeunit "Sales Invoice Aggregator";
begin
Clear(SalesInvoiceId);
if rec."Applies-to Doc. No." = '' then
exit;
if SalesInvoiceHeader.Get(rec."Applies-to Doc. No.") then
SalesInvoiceId := SalesInvoiceAggregator.GetSalesInvoiceHeaderId(SalesInvoiceHeader);
end;
local procedure SetPemissionsFilters()
var
SalesHeader: Record "Sales Header";
SalesCrMemoHeader: Record "Sales Cr.Memo Header";
FilterText: Text;
begin
SalesHeader.SetRange("Document Type", SalesHeader."Document Type"::"Credit Memo");
if not SalesHeader.ReadPermission() then
FilterText := StrSubstNo(PermissionFilterFormatTxt, rec.Status::Draft, rec.Status::"In Review");
if not SalesCrMemoHeader.ReadPermission() then begin
if FilterText <> '' then
FilterText = '&';
FilterText =
StrSubstNo(
PermissionCrMemoFilterformatTxt, rec.Status::Canceled, rec.Status::Corrective,
rec.Status::Open, rec.Status::Paid);
end;
if FilterText <> '' then begin
rec.FilterGroup(2);
rec.SetFilter(Status, FilterText);
rec.FilterGroup(0);
end;
HasWritePermissionForDraft := SalesHeader.WritePermission();
end;
local procedure UpdateDiscount()
var
SalesHeader: Record "Sales Header";
SalesCalcDiscountByType: Codeunit "Sales - Calc Discount By Type";
begin
if not DiscountAmountSet then begin
GraphMgtSalCrMemoBuf.RedistributeCreditMemoDiscounts(Rec);
exit;
end;
SalesHeader.Get(SalesHeader."Document Type"::"Credit Memo", rec."No.");
SalesCalcDiscountByType.ApplyInvDiscBasedOnAmt(InvoiceDiscountAmount, SalesHeader);
end;
local procedure SetDates()
begin
if not (DueDateSet or DocumentDateSet or PostingDateSet) then
exit;
TempFieldBuffer.Reset();
TempFieldBuffer.DeleteAll();
if DocumentDateSet then begin
rec."Document Date" := DocumentDateVar;
RegisterFieldSet(rec.FieldNo("Document Date"));
end;
if PostingDateSet then begin
rec."Posting Date" := PostingDateVar;
RegisterFieldSet(rec.FieldNo("Posting Date"));
end;
if DueDateSet then begin
rec."Due Date" := DueDateVar;
RegisterFieldSet(rec.FieldNo("Due Date"));
end;
GraphMgtSalCrMemoBuf.PropagateOnModify(Rec, TempFieldBuffer);
rec.Find();
end;
local procedure GetPostedCreditMemo(var SalesCrMemoHeader: Record "Sales Cr.Memo Header")
begin
if not rec.Posted then
Error(PostedCreditMemoActionErr);
if not GraphMgtSalCrMemoBuf.GetSalesCrMemoHeaderFromId(rec.SystemId, SalesCrMemoHeader) then
Error(CannotFindCreditMemoErr);
end;
local procedure GetDraftCreditMemo(var SalesHeader: Record "Sales Header")
begin
if rec.Posted then
Error(DraftCreditMemoActionErr);
if not SalesHeader.GetBySystemId(rec.SystemId) then
Error(CannotFindCreditMemoErr);
end;
local procedure CheckCreditMemoCanBeCancelled(var SalesCrMemoHeader: Record "Sales Cr.Memo Header")
var
CancelPostedSalesCrMemo: Codeunit "Cancel Posted Sales Cr. Memo";
begin
if IsCreditMemoCancelled() then
Error(AlreadyCancelledErr);
CancelPostedSalesCrMemo.TestCorrectCrMemoIsAllowed(SalesCrMemoHeader);
end;
local procedure IsCreditMemoCancelled(): Boolean
begin
exit(rec.Status = rec.Status::Canceled);
end;
local procedure PostCreditMemo(var SalesHeader: Record "Sales Header"; var SalesCrMemoHeader: Record "Sales Cr.Memo Header")
var
LinesInstructionMgt: Codeunit "Lines Instruction Mgt.";
PreAssignedNo: Code[20];
begin
if not SalesHeader.SalesLinesExist() then
Error(NoLineErr);
LinesInstructionMgt.SalesCheckAllLinesHaveQuantityAssigned(SalesHeader);
PreAssignedNo := SalesHeader."No.";
SalesHeader.SendToPosting(Codeunit::"Sales-Post");
SalesCrMemoHeader.SETCURRENTKEY("Pre-Assigned No.");
SalesCrMemoHeader.SetRange("Pre-Assigned No.", PreAssignedNo);
SalesCrMemoHeader.FindFirst();
end;
local procedure CancelCreditMemo(var SalesCrMemoHeader: Record "Sales Cr.Memo Header")
var
SalesInvoiceHeader: Record "Sales Invoice Header";
SalesHeader: Record "Sales Header";
begin
GetPostedCreditMemo(SalesCrMemoHeader);
CheckCreditMemoCanBeCancelled(SalesCrMemoHeader);
if not Codeunit.Run(Codeunit::"Cancel Posted Sales Cr. Memo", SalesCrMemoHeader) then begin
SalesInvoiceHeader.SetRange("Applies-to Doc. No.", SalesCrMemoHeader."No.");
if not SalesInvoiceHeader.IsEmpty() then
Error(CancelingCreditMemoFailedInvoiceCreatedAndPostedErr, GetLastErrorText());
SalesHeader.SetRange("Applies-to Doc. No.", SalesCrMemoHeader."No.");
if not SalesHeader.IsEmpty() then
Error(CancelingCreditMemoFailedInvoiceCreatedButNotPostedErr, GetLastErrorText());
Error(CancelingCreditMemoFailedNothingCreatedErr, GetLastErrorText());
end;
end;
local procedure SetActionResponse(var ActionContext: WebServiceActionContext; ParamInvoiceId: Guid)
begin
ActionContext.SetObjectType(ObjectType::Page);
ActionContext.SetObjectId(Page::"APIV2 - Sales Credit Memos");
ActionContext.AddEntityKey(Rec.FieldNo(Id), ParamInvoiceId);
ActionContext.SetResultCode(WebServiceActionResultCode::Deleted);
end;
[ServiceEnabled]
[Scope('Cloud')]
procedure Post(var ActionContext: WebServiceActionContext)
var
SalesHeader: Record "Sales Header";
SalesCrMemoHeader: Record "Sales Cr.Memo Header";
begin
GetDraftCreditMemo(SalesHeader);
PostCreditMemo(SalesHeader, SalesCrMemoHeader);
SetActionResponse(ActionContext, GraphMgtSalCrMemoBuf.GetSalesCrMemoHeaderId(SalesCrMemoHeader));
end;
[ServiceEnabled]
[Scope('Cloud')]
procedure PostAndSend(var ActionContext: WebServiceActionContext)
var
SalesHeader: Record "Sales Header";
SalesCrMemoHeader: Record "Sales Cr.Memo Header";
APIV2SendSalesDocument: Codeunit "APIV2 - Send Sales Document";
begin
GetDraftCreditMemo(SalesHeader);
PostCreditMemo(SalesHeader, SalesCrMemoHeader);
Commit();
APIV2SendSalesDocument.SendCreditMemo(SalesCrMemoHeader);
SetActionResponse(ActionContext, GraphMgtSalCrMemoBuf.GetSalesCrMemoHeaderId(SalesCrMemoHeader));
end;
[ServiceEnabled]
[Scope('Cloud')]
procedure Send(var ActionContext: WebServiceActionContext)
var
SalesCrMemoHeader: Record "Sales Cr.Memo Header";
APIV2SendSalesDocument: Codeunit "APIV2 - Send Sales Document";
begin
GetPostedCreditMemo(SalesCrMemoHeader);
APIV2SendSalesDocument.SendCreditMemo(SalesCrMemoHeader);
SetActionResponse(ActionContext, GraphMgtSalCrMemoBuf.GetSalesCrMemoHeaderId(SalesCrMemoHeader));
exit;
end;
[ServiceEnabled]
[Scope('Cloud')]
procedure Cancel(var ActionContext: WebServiceActionContext)
var
SalesCrMemoHeader: Record "Sales Cr.Memo Header";
begin
GetPostedCreditMemo(SalesCrMemoHeader);
CancelCreditMemo(SalesCrMemoHeader);
SetActionResponse(ActionContext, GraphMgtSalCrMemoBuf.GetSalesCrMemoHeaderId(SalesCrMemoHeader));
end;
[ServiceEnabled]
[Scope('Cloud')]
procedure CancelAndSend(var ActionContext: WebServiceActionContext)
var
SalesCrMemoHeader: Record "Sales Cr.Memo Header";
APIV2SendSalesDocument: Codeunit "APIV2 - Send Sales Document";
begin
GetPostedCreditMemo(SalesCrMemoHeader);
CancelCreditMemo(SalesCrMemoHeader);
APIV2SendSalesDocument.SendCreditMemo(SalesCrMemoHeader);
SetActionResponse(ActionContext, GraphMgtSalCrMemoBuf.GetSalesCrMemoHeaderId(SalesCrMemoHeader));
end;
}
Lines:
page 50107 "T - Sales Credit Mem Lines"
{
DelayedInsert = true;
APIVersion = 'v2.0';
EntityCaption = 'Sales Credit Memo Line';
EntitySetCaption = 'Sales Credit Memo Lines';
PageType = API;
ODataKeyFields = SystemId;
EntityName = 'salesCreditMemoLine';
EntitySetName = 'salesCreditMemoLines';
SourceTable = "Sales Invoice Line Aggregate";
SourceTableTemporary = true;
Extensible = false;
APIPublisher = 'test';
APIGroup = 'crMemo';
layout
{
area(content)
{
repeater(Group)
{
field(id; rec.SystemId)
{
Caption = 'Id';
Editable = false;
trigger OnValidate()
begin
RegisterFieldSet(Rec.FieldNo(SystemId));
end;
}
field(documentId; rec."Document Id")
{
Caption = 'Document Id';
trigger OnValidate()
begin
if (not IsNullGuid(xRec."Document Id")) and (xRec."Document Id" <> rec."Document Id") then
Error(CannotChangeDocumentIdNoErr);
RegisterFieldSet(Rec.FieldNo("Document Id"));
end;
}
field(sequence; rec."Line No.")
{
Caption = 'Sequence';
trigger OnValidate()
begin
if (xRec."Line No." <> rec."Line No.") and
(xRec."Line No." <> 0)
then
Error(CannotChangeLineNoErr);
RegisterFieldSet(rec.FieldNo("Line No."));
end;
}
field(itemId; rec."Item Id")
{
Caption = 'Item Id';
trigger OnValidate()
begin
if not Item.GetBySystemId(rec."Item Id") then
Error(ItemDoesNotExistErr);
RegisterFieldSet(rec.FieldNo(Type));
RegisterFieldSet(rec.FieldNo("No."));
RegisterFieldSet(rec.FieldNo("Item Id"));
rec."No." := Item."No.";
end;
}
field(accountId; rec."Account Id")
{
Caption = 'Account Id';
trigger OnValidate()
var
EmptyGuid: Guid;
begin
if rec."Account Id" <> EmptyGuid then
if Item."No." <> '' then
Error(BothItemIdAndAccountIdAreSpecifiedErr);
RegisterFieldSet(rec.FieldNo(Type));
RegisterFieldSet(rec.FieldNo("Account Id"));
RegisterFieldSet(rec.FieldNo("No."));
end;
}
field(lineType; rec."API Type")
{
Caption = 'Line Type';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo(Type));
end;
}
field(lineObjectNumber; rec."No.")
{
Caption = 'Line Object No.';
trigger OnValidate()
var
GLAccount: Record "G/L Account";
begin
if (xRec."No." <> rec."No.") and (xRec."No." <> '') then
Error(CannotChangeLineObjectNoErr);
case Rec."API Type" of
Rec."API Type"::Item:
begin
if not Item.Get(rec."No.") then
Error(ItemDoesNotExistErr);
RegisterFieldSet(rec.FieldNo("Item Id"));
rec."Item Id" := Item.SystemId;
end;
Rec."API Type"::Account:
begin
if not GLAccount.Get(rec."No.") then
Error(AccountDoesNotExistErr);
RegisterFieldSet(rec.FieldNo("Account Id"));
rec."Account Id" := GLAccount.SystemId;
end;
end;
RegisterFieldSet(rec.FieldNo("No."));
end;
}
field(description; rec.Description)
{
Caption = 'Description';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo(Description));
end;
}
field(unitOfMeasureId; rec."Unit of Measure Id")
{
Caption = 'Unit Of Measure Id';
trigger OnValidate()
var
SalesInvoiceAggregator: Codeunit "Sales Invoice Aggregator";
begin
SalesInvoiceAggregator.VerifyCanUpdateUOM(Rec);
RegisterFieldSet(rec.FieldNo("Unit of Measure Code"));
end;
}
field(unitOfMeasureCode; rec."Unit of Measure Code")
{
Caption = 'Unit Of Measure Code';
trigger OnValidate()
var
SalesInvoiceAggregator: Codeunit "Sales Invoice Aggregator";
begin
SalesInvoiceAggregator.VerifyCanUpdateUOM(Rec);
RegisterFieldSet(rec.FieldNo("Unit of Measure Code"));
end;
}
field(unitPrice; rec."Unit Price")
{
Caption = 'Unit Price';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Unit Price"));
end;
}
field(quantity; rec.Quantity)
{
Caption = 'Quantity';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo(Quantity));
end;
}
field(discountAmount; rec."Line Discount Amount")
{
Caption = 'Discount Amount';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Line Discount Amount"));
end;
}
field(discountPercent; rec."Line Discount %")
{
Caption = 'Discount Percent';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Line Discount %"));
end;
}
field(discountAppliedBeforeTax; rec."Discount Applied Before Tax")
{
Caption = 'Discount Applied Before Tax';
Editable = false;
}
field(amountExcludingTax; rec."Line Amount Excluding Tax")
{
Caption = 'Amount Excluding Tax';
Editable = false;
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo(Amount));
end;
}
field(taxCode; rec."Tax Code")
{
Caption = 'Tax Code';
trigger OnValidate()
var
GeneralLedgerSetup: Record "General Ledger Setup";
begin
if GeneralLedgerSetup.UseVat() then begin
rec.Validate("VAT Prod. Posting Group", COPYSTR(rec."Tax Code", 1, 20));
RegisterFieldSet(rec.FieldNo("VAT Prod. Posting Group"));
end else begin
rec.Validate("Tax Group Code", COPYSTR(rec."Tax Code", 1, 20));
RegisterFieldSet(rec.FieldNo("Tax Group Code"));
end;
end;
}
field(taxPercent; rec."VAT %")
{
Caption = 'Tax Percent';
Editable = false;
}
field(totalTaxAmount; rec."Line Tax Amount")
{
Caption = 'Total Tax Amount';
Editable = false;
}
field(amountIncludingTax; rec."Line Amount Including Tax")
{
Caption = 'Amount Including Tax';
Editable = false;
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Amount Including VAT"));
end;
}
field(invoiceDiscountAllocation; rec."Inv. Discount Amount Excl. VAT")
{
Caption = 'Invoice Discount Allocation';
Editable = false;
}
field(netAmount; rec.Amount)
{
Caption = 'Net Amount';
Editable = false;
}
field(netTaxAmount; rec."Tax Amount")
{
Caption = 'Net Tax Amount';
Editable = false;
}
field(netAmountIncludingTax; rec."Amount Including VAT")
{
Caption = 'Net Amount Including Tax';
Editable = false;
}
field(shipmentDate; rec."Shipment Date")
{
Caption = 'Shipment Date';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Shipment Date"));
end;
}
field(itemVariantId; rec."Variant Id")
{
Caption = 'Item Variant Id';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Variant Code"));
end;
}
field(locationId; rec."Location Id")
{
Caption = 'Location Id';
trigger OnValidate()
begin
RegisterFieldSet(rec.FieldNo("Location Code"));
end;
}
part(dimensionSetLines; "APIV2 - Dimension Set Lines")
{
Caption = 'Dimension Set Lines';
EntityName = 'dimensionSetLine';
EntitySetName = 'dimensionSetLines';
SubPageLink = "Parent Id" = Field(SystemId), "Parent Type" = const("Sales Credit Memo Line");
}
part(location; "APIV2 - Locations")
{
Caption = 'Location';
EntityName = 'location';
EntitySetName = 'locations';
Multiplicity = ZeroOrOne;
SubPageLink = SystemId = field("Location Id");
}
}
}
}
actions
{
}
trigger OnDeleteRecord(): Boolean
begin
GraphMgtSalCrMemoBuf.PropagateDeleteLine(Rec);
end;
trigger OnFindRecord(Which: Text): Boolean
var
GraphMgtSalesInvLines: Codeunit "Graph Mgt - Sales Inv. Lines";
SysId: Guid;
DocumentIdFilter: Text;
IdFilter: Text;
FilterView: Text;
begin
if not LinesLoaded then begin
FilterView := rec.GetView();
IdFilter := rec.GetFilter(SystemId);
DocumentIdFilter := rec.GetFilter("Document Id");
if (IdFilter = '') and (DocumentIdFilter = '') then
Error(IDOrDocumentIdShouldBeSpecifiedForLinesErr);
if IdFilter <> '' then begin
Evaluate(SysId, IdFilter);
DocumentIdFilter := GraphMgtSalesInvLines.GetSalesCreditMemoDocumentIdFilterFromSystemId(SysId);
end else
DocumentIdFilter := rec.GetFilter("Document Id");
GraphMgtSalCrMemoBuf.LoadLines(Rec, DocumentIdFilter);
rec.SetView(FilterView);
if not rec.FindFirst() then
exit(false);
LinesLoaded := true;
end;
exit(true);
end;
trigger OnInsertRecord(BelowxRec: Boolean): Boolean
begin
GraphMgtSalCrMemoBuf.PropagateInsertLine(Rec, TempFieldBuffer);
end;
trigger OnModifyRecord(): Boolean
begin
GraphMgtSalCrMemoBuf.PropagateModifyLine(Rec, TempFieldBuffer);
end;
trigger OnNewRecord(BelowxRec: Boolean)
begin
ClearCalculatedFields();
RegisterFieldSet(rec.FieldNo(Type));
end;
var
TempFieldBuffer: Record "Field Buffer" temporary;
TempItemFieldSet: Record 2000000041 temporary;
Item: Record "Item";
GraphMgtSalCrMemoBuf: Codeunit "Graph Mgt - Sal. Cr. Memo Buf.";
LinesLoaded: Boolean;
IDOrDocumentIdShouldBeSpecifiedForLinesErr: Label 'You must specify an id or a Document Id to get the lines.';
CannotChangeDocumentIdNoErr: Label 'The value for "documentId" cannot be modified.', Comment = 'documentId is a field name and should not be translated.';
CannotChangeLineNoErr: Label 'The value for sequence cannot be modified. Delete and insert the line again.';
BothItemIdAndAccountIdAreSpecifiedErr: Label 'Both "itemId" and "accountId" are specified. Specify only one of them.', Comment = 'itemId and accountId are field names and should not be translated.';
ItemDoesNotExistErr: Label 'Item does not exist.';
AccountDoesNotExistErr: Label 'Account does not exist.';
CannotChangeLineObjectNoErr: Label 'The value for "lineObjectNumber" cannot be modified.', Comment = 'lineObjectNumber is a field name and should not be translated.';
local procedure RegisterFieldSet(FieldNo: Integer)
var
LastOrderNo: Integer;
begin
LastOrderNo := 1;
if TempFieldBuffer.FindLast() then
LastOrderNo := TempFieldBuffer.Order 1;
Clear(TempFieldBuffer);
TempFieldBuffer.Order := LastOrderNo;
TempFieldBuffer."Table ID" := Database::"Sales Invoice Line Aggregate";
TempFieldBuffer."Field ID" := FieldNo;
TempFieldBuffer.Insert();
end;
local procedure ClearCalculatedFields()
begin
TempFieldBuffer.Reset();
TempFieldBuffer.DeleteAll();
TempItemFieldSet.Reset();
TempItemFieldSet.DeleteAll();
Clear(Item);
end;
}
Output in Postman:

So the Header & Lines API Pages work on theire own, but not together.
Any idea's?