Merge branch 'feature/库存功能优化' into feature/库存优化_3
This commit is contained in:
@@ -452,25 +452,14 @@ class ProductionLot(models.Model):
|
|||||||
"""Return the next serial number to be attributed to the product."""
|
"""Return the next serial number to be attributed to the product."""
|
||||||
if product.tracking == "serial":
|
if product.tracking == "serial":
|
||||||
last_serial = self.env['stock.lot'].search(
|
last_serial = self.env['stock.lot'].search(
|
||||||
[('company_id', '=', company.id), ('product_id', '=', product.id)],
|
[('company_id', '=', company.id), ('product_id', '=', product.id), ('name', 'ilike', product.name)],
|
||||||
limit=1, order='name desc')
|
limit=1, order='name desc')
|
||||||
if last_serial:
|
move_line_id = self.env['stock.move.line'].sudo().search(
|
||||||
if product.categ_id.name == '刀具':
|
[('product_id', '=', product.id), ('lot_name', 'ilike', product.name)], limit=1, order='lot_name desc')
|
||||||
return self.env['stock.lot'].get_tool_generate_lot_names1(company, product)
|
if last_serial or move_line_id:
|
||||||
else:
|
return self.env['stock.lot'].generate_lot_names1(product.name, last_serial.name if (
|
||||||
# 对last_serial的name进行检测,如果不是以产品名称+数字的形式的就重新搜索
|
not move_line_id or
|
||||||
if product.name.split('[')[0] not in last_serial.name:
|
(last_serial and last_serial.name > move_line_id.lot_name)) else move_line_id.lot_name, 2)[1]
|
||||||
last_serial = self.env['stock.lot'].search(
|
|
||||||
[('company_id', '=', company.id), ('product_id', '=', product.id),
|
|
||||||
('name', 'ilike', product.name.split('[')[0])],
|
|
||||||
limit=1, order='name desc')
|
|
||||||
if not last_serial:
|
|
||||||
return "%s-%03d" % (product.name, 1)
|
|
||||||
return self.env['stock.lot'].generate_lot_names1(product.name, last_serial.name, 2)[1]
|
|
||||||
now = datetime.now().strftime("%Y%m%d")
|
|
||||||
if product.cutting_tool_model_id:
|
|
||||||
split_codes = product.cutting_tool_model_id.code.split('-')
|
|
||||||
return "%s-T-%s-%s-%03d" % (split_codes[0], now, product.specification_id.name, 1)
|
|
||||||
return "%s-%03d" % (product.name, 1)
|
return "%s-%03d" % (product.name, 1)
|
||||||
|
|
||||||
qr_code_image = fields.Binary(string='二维码', compute='_generate_qr_code')
|
qr_code_image = fields.Binary(string='二维码', compute='_generate_qr_code')
|
||||||
@@ -724,6 +713,34 @@ class StockPicking(models.Model):
|
|||||||
'draft', 'sent']:
|
'draft', 'sent']:
|
||||||
picking.state = 'waiting'
|
picking.state = 'waiting'
|
||||||
|
|
||||||
|
# def write(self, vals):
|
||||||
|
#
|
||||||
|
# old_state = None
|
||||||
|
# if 'state' in vals:
|
||||||
|
# old_state = self.state
|
||||||
|
# res = super(StockPicking, self).write(vals)
|
||||||
|
# if (self.picking_type_id.use_existing_lots is False and self.picking_type_id.use_create_lots is True and
|
||||||
|
# (('move_ids_without_package' in vals and self.state == 'assigned')
|
||||||
|
# or ('state' in vals and vals['state'] == 'assigned' and old_state not in ['assigned', 'done']))):
|
||||||
|
# if self.move_ids_without_package:
|
||||||
|
# for move_id in self.move_ids_without_package:
|
||||||
|
# move_id.action_show_details()
|
||||||
|
# return res
|
||||||
|
|
||||||
|
@api.constrains('state', 'move_ids_without_package')
|
||||||
|
def _check_move_ids_without_package(self):
|
||||||
|
"""
|
||||||
|
凡库存调拨单的【作业类型】=“收料入库、客供料入库”,且其产品行的【产品_库存_追溯】="按唯一序列号/按批次”的,当调拨单的【状态】=就绪时
|
||||||
|
自动生成预分配序列号
|
||||||
|
"""
|
||||||
|
for sp in self:
|
||||||
|
if (sp.picking_type_id.use_existing_lots is False and sp.picking_type_id.use_create_lots is True
|
||||||
|
and sp.state == 'assigned'):
|
||||||
|
if sp.move_ids_without_package:
|
||||||
|
for move_id in sp.move_ids_without_package:
|
||||||
|
if move_id.product_id.tracking in ['serial', 'lot'] and not move_id.move_line_nosuggest_ids:
|
||||||
|
move_id.action_show_details()
|
||||||
|
|
||||||
|
|
||||||
class ReStockMove(models.Model):
|
class ReStockMove(models.Model):
|
||||||
_inherit = 'stock.move'
|
_inherit = 'stock.move'
|
||||||
@@ -860,11 +877,12 @@ class ReStockMove(models.Model):
|
|||||||
self.next_serial = self._get_tool_next_serial(self.company_id, self.product_id, self.origin)
|
self.next_serial = self._get_tool_next_serial(self.company_id, self.product_id, self.origin)
|
||||||
else:
|
else:
|
||||||
self.next_serial = self.env['stock.lot']._get_next_serial(self.company_id, self.product_id)
|
self.next_serial = self.env['stock.lot']._get_next_serial(self.company_id, self.product_id)
|
||||||
if (self.picking_type_id.use_existing_lots is False
|
if (self.picking_type_id.use_existing_lots is False
|
||||||
and self.picking_type_id.use_create_lots is True and not self.move_line_nosuggest_ids):
|
and self.picking_type_id.use_create_lots is True and not self.move_line_nosuggest_ids):
|
||||||
self.action_assign_serial_show_details()
|
self.action_assign_serial_show_details()
|
||||||
elif self.product_id.tracking == "lot":
|
elif self.product_id.tracking == "lot":
|
||||||
self._put_tool_lot(self.company_id, self.product_id, self.origin)
|
if self.product_id.categ_id.name == '刀具':
|
||||||
|
self._put_tool_lot(self.company_id, self.product_id, self.origin)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'name': _('Detailed Operations'),
|
'name': _('Detailed Operations'),
|
||||||
@@ -889,23 +907,6 @@ class ReStockMove(models.Model):
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
def put_move_line(self):
|
|
||||||
"""
|
|
||||||
确认订单时,自动分配序列号
|
|
||||||
"""
|
|
||||||
if self.product_id.tracking == "serial":
|
|
||||||
if self.product_id.categ_id.name == '刀具':
|
|
||||||
self.next_serial = self._get_tool_next_serial(self.company_id, self.product_id, self.origin)
|
|
||||||
else:
|
|
||||||
self.next_serial = self.env['stock.lot']._get_next_serial(self.company_id, self.product_id)
|
|
||||||
self._generate_serial_numbers()
|
|
||||||
for item in self.move_line_nosuggest_ids:
|
|
||||||
if item.lot_name:
|
|
||||||
lot_name = item.lot_name
|
|
||||||
if item.product_id.categ_id.name == '坯料':
|
|
||||||
lot_name = lot_name.split('[', 1)[0]
|
|
||||||
item.lot_qr_code = self.compute_lot_qr_code(lot_name)
|
|
||||||
|
|
||||||
def _put_tool_lot(self, company, product, origin):
|
def _put_tool_lot(self, company, product, origin):
|
||||||
if product.tracking == "lot" and self.product_id.categ_id.name == '刀具':
|
if product.tracking == "lot" and self.product_id.categ_id.name == '刀具':
|
||||||
if not self.move_line_nosuggest_ids:
|
if not self.move_line_nosuggest_ids:
|
||||||
@@ -920,6 +921,8 @@ class ReStockMove(models.Model):
|
|||||||
lot_code = '%s-%03d' % (lot_code, int(move_line_ids.lot_name[-3:]) + 1)
|
lot_code = '%s-%03d' % (lot_code, int(move_line_ids.lot_name[-3:]) + 1)
|
||||||
lot_names = self.env['stock.lot'].generate_lot_names(lot_code, 1)
|
lot_names = self.env['stock.lot'].generate_lot_names(lot_code, 1)
|
||||||
move_lines_commands = self._generate_serial_move_line_commands_tool_lot(lot_names)
|
move_lines_commands = self._generate_serial_move_line_commands_tool_lot(lot_names)
|
||||||
|
for move_lines_command in move_lines_commands:
|
||||||
|
move_lines_command[2]['qty_done'] = self.product_uom_qty
|
||||||
self.write({'move_line_nosuggest_ids': move_lines_commands})
|
self.write({'move_line_nosuggest_ids': move_lines_commands})
|
||||||
for item in self.move_line_nosuggest_ids:
|
for item in self.move_line_nosuggest_ids:
|
||||||
if item.lot_name:
|
if item.lot_name:
|
||||||
@@ -947,10 +950,15 @@ class ReStockMove(models.Model):
|
|||||||
last_serial = self.env['stock.lot'].search(
|
last_serial = self.env['stock.lot'].search(
|
||||||
[('company_id', '=', company.id), ('product_id', '=', product.id), ('name', 'ilike', origin)],
|
[('company_id', '=', company.id), ('product_id', '=', product.id), ('name', 'ilike', origin)],
|
||||||
limit=1, order='id DESC')
|
limit=1, order='id DESC')
|
||||||
|
move_line_id = self.env['stock.move.line'].sudo().search(
|
||||||
|
[('product_id', '=', product.id), ('lot_name', 'ilike', origin)], limit=1, order='lot_name desc')
|
||||||
split_codes = product.cutting_tool_model_id.code.split('-')
|
split_codes = product.cutting_tool_model_id.code.split('-')
|
||||||
if last_serial:
|
if last_serial or move_line_id:
|
||||||
return "%s-T-%s-%s-%03d" % (
|
return "%s-T-%s-%s-%03d" % (
|
||||||
split_codes[0], origin, product.specification_id.name, int(last_serial.name[-3:]) + 1)
|
split_codes[0], origin, product.specification_id.name,
|
||||||
|
int(last_serial.name[-3:] if (not move_line_id or
|
||||||
|
(last_serial and last_serial.name > move_line_id.lot_name))
|
||||||
|
else move_line_id.lot_name[-3:]) + 1)
|
||||||
else:
|
else:
|
||||||
return "%s-T-%s-%s-%03d" % (split_codes[0], origin, product.specification_id.name, 1)
|
return "%s-T-%s-%s-%03d" % (split_codes[0], origin, product.specification_id.name, 1)
|
||||||
|
|
||||||
@@ -1046,6 +1054,13 @@ class ReStockMove(models.Model):
|
|||||||
subcontract_workorder_id = fields.Many2one('mrp.workorder', '外协工单组件', check_company=True,
|
subcontract_workorder_id = fields.Many2one('mrp.workorder', '外协工单组件', check_company=True,
|
||||||
index='btree_not_null')
|
index='btree_not_null')
|
||||||
|
|
||||||
|
def button_update_the_sequence_number(self):
|
||||||
|
"""
|
||||||
|
更新序列号 功能按钮
|
||||||
|
"""
|
||||||
|
self.move_line_nosuggest_ids.unlink()
|
||||||
|
return self.action_show_details()
|
||||||
|
|
||||||
|
|
||||||
class ReStockQuant(models.Model):
|
class ReStockQuant(models.Model):
|
||||||
_inherit = 'stock.quant'
|
_inherit = 'stock.quant'
|
||||||
|
|||||||
@@ -74,5 +74,30 @@
|
|||||||
<field name="view_ids" eval="[(5, 0, 0),
|
<field name="view_ids" eval="[(5, 0, 0),
|
||||||
(0, 0, {'view_mode': 'tree', 'view_id': ref('stock.vpicktree')})]"/>
|
(0, 0, {'view_mode': 'tree', 'view_id': ref('stock.vpicktree')})]"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<record id="sf_view_stock_move_operations" model="ir.ui.view">
|
||||||
|
<field name="name">sf.stock.move.operations.form</field>
|
||||||
|
<field name="model">stock.move</field>
|
||||||
|
<field name="inherit_id" ref="stock.view_stock_move_operations"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//form//field[@name='next_serial']" position="attributes">
|
||||||
|
<attribute name="invisible">True</attribute>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//form//field[@name='next_serial_count']" position="attributes">
|
||||||
|
<attribute name="invisible">True</attribute>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//form//button[@name='action_assign_serial_show_details']" position="after">
|
||||||
|
<button name="button_update_the_sequence_number" type="object" class="btn-link" data-hotkey="k" title="Assign Serial Numbers">
|
||||||
|
<span>更新序列号</span>
|
||||||
|
</button>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//form//button[@name='action_assign_serial_show_details']" position="attributes">
|
||||||
|
<attribute name="invisible">True</attribute>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//form//button[@name='action_clear_lines_show_details']" position="attributes">
|
||||||
|
<attribute name="invisible">True</attribute>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
</data>
|
</data>
|
||||||
</odoo>
|
</odoo>
|
||||||
@@ -401,12 +401,6 @@ class RePurchaseOrder(models.Model):
|
|||||||
def button_confirm(self):
|
def button_confirm(self):
|
||||||
result = super(RePurchaseOrder, self).button_confirm()
|
result = super(RePurchaseOrder, self).button_confirm()
|
||||||
for item in self:
|
for item in self:
|
||||||
# 确认订单时,自动分配序列号
|
|
||||||
if item.picking_ids:
|
|
||||||
for picking_id in item.picking_ids:
|
|
||||||
if picking_id.move_ids:
|
|
||||||
for move_id in picking_id.move_ids:
|
|
||||||
move_id.put_move_line()
|
|
||||||
for line in item.order_line:
|
for line in item.order_line:
|
||||||
if line.product_id.categ_type == '表面工艺':
|
if line.product_id.categ_type == '表面工艺':
|
||||||
if item.origin:
|
if item.origin:
|
||||||
|
|||||||
@@ -956,7 +956,7 @@ class SfStockPicking(models.Model):
|
|||||||
qc_ids = self.env['quality.check'].sudo().search(
|
qc_ids = self.env['quality.check'].sudo().search(
|
||||||
[('picking_id', 'in', sp_ids), ('quality_state', 'in', ['waiting', 'none'])])
|
[('picking_id', 'in', sp_ids), ('quality_state', 'in', ['waiting', 'none'])])
|
||||||
if qc_ids:
|
if qc_ids:
|
||||||
raise ValidationError(f'单据{[qc.picking_id.name for qc in qc_ids]}未完成质量检查,完成后再试。')
|
raise ValidationError(f'单据{list(set(qc.picking_id.name for qc in qc_ids))}未完成质量检查,完成后再试。')
|
||||||
for record in self:
|
for record in self:
|
||||||
if record.state != 'assigned':
|
if record.state != 'assigned':
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -79,6 +79,9 @@
|
|||||||
<xpath expr="//field[@name='lot_name']" position="after">
|
<xpath expr="//field[@name='lot_name']" position="after">
|
||||||
<field name="rfid"/>
|
<field name="rfid"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
<xpath expr="//field[@name='lot_name']" position="attributes">
|
||||||
|
<attribute name="readonly">True</attribute>
|
||||||
|
</xpath>
|
||||||
<xpath expr="//field[@name='product_uom_id']" position="after">
|
<xpath expr="//field[@name='product_uom_id']" position="after">
|
||||||
<field name="lot_qr_code" widget="image"/>
|
<field name="lot_qr_code" widget="image"/>
|
||||||
<button name="print_single_method" string="打印编码" type="object" class="oe_highlight"/>
|
<button name="print_single_method" string="打印编码" type="object" class="oe_highlight"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user