feat(configurator): B4+B8 - Express onchange auto-fill cascade + DWG/OPEN on direct-order line

This commit is contained in:
gsinghpal
2026-05-26 21:11:15 -04:00
parent 76a80badff
commit 200a2efeb8

View File

@@ -494,34 +494,115 @@ class FpDirectOrderLine(models.Model):
@api.onchange('part_catalog_id')
def _onchange_part_default_thickness(self):
"""Auto-fill thickness range — same chain as the SO line.
"""Auto-fill thickness range + Express defaults — same chain as the SO line.
For each cell, the chain is:
1. Operator already typed → keep
2. Most recent SO line for (part, customer) with a thickness → copy
3. Part's x_fc_default_thickness_range → copy
2. Most recent SO line for (part, customer) with a value → copy
3. Part's default field → copy
4. Blank
"""
for rec in self:
if rec.thickness_range:
continue
if not rec.part_catalog_id:
continue
part = rec.part_catalog_id
partner = rec.wizard_id.partner_id
if partner:
recent = self.env['sale.order.line'].search([
('x_fc_part_catalog_id', '=', rec.part_catalog_id.id),
('order_id.partner_id', '=', partner.id),
('x_fc_thickness_range', '!=', False),
('x_fc_thickness_range', '!=', ''),
], order='create_date desc', limit=1)
if recent:
rec.thickness_range = recent.x_fc_thickness_range
continue
part_default = getattr(
rec.part_catalog_id, 'x_fc_default_thickness_range', None,
)
if part_default:
rec.thickness_range = part_default
# ---- Thickness range (existing) ----
if not rec.thickness_range:
done = False
if partner:
recent = self.env['sale.order.line'].search([
('x_fc_part_catalog_id', '=', part.id),
('order_id.partner_id', '=', partner.id),
('x_fc_thickness_range', '!=', False),
('x_fc_thickness_range', '!=', ''),
], order='create_date desc', limit=1)
if recent:
rec.thickness_range = recent.x_fc_thickness_range
done = True
if not done:
part_default = getattr(part, 'x_fc_default_thickness_range', None)
if part_default:
rec.thickness_range = part_default
# ---- Express bake_instructions (2026-05-26) ----
if not rec.bake_instructions:
done = False
if partner:
recent = self.env['sale.order.line'].search([
('x_fc_part_catalog_id', '=', part.id),
('order_id.partner_id', '=', partner.id),
('x_fc_bake_instructions', '!=', False),
('x_fc_bake_instructions', '!=', ''),
], order='create_date desc', limit=1)
if recent:
rec.bake_instructions = recent.x_fc_bake_instructions
done = True
if not done:
bake_default = getattr(part, 'default_bake_instructions', None)
if bake_default:
rec.bake_instructions = bake_default
# ---- Express line_description (Specification) ----
# Only seed if currently empty (don't clobber operator-typed text).
if not rec.line_description:
spec_default = getattr(part, 'default_specification_text', None)
if spec_default:
rec.line_description = spec_default
# ---- Express masking_enabled (always re-seed from part default) ----
# Boolean has no "empty" state; explicit reseed on every part-change
# matches the spec ("part default wins unless operator flips it after").
mask_default = getattr(part, 'default_masking_enabled', True)
rec.masking_enabled = mask_default
def action_open_part(self):
"""Open the linked fp.part.catalog form in a modal."""
self.ensure_one()
if not self.part_catalog_id:
return False
return {
'type': 'ir.actions.act_window',
'name': self.part_catalog_id.display_name,
'res_model': 'fp.part.catalog',
'view_mode': 'form',
'res_id': self.part_catalog_id.id,
'target': 'new',
}
def action_upload_drawing(self):
"""Attach a file (via context) to the line's part as a drawing.
Mirrors sale.order.line.action_upload_drawing — same behaviour,
same context keys (fp_drawing_file + fp_drawing_filename).
"""
self.ensure_one()
from odoo.exceptions import UserError
if not self.part_catalog_id:
raise UserError(_('Pick or create a part on this line first.'))
file_data = self.env.context.get('fp_drawing_file')
filename = self.env.context.get('fp_drawing_filename', 'drawing.pdf')
if not file_data:
raise UserError(_('No file data received.'))
att = self.env['ir.attachment'].sudo().create({
'name': filename,
'datas': file_data,
'res_model': 'fp.part.catalog',
'res_id': self.part_catalog_id.id,
})
self.part_catalog_id.sudo().write({
'drawing_attachment_ids': [(4, att.id)],
})
self.part_catalog_id.sudo().message_post(body=_(
'Drawing "%(name)s" uploaded by %(user)s from line %(seq)s on draft %(draft)s.'
) % {
'name': filename,
'user': self.env.user.display_name,
'seq': self.sequence or self.id,
'draft': self.wizard_id.name,
})
return {'type': 'ir.actions.client', 'tag': 'reload'}
def action_generate_serial(self):
"""Generate one auto-sequenced fp.serial and append to the M2M.