Close review gaps: gate fixes, cylinder register, roll tracking, costing, Uganda setup #1

Merged
denis_ireri merged 8 commits from feat/review-backlog-fixes into develop 2026-10-10 10:02:47 +00:00
4 changed files with 365 additions and 3 deletions
Showing only changes of commit 970f4bdfcf - Show all commits
@@ -403,8 +403,14 @@
"options": "Critical Acceptance Requirement"
}
],
"links": [],
"modified": "2026-09-02 00:05:48.067955",
"links": [
{
"group": "Tooling",
"link_doctype": "Print Cylinder",
"link_fieldname": "packaging_specification"
}
],
"modified": "2026-10-09 00:00:00",
"modified_by": "Administrator",
"module": "makap_backend",
"name": "Packaging Specification",
@@ -0,0 +1,337 @@
{
"actions": [],
"autoname": "field:cylinder_id",
"creation": "2026-10-09 00:00:00",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"identity_section",
"cylinder_id",
"tooling_type",
"status",
"identity_col",
"packaging_specification",
"item",
"customer",
"colour_station",
"colour_name",
"dimensions_section",
"circumference_mm",
"face_width_mm",
"dimensions_col",
"repeat_length_mm",
"engraving_reference",
"ownership_section",
"ownership",
"engraver",
"ownership_col",
"purchase_cost",
"customer_charge",
"condition_section",
"location",
"condition",
"last_used_on",
"last_used_work_order",
"condition_col",
"impression_count",
"impression_limit",
"retirement_reason",
"notes"
],
"fields": [
{
"fieldname": "identity_section",
"fieldtype": "Section Break",
"label": "Identity"
},
{
"fieldname": "cylinder_id",
"fieldtype": "Data",
"label": "Cylinder / Plate ID",
"reqd": 1,
"unique": 1,
"in_list_view": 1,
"description": "The number engraved or labelled on the cylinder, sleeve or plate."
},
{
"fieldname": "tooling_type",
"fieldtype": "Select",
"label": "Tooling Type",
"options": "Gravure Cylinder\nFlexo Plate\nFlexo Sleeve\nAnilox Roll\nCutting Die",
"reqd": 1,
"in_list_view": 1,
"in_standard_filter": 1
},
{
"fieldname": "status",
"fieldtype": "Select",
"label": "Status",
"options": "Ordered\nIn Prepress\nReady\nIn Use\nUnder Repair\nRetired",
"default": "Ordered",
"reqd": 1,
"in_list_view": 1,
"in_standard_filter": 1
},
{
"fieldname": "identity_col",
"fieldtype": "Column Break"
},
{
"fieldname": "packaging_specification",
"fieldtype": "Link",
"label": "Packaging Specification",
"options": "Packaging Specification",
"in_standard_filter": 1
},
{
"fieldname": "item",
"fieldtype": "Link",
"label": "Item",
"options": "Item",
"fetch_from": "packaging_specification.item",
"read_only": 1
},
{
"fieldname": "customer",
"fieldtype": "Link",
"label": "Customer",
"options": "Customer",
"fetch_from": "packaging_specification.customer",
"read_only": 1,
"in_standard_filter": 1
},
{
"fieldname": "colour_station",
"fieldtype": "Int",
"label": "Colour Station"
},
{
"fieldname": "colour_name",
"fieldtype": "Data",
"label": "Colour",
"in_list_view": 1
},
{
"fieldname": "dimensions_section",
"fieldtype": "Section Break",
"label": "Dimensions"
},
{
"fieldname": "circumference_mm",
"fieldtype": "Float",
"label": "Circumference (mm)"
},
{
"fieldname": "face_width_mm",
"fieldtype": "Float",
"label": "Face Width (mm)"
},
{
"fieldname": "dimensions_col",
"fieldtype": "Column Break"
},
{
"fieldname": "repeat_length_mm",
"fieldtype": "Float",
"label": "Repeat Length (mm)"
},
{
"fieldname": "engraving_reference",
"fieldtype": "Data",
"label": "Engraving / Screen Reference",
"description": "Screen ruling, cell depth or plate recipe reference."
},
{
"fieldname": "ownership_section",
"fieldtype": "Section Break",
"label": "Ownership and Cost"
},
{
"fieldname": "ownership",
"fieldtype": "Select",
"label": "Ownership",
"options": "Makap\nCustomer\nCharged to Customer",
"reqd": 1,
"default": "Makap"
},
{
"fieldname": "engraver",
"fieldtype": "Link",
"label": "Engraver / Supplier",
"options": "Supplier"
},
{
"fieldname": "ownership_col",
"fieldtype": "Column Break"
},
{
"fieldname": "purchase_cost",
"fieldtype": "Currency",
"label": "Purchase Cost"
},
{
"fieldname": "customer_charge",
"fieldtype": "Currency",
"label": "Charged to Customer",
"depends_on": "eval:doc.ownership=='Charged to Customer'"
},
{
"fieldname": "condition_section",
"fieldtype": "Section Break",
"label": "Location and Condition"
},
{
"fieldname": "location",
"fieldtype": "Data",
"label": "Rack / Location",
"in_list_view": 1
},
{
"fieldname": "condition",
"fieldtype": "Select",
"label": "Condition",
"options": "New\nGood\nWorn\nNeeds Re-chrome\nDamaged",
"default": "New"
},
{
"fieldname": "last_used_on",
"fieldtype": "Date",
"label": "Last Used On"
},
{
"fieldname": "last_used_work_order",
"fieldtype": "Link",
"label": "Last Used On Work Order",
"options": "Work Order"
},
{
"fieldname": "condition_col",
"fieldtype": "Column Break"
},
{
"fieldname": "impression_count",
"fieldtype": "Float",
"label": "Impressions to Date",
"default": "0"
},
{
"fieldname": "impression_limit",
"fieldtype": "Float",
"label": "Impression Limit",
"description": "Re-chrome or replace at this count. Leave empty if not tracked."
},
{
"fieldname": "retirement_reason",
"fieldtype": "Small Text",
"label": "Retirement Reason",
"depends_on": "eval:doc.status=='Retired'",
"mandatory_depends_on": "eval:doc.status=='Retired'"
},
{
"fieldname": "notes",
"fieldtype": "Small Text",
"label": "Notes"
}
],
"links": [],
"modified": "2026-10-09 00:00:00",
"modified_by": "Administrator",
"module": "makap_backend",
"name": "Print Cylinder",
"naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
"role": "System Manager",
"read": 1,
"write": 1,
"create": 1,
"delete": 1,
"print": 1,
"report": 1,
"export": 1,
"email": 1,
"share": 1
},
{
"role": "Manufacturing Manager",
"read": 1,
"write": 1,
"create": 1,
"delete": 0,
"print": 1,
"report": 1,
"export": 1,
"email": 1,
"share": 1
},
{
"role": "Technical Authority",
"read": 1,
"write": 1,
"create": 1,
"delete": 0,
"print": 1,
"report": 1,
"export": 1,
"email": 1,
"share": 1
},
{
"role": "Production Authority",
"read": 1,
"write": 1,
"create": 0,
"delete": 0,
"print": 1,
"report": 1,
"export": 1,
"email": 1,
"share": 1
},
{
"role": "Manufacturing User",
"read": 1,
"write": 0,
"create": 0,
"delete": 0,
"print": 1,
"report": 1,
"export": 0,
"email": 0,
"share": 0
},
{
"role": "Stock User",
"read": 1,
"write": 0,
"create": 0,
"delete": 0,
"print": 1,
"report": 1,
"export": 0,
"email": 0,
"share": 0
},
{
"role": "Sales User",
"read": 1,
"write": 0,
"create": 0,
"delete": 0,
"print": 1,
"report": 1,
"export": 0,
"email": 0,
"share": 0
}
],
"row_format": "Dynamic",
"search_fields": "colour_name,packaging_specification,customer",
"show_title_field_in_link": 0,
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"title_field": "cylinder_id",
"track_changes": 1
}
@@ -0,0 +1,19 @@
import frappe
from frappe.model.document import Document
UNFIT_CONDITIONS = {"Needs Re-chrome", "Damaged"}
class PrintCylinder(Document):
def validate(self):
# Work Order release reads "Ready" as fit to print, so a cylinder that
# isn't can't be marked Ready.
if self.status == "Ready" and self.condition in UNFIT_CONDITIONS:
frappe.throw(f"A cylinder in condition '{self.condition}' cannot be Ready. Send it for repair first.")
if self.impression_limit and (self.impression_count or 0) >= self.impression_limit:
frappe.msgprint(
f"{self.name} has reached its impression limit ({self.impression_limit:,.0f}). Plan a re-chrome or replacement.",
indicator="orange",
alert=True,
)