Начальное наполнение
This commit is contained in:
parent
36c1cff7ca
commit
de1961184d
4
__init__.py
Normal file
4
__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import models
|
13
__manifest__.py
Normal file
13
__manifest__.py
Normal file
@ -0,0 +1,13 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
|
||||
{
|
||||
'name': 'Mrp Repairs',
|
||||
'version': '1.0',
|
||||
'category': 'Inventory/Inventory',
|
||||
'depends': ['repair', 'mrp'],
|
||||
'installable': True,
|
||||
'auto_install': True,
|
||||
'license': 'LGPL-3',
|
||||
}
|
26
i18n/mrp_repair.pot
Normal file
26
i18n/mrp_repair.pot
Normal file
@ -0,0 +1,26 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * mrp_repair
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 17.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-10-26 21:55+0000\n"
|
||||
"PO-Revision-Date: 2023-10-26 21:55+0000\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: mrp_repair
|
||||
#: model:ir.model,name:mrp_repair.model_repair_order
|
||||
msgid "Repair Order"
|
||||
msgstr ""
|
||||
|
||||
#. module: mrp_repair
|
||||
#: model:ir.model,name:mrp_repair.model_stock_move
|
||||
msgid "Stock Move"
|
||||
msgstr ""
|
28
i18n/ru.po
Normal file
28
i18n/ru.po
Normal file
@ -0,0 +1,28 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * mrp_repair
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 17.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-10-26 21:55+0000\n"
|
||||
"PO-Revision-Date: 2024-01-30 15:14+0400\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Russian (https://app.transifex.com/odoo/teams/41243/ru/)\n"
|
||||
"Language: ru\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n"
|
||||
|
||||
#. module: mrp_repair
|
||||
#: model:ir.model,name:mrp_repair.model_repair_order
|
||||
msgid "Repair Order"
|
||||
msgstr "Заказ на ремонт"
|
||||
|
||||
#. module: mrp_repair
|
||||
#: model:ir.model,name:mrp_repair.model_stock_move
|
||||
msgid "Stock Move"
|
||||
msgstr "Движение запасов"
|
4
models/__init__.py
Normal file
4
models/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import repair
|
55
models/repair.py
Normal file
55
models/repair.py
Normal file
@ -0,0 +1,55 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class Repair(models.Model):
|
||||
_inherit = 'repair.order'
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
orders = super().create(vals_list)
|
||||
orders.action_explode()
|
||||
return orders
|
||||
|
||||
def write(self, vals):
|
||||
res = super().write(vals)
|
||||
self.action_explode()
|
||||
return res
|
||||
|
||||
def action_explode(self):
|
||||
lines_to_unlink_ids = set()
|
||||
line_vals_list = []
|
||||
for op in self.move_ids:
|
||||
bom = self.env['mrp.bom'].sudo()._bom_find(op.product_id, company_id=op.company_id.id, bom_type='phantom')[op.product_id]
|
||||
if not bom:
|
||||
continue
|
||||
factor = op.product_uom._compute_quantity(op.product_uom_qty, bom.product_uom_id) / bom.product_qty
|
||||
_boms, lines = bom.sudo().explode(op.product_id, factor, picking_type=bom.picking_type_id)
|
||||
for bom_line, line_data in lines:
|
||||
if bom_line.product_id.type != 'service':
|
||||
line_vals_list.append(op._prepare_phantom_line_vals(bom_line, line_data['qty']))
|
||||
lines_to_unlink_ids.add(op.id)
|
||||
|
||||
self.env['stock.move'].browse(lines_to_unlink_ids).sudo().unlink()
|
||||
if line_vals_list:
|
||||
self.env['stock.move'].create(line_vals_list)
|
||||
|
||||
|
||||
class StockMove(models.Model):
|
||||
_inherit = 'stock.move'
|
||||
|
||||
def _prepare_phantom_line_vals(self, bom_line, qty):
|
||||
self.ensure_one()
|
||||
product = bom_line.product_id
|
||||
return {
|
||||
'name': self.name,
|
||||
'repair_id': self.repair_id.id,
|
||||
'repair_line_type': self.repair_line_type,
|
||||
'product_id': product.id,
|
||||
'price_unit': self.price_unit,
|
||||
'product_uom_qty': qty,
|
||||
'location_id': self.location_id.id,
|
||||
'location_dest_id': self.location_dest_id.id,
|
||||
'state': 'draft',
|
||||
}
|
4
tests/__init__.py
Normal file
4
tests/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import test_tracability
|
144
tests/test_tracability.py
Normal file
144
tests/test_tracability.py
Normal file
@ -0,0 +1,144 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.tests import Form, tagged
|
||||
from odoo.addons.mrp.tests.common import TestMrpCommon
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestRepairTraceability(TestMrpCommon):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.env.ref('base.group_user').write({'implied_ids': [(4, cls.env.ref('stock.group_production_lot').id)]})
|
||||
|
||||
def test_tracking_repair_production(self):
|
||||
"""
|
||||
Test that removing a tracked component with a repair does not block the flow of using that component in another
|
||||
bom
|
||||
"""
|
||||
picking_type = self.env['stock.picking.type'].search([('code', '=', 'mrp_operation')])[0]
|
||||
picking_type.use_auto_consume_components_lots = True
|
||||
product_to_repair = self.env['product.product'].create({
|
||||
'name': 'product first serial to act repair',
|
||||
'tracking': 'serial',
|
||||
})
|
||||
ptrepair_lot = self.env['stock.lot'].create({
|
||||
'name': 'A1',
|
||||
'product_id': product_to_repair.id,
|
||||
'company_id': self.env.user.company_id.id
|
||||
})
|
||||
product_to_remove = self.env['product.product'].create({
|
||||
'name': 'other first serial to remove with repair',
|
||||
'tracking': 'serial',
|
||||
})
|
||||
ptremove_lot = self.env['stock.lot'].create({
|
||||
'name': 'B2',
|
||||
'product_id': product_to_remove.id,
|
||||
'company_id': self.env.user.company_id.id
|
||||
})
|
||||
# Create a manufacturing order with product (with SN A1)
|
||||
mo_form = Form(self.env['mrp.production'])
|
||||
mo_form.product_id = product_to_repair
|
||||
with mo_form.move_raw_ids.new() as move:
|
||||
move.product_id = product_to_remove
|
||||
move.product_uom_qty = 1
|
||||
mo = mo_form.save()
|
||||
mo.action_confirm()
|
||||
# Set serial to A1
|
||||
mo.lot_producing_id = ptrepair_lot
|
||||
# Set component serial to B2
|
||||
mo.move_raw_ids.move_line_ids.lot_id = ptremove_lot
|
||||
mo.move_raw_ids.picked = True
|
||||
mo.button_mark_done()
|
||||
|
||||
with Form(self.env['repair.order']) as ro_form:
|
||||
ro_form.product_id = product_to_repair
|
||||
ro_form.lot_id = ptrepair_lot # Repair product Serial A1
|
||||
with ro_form.move_ids.new() as operation:
|
||||
operation.repair_line_type = 'remove'
|
||||
operation.product_id = product_to_remove
|
||||
ro = ro_form.save()
|
||||
ro.action_validate()
|
||||
ro.move_ids[0].lot_ids = ptremove_lot # Remove product Serial B2 from the product.
|
||||
ro.action_repair_start()
|
||||
ro.move_ids.picked = True
|
||||
ro.action_repair_end()
|
||||
|
||||
# Create a manufacturing order with product (with SN A2)
|
||||
mo2_form = Form(self.env['mrp.production'])
|
||||
mo2_form.product_id = product_to_repair
|
||||
with mo2_form.move_raw_ids.new() as move:
|
||||
move.product_id = product_to_remove
|
||||
move.product_uom_qty = 1
|
||||
mo2 = mo2_form.save()
|
||||
mo2.action_confirm()
|
||||
# Set serial to A2
|
||||
mo2.lot_producing_id = self.env['stock.lot'].create({
|
||||
'name': 'A2',
|
||||
'product_id': product_to_repair.id,
|
||||
'company_id': self.env.user.company_id.id
|
||||
})
|
||||
# Set component serial to B2 again, it is possible
|
||||
mo2.move_raw_ids.move_line_ids.lot_id = ptremove_lot
|
||||
mo2.move_raw_ids.picked = True
|
||||
# We are not forbidden to use that serial number, so nothing raised here
|
||||
mo2.button_mark_done()
|
||||
|
||||
def test_mo_with_used_sn_component(self):
|
||||
"""
|
||||
Suppose a tracked-by-usn component has been used to produce a product. Then, using a repair order,
|
||||
this component is removed from the product and returned as available stock. The user should be able to
|
||||
use the component in a new MO
|
||||
"""
|
||||
def produce_one(product, component):
|
||||
mo_form = Form(self.env['mrp.production'])
|
||||
mo_form.product_id = product
|
||||
with mo_form.move_raw_ids.new() as raw_line:
|
||||
raw_line.product_id = component
|
||||
raw_line.product_uom_qty = 1
|
||||
mo = mo_form.save()
|
||||
mo.action_confirm()
|
||||
mo.action_assign()
|
||||
mo.move_raw_ids.picked = True
|
||||
mo.button_mark_done()
|
||||
return mo
|
||||
|
||||
picking_type = self.env['stock.picking.type'].search([('code', '=', 'mrp_operation')])[0]
|
||||
picking_type.use_auto_consume_components_lots = True
|
||||
|
||||
stock_location = self.env.ref('stock.stock_location_stock')
|
||||
|
||||
finished, component = self.env['product.product'].create([{
|
||||
'name': 'Finished Product',
|
||||
'type': 'product',
|
||||
}, {
|
||||
'name': 'SN Componentt',
|
||||
'type': 'product',
|
||||
'tracking': 'serial',
|
||||
}])
|
||||
|
||||
sn_lot = self.env['stock.lot'].create({
|
||||
'product_id': component.id,
|
||||
'name': 'USN01',
|
||||
'company_id': self.env.company.id,
|
||||
})
|
||||
self.env['stock.quant']._update_available_quantity(component, stock_location, 1, lot_id=sn_lot)
|
||||
|
||||
mo = produce_one(finished, component)
|
||||
self.assertEqual(mo.state, 'done')
|
||||
self.assertEqual(mo.move_raw_ids.lot_ids, sn_lot)
|
||||
ro_form = Form(self.env['repair.order'])
|
||||
ro_form.product_id = finished
|
||||
with ro_form.move_ids.new() as ro_line:
|
||||
ro_line.repair_line_type = 'recycle'
|
||||
ro_line.product_id = component
|
||||
ro = ro_form.save()
|
||||
ro.action_validate()
|
||||
ro.move_ids[0].lot_ids = sn_lot
|
||||
ro.action_repair_start()
|
||||
ro.move_ids.picked = True
|
||||
ro.action_repair_end()
|
||||
mo = produce_one(finished, component)
|
||||
self.assertEqual(mo.state, 'done')
|
||||
self.assertEqual(mo.move_raw_ids.lot_ids, sn_lot)
|
Loading…
x
Reference in New Issue
Block a user