Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/优化制造功能
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import traceback
|
||||
from datetime import datetime
|
||||
import logging
|
||||
import requests
|
||||
@@ -53,11 +54,14 @@ class StatusChange(models.Model):
|
||||
if not ret.get('error'):
|
||||
logging.info('接口已经执行=============')
|
||||
else:
|
||||
logging.error('工厂加工同步订单状态失败 {}'.format(ret))
|
||||
raise UserError('工厂加工同步订单状态失败')
|
||||
traceback_error = traceback.format_exc()
|
||||
logging.error("bfm订单状态同步失败:%s request info %s" % traceback_error)
|
||||
logging.error('/api/get/state/get_order 请求失败{}'.format(ret))
|
||||
raise UserError('工厂加工同步订单状态到bfm失败')
|
||||
except UserError as e:
|
||||
logging.error('工厂加工同步订单状态失败 {}'.format(e))
|
||||
raise UserError('工厂加工同步订单状态失败')
|
||||
traceback_error = traceback.format_exc()
|
||||
logging.error("工厂加工同步订单状态失败:%s " % traceback_error)
|
||||
raise UserError(e)
|
||||
return res
|
||||
|
||||
def action_cancel(self):
|
||||
|
||||
@@ -45,7 +45,6 @@
|
||||
'sf_manufacturing/static/src/scss/kanban_change.scss',
|
||||
'sf_manufacturing/static/src/xml/button_show_on_tree.xml',
|
||||
'sf_manufacturing/static/src/js/workpiece_delivery_wizard_confirm.js',
|
||||
'sf_manufacturing/static/src/js/custom_barcode_handlers.js',
|
||||
]
|
||||
|
||||
},
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
|
||||
import logging
|
||||
import requests
|
||||
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
import logging
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ class AgvScheduling(models.Model):
|
||||
def web_search_read(self, domain=None, fields=None, offset=0, limit=None, order=None, count_limit=None):
|
||||
domain = domain or []
|
||||
new_domain = []
|
||||
for index, item in enumerate(domain):
|
||||
for item in domain:
|
||||
if isinstance(item, list):
|
||||
if item[0] == 'delivery_workpieces':
|
||||
new_domain.append('&')
|
||||
@@ -63,7 +63,7 @@ class AgvScheduling(models.Model):
|
||||
continue
|
||||
new_domain.append(item)
|
||||
|
||||
return super(AgvScheduling, self).web_search_read(new_domain, fields, limit=limit, offset=offset)
|
||||
return super(AgvScheduling, self).web_search_read(new_domain, fields, offset, limit, order, count_limit)
|
||||
|
||||
@api.depends('task_completion_time', 'task_delivery_time')
|
||||
def _compute_task_duration(self):
|
||||
|
||||
@@ -318,8 +318,10 @@ class MrpProduction(models.Model):
|
||||
# cnc程序获取
|
||||
def fetchCNC(self, production_names):
|
||||
cnc = self.env['mrp.production'].search([('id', '=', self.id)])
|
||||
quick_order = self.env['quick.easy.order'].search(
|
||||
[('name', '=', cnc.product_id.default_code.rsplit('-', 1)[0])])
|
||||
quick_order = False
|
||||
if cnc.product_id.default_code:
|
||||
quick_order = self.env['quick.easy.order'].search(
|
||||
[('name', '=', cnc.product_id.default_code.rsplit('-', 1)[0])])
|
||||
programme_way = False
|
||||
if cnc.manual_quotation is True:
|
||||
programme_way = 'manual operation'
|
||||
|
||||
@@ -222,7 +222,7 @@ class ResMrpWorkOrder(models.Model):
|
||||
material_width = fields.Float(string='宽')
|
||||
material_height = fields.Float(string='高')
|
||||
# 零件图号
|
||||
part_number = fields.Char(string='零件图号')
|
||||
part_number = fields.Char(related='production_id.part_number', string='零件图号')
|
||||
# 工序状态
|
||||
process_state = fields.Selection([
|
||||
('待装夹', '待装夹'),
|
||||
|
||||
@@ -267,6 +267,10 @@ class StockRule(models.Model):
|
||||
workorder_duration += workorder.duration_expected
|
||||
|
||||
sale_order = self.env['sale.order'].sudo().search([('name', '=', production.origin)])
|
||||
# 根据销售订单号查询快速订单
|
||||
quick_easy_order = self.env['quick.easy.order'].sudo().search([('sale_order_id', '=', sale_order.id)])
|
||||
production.write({'part_number': quick_easy_order.part_drawing_number,
|
||||
'part_drawing': quick_easy_order.machining_drawings})
|
||||
if sale_order:
|
||||
# sale_order.write({'schedule_status': 'to schedule'})
|
||||
self.env['sf.production.plan'].sudo().with_company(company_id).create({
|
||||
@@ -288,6 +292,7 @@ class StockRule(models.Model):
|
||||
# 为同一个product_id创建一个生产订单名称列表
|
||||
product_id_to_production_names[product_id] = [production.name for production in all_production]
|
||||
for production_item in productions:
|
||||
|
||||
production_programming = self.env['mrp.production'].search(
|
||||
[('product_id.id', '=', production_item.product_id.id),
|
||||
('origin', '=', production_item.origin)],
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<group col="1">
|
||||
<field name="production_ids" readonly="1" widget="many2many_tags" string="制造订单号"/>
|
||||
<field name="delivery_type" readonly="1"/>
|
||||
<field name="feeder_station_start_id" options="{'no_create': True}" required="1"/>
|
||||
<field name="feeder_station_start_id" string="当前接驳站" options="{'no_create': True}" required="1"/>
|
||||
<field name="workcenter_id" options="{'no_create': True}"/>
|
||||
</group>
|
||||
<footer>
|
||||
|
||||
@@ -6,6 +6,7 @@ from datetime import datetime
|
||||
from odoo import fields, models
|
||||
# from odoo.exceptions import ValidationError
|
||||
from odoo.exceptions import UserError
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -17,7 +18,7 @@ class Action_Plan_All_Wizard(models.TransientModel):
|
||||
# 选择生产线
|
||||
production_line_id = fields.Many2one('sf.production.line', string=u'生产线', required=True)
|
||||
date_planned_start = fields.Datetime(string='计划开始时间', index=True, copy=False,
|
||||
default=fields.Datetime.now)
|
||||
default=datetime.now() + timedelta(minutes=10))
|
||||
|
||||
# 接收传递过来的计划ID
|
||||
plan_ids = fields.Many2many('sf.production.plan', string=u'计划ID')
|
||||
|
||||
@@ -1505,29 +1505,26 @@ class FunctionalToolDismantle(models.Model):
|
||||
'handle_code_id': self.handle_lot_id.id,
|
||||
'handle_product_id': self.handle_product_id.id,
|
||||
'loading_task_source': '3',
|
||||
'use_tool_time': fields.Datetime.now() + timedelta(hours=4),
|
||||
'reason_for_applying': '刀具寿命到期'
|
||||
})
|
||||
action = self.env.ref('sf_tool_management.sf_functional_tool_assembly_form')
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'display_notification',
|
||||
'params': {
|
||||
'title': '组装单创建完成',
|
||||
'message': '请组装同名称的功能刀具',
|
||||
'type': 'info',
|
||||
'links': [{
|
||||
'label': '组装单',
|
||||
'url': f'#action={action.id}&id={assembly_id.id}&model=sf.functional.tool.assembly',
|
||||
}],
|
||||
},
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'sf.functional.tool.assembly',
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form',
|
||||
'res_id': assembly_id.id,
|
||||
# 'target': 'new'
|
||||
}
|
||||
# {
|
||||
# 'type': 'ir.actions.act_window',
|
||||
# 'res_model': 'sf.functional.tool.assembly',
|
||||
# 'view_type': 'form',
|
||||
# 'view_mode': 'form',
|
||||
# 'res_id': assembly_id.id,
|
||||
# 'type': 'ir.actions.client',
|
||||
# 'tag': 'display_notification',
|
||||
# 'params': {
|
||||
# 'title': '组装单创建完成',
|
||||
# 'message': '请组装同名称的功能刀具',
|
||||
# 'type': 'info'
|
||||
# }
|
||||
# }
|
||||
|
||||
# 'params': {
|
||||
|
||||
@@ -30,9 +30,23 @@ class jikimo_bom(models.Model):
|
||||
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('+')
|
||||
"""
|
||||
检查产品列表中的元素是否包含了所有指定的类型,并且每种类型至少出现一次。
|
||||
:return: 如果条件满足返回True,否则返回False
|
||||
"""
|
||||
if not self.product_ids:
|
||||
return False
|
||||
try:
|
||||
# 统计每个类型的出现次数
|
||||
type_counts = Counter(item.cutting_tool_material_id.name for item in self.product_ids)
|
||||
|
||||
# 检查是否每种类型的出现次数都大于0,并且类型的数量与选项字符串中的数量相等
|
||||
return all(count > 0 for count in type_counts.values()) and len(type_counts) == len(self.options.split('+'))
|
||||
except AttributeError:
|
||||
# 如果出现属性错误,说明产品列表中的元素可能缺少必要的属性
|
||||
return False
|
||||
# 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 列表
|
||||
@@ -47,9 +61,15 @@ class jikimo_bom(models.Model):
|
||||
return True
|
||||
else:
|
||||
raise UserError('每种物料最少要有一个')
|
||||
return True
|
||||
return super(jikimo_bom, self).write(vals)
|
||||
|
||||
def bom_product_domains(self, assembly_options):
|
||||
"""
|
||||
根据装配选项生成产品域列表
|
||||
:param assembly_options: 装配选项字符串,各选项以'+'分隔
|
||||
:return: 动态生成的产品搜索条件
|
||||
"""
|
||||
self.options = assembly_options
|
||||
cutting_tool_materials = self.env['sf.cutting.tool.material'].search(
|
||||
[('name', 'in', assembly_options.split('+'))])
|
||||
@@ -82,23 +102,22 @@ class jikimo_bom(models.Model):
|
||||
domains = domains + domain
|
||||
if index != 0:
|
||||
domains = ['|'] + domains
|
||||
# wqwqwe = self.env['product.product'].search(ddd)
|
||||
# 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):
|
||||
"""
|
||||
生成物料清单
|
||||
|
||||
根据装配选项生成物料清单,首先获取产品领域,然后搜索相关产品,并设置产品ID。
|
||||
|
||||
:param assembly_options: 组装方式
|
||||
:type assembly_options: 装配选项字符串,各选项以'+'分隔
|
||||
"""
|
||||
domains = self.bom_product_domains(assembly_options)
|
||||
products = self.env['product.product'].search(domains)
|
||||
if products:
|
||||
self.product_ids = [Command.set(products.ids)]
|
||||
# if option.name == '刀盘':
|
||||
# hilt = self.env['product.product'].search(
|
||||
# [('cutting_tool_blade_diameter', '=', self.tool_inventory_id.diameter),
|
||||
# ('cutting_tool_material_id', '=', option.id)])
|
||||
# self.product_ids = [Command.set(hilt.ids)]k
|
||||
|
||||
|
||||
class jikimo_bom_line(models.Model):
|
||||
|
||||
@@ -14,10 +14,7 @@ class ToolInventory(models.Model):
|
||||
self._bom_mainfest()
|
||||
return self.bom_mainfest()
|
||||
request.session['jikimo_bom_product'] = {'bom_id': int(self.jikimo_bom_ids)}
|
||||
# context = dict(self.env.context)
|
||||
# context.update({'jikimo_bom_product': self.jikimo_bom_ids.options})
|
||||
# if self.functional_cutting_tool_model_id.cutting_tool_type_ids:
|
||||
# context.update({'jikimo_bom_product_cutting_tool_type': self.functional_cutting_tool_model_id.cutting_tool_type_ids.ids})
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': '刀具组装清单',
|
||||
@@ -26,7 +23,6 @@ class ToolInventory(models.Model):
|
||||
'view_id': self.env.ref('sf_tool_management.view_jikimo_bom_form').id,
|
||||
'res_id': int(self.jikimo_bom_ids),
|
||||
'target': 'current', # Use 'new' to open in a new window/tab
|
||||
# {'jikimo_bom_product': self.jikimo_bom_ids.options}
|
||||
}
|
||||
|
||||
# 创建bom单
|
||||
|
||||
@@ -891,7 +891,8 @@
|
||||
<group attrs="{'invisible': [('dismantle_cause', 'not in', ['寿命到期报废','崩刀报废'])]}">
|
||||
<!-- <group col="3">-->
|
||||
<group>
|
||||
<field name="scrap_boolean" string="是否报废" readonly="0"/>
|
||||
<field name="scrap_boolean" string="是否报废"
|
||||
attrs="{'readonly': [('state' , '=', '已拆解')]}"/>
|
||||
</group>
|
||||
<!-- <group></group>-->
|
||||
<!-- <group>-->
|
||||
|
||||
@@ -15,7 +15,6 @@ class JikimoBomWizard(models.TransientModel):
|
||||
('刀柄+刀杆+刀片', '刀柄+刀杆+刀片'),
|
||||
('刀柄+刀盘+刀片', '刀柄+刀盘+刀片')
|
||||
], string='组装方式', required=True)
|
||||
# assembly_options_ids = fields.Many2many('sf.cutting.tool.material', string="组装方式")
|
||||
is_ok = fields.Boolean('确认上述信息正确无误。')
|
||||
|
||||
def submit(self):
|
||||
|
||||
Reference in New Issue
Block a user