Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/优化外协采购和出入库单(工艺退回调整)

This commit is contained in:
jinling.yang
2024-11-20 16:08:54 +08:00
15 changed files with 190 additions and 93 deletions

View File

@@ -22,7 +22,7 @@
<attribute name="name">confirm_to_supply_method</attribute>
</xpath>
<xpath expr="//header/button[@name='confirm_to_supply_method']" position="before">
<button name="action_confirm" string="供货方式确认" type="object" attrs="{'invisible': [('state', '!=', 'supply method')]}" confirm="您确定要确认供货方式吗?"/>
<button name="action_confirm" string="供货方式确认" type="object" attrs="{'invisible': [('state', '!=', 'supply method')]}" confirm="确认供货方式"/>
</xpath>
<xpath expr="//header/field[@name='state']" position="attributes">
<attribute name="statusbar_visible">draft,sent,supply method,sale</attribute>

View File

@@ -416,7 +416,8 @@ class EmbryoRedundancy(models.Model):
_name = "sf.embryo.redundancy"
name = fields.Char('名称', required=True)
long = fields.Float('长度', required=True)
width = fields.Float('宽度', required=True)
height = fields.Float('高度', required=True)
long = fields.Float('长度(mm)', required=True)
width = fields.Float('宽度(mm)', required=True)
height = fields.Float('高度(mm)', required=True)
code = fields.Char('编码', required=True)
active = fields.Boolean('有效', default=True)

View File

@@ -633,4 +633,26 @@
<field name="res_model">sf.machining.accuracy</field>
<field name="view_mode">tree</field>
</record>
#------------------坯料冗余量------------------
<record model="ir.ui.view" id="tree_sf_embryo_redundancy_view">
<field name="name">tree.sf.embryo.redundancy</field>
<field name="model">sf.embryo.redundancy</field>
<field name="arch" type="xml">
<tree string="坯料冗余量" create="0" edit="0" delete="0">
<field name="name"/>
<field name="code"/>
<field name="long"/>
<field name="width"/>
<field name="height"/>
</tree>
</field>
</record>
<record id="action_sf_embryo_redundancy" model="ir.actions.act_window">
<field name="name">坯料冗余量</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">sf.embryo.redundancy</field>
<field name="view_mode">tree</field>
</record>
</odoo>

View File

@@ -141,18 +141,25 @@
sequence="1"
action="action_sf_machine_brand"/>
<menuitem
id="menu_sf_embryo_redundancy"
parent="menu_sf_base"
name="坯料冗余"
sequence="2"
action="action_sf_embryo_redundancy"/>
<menuitem
id="menu_sf_machining_accuracy"
parent="menu_sf_base"
name="加工精度"
sequence="1"
sequence="3"
action="action_sf_machining_accuracy"/>
<menuitem
id="menu_sf_machine_control_system"
parent="menu_sf_base"
name="数控系统"
sequence="2"
sequence="4"
action="action_sf_machine_control_system"/>

View File

@@ -1,3 +1,4 @@
import logging
from odoo import models, fields, api, _
@@ -29,7 +30,14 @@ class StockRuleInherit(models.Model):
if supplier:
domain = rule._make_po_get_domain(procurement.company_id, procurement.values,
supplier.partner_id)
po = self.env['purchase.order'].sudo().search([dom for dom in domain], limit=1)
logging.info("domain=============: %s", domain)
po = self.env['purchase.order'].sudo().search([
('partner_id', '=', supplier.partner_id.id),
('company_id', '=', procurement.company_id.id), # 保证公司一致
('origin', '=', procurement.origin), # 根据来源匹配
('state', '=', 'draft') # 状态为草稿
], limit=1)
logging.info("po=: %s", po)
if po:
po.write({'purchase_type': 'consignment'})
break

View File

@@ -1264,6 +1264,7 @@ class Sf_Dashboard_Connect(http.Controller):
"""
获取
"""
logging.info("kw=============:%s" % kw)
res = {'status': 1, 'message': '成功', 'data': {}}
# 连接数据库
conn = psycopg2.connect(**db_config)

View File

@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import re
import json
import logging
import datetime
import requests
from odoo import api, fields, models, _
@@ -90,11 +91,18 @@ class SfMaintenanceEquipmentOEE(models.Model):
def get_running_datas(self):
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
url_time = base_url + '/api/RunningTimeDetail'
logging.info("base_url=============:%s" % base_url)
# 只有当原始 URL 使用 http 时才替换为 https
if base_url.startswith("http://"):
secure_base_url = base_url.replace("http://", "https://")
else:
secure_base_url = base_url
url_time = secure_base_url + '/api/RunningTimeDetail'
logging.info("url_time=============:%s" % url_time)
cnc_list_obj = self.env['maintenance.equipment'].sudo().search(
[('function_type', '!=', False), ('active', '=', True)])
machine_list = list(map(lambda x: x.code, cnc_list_obj))
# print('machine_list: %s' % machine_list)
logging.info("machine_list=============:%s" % machine_list)
data_time = {
"machine_list": str(machine_list)

View File

@@ -6,7 +6,8 @@ class ModelType(models.Model):
_description = '模型类型'
name = fields.Char('名称')
embryo_tolerance = fields.Integer('坯料容余')
# embryo_tolerance = fields.Char('坯料容余')
embryo_tolerance_id = fields.Many2one('sf.embryo.redundancy', string='坯料容余')
product_routing_tmpl_ids = fields.One2many('sf.product.model.type.routing.sort', 'product_model_type_id',
'成品工序模板(自动化产线加工')
embryo_routing_tmpl_ids = fields.One2many('sf.embryo.model.type.routing.sort', 'embryo_model_type_id',

View File

@@ -34,6 +34,28 @@ class MrpProduction(models.Model):
tool_state_remark = fields.Text(string='功能刀具状态备注(缺刀)', compute='_compute_tool_state_remark', store=True)
tool_state_remark2 = fields.Text(string='功能刀具状态备注(无效刀)', readonly=True)
@api.depends('procurement_group_id.mrp_production_ids.move_dest_ids.group_id.sale_id')
def _compute_deadline_of_delivery(self):
for production in self:
# 确保 procurement_group_id 和相关字段存在
if production.procurement_group_id:
# 获取相关的 sale_id
sale_order_id = production.procurement_group_id.mrp_production_ids.mapped(
'move_dest_ids.group_id.sale_id')
# 确保 sale_order_id 是有效的 ID 列表
if sale_order_id:
# 获取 sale.order 记录
sale_id = self.env['sale.order'].sudo().browse(sale_order_id.ids) # 使用 mapped 返回的 ID 列表
# 处理 sale_id
if sale_id:
# 假设我们只需要第一个 sale_id
production.deadline_of_delivery = sale_id[0].deadline_of_delivery if sale_id else False
else:
production.deadline_of_delivery = False
else:
production.deadline_of_delivery = False
def _compute_default_delivery_status(self):
try:
if self.state == 'cancel':
@@ -123,29 +145,6 @@ class MrpProduction(models.Model):
else:
return 0.0
@api.depends('procurement_group_id.mrp_production_ids.move_dest_ids.group_id.sale_id')
def _compute_deadline_of_delivery(self):
for production in self:
# 确保 procurement_group_id 和相关字段存在
if production.procurement_group_id:
# 获取相关的 sale_id
sale_order_id = production.procurement_group_id.mrp_production_ids.mapped(
'move_dest_ids.group_id.sale_id')
# 确保 sale_order_id 是有效的 ID 列表
if sale_order_id:
# 获取 sale.order 记录
sale_id = self.env['sale.order'].sudo().browse(sale_order_id.ids) # 使用 mapped 返回的 ID 列表
# 处理 sale_id
if sale_id:
# 假设我们只需要第一个 sale_id
production.deadline_of_delivery = sale_id[0].deadline_of_delivery if sale_id else False
else:
production.deadline_of_delivery = False
else:
production.deadline_of_delivery = False
@api.depends('workorder_ids.tool_state_remark')
def _compute_tool_state_remark(self):
for item in self:
@@ -984,54 +983,30 @@ class MrpProduction(models.Model):
self._reset_work_order_sequence()
return True
def production_process(self, pro_plan):
type_map = {'装夹预调': False, 'CNC加工': False, '解除装夹': False}
# 最后一次加工结束时间
last_time = pro_plan.date_planned_start
# 预置时间
works = self.workorder_ids
for index,work in enumerate(works):
count = type_map.get(work.routing_type)
date_planned_end = None
date_planned_start = None
if self.production_type=='自动化产线加工':
date_planned_start,date_planned_end,last_time = work.auto_production_process(last_time,count,type_map)
elif self.production_type=='':
date_planned_start,date_planned_end,last_time = work.manual_offline_process(last_time,index)
work.update_work_start_end(date_planned_start,date_planned_end)
# def
def process_range_time(self):
for production in self:
works = production.workorder_ids
pro_plan = self.env['sf.production.plan'].search([('production_id', '=', production.id)], limit=1)
if not pro_plan:
continue
type_map = {'装夹预调': False, 'CNC加工': False, '解除装夹': False}
# 最后一次加工结束时间
last_time = pro_plan.date_planned_start
# 预置时间
for work in works:
count = type_map.get(work.routing_type)
date_planned_end = None
date_planned_start = None
duration_expected = datetime.timedelta(minutes=work.duration_expected)
reserve_time = datetime.timedelta(minutes=work.reserved_duration)
if not count:
# 第一轮加工
if work.routing_type == '装夹预调':
date_planned_end = last_time - reserve_time
date_planned_start = date_planned_end - duration_expected
elif work.routing_type == 'CNC加工':
date_planned_start = last_time
date_planned_end = last_time + duration_expected
last_time = date_planned_end
else:
date_planned_start = last_time + reserve_time
date_planned_end = date_planned_start + duration_expected
last_time = date_planned_end
type_map.update({work.routing_type: True})
else:
date_planned_start = last_time + reserve_time
date_planned_end = date_planned_start + duration_expected
last_time = date_planned_end
work.leave_id.write({
'date_from': date_planned_start,
'date_to': date_planned_end,
})
# work.write({'date_planned_start': date_planned_start, 'date_planned_finished': date_planned_end})
# 设置一个较大的结束时间,防止在设置开始时间时,结束时间小于开始时间
work.date_planned_finished = datetime.datetime.today() + datetime.timedelta(days=100)
work.date_planned_start = date_planned_start
work.date_planned_finished = date_planned_end
routing_workcenter = self.env['mrp.routing.workcenter'].sudo().search(
[('name', '=', work.routing_type)])
work.write({'date_planned_start': date_planned_start, 'date_planned_finished': date_planned_end,
'duration_expected': routing_workcenter.time_cycle})
if production.production_type:
production.production_process(pro_plan)
# 修改标记已完成方法
def button_mark_done1(self):

View File

@@ -2032,3 +2032,55 @@ class CMMprogram(models.Model):
'program_create_date': datetime.strptime(item['program_create_date'], '%Y-%m-%d %H:%M:%S'),
}))
return cmm_program
def update_work_start_end(self,date_planned_start,date_planned_end):
self.leave_id.write({
'date_from': date_planned_start,
'date_to': date_planned_end,
})
self.date_planned_finished = datetime.datetime.today() + datetime.timedelta(days=100)
self.date_planned_start = date_planned_start
self.date_planned_finished = date_planned_end
routing_workcenter = self.env['mrp.routing.workcenter'].sudo().search(
[('name', '=', self.routing_type)])
self.write({'date_planned_start': date_planned_start, 'date_planned_finished': date_planned_end,
'duration_expected': routing_workcenter.time_cycle})
def auto_production_process(self, last_time, is_first, type_map):
date_planned_end = None
date_planned_start = None
duration_expected = datetime.timedelta(minutes=self.duration_expected)
reserve_time = datetime.timedelta(minutes=self.reserved_duration)
if is_first:
# 第一轮加工
if self.routing_type == '装夹预调':
date_planned_end = last_time - reserve_time
date_planned_start = date_planned_end - duration_expected
elif self.routing_type == 'CNC加工':
date_planned_start = last_time
date_planned_end = last_time + duration_expected
last_time = date_planned_end
else:
date_planned_start = last_time + reserve_time
date_planned_end = date_planned_start + duration_expected
last_time = date_planned_end
type_map.update({self.routing_type: True})
else:
date_planned_start = last_time + reserve_time
date_planned_end = date_planned_start + duration_expected
last_time = date_planned_end
return date_planned_start, date_planned_end, last_time
def manual_offline_process(self,last_time,is_first):
date_planned_end = None
date_planned_start = None
duration_expected = datetime.timedelta(minutes=self.duration_expected)
reserve_time = datetime.timedelta(minutes=self.reserved_duration)
if is_first:
date_planned_start = last_time
date_planned_end = last_time + duration_expected
else:
date_planned_start = last_time + reserve_time
date_planned_end = date_planned_start + duration_expected
return date_planned_start, date_planned_end,last_time

View File

@@ -852,9 +852,11 @@ class ResProductMo(models.Model):
attachment = self.attachment_create(item['model_name'], item['model_data'])
# 获取坯料冗余配置
if not item.get('embryo_redundancy'):
embryo_redundancy_id = self.env['sf.embryo.redundancy'].search([('name', '=', '粗坯料')], limit=1)
embryo_redundancy_id = model_type.embryo_tolerance_id
else:
embryo_redundancy_id = item.get('embryo_redundancy')
if not embryo_redundancy_id:
raise UserError('请先配置模型类型内的坯料冗余')
vals = {
'name': '%s-%s-%s' % ('P', order_id.name, i),
'model_long': item['model_long'] + embryo_redundancy_id.long,
@@ -938,11 +940,6 @@ class ResProductMo(models.Model):
# surface_technology = self.env['stock.route'].sudo().search([('name', '=', '表面工艺外协')])
# if surface_technology:
# no_bom_copy_product_id.route_ids |= surface_technology
# 获取坯料冗余配置
if not item.get('embryo_redundancy_id'):
embryo_redundancy_id = self.env['sf.embryo.redundancy'].search([('name', '=', '粗坯料')], limit=1)
else:
embryo_redundancy_id = item.get('embryo_redundancy_id')
no_bom_copy_product_id.product_tmpl_id.active = True
logging.info('no_bom_copy_product_id[is_manual_processing]:%s' % no_bom_copy_product_id.is_manual_processing)
materials_id = self.env['sf.production.materials'].search(
@@ -951,6 +948,13 @@ class ResProductMo(models.Model):
[('materials_no', '=', item['texture_type_code'])])
model_type = self.env['sf.model.type'].search([], limit=1)
supplier = self.env['mrp.bom'].get_supplier(materials_type_id)
# 获取坯料冗余配置
if not item.get('embryo_redundancy_id'):
embryo_redundancy_id = model_type.embryo_tolerance_id
else:
embryo_redundancy_id = item.get('embryo_redundancy_id')
if not embryo_redundancy_id:
raise UserError('请先配置模型类型内的坯料冗余')
logging.info('no_bom_copy_product_supplier-vals:%s' % supplier)
vals = {
'name': '%s-%s-%s [%s %s-%s * %s * %s]' % ('R',

View File

@@ -309,18 +309,21 @@ class StockRule(models.Model):
production_item.write({'programming_no': production_programming.programming_no,
'programming_state': '编程中'})
if not technology_design_values:
i = 0
if production_item.product_id.categ_id.type == '成品':
# 根据加工面板的面数及成品工序模板生成工序设计
i = 0
for k in (production_item.product_id.model_processing_panel.split(',')):
if production_item.production_type == '自动化产线加工':
model = 'sf.product.model.type.routing.sort'
product_routing_workcenter = self.env['sf.product.model.type.routing.sort'].search(
[('product_model_type_id', '=', production_item.product_id.product_model_type_id.id)],
order='sequence asc'
)
else:
model = 'sf.manual.product.model.type.routing.sort'
product_routing_workcenter = self.env[model].search(
[('product_model_type_id', '=', production_item.product_id.product_model_type_id.id)],
order='sequence asc'
)
product_routing_workcenter = self.env['sf.manual.product.model.type.routing.sort'].search(
[('manual_product_model_type_id', '=', production_item.product_id.product_model_type_id.id)],
order='sequence asc'
)
for route in product_routing_workcenter:
i += 1
technology_design_values.append(
@@ -935,6 +938,11 @@ class ReStockMove(models.Model):
move_lines_commands.append((0, 0, move_line_cmd))
qty_by_location[loc.id] += 1
return move_lines_commands
# def _prepare_procurement_origin(self):
# """修改采购来源"""
# self.ensure_one()
# return self.group_id and self.group_id.name or (self.origin or self.picking_id.name or "/")
class ReStockQuant(models.Model):

View File

@@ -31,7 +31,7 @@
<form string="模型类型">
<group>
<field name="name" required="1"/>
<field name="embryo_tolerance" required="1" string="坯料容余(mm)"/>
<field name="embryo_tolerance_id" required="1" string="坯料容余(mm)"/>
</group>
<group>
<field name='product_routing_tmpl_ids'>

View File

@@ -3199,6 +3199,7 @@ class EmbryoRedundancySync(models.Model):
embryo_redundancy.long = item['long']
embryo_redundancy.width = item['width']
embryo_redundancy.height = item['height']
embryo_redundancy.active = item['active']
else:
self.env['sf.embryo.redundancy'].sudo().create({
"name": item['name'],
@@ -3206,4 +3207,5 @@ class EmbryoRedundancySync(models.Model):
"long": item['long'],
"width": item['width'],
"height": item['height'],
"active": item['active'],
})

View File

@@ -93,7 +93,11 @@ class sf_production_plan(models.Model):
@api.model
def search_read(self, domain=None, fields=None, offset=0, limit=None, order=None):
"""
修改搜索方法,只有制造订单状态为待排程时才显示
"""
domain = domain or []
domain.append(('production_id.state', 'not in', ['draft', 'technology_to_confirmed']))
info = super(sf_production_plan, self).search_read(domain, fields, offset, limit, order)
return info
@@ -446,8 +450,12 @@ class MrpProductionInheritForPlan(models.Model):
def toggle_active(self):
# 调用父类方法切换 active 状态
res = super(MrpProductionInheritForPlan, self).toggle_active()
stage_active = self.filtered('active')
stage_inactive = self - stage_active
self.env['sf.production.plan'].search(
[('production_id', '=', self.id), '|', ('active', '=', False), ('active', '=', True)]).write(
{'active': self.active})
[('production_id', 'in', stage_active.ids)]).write(
{'active': True})
self.env['sf.production.plan'].search(
[('production_id', 'in', stage_inactive.ids)]).write(
{'active': False})
return res