Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 169 additions & 0 deletions Prototyping/src/Codeunits/Cod50100.CKManagement.al
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
codeunit 50100 "CK Management"
{
/// <summary>
/// Generates a unique LOT number for a newly mixed ink batch.
/// Format: CK-YYYYMMDDHHMMSS
/// </summary>
procedure GenerateLOTNo(): Code[50]
var
DateTimeText: Text;
begin
DateTimeText := Format(CurrentDateTime(), 0, '<Year4><Month,2><Day,2><Hours24,2><Minutes,2><Seconds,2>');
exit(CopyStr('CK-' + DateTimeText, 1, 50));
end;

/// <summary>
/// Populates Mix Lines from the Color Kitchen Recipe for the given Mix Header.
/// Existing lines are replaced. Quantities are calculated from the recipe percentages
/// and the Quantity to Mix on the header.
/// </summary>
procedure LoadRecipeLines(MixHeaderEntryNo: Integer)
var
MixHeader: Record "CK Mix Header";
RecipeLine: Record "CK Recipe Line";
MixLine: Record "CK Mix Line";
LineNo: Integer;
begin
if not MixHeader.Get(MixHeaderEntryNo) then
exit;

// Remove any previously loaded lines so we start fresh
MixLine.SetRange("Mix Header Entry No.", MixHeaderEntryNo);
MixLine.DeleteAll(true);

RecipeLine.SetRange("Item No.", MixHeader."Item No.");
if not RecipeLine.FindSet() then
exit;

LineNo := 10000;
repeat
MixLine.Init();
MixLine."Mix Header Entry No." := MixHeaderEntryNo;
MixLine."Line No." := LineNo;
MixLine."Base Component Item No." := RecipeLine."Base Component Item No.";
MixLine."Base Component Description" := RecipeLine."Base Component Description";
MixLine.Percentage := RecipeLine.Percentage;
if MixHeader."Quantity to Mix" > 0 then
MixLine."Quantity Required" :=
Round(MixHeader."Quantity to Mix" * RecipeLine.Percentage / 100, 0.001);
MixLine."Quantity Used" := MixLine."Quantity Required";
MixLine.Status := "CK Mix Line Status"::Pending;
MixLine.Insert(true);
LineNo += 10000;
until RecipeLine.Next() = 0;
end;

/// <summary>
/// Posts negative item adjustments for each pending base component line,
/// recording the operator-supplied LOT numbers. Advances header status to In Progress.
/// </summary>
procedure PostConsumption(MixHeaderEntryNo: Integer)
var
MixHeader: Record "CK Mix Header";
MixLine: Record "CK Mix Line";
ItemJnlLine: Record "Item Journal Line";
ItemJnlPostLine: Codeunit "Item Jnl.-Post Line";
LineNo: Integer;
DocumentNo: Code[20];
begin
if not MixHeader.Get(MixHeaderEntryNo) then
exit;

DocumentNo := CopyStr('CK-' + Format(MixHeaderEntryNo), 1, 20);

MixLine.SetRange("Mix Header Entry No.", MixHeaderEntryNo);
MixLine.SetRange(Status, "CK Mix Line Status"::Pending);
if not MixLine.FindSet() then
exit;

LineNo := 10000;
repeat
if MixLine."Quantity Used" > 0 then begin
Clear(ItemJnlLine);
ItemJnlLine."Line No." := LineNo;
ItemJnlLine.Validate("Posting Date", Today());
ItemJnlLine.Validate("Entry Type", ItemJnlLine."Entry Type"::"Negative Adjmt.");
ItemJnlLine.Validate("Item No.", MixLine."Base Component Item No.");
ItemJnlLine.Validate(Quantity, MixLine."Quantity Used");
if MixLine."LOT No." <> '' then
ItemJnlLine."Lot No." := MixLine."LOT No.";
ItemJnlLine."Document No." := DocumentNo;
ItemJnlLine."Source Code" := GetSourceCode();
ItemJnlPostLine.RunWithCheck(ItemJnlLine);

MixLine.Status := "CK Mix Line Status"::Consumed;
MixLine.Modify(true);
end;
LineNo += 10000;
until MixLine.Next() = 0;

MixHeader.Status := "CK Mix Status"::"In Progress";
MixHeader.Modify(true);
end;

/// <summary>
/// Generates a new LOT number if needed, then posts a positive item adjustment
/// to put the mixed ink into stock. Advances header status to Completed.
/// </summary>
procedure PostMixedInkToStock(MixHeaderEntryNo: Integer)
var
MixHeader: Record "CK Mix Header";
ItemJnlLine: Record "Item Journal Line";
ItemJnlPostLine: Codeunit "Item Jnl.-Post Line";
DocumentNo: Code[20];
begin
if not MixHeader.Get(MixHeaderEntryNo) then
exit;

if MixHeader."LOT No." = '' then
MixHeader."LOT No." := GenerateLOTNo();

if MixHeader."Quantity Mixed" = 0 then
MixHeader."Quantity Mixed" := MixHeader."Quantity to Mix";

DocumentNo := CopyStr('CK-' + Format(MixHeaderEntryNo), 1, 20);

Clear(ItemJnlLine);
ItemJnlLine."Line No." := 10000;
ItemJnlLine.Validate("Posting Date", Today());
ItemJnlLine.Validate("Entry Type", ItemJnlLine."Entry Type"::"Positive Adjmt.");
ItemJnlLine.Validate("Item No.", MixHeader."Item No.");
ItemJnlLine.Validate(Quantity, MixHeader."Quantity Mixed");
ItemJnlLine."Lot No." := MixHeader."LOT No.";
ItemJnlLine."Document No." := DocumentNo;
ItemJnlLine."Source Code" := GetSourceCode();
ItemJnlPostLine.RunWithCheck(ItemJnlLine);

MixHeader.Status := "CK Mix Status"::Completed;
MixHeader.Modify(true);
end;

/// <summary>
/// Returns a formatted text of all base component LOT numbers recorded on a mix.
/// Used for label printing and job ticket display.
/// </summary>
procedure GetBaseComponentLOTsText(MixHeaderEntryNo: Integer): Text
var
MixLine: Record "CK Mix Line";
LOTText: Text;
begin
MixLine.SetRange("Mix Header Entry No.", MixHeaderEntryNo);
MixLine.SetFilter("LOT No.", '<>%1', '');
if MixLine.FindSet() then
repeat
if LOTText <> '' then
LOTText += '; ';
LOTText += MixLine."Base Component Item No." + ': ' + MixLine."LOT No.";
until MixLine.Next() = 0;
exit(LOTText);
end;

local procedure GetSourceCode(): Code[10]
var
SourceCodeSetup: Record "Source Code Setup";
begin
if SourceCodeSetup.Get() then
exit(SourceCodeSetup."Item Journal");
exit('');
end;
}
18 changes: 18 additions & 0 deletions Prototyping/src/Enums/Enum50100.CKMixStatus.al
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
enum 50100 "CK Mix Status"
{
Extensible = true;
Caption = 'Color Kitchen Mix Status';

value(0; "Not Started")
{
Caption = 'Not Started';
}
value(1; "In Progress")
{
Caption = 'In Progress';
}
value(2; Completed)
{
Caption = 'Completed';
}
}
14 changes: 14 additions & 0 deletions Prototyping/src/Enums/Enum50101.CKMixLineStatus.al
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
enum 50101 "CK Mix Line Status"
{
Extensible = true;
Caption = 'Color Kitchen Mix Line Status';

value(0; Pending)
{
Caption = 'Pending';
}
value(1; Consumed)
{
Caption = 'Consumed';
}
}
24 changes: 24 additions & 0 deletions Prototyping/src/PageExtensions/PagExt50100.ItemCardCKExt.al
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
pageextension 50100 "CK Item Card Ext" extends "Item Card"
{
actions
{
addlast(Navigation)
{
action(ColorKitchenRecipe)
{
Caption = 'Color Kitchen Recipe';
ApplicationArea = All;
Image = BOMVersions;
ToolTip = 'Opens the Color Kitchen Recipe for this item. Define the base component inks and their percentages that make up this mixed ink.';

trigger OnAction()
var
RecipeLine: Record "CK Recipe Line";
begin
RecipeLine.SetRange("Item No.", Rec."No.");
Page.Run(Page::"CK Recipe Page", RecipeLine);
end;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Extends the PrintVis Shop Floor Electronic Ticket page (6010731).
// Adds the Color Kitchen button to the header so the mixing station operator
// can open the Color Kitchen directly from their active job ticket.
//
// NOTE: The field names "Case No." and "Job No." used below reflect the typical
// PrintVis Job Sheet structure. Verify these field names match your PrintVis version
// and adjust if required before compiling.
pageextension 50101 "CK SF Electronic Ticket Ext" extends "PVS SF Electronic Ticket"
{
actions
{
addlast(Processing)
{
action(ColorKitchen)
{
Caption = 'Color Kitchen';
ApplicationArea = All;
Image = ResourcePlanning;
ToolTip = 'Opens the Color Kitchen for this job. Mix inks, scan LOT numbers and put mixed ink into stock.';

trigger OnAction()
var
MixHeader: Record "CK Mix Header";
CaseNo: Integer;
JobNo: Integer;
begin
// Retrieve the PrintVis Case and Job numbers from the current record.
// Adjust the field names below if they differ in your PrintVis installation.
CaseNo := Rec."Case No.";
JobNo := Rec."Job No.";

MixHeader.SetRange("PVS Case No.", CaseNo);
MixHeader.SetRange("PVS Job No.", JobNo);
Page.Run(Page::"CK Page", MixHeader);
end;
}
}
}
}
90 changes: 90 additions & 0 deletions Prototyping/src/Pages/Pag50100.CKRecipePage.al
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
page 50100 "CK Recipe Page"
{
Caption = 'Color Kitchen Recipe';
PageType = List;
SourceTable = "CK Recipe Line";
UsageCategory = None;
Editable = true;
InsertAllowed = true;
DeleteAllowed = true;

layout
{
area(Content)
{
repeater(Lines)
{
field("Base Component Item No."; Rec."Base Component Item No.")
{
ApplicationArea = All;
ToolTip = 'Specifies the item number of the base component ink.';
}
field("Base Component Description"; Rec."Base Component Description")
{
ApplicationArea = All;
ToolTip = 'Specifies the description of the base component ink.';
}
field(Percentage; Rec.Percentage)
{
ApplicationArea = All;
ToolTip = 'Specifies the weight percentage of this component in the mixed ink recipe. All percentages should sum to 100.';
}
}
}
}

actions
{
area(Processing)
{
action(ValidateTotal)
{
Caption = 'Check Total %';
ApplicationArea = All;
Image = CheckRecs;
ToolTip = 'Validates that all recipe percentages add up to 100.';

trigger OnAction()
var
RecipeLine: Record "CK Recipe Line";
Total: Decimal;
ItemFilter: Code[20];
begin
ItemFilter := CopyStr(Rec.GetFilter("Item No."), 1, 20);
RecipeLine.SetRange("Item No.", ItemFilter);
if RecipeLine.FindSet() then
repeat
Total += RecipeLine.Percentage;
until RecipeLine.Next() = 0;

if Abs(Total - 100) < 0.01 then
Message('Recipe total is 100%%. OK.')
else
Message('Recipe total is %1%%. Components should add up to 100%%.', Total);
end;
}
}
}

trigger OnNewRecord(BelowxRec: Boolean)
var
ItemFilter: Code[20];
begin
ItemFilter := GetSingleCodeFilter();
if ItemFilter <> '' then begin
Rec."Item No." := ItemFilter;
Rec."Line No." := Rec.GetNextLineNo(ItemFilter);
end;
end;

local procedure GetSingleCodeFilter(): Code[20]
var
FilterTxt: Text;
begin
FilterTxt := Rec.GetFilter("Item No.");
// Only use the filter when it represents exactly one value (no wildcards or OR)
if (FilterTxt <> '') and (FilterTxt.IndexOf('|') = 0) and (FilterTxt.IndexOf('*') = 0) and (FilterTxt.IndexOf('&') = 0) then
exit(CopyStr(FilterTxt, 1, 20));
exit('');
end;
}
Loading
Loading