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
5 changed files with 91 additions and 8 deletions
Showing only changes of commit b2fd83dc51 - Show all commits
+1 -1
View File
@@ -6,7 +6,7 @@ app_email = "josephnjuki833@gmail.com"
app_license = "mit" app_license = "mit"
# MAKAP Module 3 child-table registration # MAKAP Module 3 child-table registration
after_migrate = ["makap_backend.makap_backend.setup.ensure_makap_functional_roles", "makap_backend.makap_backend.setup.ensure_makap_object_permissions", "makap_backend.makap_backend.setup_module3.ensure_module3_child_tables", "makap_backend.makap_backend.setup_extensions.ensure_custom_fields", "makap_backend.makap_backend.setup_module8_dashboard.ensure_module8_number_cards", "makap_backend.makap_backend.setup_workspace_dashboard.ensure_workspace_number_cards", "makap_backend.makap_backend.workspace_setup.ensure_makap_workspace", "makap_backend.makap_backend.setup_module8_permissions.ensure_module8_role_permissions", "makap_backend.makap_backend.portal_shortcut.ensure_portal_shortcut"] after_migrate = ["makap_backend.makap_backend.setup.ensure_makap_functional_roles", "makap_backend.makap_backend.setup.ensure_makap_object_permissions", "makap_backend.makap_backend.setup_module3.ensure_module3_child_tables", "makap_backend.makap_backend.setup_extensions.ensure_custom_fields", "makap_backend.makap_backend.setup_module8_dashboard.ensure_module8_number_cards", "makap_backend.makap_backend.setup_workspace_dashboard.ensure_workspace_number_cards", "makap_backend.makap_backend.workspace_setup.ensure_makap_workspace", "makap_backend.makap_backend.setup_module8_permissions.ensure_module8_role_permissions", "makap_backend.makap_backend.setup_roles.ensure_shopfloor_permissions", "makap_backend.makap_backend.setup_roles.ensure_makap_role_profiles", "makap_backend.makap_backend.portal_shortcut.ensure_portal_shortcut"]
# MAKAP cross-module server-side controls # MAKAP cross-module server-side controls
doc_events = { doc_events = {
+3
View File
@@ -103,6 +103,9 @@ def ensure_makap_functional_roles():
"Commercial Authority", "Commercial Authority",
# Module 8B # Module 8B
"Credit Authority", "Credit Authority",
# Shop floor and prepress (PRD Section 3)
"Machine Operator",
"Prepress",
] ]
created = [] created = []
for role_name in role_names: for role_name in role_names:
@@ -174,6 +174,15 @@ FIELDS = [
] ]
# Quality decisions: only roles granted permlevel 1 on Quality Inspection
# (QA, see setup_roles) can change these.
QUALITY_DECISION_FIELDS = {
"makap_quality_eligibility", "makap_quality_disposition", "makap_disposition_quantity",
"makap_disposition_uom", "makap_disposition_reason", "makap_concession_scope",
"makap_concession_quantity", "makap_concession_uom", "makap_concession_reference",
"makap_released_not_before",
}
# Where each DocType's Makap fields live. Parent forms get one "Makap" tab; # Where each DocType's Makap fields live. Parent forms get one "Makap" tab;
# child rows get a section. Operator and roll fields sit in the main view # child rows get a section. Operator and roll fields sit in the main view
# because they are filled in on the shop floor, not reviewed later. # because they are filled in on the shop floor, not reviewed later.
@@ -194,9 +203,10 @@ def _end_anchor(meta):
def build_custom_fields(): def build_custom_fields():
grouped = {} grouped = {}
for dt, fieldname, label, fieldtype, options, read_only in FIELDS: for dt, fieldname, label, fieldtype, options, read_only in FIELDS:
grouped.setdefault(dt, []).append( field = {"fieldname": fieldname, "label": label, "fieldtype": fieldtype, "options": options, "read_only": read_only}
{"fieldname": fieldname, "label": label, "fieldtype": fieldtype, "options": options, "read_only": read_only} if dt == "Quality Inspection" and fieldname in QUALITY_DECISION_FIELDS:
) field["permlevel"] = 1
grouped.setdefault(dt, []).append(field)
result = {} result = {}
for dt, fields in grouped.items(): for dt, fields in grouped.items():
@@ -2,15 +2,15 @@ import frappe
from frappe.permissions import add_permission, update_permission_property from frappe.permissions import add_permission, update_permission_property
def _grant(doctype, role, **flags): def _grant(doctype, role, permlevel=0, **flags):
if not frappe.db.exists("DocType", doctype): if not frappe.db.exists("DocType", doctype):
return return
if not frappe.db.exists("Role", role): if not frappe.db.exists("Role", role):
return return
if not frappe.db.exists("Custom DocPerm", {"parent": doctype, "role": role, "permlevel": 0}): if not frappe.db.exists("Custom DocPerm", {"parent": doctype, "role": role, "permlevel": permlevel}):
add_permission(doctype, role, permlevel=0) add_permission(doctype, role, permlevel=permlevel)
for ptype, value in flags.items(): for ptype, value in flags.items():
update_permission_property(doctype, role, 0, ptype, value) update_permission_property(doctype, role, permlevel, ptype, value)
def ensure_module8_role_permissions(): def ensure_module8_role_permissions():
@@ -0,0 +1,70 @@
"""Role profiles for the user roles in the PRD (Section 3), and the shop-floor
permissions they need. Both are created only when missing, so changes Makap
makes later in the desk are never overwritten on migrate.
"""
import frappe
from makap_backend.makap_backend.setup_module8_permissions import _grant
ROLE_PROFILES = {
"Makap - Sales / Account Manager": ["Sales User", "Commercial Reviewer"],
"Makap - Design / Prepress": ["Prepress", "Technical Authority"],
"Makap - Production Planner": ["Manufacturing Manager", "Production Authority", "Stock User"],
"Makap - Procurement": ["Purchase User", "Purchase Manager", "Supply Assurance Manager", "Stock User"],
"Makap - Warehouse": ["Stock User", "Materials Controller", "Dispatch Preparer"],
"Makap - Machine Operator": ["Machine Operator"],
"Makap - Shift Supervisor": ["Machine Operator", "Manufacturing User"],
"Makap - QC / QA": ["Quality Manager", "Concession Authority"],
"Makap - Finance": ["Accounts User", "Accounts Manager", "Credit Authority", "Commercial Authority"],
"Makap - Management": ["Analytics", "Auditor"],
}
# Operators record work on Job Cards and label rolls; they don't plan, buy or release.
SHOPFLOOR_GRANTS = [
("Job Card", "Machine Operator", dict(read=1, write=1, create=1, submit=1)),
("Work Order", "Machine Operator", dict(read=1)),
("Operation", "Machine Operator", dict(read=1)),
("Workstation", "Machine Operator", dict(read=1)),
("Item", "Machine Operator", dict(read=1)),
("Batch", "Machine Operator", dict(read=1, write=1, create=1)),
("Print Cylinder", "Machine Operator", dict(read=1)),
("Quality Inspection", "Machine Operator", dict(read=1, write=1, create=1)),
("Print Cylinder", "Prepress", dict(read=1, write=1, create=1)),
("Packaging Specification", "Prepress", dict(read=1, write=1)),
("Item", "Prepress", dict(read=1)),
]
# Eligibility and disposition decide whether stock can move on or ship, so
# only QA may set them; everyone who can open an inspection may still read them.
QUALITY_DECISION_WRITERS = ["Quality Manager", "Concession Authority", "System Manager"]
QUALITY_DECISION_READERS = [
"Manufacturing User", "Manufacturing Manager", "Machine Operator", "Stock User",
"Dispatch Preparer", "Dispatch Authority", "Production Authority",
]
def ensure_makap_role_profiles():
created = []
for profile, roles in ROLE_PROFILES.items():
if frappe.db.exists("Role Profile", profile):
continue
doc = frappe.new_doc("Role Profile")
doc.role_profile = profile
for role in roles:
if frappe.db.exists("Role", role):
doc.append("roles", {"role": role})
doc.insert(ignore_permissions=True)
created.append(profile)
return created
def ensure_shopfloor_permissions():
for doctype, role, flags in SHOPFLOOR_GRANTS:
_grant(doctype, role, **flags)
for role in QUALITY_DECISION_WRITERS:
_grant("Quality Inspection", role, permlevel=1, read=1, write=1)
for role in QUALITY_DECISION_READERS:
_grant("Quality Inspection", role, permlevel=1, read=1)
return True