changes
This commit is contained in:
@@ -37,6 +37,25 @@ _INPUT_SNAPSHOT_FIELDS = [
|
||||
]
|
||||
|
||||
|
||||
def _copy_snapshot_fields(source, fields):
|
||||
"""Copy ``fields`` from ``source`` record into a write-ready dict.
|
||||
|
||||
Many2one values must be unwrapped to their integer id — passing a
|
||||
recordset to ``create`` triggers psycopg2 ``can't adapt type X``
|
||||
because the SQL adapter doesn't know how to serialize a recordset.
|
||||
Scalar fields pass through untouched.
|
||||
"""
|
||||
out = {}
|
||||
for f in fields:
|
||||
field = source._fields[f]
|
||||
val = source[f]
|
||||
if field.type == 'many2one':
|
||||
out[f] = val.id if val else False
|
||||
else:
|
||||
out[f] = val
|
||||
return out
|
||||
|
||||
|
||||
class SimpleRecipeController(http.Controller):
|
||||
|
||||
# ------------------------------------------------------------------ load
|
||||
@@ -115,6 +134,18 @@ class SimpleRecipeController(http.Controller):
|
||||
),
|
||||
'measurements_badge_text': badge_text,
|
||||
'measurements_badge_class': badge_class,
|
||||
# Reference images attached to the step. Operators see
|
||||
# these in the Record Inputs dialog and the step quick-look
|
||||
# modal — recipe authors upload via the inline edit panel.
|
||||
'instruction_images': [
|
||||
{
|
||||
'id': att.id,
|
||||
'name': att.name or '',
|
||||
'mimetype': att.mimetype or '',
|
||||
'url': '/web/image/%s' % att.id,
|
||||
}
|
||||
for att in step.instruction_attachment_ids
|
||||
],
|
||||
'inputs': [
|
||||
{
|
||||
'id': i.id,
|
||||
@@ -457,8 +488,7 @@ class SimpleRecipeController(http.Controller):
|
||||
tpl = False
|
||||
if template_id:
|
||||
tpl = request.env['fp.step.template'].browse(template_id)
|
||||
for f in _SNAPSHOT_FIELDS:
|
||||
new_vals[f] = tpl[f]
|
||||
new_vals.update(_copy_snapshot_fields(tpl, _SNAPSHOT_FIELDS))
|
||||
if tpl.process_type_id:
|
||||
new_vals['process_type_id'] = tpl.process_type_id.id
|
||||
if tpl.tank_ids:
|
||||
@@ -598,8 +628,7 @@ class SimpleRecipeController(http.Controller):
|
||||
'sequence': src_node.sequence,
|
||||
'source_template_id': src_node.source_template_id.id or False,
|
||||
}
|
||||
for f in _SNAPSHOT_FIELDS:
|
||||
new_vals[f] = src_node[f]
|
||||
new_vals.update(_copy_snapshot_fields(src_node, _SNAPSHOT_FIELDS))
|
||||
if src_node.process_type_id:
|
||||
new_vals['process_type_id'] = src_node.process_type_id.id
|
||||
if src_node.tank_ids:
|
||||
@@ -690,6 +719,69 @@ class SimpleRecipeController(http.Controller):
|
||||
rec.unlink()
|
||||
return {'ok': True}
|
||||
|
||||
# ============================================================
|
||||
# Step instruction images — recipe authors attach reference photos
|
||||
# / screenshots / diagrams to a step from the Simple Editor's inline
|
||||
# edit panel. Operators see them on the Record Inputs dialog and
|
||||
# the step quick-look modal at runtime.
|
||||
# ============================================================
|
||||
|
||||
@http.route('/fp/simple_recipe/step/image/add', type='jsonrpc', auth='user')
|
||||
def step_image_add(self, node_id, filename, datas, mimetype=None):
|
||||
"""Upload a new instruction image to a recipe step.
|
||||
|
||||
Args:
|
||||
node_id: recipe node (fusion.plating.process.node) id
|
||||
filename: display name (with extension) for the attachment
|
||||
datas: base64-encoded image payload (no data: URL prefix)
|
||||
mimetype: optional override; falls back to image/png
|
||||
|
||||
Returns the new attachment metadata so the JS can append it to
|
||||
the step's gallery without a full reload.
|
||||
"""
|
||||
node = request.env['fusion.plating.process.node'].browse(int(node_id))
|
||||
node.check_access('write')
|
||||
att = request.env['ir.attachment'].create({
|
||||
'name': filename or 'image.png',
|
||||
'datas': datas,
|
||||
'res_model': 'fusion.plating.process.node',
|
||||
'res_id': node.id,
|
||||
'mimetype': mimetype or 'image/png',
|
||||
})
|
||||
node.instruction_attachment_ids = [(4, att.id)]
|
||||
return {
|
||||
'ok': True,
|
||||
'image': {
|
||||
'id': att.id,
|
||||
'name': att.name,
|
||||
'mimetype': att.mimetype or '',
|
||||
'url': '/web/image/%s' % att.id,
|
||||
},
|
||||
}
|
||||
|
||||
@http.route('/fp/simple_recipe/step/image/remove', type='jsonrpc', auth='user')
|
||||
def step_image_remove(self, node_id, attachment_id):
|
||||
"""Unlink an instruction image from a recipe step.
|
||||
|
||||
Soft-removes from the M2M; the underlying ir.attachment is
|
||||
deleted only if it isn't referenced by any other recipe node.
|
||||
"""
|
||||
node = request.env['fusion.plating.process.node'].browse(int(node_id))
|
||||
node.check_access('write')
|
||||
Att = request.env['ir.attachment']
|
||||
att = Att.browse(int(attachment_id))
|
||||
if not att.exists():
|
||||
return {'ok': False, 'error': 'not_found'}
|
||||
node.instruction_attachment_ids = [(3, att.id)]
|
||||
# Drop the attachment file too if no other node still links to it.
|
||||
Node = request.env['fusion.plating.process.node']
|
||||
still_used = Node.search_count([
|
||||
('instruction_attachment_ids', '=', att.id),
|
||||
])
|
||||
if not still_used:
|
||||
att.sudo().unlink()
|
||||
return {'ok': True}
|
||||
|
||||
@http.route('/fp/simple_recipe/step/reset_to_library', type='jsonrpc', auth='user')
|
||||
def step_reset_to_library(self, node_id):
|
||||
"""Re-sync the recipe step's input_ids + description from the linked
|
||||
|
||||
Reference in New Issue
Block a user