feat(portal): _fp_group_documents helper for detail-page doc panel
V1 surfaces only the fields directly on fp.portal.job (CoC + packing list). Other 2 groups (From You, Specifications) render placeholder rows. V2 will wire in sale.order linking for full doc surfacing. Also adds _fp_size_label helper for friendly file-size strings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -170,6 +170,93 @@ class FpCustomerPortal(CustomerPortal):
|
||||
})
|
||||
return out
|
||||
|
||||
def _fp_group_documents(self, job):
|
||||
"""Build the 4-group document panel for the job detail page.
|
||||
|
||||
V1: surfaces only the directly-attached fields on fp.portal.job
|
||||
(coc_attachment_id, packing_list_attachment_id). Other 3 groups
|
||||
render placeholder/pending rows. V2 (separate change) will wire in
|
||||
sale_order_id, quote_request_id, part_catalog_id sources.
|
||||
|
||||
Returns a list of 4 dicts: {key, label, docs}, where docs is a list
|
||||
of {label, sub, url, icon_class, icon, pending}.
|
||||
"""
|
||||
groups = [
|
||||
{'key': 'from_you', 'label': 'From You', 'docs': []},
|
||||
{'key': 'specs', 'label': 'Specifications', 'docs': []},
|
||||
{'key': 'quality', 'label': 'Quality', 'docs': []},
|
||||
{'key': 'shipping', 'label': 'Shipping', 'docs': []},
|
||||
]
|
||||
|
||||
# FROM YOU — V1: placeholder (V2 will pull PO + drawings via SO link)
|
||||
groups[0]['docs'].append({
|
||||
'label': 'Customer documents',
|
||||
'sub': 'Upload your PO and drawings via your sales contact for now',
|
||||
'pending': True,
|
||||
'icon': '📄',
|
||||
})
|
||||
|
||||
# SPECIFICATIONS — V1: placeholder (V2 will pull customer spec)
|
||||
groups[1]['docs'].append({
|
||||
'label': 'Customer Specification',
|
||||
'sub': 'Will appear when EN Plating links the spec',
|
||||
'pending': True,
|
||||
'icon': '📋',
|
||||
})
|
||||
|
||||
# QUALITY — CoC from coc_attachment_id (the legacy direct field)
|
||||
if job.coc_attachment_id:
|
||||
groups[2]['docs'].append({
|
||||
'label': 'Certificate of Conformance',
|
||||
'sub': 'EN Plating · %s · %s' % (
|
||||
job.actual_ship_date and job.actual_ship_date.strftime('%b %d') or '',
|
||||
self._fp_size_label(job.coc_attachment_id),
|
||||
),
|
||||
'url': '/my/jobs/%s/coc' % job.id,
|
||||
'icon_class': 'o_fp_doc_icon_quality',
|
||||
'icon': '📑',
|
||||
})
|
||||
else:
|
||||
groups[2]['docs'].append({
|
||||
'label': 'Certificate of Conformance',
|
||||
'sub': 'Will appear after QC completes',
|
||||
'pending': True,
|
||||
'icon': '📑',
|
||||
})
|
||||
|
||||
# SHIPPING — packing list + tracking
|
||||
if job.packing_list_attachment_id:
|
||||
groups[3]['docs'].append({
|
||||
'label': 'Packing Slip',
|
||||
'sub': 'EN Plating · %s · %s' % (
|
||||
job.actual_ship_date and job.actual_ship_date.strftime('%b %d') or '',
|
||||
self._fp_size_label(job.packing_list_attachment_id),
|
||||
),
|
||||
'url': '/web/content/%s?download=true' % job.packing_list_attachment_id.id,
|
||||
'icon_class': 'o_fp_doc_icon_shipping',
|
||||
'icon': '📦',
|
||||
})
|
||||
else:
|
||||
groups[3]['docs'].append({
|
||||
'label': 'Packing Slip · Tracking #',
|
||||
'sub': 'Available when shipped' + (' — ' + job.tracking_ref if job.tracking_ref else ''),
|
||||
'pending': not job.tracking_ref,
|
||||
'icon': '📦',
|
||||
})
|
||||
|
||||
return groups
|
||||
|
||||
def _fp_size_label(self, attachment):
|
||||
"""Render attachment.file_size as a friendly KB/MB string."""
|
||||
if not attachment or not attachment.file_size:
|
||||
return ''
|
||||
size = attachment.file_size
|
||||
if size < 1024:
|
||||
return '%d B' % size
|
||||
if size < 1024 * 1024:
|
||||
return '%.0f KB' % (size / 1024)
|
||||
return '%.1f MB' % (size / (1024 * 1024))
|
||||
|
||||
# ==========================================================================
|
||||
# DASHBOARD
|
||||
# ==========================================================================
|
||||
|
||||
Reference in New Issue
Block a user