table 50100 "Customer Feedback" { DataClassification = CustomerContent; Caption = 'Customer Feedback'; fields { field(1; "Feedback ID"; Integer) { Caption = 'Feedback ID'; AutoIncrement = true; } field(2; "Customer No."; Code[20]) { Caption = 'Customer No.'; TableRelation = Customer."No."; } field(3; "Order No."; Code[20]) { Caption = 'Order No.'; TableRelation = "Sales Header"."No." where("Document Type" = const(Order)); } field(4; Rating; Integer) { Caption = 'Rating'; MinValue = 1; MaxValue = 5; } field(5; Comments; Text[250]) { Caption = 'Comments'; } field(6; "Feedback Date"; Date) { Caption = 'Feedback Date'; Editable = false; } } keys { key(PK; "Feedback ID") { Clustered = true; } key(OrderNo; "Order No.") {} } trigger OnInsert() begin "Feedback Date" := Today; end; } page 50100 "Customer Feedback List" { PageType = List; ApplicationArea = All; UsageCategory = Lists; SourceTable = "Customer Feedback"; Caption = 'Customer Feedback List'; layout { area(Content) { repeater(Group) { field("Feedback ID"; Rec."Feedback ID") { } field("Customer No."; Rec."Customer No.") { } field("Order No."; Rec."Order No.") { } field(Rating; Rec.Rating) { } field(Comments; Rec.Comments) { } field("Feedback Date"; Rec."Feedback Date") { } } } } } // Add to Sales Header table field(50100; "Has Feedback"; Boolean) { Caption = 'Has Feedback'; FieldClass = FlowField; CalcFormula = exist("Customer Feedback" where("Order No." = field("No."))); Editable = false; } // Modify Sales Order Page page 42 "Sales Order" { // Existing code layout { modify("Work Description") { trigger OnAfterValidate() begin end; } addafter("Work Description") { field("Has Feedback"; Rec."Has Feedback") { ApplicationArea = All; ToolTip = 'Specifies if feedback exists'; Editable = false; } } } } codeunit 50100 "Feedback Notification Mgt." { [EventSubscriber(ObjectType::Codeunit, Codeunit::"Sales-Post", 'OnAfterPostSalesDoc', '', true, true)] local procedure CheckFeedbackAfterPosting(var SalesHeader: Record "Sales Header") var CustomerFeedback: Record "Customer Feedback"; NotificationMsg: Notification; begin if SalesHeader."Document Type" <> SalesHeader."Document Type"::Invoice then exit; CustomerFeedback.SetRange("Order No.", SalesHeader."No."); if CustomerFeedback.IsEmpty then begin NotificationMsg.Message := 'No feedback exists for this invoiced order.'; NotificationMsg.Scope := NotificationScope::LocalScope; NotificationMsg.Send(); end; end; } page 50101 "Customer Feedback API" { PageType = API; Caption = 'Customer Feedback API'; APIPublisher = 'contoso'; APIGroup = 'feedback'; APIVersion = 'v1.0'; EntityName = 'feedback'; EntitySetName = 'feedbacks'; SourceTable = "Customer Feedback"; DelayedInsert = true; layout { area(Content) { repeater(Group) { field(feedbackID; Rec."Feedback ID") { } field(customerNo; Rec."Customer No.") { } field(orderNo; Rec."Order No.") { } field(rating; Rec.Rating) { } field(comments; Rec.Comments) { } field(feedbackDate; Rec."Feedback Date") { } } } } actions { // Built-in CRUD operations } [ServiceEnabled] procedure FilterByRating(RatingFilter: Integer): Text begin Rec.SetRange(Rating, RatingFilter); exit('Filter applied: ' + Format(RatingFilter) + ' stars'); end; } report 50100 "Customer Feedback Summary" { UsageCategory = ReportsAndAnalysis; ApplicationArea = All; DefaultLayout = RDLC; RDLCLayout = 'CustomerFeedbackSummary.rdl'; dataset { dataitem(Customer; Customer) { column(No; "No.") { } column(Name; Name) { } dataitem(Feedback; "Customer Feedback") { DataItemLink = "Customer No." = field("No."); DataItemTableView = sorting("Customer No."); column(TotalFeedback; TotalFeedback) { IncludeCaption = true; } column(AverageRating; AverageRating) { IncludeCaption = true; } trigger OnPreDataItem() begin SetRange("Feedback Date", StartDate, EndDate); end; trigger OnAfterGetRecord() begin TotalFeedback += 1; TotalRating += Rating; AverageRating := TotalRating / TotalFeedback; end; } trigger OnPreDataItem() begin Clear(TotalFeedback); Clear(TotalRating); end; } } requestpage { layout { area(Content) { group(Options) { field(StartDate; StartDate) { Caption = 'Start Date'; } field(EndDate; EndDate) { Caption = 'End Date'; } } } } } var StartDate: Date; EndDate: Date; TotalFeedback: Integer; TotalRating: Integer; AverageRating: Decimal; } codeunit 50101 "Customer Feedback Reminder" { procedure SendReminders() var SalesHeader: Record "Sales Header"; Customer: Record Customer; EmailMessage: Codeunit "Email Message"; Email: Codeunit Email; begin SalesHeader.SetRange("Document Type", SalesHeader."Document Type"::Order); SalesHeader.SetRange("Has Feedback", false); SalesHeader.SetRange(Status, SalesHeader.Status::Released); if SalesHeader.FindSet() then repeat if Customer.Get(SalesHeader."Sell-to Customer No.") then if Customer."E-Mail" <> '' then begin EmailMessage.Create(Customer."E-Mail", 'Feedback Request for Order ' + SalesHeader."No.", CreateEmailBody(SalesHeader)); Email.Send(EmailMessage); end; until SalesHeader.Next() = 0; end; local procedure CreateEmailBody(SalesHeader: Record "Sales Header"): Text begin exit('Dear Customer,\\Please provide feedback for your recent order ' + SalesHeader."No." + '\\Regards,\\Contoso Team'); end; }