QC Reason Documentation¶
Overview¶
The QC Reason module (qc.reason) provides a simple lookup table for quality control rejection reasons. This allows standardization of QC failure reasons across the organization for reporting and analysis.
Model Information¶
Model Name: qc.reason
Display Name: QC Reason
Key Fields: None (commented out in code)
Features¶
- ❌ Audit logging enabled (
_audit_log) - ❌ Multi-company support (commented out in code)
- ❌ Full-text content search (
_content_search) - ❌ Unique key constraint (commented out in code)
Commented Features¶
The model has commented code suggesting these features were considered but not implemented:
#_key=["name"] # Would enforce unique reason names
#_multi_company=True # Would enable company-specific reasons
Field Reference¶
Header Fields¶
| Field | Type | Required | Description |
|---|---|---|---|
name |
Char | ❌ | Name/description of the QC rejection reason (searchable) |
Common QC Reason Examples¶
Typical QC reasons that might be configured:
| Category | Example Reasons |
|---|---|
| Visual Defects | Scratches, Dents, Discoloration, Surface Contamination |
| Dimensional | Undersized, Oversized, Out of Tolerance, Warpage |
| Material | Wrong Material, Material Defect, Contamination |
| Functional | Does Not Function, Performance Below Spec, Leaks |
| Packaging | Damaged Packaging, Missing Components, Wrong Labeling |
| Process | Incomplete Processing, Wrong Process Applied, Rework Required |
API Methods¶
1. Create QC Reason¶
Method: create(vals, context)
Creates a new QC reason record.
Parameters:
Returns: int - New reason ID
Example:
# Create standard QC reasons
reasons = [
"Surface Scratches",
"Dimensional Out of Tolerance",
"Material Contamination",
"Incomplete Processing",
"Damaged Packaging"
]
for reason_name in reasons:
get_model("qc.reason").create({"name": reason_name})
Related Models¶
| Model | Relationship | Description |
|---|---|---|
qc.result |
Potential Reference | QC results may reference these reasons for rejections |
stock.move |
Indirect | QC results link to stock moves which may use these reasons |
Common Use Cases¶
Use Case 1: Initialize Standard Reasons¶
# Set up company-wide QC reasons
standard_reasons = [
# Visual defects
"Surface Scratches",
"Dents or Deformation",
"Discoloration",
"Paint Defects",
# Dimensional issues
"Undersized",
"Oversized",
"Out of Tolerance",
# Material issues
"Wrong Material Grade",
"Material Contamination",
"Porosity",
# Functional issues
"Failed Performance Test",
"Does Not Meet Specification",
# Process issues
"Incomplete Heat Treatment",
"Improper Coating",
"Rework Required"
]
for reason in standard_reasons:
# Check if exists first
existing = get_model("qc.reason").search([["name", "=", reason]])
if not existing:
get_model("qc.reason").create({"name": reason})
Use Case 2: QC Reason Selection in UI¶
# Get all reasons for dropdown/selection
def get_qc_reasons():
reason_ids = get_model("qc.reason").search([])
reasons = get_model("qc.reason").browse(reason_ids)
return [(r.id, r.name) for r in reasons]
# Use in QC inspection
qc_reasons = get_qc_reasons()
# Returns: [(1, "Surface Scratches"), (2, "Undersized"), ...]
Use Case 3: QC Reason Reporting¶
# Analyze rejection patterns (if QC results reference reasons)
def analyze_rejection_reasons():
"""
Note: This assumes qc.result has a reason_id field
(not present in provided code but logical extension)
"""
# Count rejections by reason
rejection_counts = {}
# Get all rejected QC results
qc_results = get_model("qc.result").search([
["result", "=", "reject"]
])
for result in get_model("qc.result").browse(qc_results):
# If reason_id field exists:
# reason_name = result.reason_id.name
# rejection_counts.setdefault(reason_name, 0)
# rejection_counts[reason_name] += 1
pass
# Sort by frequency
sorted_reasons = sorted(
rejection_counts.items(),
key=lambda x: x[1],
reverse=True
)
print("Top Rejection Reasons:")
for reason, count in sorted_reasons[:10]:
print(f" {reason}: {count} rejections")
Use Case 4: Reason Category Management¶
# Organize reasons by category for better reporting
def categorize_reasons():
all_reasons = get_model("qc.reason").search([])
reasons = get_model("qc.reason").browse(all_reasons)
categories = {
"Visual": [],
"Dimensional": [],
"Material": [],
"Functional": [],
"Process": [],
"Other": []
}
# Simple keyword-based categorization
for reason in reasons:
name_lower = reason.name.lower()
if any(kw in name_lower for kw in ["scratch", "dent", "visual", "surface", "paint"]):
categories["Visual"].append(reason)
elif any(kw in name_lower for kw in ["size", "dimension", "tolerance", "measurement"]):
categories["Dimensional"].append(reason)
elif any(kw in name_lower for kw in ["material", "grade", "contamination"]):
categories["Material"].append(reason)
elif any(kw in name_lower for kw in ["function", "performance", "test", "specification"]):
categories["Functional"].append(reason)
elif any(kw in name_lower for kw in ["process", "treatment", "rework", "incomplete"]):
categories["Process"].append(reason)
else:
categories["Other"].append(reason)
# Print categorized reasons
for category, reason_list in categories.items():
if reason_list:
print(f"\n{category}:")
for r in reason_list:
print(f" - {r.name}")
Best Practices¶
1. Use Consistent Naming¶
# Good: Clear, standardized names
good_reasons = [
"Surface Scratches - Minor",
"Surface Scratches - Major",
"Dimensional Tolerance Exceeded - Length",
"Dimensional Tolerance Exceeded - Width"
]
# Bad: Inconsistent, vague names
bad_reasons = [
"scratches",
"Scratch",
"bad surface",
"too big"
]
2. Create Hierarchical Reasons¶
# Organize reasons in parent-child hierarchy
# (Would require additional parent_id field)
hierarchical_reasons = [
"Visual Defects",
" ├─ Surface Scratches",
" ├─ Dents",
" └─ Discoloration",
"Dimensional Issues",
" ├─ Undersized",
" └─ Oversized"
]
3. Periodic Reason Review¶
# Identify unused reasons for cleanup
def find_unused_reasons():
"""
Find reasons that haven't been used in QC results
(Assumes qc.result has reason_id field)
"""
all_reason_ids = get_model("qc.reason").search([])
# Get reasons used in QC results
# used_reason_ids = set()
# for result in get_model("qc.result").search([]):
# if result.reason_id:
# used_reason_ids.add(result.reason_id.id)
# unused = set(all_reason_ids) - used_reason_ids
# return unused
pass
Potential Enhancements¶
The model could be enhanced with these features:
1. Enable Multi-Company Support¶
_multi_company = True
_fields = {
"name": fields.Char("Name", search=True),
"company_id": fields.Many2One("company", "Company")
}
2. Add Unique Constraint¶
3. Add Categorization¶
_fields = {
"name": fields.Char("Name", search=True, required=True),
"category": fields.Selection([
["visual", "Visual Defects"],
["dimensional", "Dimensional Issues"],
["material", "Material Issues"],
["functional", "Functional Issues"],
["process", "Process Issues"]
], "Category"),
"description": fields.Text("Detailed Description"),
"severity": fields.Selection([
["minor", "Minor"],
["major", "Major"],
["critical", "Critical"]
], "Severity Level")
}
4. Add Activity Tracking¶
_fields = {
"name": fields.Char("Name", search=True, required=True),
"active": fields.Boolean("Active", default=True),
"usage_count": fields.Integer("Usage Count", readonly=True)
}
Search Examples¶
Find Reasons by Keyword¶
# Search for reasons containing "scratch"
reason_ids = get_model("qc.reason").search([
["name", "ilike", "%scratch%"]
])
Get All Active Reasons¶
Performance Tips¶
1. Cache Reason List¶
# Cache reasons for dropdown lists
_reason_cache = None
_reason_cache_time = None
def get_cached_reasons():
global _reason_cache, _reason_cache_time
# Refresh cache every hour
now = time.time()
if not _reason_cache or (now - _reason_cache_time) > 3600:
reason_ids = get_model("qc.reason").search([])
_reason_cache = get_model("qc.reason").browse(reason_ids)
_reason_cache_time = now
return _reason_cache
Troubleshooting¶
"Duplicate reason names"¶
Cause: No unique constraint on name field
Solution:
- Manually check for duplicates before creating
- Consider uncommenting _key = ["name"] to enforce uniqueness
"Too many similar reasons"¶
Cause: Lack of standardization, multiple people creating reasons
Solution:
- Implement approval process for new reasons
- Periodically consolidate similar reasons
- Create category structure
Version History¶
Last Updated: October 2025
Model Version: qc_reason.py
Framework: Netforce
Additional Resources¶
- QC Result Documentation:
qc.result - Quality Control Process Documentation
- Stock Movement Documentation:
stock.move
This documentation is generated for developer onboarding and reference purposes.