Skip to content

Conversation

@chga-odoo
Copy link
Contributor

@chga-odoo chga-odoo commented Jan 9, 2026

Product Conversion & Grading Management

Purpose

  • Take full control of inventory transitions. This module enables you to reclassify products and adjust grades seamlessly, ensuring total traceability for every Lot and Serial Number.
  • Effortless Downgrading: Instantly reassign a Lot from "Grade 1" to "Grade 2" during inventory adjustments while maintaining a comprehensive audit trail.
  • Product Adaptation: Pivot quickly by triggering a product change or reclassification immediately following a quality inspection.
  • Post-Production Flexibility: If output no longer meets its primary purpose, you can convert units into a secondary product—even after the production order is closed.

Task- 5362405

@robodoo
Copy link
Collaborator

robodoo commented Jan 9, 2026

Pull request status dashboard

@chga-odoo chga-odoo force-pushed the 19.0-convert-mo-chga branch 9 times, most recently from 80e5c01 to 78d3b09 Compare January 21, 2026 10:11
- Take full control of inventory transitions. This module enables you to
  reclassify products and adjust grades seamlessly, ensuring total traceability
  for every Lot and Serial Number.
- Effortless Downgrading: Instantly reassign a Lot from "Grade 1" to "Grade 2"
  during inventory adjustments while maintaining a comprehensive audit trail.
- Product Adaptation: Pivot quickly by triggering a product change or
  reclassification immediately following a quality inspection.
- Post-Production Flexibility: If output no longer meets its primary purpose,
  you can convert units into a secondary product—even after the production order
  is closed.

Task- 5362405
Add convert_mo in depends to add feature of conversion
Update knowledge article for conversion functionality

Task- 5362405
@chga-odoo chga-odoo force-pushed the 19.0-convert-mo-chga branch from 78d3b09 to f54790e Compare January 28, 2026 13:20
Copy link
Contributor

@pgu-odoo pgu-odoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chga-odoo here are a few remarks. But still in progress.

<field name="model_id" ref="x_model_convert_product_wizard"/>
<field name="state">code</field>
<field name="code"><![CDATA[
wizard = records[0]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why processing only 1 record? instead of having a for loop?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, It should be a loop. 😊

Comment on lines 18 to 19
'location_src_id': wizard.x_quant_id.location_id.id,
'location_dest_id': wizard.x_quant_id.location_id.id,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are you sure? source and destination locations are same?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes It is a requirement of task 😊

'location_dest_id': wizard.x_quant_id.location_id.id,
'origin': move.reference or move.picking_id.name if move else wizard.x_quant_id.display_name,
'user_id': env.user.id,
'bom_id': False,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'bom_id': False,

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is necessary because bom_id always NULL for conversion MO

lot_name = False
if wizard.x_keep_lot_sn:
lot_name = wizard.x_quant_id.lot_id.name
elif not wizard.x_keep_lot_sn and wizard.x_new_lot_sn:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
elif not wizard.x_keep_lot_sn and wizard.x_new_lot_sn:
elif wizard.x_new_lot_sn:

elif will run only if wizard.x_keep_lot_sn is false.

Comment on lines 52 to 77
if move:
mo.message_post(
body=(
'Manufacturing Order created from Convert action in this operation: '
'<a href="/odoo" data-oe-id="%i" data-oe-model="stock.picking" >%s</a>'
% (move.picking_id.id, move.picking_id.name)
),
body_is_html=True
)
move.picking_id.message_post(
body=(
f'<b>{move.product_id.display_name}</b> from location <b>{move.location_id.display_name}</b> converted into <b>{wizard.x_product_convert_into.display_name}</b> in Manufacturing Order '
'<a href="/odoo" data-oe-id="%i" data-oe-model="mrp.production" >%s</a>'
% (mo.id, mo.name)
),
body_is_html=True
)
else:
mo.message_post(
body=(
'Manufacturing Order created from Convert action in this Physical Inventory: '
'<a href="/odoo" data-oe-id="%i" data-oe-model="stock.quant" >%s</a>'
% (wizard.x_quant_id.id, wizard.x_quant_id.display_name)
),
body_is_html=True
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can avoid the duplicate code like -

model, rec_id, name, label = (
    ("stock.picking", move.picking_id.id, move.picking_id.name, "operation")
    if move
    else ("stock.quant", wizard.x_quant_id.id, wizard.x_quant_id.display_name, "Physical Inventory")
)

mo.message_post(
    body=(
        f'Manufacturing Order created from Convert action in this {label}: '
        '<a href="/odoo" data-oe-id="%i" data-oe-model="%s">%s</a>'
        % (rec_id, model, name)
    ),
    body_is_html=True,
)

if move:
    move.picking_id.message_post(
        body=(
            '<b>%s</b> from location <b>%s</b> converted into <b>%s</b> in Manufacturing Order '
            '<a href="/odoo" data-oe-id="%i" data-oe-model="mrp.production">%s</a>'
            % (
                move.product_id.display_name,
                move.location_id.display_name,
                wizard.x_product_convert_into.display_name,
                mo.id,
                mo.name,
            )
        ),
        body_is_html=True,
    )

<field name="ttype">boolean</field>
</record>
<record id="x_show_convert_visible_field_stock_picking" model="ir.model.fields">
<field name="name">x_show_convert_visible</field>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<field name="name">x_show_convert_visible</field>
<field name="name">x_show_convert</field>

or is can be x_can_convert also.

Comment on lines 49 to 51
for wizard in self:
move_line = wizard.x_move_id.move_line_ids[:1]
wizard['x_quant_id'] = move_line and self.env['stock.quant'].search([('product_id', '=', move_line.product_id.id), ('location_id', '=', move_line.location_id.id), ('lot_id', '=', move_line.lot_id.id)], limit=1) or False
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can also be written as to have safe checks -

for wizard in self:
    wizard.x_quant_id = False
    if wizard.x_move_id and wizard.x_move_id.move_line_ids:
        move_line = wizard.x_move_id.move_line_ids[:1]
        wizard['x_quant_id'] = self.env['stock.quant'].search([('product_id', '=', move_line.product_id.id), ('location_id', '=', move_line.location_id.id), ('lot_id', '=', move_line.lot_id.id)], limit=1)

<field name="arch" type="xml">
<xpath expr="//list/field[@name='forecast_availability']" position="after">
<button name="%(action_convert_product_wizard)d"
string="convert"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
string="convert"
string="Convert"

<list string="Convert Products" create="false" edit="false" delete="false">
<field name="display_name" string="Product Display Name"/>
<field name="is_storable" string="Is Storable ?"/>
<field name="tracking" string="Trace by"/>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<field name="tracking" string="Trace by"/>
<field name="tracking" string="Trace By"/>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants