Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/优化制造功能
This commit is contained in:
@@ -668,7 +668,7 @@ class Manufacturing_Connect(http.Controller):
|
||||
logging.info('AGVDownProduct error:%s' % e)
|
||||
return json.JSONEncoder().encode(res)
|
||||
|
||||
@http.route('/AutoDeviceApi/AgvStationState', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
|
||||
@http.route('/AutoDeviceApi/AgvStationState', type='json', auth='public', methods=['GET', 'POST'], csrf=False,
|
||||
cors="*")
|
||||
def AGVStationState(self, **kw):
|
||||
"""
|
||||
|
||||
@@ -270,6 +270,7 @@ class ResMrpWorkOrder(models.Model):
|
||||
"""
|
||||
获取关联的制造订单下产线的agv任务
|
||||
"""
|
||||
self.ensure_one()
|
||||
workorder_ids = self.production_id.workorder_ids
|
||||
cnc_workorder = workorder_ids.filtered(
|
||||
lambda w: w.routing_type == 'CNC加工' and w.state == 'done' and w.processing_panel == self.processing_panel
|
||||
|
||||
@@ -1361,23 +1361,23 @@ class ResMrpWorkOrder(models.Model):
|
||||
return res
|
||||
|
||||
def button_delivery(self):
|
||||
production_ids = []
|
||||
workorder_ids = []
|
||||
# production_ids = []
|
||||
# workorder_ids = []
|
||||
delivery_type = '运送空料架'
|
||||
max_num = 4 # 最大配送数量
|
||||
feeder_station_start_id = False
|
||||
if len(self) > max_num:
|
||||
raise UserError('仅限于拆卸1-4个制造订单,请重新选择')
|
||||
for item in self:
|
||||
if item.state != 'ready':
|
||||
raise UserError('请选择状态为【就绪】的工单进行解除装夹')
|
||||
|
||||
production_ids.append(item.production_id.id)
|
||||
workorder_ids.append(item.id)
|
||||
if not feeder_station_start_id:
|
||||
down_product_agv_scheduling = self.get_down_product_agv_scheduling()
|
||||
if down_product_agv_scheduling:
|
||||
feeder_station_start_id = down_product_agv_scheduling.end_site_id.id
|
||||
# max_num = 4 # 最大配送数量
|
||||
# feeder_station_start_id = False
|
||||
# if len(self) > max_num:
|
||||
# raise UserError('仅限于拆卸1-4个制造订单,请重新选择')
|
||||
# for item in self:
|
||||
# if item.state != 'ready':
|
||||
# raise UserError('请选择状态为【就绪】的工单进行解除装夹')
|
||||
#
|
||||
# production_ids.append(item.production_id.id)
|
||||
# workorder_ids.append(item.id)
|
||||
# if not feeder_station_start_id:
|
||||
# down_product_agv_scheduling = item.get_down_product_agv_scheduling()
|
||||
# if down_product_agv_scheduling:
|
||||
# feeder_station_start_id = down_product_agv_scheduling.end_site_id.id
|
||||
return {
|
||||
'name': _('确认'),
|
||||
'type': 'ir.actions.act_window',
|
||||
@@ -1386,12 +1386,12 @@ class ResMrpWorkOrder(models.Model):
|
||||
'target': 'new',
|
||||
'context': {
|
||||
# 'default_delivery_ids': [(6, 0, delivery_ids)],
|
||||
'default_production_ids': [(6, 0, production_ids)],
|
||||
# 'default_production_ids': [(6, 0, production_ids)],
|
||||
'default_delivery_type': delivery_type,
|
||||
'default_workorder_ids': [(6, 0, workorder_ids)],
|
||||
# 'default_workorder_ids': [(6, 0, workorder_ids)],
|
||||
'default_workcenter_id': self.env.context.get('default_workcenter_id'),
|
||||
'default_confirm_button': '确认解除',
|
||||
'default_feeder_station_start_id': feeder_station_start_id,
|
||||
# 'default_feeder_station_start_id': feeder_station_start_id,
|
||||
}}
|
||||
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
<field name="workcenter_id" options="{'no_create': True}"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button string="确认配送" name="dispatch_confirm" type="object" class="oe_highlight o_wizard_confirm_button jikimo_button_confirm" attrs="{'invisible': [('confirm_button', '!=', '确认配送')]}"/>
|
||||
<button string="确认解除" name="dispatch_confirm" type="object" class="oe_highlight o_wizard_confirm_button jikimo_button_confirm" attrs="{'invisible': [('confirm_button', '!=', '确认解除')]}"/>
|
||||
<button string="确认配送" name="confirm" type="object" class="oe_highlight o_wizard_confirm_button jikimo_button_confirm" attrs="{'invisible': [('confirm_button', '!=', '确认配送')]}"/>
|
||||
<button string="确认解除" name="confirm" type="object" class="oe_highlight o_wizard_confirm_button jikimo_button_confirm" attrs="{'invisible': [('confirm_button', '!=', '确认解除')]}"/>
|
||||
<button string="取消" class="btn btn-secondary" special="cancel"/>
|
||||
</footer>
|
||||
</sheet>
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of YiZuo. See LICENSE file for full copyright and licensing details.
|
||||
import json
|
||||
import logging
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from datetime import datetime, date
|
||||
from odoo.exceptions import UserError
|
||||
from odoo import models, api, fields
|
||||
|
||||
|
||||
@@ -79,29 +78,18 @@ class WorkpieceDeliveryWizard(models.TransientModel):
|
||||
'tag': 'display_notification',
|
||||
'target': 'new',
|
||||
'params': {
|
||||
'message': '任务下发成功!AGV任务调度编号为【%s】' % scheduling['name'],
|
||||
'message': f'任务下发成功!AGV任务调度编号为【{scheduling["name"]}】',
|
||||
'type': 'success',
|
||||
'sticky': False,
|
||||
'next': {'type': 'ir.actions.act_window_close'},
|
||||
}
|
||||
}
|
||||
|
||||
def confirm(self):
|
||||
try:
|
||||
# if self.workorder_id:
|
||||
# self.workorder_id.workpiece_delivery_ids[0].agv_scheduling_id()
|
||||
# else:
|
||||
# is_not_production_line = 0
|
||||
# same_production_line_id = None
|
||||
# notsame_production_line_arr = []
|
||||
# for item in self.production_ids:
|
||||
# if same_production_line_id is None:
|
||||
# same_production_line_id = item.production_line_id.id
|
||||
# if item.production_line_id.id != same_production_line_id:
|
||||
# notsame_production_line_arr.append(item.name)
|
||||
# notsame_production_line_str = ','.join(map(str, notsame_production_line_arr))
|
||||
# if is_not_production_line >= 1:
|
||||
# raise UserError('制造订单号为%s的目的生产线不一致' % notsame_production_line_str)
|
||||
# else:
|
||||
if not self.workorder_ids:
|
||||
raise UserError('制造订单不能为空')
|
||||
|
||||
scheduling = self.env['sf.agv.scheduling'].add_scheduling(
|
||||
agv_start_site_name=self.feeder_station_start_id.name,
|
||||
agv_route_type=self.delivery_type,
|
||||
@@ -129,10 +117,21 @@ class WorkpieceDeliveryWizard(models.TransientModel):
|
||||
item.button_start()
|
||||
item.button_finish()
|
||||
|
||||
return scheduling.read()[0]
|
||||
# return scheduling.read()[0]
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'display_notification',
|
||||
'target': 'new',
|
||||
'params': {
|
||||
'message': f'任务下发成功!AGV任务调度编号为【{scheduling.name}】',
|
||||
'type': 'success',
|
||||
'sticky': False,
|
||||
'next': {'type': 'ir.actions.act_window_close'},
|
||||
}
|
||||
}
|
||||
except Exception as e:
|
||||
logging.info('%s任务下发失败:%s' % (self.delivery_type, e))
|
||||
raise UserError('%s任务下发失败:%s' % (self.delivery_type, e))
|
||||
logging.info('%s任务下发失败:%s', self.delivery_type, e)
|
||||
raise UserError(f'{self.delivery_type}任务下发失败:{e}') from e
|
||||
|
||||
# def recognize_production(self):
|
||||
# # production_ids = []
|
||||
@@ -185,7 +184,11 @@ class WorkpieceDeliveryWizard(models.TransientModel):
|
||||
# 判断是否是AGV接驳站名称
|
||||
agv_site = self.env['sf.agv.site'].search([('name', '=', barcode)])
|
||||
if agv_site:
|
||||
if not self.feeder_station_start_id:
|
||||
self.feeder_station_start_id = agv_site.id
|
||||
else:
|
||||
if self.feeder_station_start_id.id != agv_site.id:
|
||||
raise UserError('起点接驳站不匹配!')
|
||||
return
|
||||
delivery_type = self.env.context.get('default_delivery_type')
|
||||
if delivery_type == '上产线':
|
||||
@@ -205,16 +208,20 @@ class WorkpieceDeliveryWizard(models.TransientModel):
|
||||
if workorder:
|
||||
if (len(self.production_ids) > 0 and
|
||||
workorder.production_line_id.id != self.production_ids[0].production_line_id.id):
|
||||
raise UserError('该rfid对应的制造订单号为%s的目的生产线不一致' % workorder.production_id.name)
|
||||
raise UserError(f'该rfid对应的制造订单号为{workorder.production_id.name}的目的生产线不一致')
|
||||
|
||||
# 将对象添加到对应的同模型且是多对多类型里
|
||||
self.production_ids |= workorder.production_id
|
||||
self.workorder_ids |= workorder
|
||||
|
||||
if not self.feeder_station_start_id:
|
||||
down_product_agv_scheduling = self.get_down_product_agv_scheduling()
|
||||
if down_product_agv_scheduling:
|
||||
if not self.feeder_station_start_id:
|
||||
self.feeder_station_start_id = down_product_agv_scheduling.end_site_id.id
|
||||
else:
|
||||
if self.feeder_station_start_id.id != down_product_agv_scheduling.end_site_id.id:
|
||||
raise UserError(f'该rfid不在{self.feeder_station_start_id.name}接驳站内')
|
||||
|
||||
else:
|
||||
raise UserError('该rfid码对应的工单不存在')
|
||||
return
|
||||
|
||||
@@ -11,3 +11,4 @@ from . import stock
|
||||
from . import jikimo_bom
|
||||
from . import tool_inventory
|
||||
from . import functional_cutting_tool_model
|
||||
# from . import product_product
|
||||
@@ -3,4 +3,4 @@ from odoo import models, fields
|
||||
|
||||
class SyncFunctionalCuttingToolModel(models.Model):
|
||||
_inherit = 'sf.functional.cutting.tool.model'
|
||||
cutting_tool_type_ids = fields.Many2many('sf.cutting.tool.type', string='刀具物料类型')
|
||||
cutting_tool_type_ids = fields.Many2many('sf.cutting.tool.type', string='适用刀具物料类型', required=True)
|
||||
@@ -1,8 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from collections import Counter
|
||||
from xml import etree
|
||||
|
||||
from odoo import models, fields, api, Command
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.exceptions import UserError, AccessError
|
||||
from odoo.http import request
|
||||
|
||||
|
||||
@@ -28,6 +29,26 @@ class jikimo_bom(models.Model):
|
||||
result.append((bom.id, '功能刀具物料清单'))
|
||||
return result
|
||||
|
||||
def check_types_in_list(self):
|
||||
# 统计每个元素的类型
|
||||
type_counts = Counter(item.cutting_tool_material_id.name for item in self.product_ids)
|
||||
return all(count > 0 for count in type_counts.values()) and len(type_counts) == self.options.split('+')
|
||||
|
||||
def write(self, vals):
|
||||
# 在更新模型时记录旧的 Many2many ID 列表
|
||||
if 'product_ids' in vals:
|
||||
old_product_counter = Counter(self.product_ids.ids)
|
||||
super(jikimo_bom, self).write(vals)
|
||||
new_product_counter = Counter(self.product_ids.ids)
|
||||
delete_product_counter = old_product_counter - new_product_counter
|
||||
if delete_product_counter:
|
||||
# 删除操作
|
||||
if self.check_types_in_list():
|
||||
return True
|
||||
else:
|
||||
raise UserError('每种物料最少要有一个')
|
||||
return super(jikimo_bom, self).write(vals)
|
||||
|
||||
def bom_product_domains(self, assembly_options):
|
||||
self.options = assembly_options
|
||||
cutting_tool_materials = self.env['sf.cutting.tool.material'].search(
|
||||
@@ -65,6 +86,7 @@ class jikimo_bom(models.Model):
|
||||
# product = self.env['product.product'].search(domain)
|
||||
# if product:
|
||||
# products = products + product
|
||||
domains = domains + [('stock_move_count', '>', 0)]
|
||||
return domains
|
||||
|
||||
def generate_bill_materials(self, assembly_options):
|
||||
@@ -88,6 +110,16 @@ class jikimo_bom_line(models.Model):
|
||||
|
||||
class ProductProduct(models.Model):
|
||||
_inherit = 'product.product'
|
||||
_order = 'cutting_tool_material_id, cutting_tool_type_id'
|
||||
stock_move_count = fields.Integer(string='stock_move count', compute='_compute_stock_move_count', store=True)
|
||||
|
||||
@api.depends('stock_move_ids')
|
||||
def _compute_stock_move_count(self):
|
||||
for record in self:
|
||||
if record.stock_move_ids:
|
||||
record.stock_move_count = len(record.stock_move_ids)
|
||||
else:
|
||||
record.stock_move_count = 0
|
||||
|
||||
def search(self, args, offset=0, limit=None, order=None, count=False):
|
||||
# 你可以在这里修改 `args` 以调整搜索条件
|
||||
|
||||
@@ -5,10 +5,10 @@ from odoo.http import request
|
||||
class ToolInventory(models.Model):
|
||||
_inherit = 'sf.tool.inventory'
|
||||
_description = '功能刀具清单'
|
||||
knife_handle_model = fields.Selection([('BT30', 'BT30'), ('BT40', 'BT40'), ('BT50', 'BT50'), ('GSK30', 'GSK30'), ('GSK40', 'GSK40'), ('GSK50', 'GSK50')], string='使用刀柄型号')
|
||||
knife_handle_model = fields.Selection([('BT30', 'BT30'), ('BT40', 'BT40'), ('BT50', 'BT50'), ('GSK30', 'GSK30'), ('GSK40', 'GSK40'), ('GSK50', 'GSK50')], string='使用刀柄型号', required=True)
|
||||
jikimo_bom_ids = fields.One2many('jikimo.bom','tool_inventory_id', 'bom单')
|
||||
blade_length = fields.Float('刃长(mm)')
|
||||
def bom_mainfest(self):
|
||||
|
||||
jikimo_bom_ids = self.mapped('jikimo_bom_ids')
|
||||
if not jikimo_bom_ids:
|
||||
self._bom_mainfest()
|
||||
|
||||
@@ -35,11 +35,12 @@
|
||||
<field name="name"/>
|
||||
<!-- <field name="categ_id"/>-->
|
||||
<field name="cutting_tool_material_id"/>
|
||||
<field name="cutting_tool_type_id"/>
|
||||
|
||||
<field name="cutting_tool_model_id"/>
|
||||
<field name="specification_id"/>
|
||||
<field name="brand_id"/>
|
||||
<field name="qty_available"/>
|
||||
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<field name="model">sf.tool.inventory</field>
|
||||
<field name="inherit_id" ref="sf_base.view_tool_inventory_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='type']" position="before">
|
||||
<xpath expr="//field[@name='extension']" position="before">
|
||||
<field name="knife_handle_model" />
|
||||
<button name="bom_mainfest" string="bom清单" type="object" class="btn-link"
|
||||
icon="fa-refresh" />
|
||||
|
||||
Reference in New Issue
Block a user