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?