Merge branch 'refs/heads/develop' into feature/delivery_status

# Conflicts:
#	sf_manufacturing/models/mrp_production.py
This commit is contained in:
liaodanlong
2024-11-20 15:23:07 +08:00
33 changed files with 1030 additions and 685 deletions

View File

@@ -10,7 +10,7 @@ def _data_install(cr, registry):
env.ref('jikimo_sale_multiple_supply_methods.product_template_purchase').product_variant_id.write({'active': False, 'is_bfm': True}) env.ref('jikimo_sale_multiple_supply_methods.product_template_purchase').product_variant_id.write({'active': False, 'is_bfm': True})
env.ref('jikimo_sale_multiple_supply_methods.product_template_manual_processing').product_variant_id.write({'active': False, 'single_manufacturing': True, 'is_bfm': True}) env.ref('jikimo_sale_multiple_supply_methods.product_template_manual_processing').product_variant_id.write({'active': False, 'single_manufacturing': True, 'is_bfm': True})
env.ref('jikimo_sale_multiple_supply_methods.product_template_default').product_variant_id.write({'active': False, 'is_bfm': True}) env.ref('jikimo_sale_multiple_supply_methods.product_template_default').product_variant_id.write({'active': False, 'is_bfm': True})
env.ref('jikimo_sale_multiple_supply_methods.product_template_raw_material_customer_provided').product_variant_id.write({'active': False}) env.ref('jikimo_sale_multiple_supply_methods.product_template_embryo_customer_provided').product_variant_id.write({'active': False})
env.ref('jikimo_sale_multiple_supply_methods.product_template_outsourcing').product_variant_id.write({'active': False, 'is_bfm': True}) env.ref('jikimo_sale_multiple_supply_methods.product_template_outsourcing').product_variant_id.write({'active': False, 'is_bfm': True})
env.ref('sf_dlm.product_embryo_sf_self_machining').product_tmpl_id.write({'categ_type': '坯料'}) env.ref('sf_dlm.product_embryo_sf_self_machining').product_tmpl_id.write({'categ_type': '坯料'})
env.ref('sf_dlm.product_template_sf').product_tmpl_id.write({'categ_type': '成品'}) env.ref('sf_dlm.product_template_sf').product_tmpl_id.write({'categ_type': '成品'})

View File

@@ -34,6 +34,9 @@ class JikimoSaleRoutePicking(Sf_Bf_Connect):
if kw.get('logistics_way'): if kw.get('logistics_way'):
order_id.logistics_way = kw['logistics_way'] order_id.logistics_way = kw['logistics_way']
for item in bfm_process_order_list: for item in bfm_process_order_list:
if item.get('embryo_redundancy_id'):
item['embryo_redundancy'] = request.env['sf.embryo.redundancy'].sudo().search([('code', '=', item['embryo_redundancy_id'])], limit=1)
item['embryo_redundancy_id'] = item['embryo_redundancy'].id
product = request.env['product.template'].sudo().product_create(product_id, item, order_id, product = request.env['product.template'].sudo().product_create(product_id, item, order_id,
kw['order_number'], i) kw['order_number'], i)
order_id.with_user(request.env.ref("base.user_admin")).sale_order_create_line(product, item) order_id.with_user(request.env.ref("base.user_admin")).sale_order_create_line(product, item)

View File

@@ -65,7 +65,7 @@
<field name="partner_id" eval="91"/> <field name="partner_id" eval="91"/>
</record> </record>
<record id="product_template_raw_material_customer_provided" model="product.template"> <record id="product_template_embryo_customer_provided" model="product.template">
<field name="name">坯料客供料模板</field> <field name="name">坯料客供料模板</field>
<field name="active" eval="False"/> <field name="active" eval="False"/>
<field name="categ_id" ref="sf_dlm.product_category_embryo_sf"/> <field name="categ_id" ref="sf_dlm.product_category_embryo_sf"/>

View File

@@ -8,7 +8,7 @@ class ProductTemplate(models.Model):
def product_create(self, product_id, item, order_id, order_number, i): def product_create(self, product_id, item, order_id, order_number, i):
product_id = super(ProductTemplate, self).product_create(product_id, item, order_id, order_number, i) product_id = super(ProductTemplate, self).product_create(product_id, item, order_id, order_number, i)
product_id.product_tmpl_id.is_customer_provided = item['is_incoming_material'] product_id.product_tmpl_id.is_customer_provided = True if item['embryo_redundancy_id'] else False
return product_id return product_id

View File

@@ -54,7 +54,10 @@ class SaleOrder(models.Model):
'model_width': product.width, 'model_width': product.width,
'model_height': product.height, 'model_height': product.height,
'price': product.list_price, 'price': product.list_price,
'embryo_redundancy_id': line.embryo_redundancy_id,
} }
# 获取成品名结尾-n的n
product_seria = int(product.name.split('-')[-1])
# 成品供货方式为采购则不生成bom # 成品供货方式为采购则不生成bom
if line.supply_method != 'purchase': if line.supply_method != 'purchase':
bom_data = self.env['mrp.bom'].with_user(self.env.ref("base.user_admin")).get_bom(product) bom_data = self.env['mrp.bom'].with_user(self.env.ref("base.user_admin")).get_bom(product)
@@ -64,14 +67,14 @@ class SaleOrder(models.Model):
bom.with_user(self.env.ref("base.user_admin")).bom_create_line_has(bom_data) bom.with_user(self.env.ref("base.user_admin")).bom_create_line_has(bom_data)
else: else:
# 当成品上带有客供料选项时,生成坯料时选择“客供料”路线 # 当成品上带有客供料选项时,生成坯料时选择“客供料”路线
if line.is_incoming_material: if line.embryo_redundancy_id:
# 将成品模板的内容复制到成品上 # 将成品模板的内容复制到成品上
customer_provided_embryo = self.env.ref('jikimo_sale_multiple_supply_methods.product_tempalte_raw_material_customer_provided').sudo() customer_provided_embryo = self.env.ref('jikimo_sale_multiple_supply_methods.product_template_embryo_customer_provided').sudo()
# 创建坯料客供料的批量不需要创建bom # 创建坯料客供料的批量不需要创建bom
material_customer_provided_embryo = self.env['product.template'].sudo().no_bom_product_create( material_customer_provided_embryo = self.env['product.template'].sudo().no_bom_product_create(
customer_provided_embryo.with_context(active_test=False).product_variant_id, customer_provided_embryo.with_context(active_test=False).product_variant_id,
item, item,
order_id, 'material_customer_provided', 0, product) order_id, 'material_customer_provided', product_seria, product)
# 成品配置bom # 成品配置bom
product_bom_material_customer_provided = self.env['mrp.bom'].with_user( product_bom_material_customer_provided = self.env['mrp.bom'].with_user(
self.env.ref("base.user_admin")).bom_create( self.env.ref("base.user_admin")).bom_create(
@@ -84,7 +87,7 @@ class SaleOrder(models.Model):
self_machining_embryo = self.env['product.template'].sudo().no_bom_product_create( self_machining_embryo = self.env['product.template'].sudo().no_bom_product_create(
self_machining_id, self_machining_id,
item, item,
order_id, 'self_machining', 0, product) order_id, 'self_machining', product_seria, product)
# 创建坯料的bom # 创建坯料的bom
self_machining_bom = self.env['mrp.bom'].with_user( self_machining_bom = self.env['mrp.bom'].with_user(
self.env.ref("base.user_admin")).bom_create( self.env.ref("base.user_admin")).bom_create(
@@ -108,7 +111,7 @@ class SaleOrder(models.Model):
item, item,
order_id, order_id,
'subcontract', 'subcontract',
0, product) product_seria, product)
if outsource_embryo == -3: if outsource_embryo == -3:
raise UserError('该订单模型的材料型号暂未设置获取方式和供应商,请先配置再进行分配') raise UserError('该订单模型的材料型号暂未设置获取方式和供应商,请先配置再进行分配')
# 创建坯料的bom # 创建坯料的bom
@@ -130,7 +133,7 @@ class SaleOrder(models.Model):
purchase_embryo = self.env['product.template'].sudo().no_bom_product_create(purchase_id, purchase_embryo = self.env['product.template'].sudo().no_bom_product_create(purchase_id,
item, item,
order_id, order_id,
'purchase', 0, 'purchase', product_seria,
product) product)
if purchase_embryo == -3: if purchase_embryo == -3:
raise UserError('该订单模型的材料型号暂未设置获取方式和供应商,请先配置再进行分配') raise UserError('该订单模型的材料型号暂未设置获取方式和供应商,请先配置再进行分配')

View File

@@ -22,7 +22,7 @@
<attribute name="name">confirm_to_supply_method</attribute> <attribute name="name">confirm_to_supply_method</attribute>
</xpath> </xpath>
<xpath expr="//header/button[@name='confirm_to_supply_method']" position="before"> <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>
<xpath expr="//header/field[@name='state']" position="attributes"> <xpath expr="//header/field[@name='state']" position="attributes">
<attribute name="statusbar_visible">draft,sent,supply method,sale</attribute> <attribute name="statusbar_visible">draft,sent,supply method,sale</attribute>
@@ -59,6 +59,7 @@
<record id="sale.action_quotations_with_onboarding" model="ir.actions.act_window"> <record id="sale.action_quotations_with_onboarding" model="ir.actions.act_window">
<field name="search_view_id" ref="jikimo_sale_order_view_search_inherit_quotation_supply_method"/> <field name="search_view_id" ref="jikimo_sale_order_view_search_inherit_quotation_supply_method"/>
<field name="context">{'search_default_draft': 1}</field>
</record> </record>
<record id="action_quotations_supply_method" model="ir.actions.act_window"> <record id="action_quotations_supply_method" model="ir.actions.act_window">

View File

@@ -410,3 +410,14 @@ class ReSaleOrder(models.Model):
person_of_delivery = fields.Char('收货人') person_of_delivery = fields.Char('收货人')
telephone_of_delivery = fields.Char('电话号码') telephone_of_delivery = fields.Char('电话号码')
address_of_delivery = fields.Char('联系地址') address_of_delivery = fields.Char('联系地址')
class EmbryoRedundancy(models.Model):
_name = "sf.embryo.redundancy"
name = fields.Char('名称', 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

@@ -158,6 +158,8 @@ class MrsProductionProcessParameter(models.Model):
for parameter in self: for parameter in self:
if parameter.process_id: if parameter.process_id:
name = parameter.process_id.name + '-' + parameter.name name = parameter.process_id.name + '-' + parameter.name
else:
name = parameter.name
result.append((parameter.id, name)) result.append((parameter.id, name))
return result return result

View File

@@ -251,3 +251,6 @@ access_sf_cutting_tool_type_group_plan_dispatch,sf_cutting_tool_type_group_plan_
access_sf_machining_accuracy,sf_machining_accuracy,model_sf_machining_accuracy,base.group_user,1,0,0,0 access_sf_machining_accuracy,sf_machining_accuracy,model_sf_machining_accuracy,base.group_user,1,0,0,0
access_sf_machining_accuracy_admin,sf_machining_accuracy_admin,model_sf_machining_accuracy,base.group_system,1,0,0,0 access_sf_machining_accuracy_admin,sf_machining_accuracy_admin,model_sf_machining_accuracy,base.group_system,1,0,0,0
access_sf_embryo_redundancy,sf_embryo_redundancy,model_sf_embryo_redundancy,base.group_user,1,0,0,0
access_sf_embryo_redundancy_admin,sf_embryo_redundancy_admin,model_sf_embryo_redundancy,base.group_system,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
251
252
253
254
255
256

View File

@@ -633,4 +633,26 @@
<field name="res_model">sf.machining.accuracy</field> <field name="res_model">sf.machining.accuracy</field>
<field name="view_mode">tree</field> <field name="view_mode">tree</field>
</record> </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> </odoo>

View File

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

View File

@@ -10,7 +10,7 @@
""", """,
'category': 'sf', 'category': 'sf',
'website': 'https://www.sf.jikimo.com', 'website': 'https://www.sf.jikimo.com',
'depends': ['sf_base', 'sf_maintenance', 'web_widget_model_viewer', 'sf_warehouse', 'jikimo_attachment_viewer'], 'depends': ['sf_base', 'sf_maintenance', 'web_widget_model_viewer', 'sf_warehouse','jikimo_attachment_viewer', 'jikimo_sale_multiple_supply_methods'],
'data': [ 'data': [
'data/cron_data.xml', 'data/cron_data.xml',
'data/stock_data.xml', 'data/stock_data.xml',
@@ -23,6 +23,7 @@
'wizard/rework_wizard_views.xml', 'wizard/rework_wizard_views.xml',
'wizard/production_wizard_views.xml', 'wizard/production_wizard_views.xml',
'wizard/production_technology_wizard_views.xml', 'wizard/production_technology_wizard_views.xml',
'wizard/production_technology_re_adjust_wizard_views.xml',
'views/mrp_views_menus.xml', 'views/mrp_views_menus.xml',
'views/agv_scheduling_views.xml', 'views/agv_scheduling_views.xml',
'views/stock_lot_views.xml', 'views/stock_lot_views.xml',

View File

@@ -6,7 +6,8 @@ class ModelType(models.Model):
_description = '模型类型' _description = '模型类型'
name = fields.Char('名称') 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', 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', embryo_routing_tmpl_ids = fields.One2many('sf.embryo.model.type.routing.sort', 'embryo_model_type_id',

View File

@@ -306,16 +306,17 @@ class MrpProduction(models.Model):
precision_rounding=move.product_uom.rounding or move.product_id.uom_id.rounding) precision_rounding=move.product_uom.rounding or move.product_id.uom_id.rounding)
for move in production.move_raw_ids if move.product_id): for move in production.move_raw_ids if move.product_id):
production.state = 'progress' production.state = 'progress'
# 新添加的状态逻辑 # 新添加的状态逻辑
if ( if (
production.state == 'to_close' or production.state == 'progress') and production.schedule_state == '未排': production.state == 'to_close' or production.state == 'progress') and production.schedule_state == '未排':
if not production.workorder_ids:
production.state = 'technology_to_confirmed'
else:
production.state = 'confirmed' production.state = 'confirmed'
elif production.state == 'pending_cam' and production.schedule_state == '未排': elif production.state == 'pending_cam' and production.schedule_state == '未排':
production.state = 'confirmed' production.state = 'confirmed'
elif production.state == 'to_close' and production.schedule_state == '已排': elif production.state == 'to_close' and production.schedule_state == '已排':
production.state = 'pending_cam' production.state = 'pending_cam'
if production.state == 'progress': if production.state == 'progress':
if all(wo_state not in ('progress', 'done', 'rework', 'scrap') for wo_state in if all(wo_state not in ('progress', 'done', 'rework', 'scrap') for wo_state in
production.workorder_ids.mapped('state')): production.workorder_ids.mapped('state')):
@@ -344,11 +345,44 @@ class MrpProduction(models.Model):
if production.tool_state == '2': if production.tool_state == '2':
production.state = 'rework' production.state = 'rework'
# 退回调整
def technology_back_adjust(self):
process_parameters = []
domain = [('state', '=', 'confirmed'), ('origin', '=', self.origin)]
if self.production_type == '自动化产线加工':
cloud_programming = self._cron_get_programming_state()
if cloud_programming['send_state'] == 'sending':
raise UserError(_("编程文件正在下发中,请稍后重试"))
domain += [('programming_no', '=', self.programming_no)]
# 带排程的制造订单
production_confirmed = self.env['mrp.production'].search(domain)
for special in production_confirmed.technology_design_ids:
if special.process_parameters_id:
product_production_process = self.env['product.template'].search(
[('server_product_process_parameters_id', '=', special.process_parameters_id.id)])
if not product_production_process:
if special.process_parameters_id not in process_parameters:
process_parameters.append(special.process_parameters_id.display_name)
if process_parameters:
raise UserError(_("【工艺设计】-【参数】为%s的在【产品】中不存在,请先创建", ", ".join(process_parameters)))
if production_confirmed:
return {
'name': _('退回调整'),
'type': 'ir.actions.act_window',
'view_mode': 'form',
'res_model': 'sf.production.technology.re_adjust.wizard',
'target': 'new',
'context': {
'default_production_id': self.id,
'default_origin': self.origin,
}}
# 工艺确认 # 工艺确认
def technology_confirm(self): def technology_confirm(self):
process_parameters = [] process_parameters = []
account_moves = []
special_design = self.technology_design_ids.filtered( special_design = self.technology_design_ids.filtered(
lambda a: a.routing_tag == 'special' and a.process_parameters_id is not False) lambda a: a.routing_tag == 'special' and a.is_auto is False)
for special in special_design: for special in special_design:
if special.process_parameters_id: if special.process_parameters_id:
product_production_process = self.env['product.template'].search( product_production_process = self.env['product.template'].search(
@@ -356,6 +390,13 @@ class MrpProduction(models.Model):
if not product_production_process: if not product_production_process:
if special.process_parameters_id not in process_parameters: if special.process_parameters_id not in process_parameters:
process_parameters.append(special.process_parameters_id.display_name) process_parameters.append(special.process_parameters_id.display_name)
purchase = self.env['purchase.order'].search([('origin', '=', special.production_id.name)])
account = self.env['account.move'].search([('id', 'in', purchase.invoice_ids)])
if account.state not in ['cancel', False]:
if purchase.name not in account_moves:
account_moves.append(purchase.name)
if account_moves:
raise UserError(_("请联系工厂生产经理对采购订单为%s生成的账单进行取消", ", ".join(account_moves)))
if process_parameters: if process_parameters:
raise UserError(_("【工艺设计】-【参数】为%s的在【产品】中不存在,请先创建", ", ".join(process_parameters))) raise UserError(_("【工艺设计】-【参数】为%s的在【产品】中不存在,请先创建", ", ".join(process_parameters)))
# 判断同一个加工面的标准工序的顺序是否依次排序 # 判断同一个加工面的标准工序的顺序是否依次排序
@@ -368,8 +409,8 @@ class MrpProduction(models.Model):
next_index = index + 1 next_index = index + 1
next_design = technology_design[next_index] next_design = technology_design[next_index]
next_design_routing_type = next_design.route_id.routing_type next_design_routing_type = next_design.route_id.routing_type
logging.info('当前工序和加工面: %s-%s' % (design.route_id.name, design.panel)) # logging.info('当前工序和加工面: %s-%s' % (design.route_id.name, design.panel))
logging.info('下一个工序和加工面: %s-%s' % (next_design.route_id.name, next_design.panel)) # logging.info('下一个工序和加工面: %s-%s' % (next_design.route_id.name, next_design.panel))
if design.panel is not False: if design.panel is not False:
if design.panel != next_design.panel: if design.panel != next_design.panel:
if index == 0: if index == 0:
@@ -636,19 +677,13 @@ class MrpProduction(models.Model):
}] }]
if production.product_id.categ_id.type == '成品': if production.product_id.categ_id.type == '成品':
# # 根据工序设计生成工单 # # 根据工序设计生成工单
for route in item.technology_design_ids: for route in production.technology_design_ids:
if route.route_id.routing_type not in ['表面工艺']: if route.route_id.routing_type not in ['表面工艺']:
workorders_values.append( workorders_values.append(
self.env['mrp.workorder'].json_workorder_str(production, route)) self.env['mrp.workorder'].json_workorder_str(production, route))
else: else:
product_production_process = self.env['product.template'].search( product_production_process = self.env['product.template'].search(
[('server_product_process_parameters_id', '=', route.process_parameters_id.id)]) [('server_product_process_parameters_id', '=', route.process_parameters_id.id)])
# if product_production_process:
# route_production_process = self.env[
# 'mrp.routing.workcenter'].search(
# [('surface_technics_id', '=', p.id),
# ('id', 'in', route_workcenter_arr)])
# if route_production_process:
workorders_values.append( workorders_values.append(
self.env[ self.env[
'mrp.workorder']._json_workorder_surface_process_str( 'mrp.workorder']._json_workorder_surface_process_str(
@@ -662,54 +697,60 @@ class MrpProduction(models.Model):
workorders_values.append( workorders_values.append(
self.env['mrp.workorder'].json_workorder_str('', production, route_embryo)) self.env['mrp.workorder'].json_workorder_str('', production, route_embryo))
production.workorder_ids = workorders_values production.workorder_ids = workorders_values
process_parameter_workorder = self.env['mrp.workorder'].search(
[('surface_technics_parameters_id', '!=', False), ('production_id', '=', production.id),
('is_subcontract', '=', True)])
if process_parameter_workorder:
is_pick = False
consecutive_workorders = []
m = 0
sorted_workorders = sorted(process_parameter_workorder, key=lambda w: w.id)
for i in range(len(sorted_workorders) - 1):
if m == 0:
is_pick = False
if sorted_workorders[i].supplier_id.id == sorted_workorders[i + 1].supplier_id.id and \
sorted_workorders[i].is_subcontract == sorted_workorders[i + 1].is_subcontract and \
sorted_workorders[i].id == sorted_workorders[i + 1].id - 1:
if sorted_workorders[i] not in consecutive_workorders:
consecutive_workorders.append(sorted_workorders[i])
consecutive_workorders.append(sorted_workorders[i + 1])
m += 1
continue
else:
if m == len(consecutive_workorders) - 1 and m != 0:
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders,
production)
if sorted_workorders[i] in consecutive_workorders:
is_pick = True
consecutive_workorders = []
m = 0
# 当前面的连续工序生成对应的外协出入库单再生成当前工序的外协出入库单
if is_pick is False:
self.env['stock.picking'].create_outcontract_picking(sorted_workorders[i],
production)
if m == len(consecutive_workorders) - 1 and m != 0:
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders,
production)
if sorted_workorders[i] in consecutive_workorders:
is_pick = True
consecutive_workorders = []
m = 0
if m == len(consecutive_workorders) - 1 and m != 0:
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production)
if is_pick is False and m == 0:
if len(sorted_workorders) == 1:
self.env['stock.picking'].create_outcontract_picking(sorted_workorders, production)
else:
self.env['stock.picking'].create_outcontract_picking(sorted_workorders[i], production)
for workorder in production.workorder_ids: for workorder in production.workorder_ids:
workorder.duration_expected = workorder._get_duration_expected() workorder.duration_expected = workorder._get_duration_expected()
# 外协出入库单处理
def get_subcontract_pick_purchase(self):
production_all = self.sorted(lambda x: x.id)
product_id_to_production_names = {}
grouped_product_ids = {k: list(g) for k, g in
groupby(production_all, key=lambda x: x.product_id.id)}
for product_id, pd in grouped_product_ids.items():
product_id_to_production_names[product_id] = [p.name for p in pd]
for production in production_all:
process_parameter_workorder = self.env['mrp.workorder'].search(
[('surface_technics_parameters_id', '!=', False), ('production_id', '=', production.id),
('is_subcontract', '=', True)], order='sequence asc')
if process_parameter_workorder:
consecutive_workorders = []
sorted_workorders = sorted(process_parameter_workorder, key=lambda w: w.sequence)
for i, workorder in enumerate(sorted_workorders):
# 检查当前工作订单和下一个工作订单是否连续,并且供应商相同
if workorder.sequence == 1:
consecutive_workorders.append(workorder)
elif workorder.sequence == sorted_workorders[
i - 1].sequence + 1 and workorder.supplier_id.id == sorted_workorders[i - 1].supplier_id.id:
consecutive_workorders.append(workorder)
else:
# 处理连续组,如果它不为空
if consecutive_workorders:
# 创建出库拣货单和采购订单
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production)
self.env['purchase.order'].get_purchase_order(consecutive_workorders, production,
product_id_to_production_names)
if i < len(sorted_workorders) - 1:
# 重置连续组,并添加当前工作订单
consecutive_workorders = [workorder]
else:
# 判断最后一笔:
if workorder.sequence == sorted_workorders[
i - 1].sequence and workorder.supplier_id.id == sorted_workorders[
i - 1].supplier_id.id:
consecutive_workorders = [workorder]
else:
# 立即创建出库拣货单和采购订单
self.env['stock.picking'].create_outcontract_picking(workorder, production)
self.env['purchase.order'].get_purchase_order(workorder, production,
product_id_to_production_names)
consecutive_workorders = []
# 处理最后一个组,即使它可能只有一个工作订单
if consecutive_workorders:
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production)
self.env['purchase.order'].get_purchase_order(consecutive_workorders, production,
product_id_to_production_names)
# 工单排序 # 工单排序
def _reset_work_order_sequence1(self, k): def _reset_work_order_sequence1(self, k):
for rec in self: for rec in self:
@@ -1305,17 +1346,17 @@ class MrpProduction(models.Model):
return production_values_str return production_values_str
# 增加制造订单类型 # 增加制造订单类型
# production_type = fields.Selection( production_type = fields.Selection(
# [('自动化产线加工', '自动化产线加工'), ('人工线下加工', '人工线下加工')], [('自动化产线加工', '自动化产线加工'), ('人工线下加工', '人工线下加工')],
# string='制造类型', string='制造类型',
# compute='_compute_production_type', compute='_compute_production_type',
# store=True store=True
# ) )
# @api.depends('product_id.is_manual_processing') @api.depends('product_id.is_manual_processing')
# def _compute_production_type(self): def _compute_production_type(self):
# for production in self: for production in self:
# production.production_type = '自动化产线加工' if not production.product_id.is_manual_processing else '人工线下加工' production.production_type = '自动化产线加工' if not production.product_id.is_manual_processing else '人工线下加工'
class sf_detection_result(models.Model): class sf_detection_result(models.Model):

View File

@@ -38,13 +38,10 @@ class ResMrpWorkOrder(models.Model):
processing_panel = fields.Char('加工面') processing_panel = fields.Char('加工面')
sequence = fields.Integer(string='工序') sequence = fields.Integer(string='工序')
routing_type = fields.Selection([ routing_type = fields.Selection([
# ('获取CNC加工程序', '获取CNC加工程序'),
('装夹预调', '装夹预调'), ('装夹预调', '装夹预调'),
# ('前置三元定位检测', '前置三元定位检测'),
('CNC加工', 'CNC加工'), ('CNC加工', 'CNC加工'),
# ('后置三元质量检测', '后置三元质量检测'),
('解除装夹', '解除装夹'), ('解除装夹', '解除装夹'),
('切割', '切割'), ('表面工艺', '表面工艺') ('切割', '切割'), ('表面工艺', '表面工艺'), ('线切割', '线切割')
], string="工序类型") ], string="工序类型")
results = fields.Char('结果') results = fields.Char('结果')
state = fields.Selection([ state = fields.Selection([
@@ -233,7 +230,7 @@ class ResMrpWorkOrder(models.Model):
def _compute_surface_technics_picking_ids(self): def _compute_surface_technics_picking_ids(self):
for workorder in self: for workorder in self:
if workorder.routing_type == '表面工艺': if workorder.routing_type == '表面工艺':
domain = [('origin', '=', workorder.production_id.name)] domain = [('origin', '=', workorder.production_id.name), ('state', 'not in', ['cancel'])]
previous_workorder = self.env['mrp.workorder'].search( previous_workorder = self.env['mrp.workorder'].search(
[('sequence', '=', workorder.sequence - 1), ('routing_type', '=', '表面工艺'), [('sequence', '=', workorder.sequence - 1), ('routing_type', '=', '表面工艺'),
('production_id', '=', workorder.production_id.id)]) ('production_id', '=', workorder.production_id.id)])
@@ -267,24 +264,47 @@ class ResMrpWorkOrder(models.Model):
def _compute_surface_technics_purchase_ids(self): def _compute_surface_technics_purchase_ids(self):
for order in self: for order in self:
if order.routing_type == '表面工艺': if order.routing_type == '表面工艺':
production_programming = self.env['mrp.production'].search( if order.production_id.production_type == '自动化产线加工':
[('programming_no', '=', order.production_id.programming_no)], order='name asc') domain = [('programming_no', '=', order.production_id.programming_no)]
production_no_remanufacture = production_programming.filtered(lambda a: a.is_remanufacture is False) else:
domain = [('origin', '=', order.production_id.origin)]
production_programming = self.env['mrp.production'].search(domain, order='name asc')
production_list = [production.name for production in production_programming] production_list = [production.name for production in production_programming]
purchase = self.env['purchase.order'].search([('origin', '=', ','.join(production_list))]) production_no_remanufacture = production_programming.filtered(lambda a: a.is_remanufacture is False)
technology_design = self.env['sf.technology.design'].search(
[('process_parameters_id', '=', order.surface_technics_parameters_id.id),
('production_id', '=', order.production_id.id)])
if technology_design.is_auto is False:
domain = [('origin', '=', order.production_id.name)]
else:
domain = [('origin', '=', ','.join(production_list))]
purchase = self.env['purchase.order'].search(domain)
if not purchase:
order.surface_technics_purchase_count = 0
for line in purchase.order_line: for line in purchase.order_line:
if line.product_id.server_product_process_parameters_id == order.surface_technics_parameters_id and line.product_qty == len( if line.product_id.server_product_process_parameters_id == order.surface_technics_parameters_id:
production_no_remanufacture): if (line.product_qty == len(production_no_remanufacture)) or technology_design.is_auto is False:
order.surface_technics_purchase_count = len(purchase) order.surface_technics_purchase_count = len(purchase)
else: else:
order.surface_technics_purchase_count = 0 order.surface_technics_purchase_count = 0
def action_view_surface_technics_purchase(self): def action_view_surface_technics_purchase(self):
self.ensure_one() self.ensure_one()
production_programming = self.env['mrp.production'].search( if self.routing_type == '表面工艺':
[('programming_no', '=', self.production_id.programming_no)], order='name asc') if self.production_id.production_type == '自动化产线加工':
domain = [('programming_no', '=', self.production_id.programming_no)]
else:
domain = [('origin', '=', self.production_id.origin)]
production_programming = self.env['mrp.production'].search(domain, order='name asc')
production_list = [production.name for production in production_programming] production_list = [production.name for production in production_programming]
purchase_orders = self.env['purchase.order'].search([('origin', '=', ','.join(production_list))]) technology_design = self.env['sf.technology.design'].search(
[('process_parameters_id', '=', self.surface_technics_parameters_id.id),
('production_id', '=', self.production_id.id)])
if technology_design.is_auto is False:
domain = [('origin', '=', self.production_id.name)]
else:
domain = [('origin', '=', ','.join(production_list))]
purchase_orders = self.env['purchase.order'].search(domain)
result = { result = {
"type": "ir.actions.act_window", "type": "ir.actions.act_window",
"res_model": "purchase.order", "res_model": "purchase.order",
@@ -410,7 +430,8 @@ class ResMrpWorkOrder(models.Model):
@api.constrains('blocked_by_workorder_ids') @api.constrains('blocked_by_workorder_ids')
def _check_no_cyclic_dependencies(self): def _check_no_cyclic_dependencies(self):
if self.production_id.state not in ['rework'] and self.state not in ['rework']: if self.production_id.state not in ['rework', 'technology_to_confirmed', 'confirmed'] and self.state not in [
'rework']:
if not self._check_m2m_recursion('blocked_by_workorder_ids'): if not self._check_m2m_recursion('blocked_by_workorder_ids'):
raise ValidationError(_("您不能创建周期性的依赖关系.")) raise ValidationError(_("您不能创建周期性的依赖关系."))
@@ -421,6 +442,7 @@ class ResMrpWorkOrder(models.Model):
for workorder in self.blocked_by_workorder_ids: for workorder in self.blocked_by_workorder_ids:
if workorder.state in ['done', 'cancel', 'rework']: if workorder.state in ['done', 'cancel', 'rework']:
continue continue
if workorder.production_id.state not in ['technology_to_confirmed', 'confirmed']:
workorder._plan_workorder(replan) workorder._plan_workorder(replan)
start_date = max(start_date, workorder.date_planned_finished) start_date = max(start_date, workorder.date_planned_finished)
# Plan only suitable workorders # Plan only suitable workorders
@@ -769,6 +791,7 @@ class ResMrpWorkOrder(models.Model):
'operation_id': False, 'operation_id': False,
'name': route.route_id.name, 'name': route.route_id.name,
'processing_panel': route.panel, 'processing_panel': route.panel,
'sequence': route.sequence,
'quality_point_ids': route.route_id.quality_point_ids, 'quality_point_ids': route.route_id.quality_point_ids,
'routing_type': route.route_id.routing_type, 'routing_type': route.route_id.routing_type,
'workcenter_id': self.env['mrp.routing.workcenter'].get_workcenter(route.route_id.workcenter_ids.ids, 'workcenter_id': self.env['mrp.routing.workcenter'].get_workcenter(route.route_id.workcenter_ids.ids,
@@ -817,6 +840,7 @@ class ResMrpWorkOrder(models.Model):
'operation_id': False, 'operation_id': False,
'name': route.process_parameters_id.display_name, 'name': route.process_parameters_id.display_name,
'processing_panel': '', 'processing_panel': '',
'sequence': route.sequence,
'routing_type': '表面工艺', 'routing_type': '表面工艺',
'surface_technics_parameters_id': route.process_parameters_id.id, 'surface_technics_parameters_id': route.process_parameters_id.id,
'work_state': '', 'work_state': '',
@@ -977,10 +1001,47 @@ class ResMrpWorkOrder(models.Model):
return workorders_values_str return workorders_values_str
@api.depends('production_availability', 'blocked_by_workorder_ids', 'blocked_by_workorder_ids.state', @api.depends('production_availability', 'blocked_by_workorder_ids', 'blocked_by_workorder_ids.state',
'production_id.tool_state') 'production_id.tool_state', 'production_id.schedule_state')
def _compute_state(self): def _compute_state(self):
super()._compute_state() # super()._compute_state()
for workorder in self: for workorder in self:
if workorder.sequence != 1:
previous_workorder = self.env['mrp.workorder'].search(
[('production_id', '=', workorder.production_id.id),
('sequence', '=', workorder.sequence - 1)])
if workorder.state == 'pending':
if all([wo.state in ('done', 'cancel') for wo in workorder.blocked_by_workorder_ids]):
if workorder.production_id.reservation_state == 'assigned' and workorder.production_id.schedule_state == '已排':
if (workorder.sequence == 1 and not workorder.blocked_by_workorder_ids) or (
workorder.blocked_by_workorder_ids.state in ('done', 'cancel')) or (
previous_workorder.state in (
'done', 'cancel') and not workorder.blocked_by_workorder_ids):
workorder.state = 'ready'
continue
if workorder.production_id.schedule_state == '未排' and workorder.state in ('waiting', 'ready'):
if workorder.sequence != 1:
workorder.state = 'pending'
continue
if workorder.state not in ('waiting', 'ready'):
continue
if workorder.state in (
'waiting') and workorder.sequence == 1 and workorder.production_id.schedule_state == '已排':
workorder.state = 'ready'
continue
if not all([wo.state in ('done', 'cancel') for wo in workorder.blocked_by_workorder_ids]):
workorder.state = 'pending'
if workorder.state in ['waiting']:
if previous_workorder.state == 'waiting':
workorder.state = 'pending'
if workorder.sequence == 1 and workorder.state == 'pending':
workorder.state = 'waiting'
continue
if workorder.production_id.reservation_state not in ('waiting', 'confirmed', 'assigned'):
continue
if workorder.production_id.reservation_state == 'assigned' and workorder.state == 'waiting' and workorder.production_id.schedule_state == '已排':
workorder.state = 'ready'
elif workorder.production_id.reservation_state != 'assigned' and workorder.state == 'ready':
workorder.state = 'waiting'
re_work = self.env['mrp.workorder'].search([('production_id', '=', workorder.production_id.id), re_work = self.env['mrp.workorder'].search([('production_id', '=', workorder.production_id.id),
('processing_panel', '=', workorder.processing_panel), ('processing_panel', '=', workorder.processing_panel),
('is_rework', '=', True), ('state', 'in', ['done', 'rework'])]) ('is_rework', '=', True), ('state', 'in', ['done', 'rework'])])
@@ -1044,7 +1105,7 @@ class ResMrpWorkOrder(models.Model):
workorder.state = 'ready' workorder.state = 'ready'
else: else:
production_programming = self.env['mrp.production'].search( production_programming = self.env['mrp.production'].search(
[('programming_no', '=', self.production_id.programming_no)], order='name asc') [('origin', '=', self.production_id.origin)], order='name asc')
production_no_remanufacture = production_programming.filtered( production_no_remanufacture = production_programming.filtered(
lambda a: a.is_remanufacture is False) lambda a: a.is_remanufacture is False)
production_list = [production.name for production in production_programming] production_list = [production.name for production in production_programming]
@@ -1060,68 +1121,68 @@ class ResMrpWorkOrder(models.Model):
elif workorder.production_id.state == 'scrap': elif workorder.production_id.state == 'scrap':
if workorder.routing_type == '解除装夹' and unclamp_workorder.test_results == '报废': if workorder.routing_type == '解除装夹' and unclamp_workorder.test_results == '报废':
workorder.state = 'waiting' workorder.state = 'waiting'
if workorder.routing_type == '装夹预调' and workorder.state in ['waiting', 'ready', 'pending']: # if workorder.routing_type == '装夹预调' and workorder.state in ['waiting', 'ready', 'pending']:
workorder_ids = workorder.production_id.workorder_ids # workorder_ids = workorder.production_id.workorder_ids
work_bo = True # work_bo = True
for wo in workorder_ids.filtered(lambda a: a.routing_type == '装夹预调' and a.state == 'rework'): # for wo in workorder_ids.filtered(lambda a: a.routing_type == '装夹预调' and a.state == 'rework'):
if not workorder_ids.filtered( # if not workorder_ids.filtered(
lambda a: (a.routing_type == '装夹预调' and a.state not in ['rework', 'cancel'] # lambda a: (a.routing_type == '装夹预调' and a.state not in ['rework', 'cancel']
and a.processing_panel == wo.processing_panel)): # and a.processing_panel == wo.processing_panel)):
work_bo = False # work_bo = False
break # break
if (workorder.production_id.programming_state == '已编程' and work_bo # if (workorder.production_id.programming_state == '已编程' and work_bo
and not workorder_ids.filtered(lambda a: a.sequence == 0)): # and not workorder_ids.filtered(lambda a: a.sequence == 0)):
# 当工单对应制造订单的功能刀具状态为 【无效刀】时,先对的第一个装夹预调工单状态设置为 【等待组件】 # # 当工单对应制造订单的功能刀具状态为 【无效刀】时,先对的第一个装夹预调工单状态设置为 【等待组件】
if workorder.production_id.tool_state in ['1', '2']: # if workorder.production_id.tool_state in ['1', '2']:
if workorder.state in ['ready']: # if workorder.state in ['ready']:
workorder.state = 'waiting' # workorder.state = 'waiting'
continue # continue
elif workorder.state in ['waiting']: # elif workorder.state in ['waiting']:
continue # continue
elif workorder.state == 'pending' and workorder == self.search( # elif workorder.state == 'pending' and workorder == self.search(
[('production_id', '=', workorder.production_id.id), # [('production_id', '=', workorder.production_id.id),
('routing_type', '=', '装夹预调'), # ('routing_type', '=', '装夹预调'),
('state', 'not in', ['rework', 'done', 'cancel'])], # ('state', 'not in', ['rework', 'done', 'cancel'])],
limit=1, # limit=1,
order="sequence"): # order="sequence"):
workorder.state = 'waiting' # workorder.state = 'waiting'
continue # continue
elif workorder.production_id.tool_state in ['0']: # elif workorder.production_id.tool_state in ['0']:
if workorder_ids.filtered(lambda a: a.state == 'rework'): # if workorder_ids.filtered(lambda a: a.state == 'rework'):
if not workorder_ids.filtered( # if not workorder_ids.filtered(
lambda a: (a.routing_type not in ['装夹预调'] and # lambda a: (a.routing_type not in ['装夹预调'] and
a.state not in ['pending', 'done', 'rework', 'cancel'])): # a.state not in ['pending', 'done', 'rework', 'cancel'])):
# 查询工序最小的非完工、非返工的装夹预调工单 # # 查询工序最小的非完工、非返工的装夹预调工单
work_id = self.search( # work_id = self.search(
[('production_id', '=', workorder.production_id.id), # [('production_id', '=', workorder.production_id.id),
('state', 'not in', ['rework', 'done', 'cancel'])], # ('state', 'not in', ['rework', 'done', 'cancel'])],
limit=1, # limit=1,
order="sequence") # order="sequence")
if work_id.routing_type == '装夹预调': # if work_id.routing_type == '装夹预调':
if workorder == work_id: # if workorder == work_id:
if workorder.production_id.reservation_state == 'assigned': # if workorder.production_id.reservation_state == 'assigned':
workorder.state = 'ready' # workorder.state = 'ready'
elif workorder.production_id.reservation_state != 'assigned': # elif workorder.production_id.reservation_state != 'assigned':
workorder.state = 'waiting' # workorder.state = 'waiting'
continue # continue
elif (workorder.name == '装夹预调' and # elif (workorder.name == '装夹预调' and
workorder.state not in ['rework', 'done', 'cancel']): # workorder.state not in ['rework', 'done', 'cancel']):
if workorder.state != 'pending': # if workorder.state != 'pending':
workorder.state = 'pending' # workorder.state = 'pending'
if workorder.production_id.tool_state in ['1', '2'] and workorder.state == 'ready': # if workorder.production_id.tool_state in ['1', '2'] and workorder.state == 'ready':
workorder.state = 'waiting' # workorder.state = 'waiting'
continue # continue
if (workorder.production_id.tool_state in ['1', '2'] # if (workorder.production_id.tool_state in ['1', '2']
and not workorder.production_id.workorder_ids.filtered(lambda a: a.sequence == 0) # and not workorder.production_id.workorder_ids.filtered(lambda a: a.sequence == 0)
and workorder.production_id.programming_state == '编程中' and workorder.name == '装夹预调'): # and workorder.production_id.programming_state == '编程中' and workorder.name == '装夹预调'):
if workorder.state == 'pending' and workorder == self.search( # if workorder.state == 'pending' and workorder == self.search(
[('production_id', '=', workorder.production_id.id), # [('production_id', '=', workorder.production_id.id),
('routing_type', '=', '装夹预调'), # ('routing_type', '=', '装夹预调'),
('state', 'not in', ['rework', 'done', 'cancel'])], # ('state', 'not in', ['rework', 'done', 'cancel'])],
limit=1, # limit=1,
order="sequence"): # order="sequence"):
workorder.state = 'waiting' # workorder.state = 'waiting'
continue # continue
# 重写工单开始按钮方法 # 重写工单开始按钮方法
def button_start(self): def button_start(self):
@@ -1131,7 +1192,7 @@ class ResMrpWorkOrder(models.Model):
'actual_start_time': datetime.now() 'actual_start_time': datetime.now()
}) })
if self.routing_type == '装夹预调': if self.sequence == 1:
# 判断是否有坯料的序列号信息 # 判断是否有坯料的序列号信息
boolean = False boolean = False
if self.production_id.move_raw_ids: if self.production_id.move_raw_ids:
@@ -1273,23 +1334,10 @@ class ResMrpWorkOrder(models.Model):
''' '''
record.date_finished = datetime.now() record.date_finished = datetime.now()
if record.routing_type == '表面工艺': if record.routing_type == '表面工艺':
logging.info('record.picking_ids:%s' % record.picking_ids)
logging.info('record.picking_out:%s' % record.picking_ids[0])
if record.picking_ids: if record.picking_ids:
for pick_item in record.picking_ids: picks = record.picking_ids.filtered(lambda p: p.state not in ('done'))
if pick_item.state not in ['done']: if picks:
raise UserError( raise UserError('请先完成该工单的工艺外协再进行操作')
'请先完成该工单的工艺外协再进行操作')
picking_out = record.env['stock.move.line'].search(
[('picking_id', '=', record.picking_ids[0].id)])
logging.info('picking_out:%s' % picking_out.picking_id.name)
# if picking_out:
# order_line_ids = []
# logging.info('surface_technics_parameters_id:%s' % record.surface_technics_parameters_id.name)
#
# else:
# raise UserError(
# '请先在产品中配置表面工艺为%s相关的外协服务产品' % item.surface_technics_parameters_id.name)
tem_date_planned_finished = record.date_planned_finished tem_date_planned_finished = record.date_planned_finished
tem_date_finished = record.date_finished tem_date_finished = record.date_finished
logging.info('routing_type:%s' % record.routing_type) logging.info('routing_type:%s' % record.routing_type)

View File

@@ -850,14 +850,21 @@ class ResProductMo(models.Model):
copy_product_id.product_tmpl_id.active = True copy_product_id.product_tmpl_id.active = True
model_type = self.env['sf.model.type'].search([], limit=1) model_type = self.env['sf.model.type'].search([], limit=1)
attachment = self.attachment_create(item['model_name'], item['model_data']) attachment = self.attachment_create(item['model_name'], item['model_data'])
# 获取坯料冗余配置
if not item.get('embryo_redundancy'):
embryo_redundancy_id = model_type.embryo_tolerance_id
else:
embryo_redundancy_id = item.get('embryo_redundancy')
if not embryo_redundancy_id:
raise UserError('请先配置模型类型内的坯料冗余')
vals = { vals = {
'name': '%s-%s-%s' % ('P', order_id.name, i), 'name': '%s-%s-%s' % ('P', order_id.name, i),
'model_long': item['model_long'] + model_type.embryo_tolerance, 'model_long': item['model_long'] + embryo_redundancy_id.long,
'model_width': item['model_width'] + model_type.embryo_tolerance, 'model_width': item['model_width'] + embryo_redundancy_id.width,
'model_height': item['model_height'] + model_type.embryo_tolerance, 'model_height': item['model_height'] + embryo_redundancy_id.height,
'model_volume': (item['model_long'] + model_type.embryo_tolerance) * ( 'model_volume': (item['model_long'] + embryo_redundancy_id.long) * (
item['model_width'] + model_type.embryo_tolerance) * ( item['model_width'] + embryo_redundancy_id.width) * (
item['model_height'] + model_type.embryo_tolerance), item['model_height'] + embryo_redundancy_id.height),
'product_model_type_id': model_type.id, 'product_model_type_id': model_type.id,
'model_processing_panel': item['processing_panel_detail'], 'model_processing_panel': item['processing_panel_detail'],
'model_machining_precision': item['model_machining_precision'], 'model_machining_precision': item['model_machining_precision'],
@@ -941,19 +948,26 @@ class ResProductMo(models.Model):
[('materials_no', '=', item['texture_type_code'])]) [('materials_no', '=', item['texture_type_code'])])
model_type = self.env['sf.model.type'].search([], limit=1) model_type = self.env['sf.model.type'].search([], limit=1)
supplier = self.env['mrp.bom'].get_supplier(materials_type_id) 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) logging.info('no_bom_copy_product_supplier-vals:%s' % supplier)
vals = { vals = {
'name': '%s-%s-%s [%s %s-%s * %s * %s]' % ('R', 'name': '%s-%s-%s [%s %s-%s * %s * %s]' % ('R',
order_id.name, i, materials_id.name, materials_type_id.name, order_id.name, i, materials_id.name, materials_type_id.name,
item['model_long'] + model_type.embryo_tolerance, item['model_long'] + embryo_redundancy_id.long,
item['model_width'] + model_type.embryo_tolerance, item['model_width'] + embryo_redundancy_id.width,
item['model_height'] + model_type.embryo_tolerance), item['model_height'] + embryo_redundancy_id.height),
'length': item['model_long'] + model_type.embryo_tolerance, 'length': item['model_long'] + embryo_redundancy_id.long,
'width': item['model_width'] + model_type.embryo_tolerance, 'width': item['model_width'] + embryo_redundancy_id.width,
'height': item['model_height'] + model_type.embryo_tolerance, 'height': item['model_height'] + embryo_redundancy_id.height,
'volume': (item['model_long'] + model_type.embryo_tolerance) * ( 'volume': (item['model_long'] + embryo_redundancy_id.long) * (
item['model_width'] + model_type.embryo_tolerance) * ( item['model_width'] + embryo_redundancy_id.width) * (
item['model_height'] + model_type.embryo_tolerance), item['model_height'] + embryo_redundancy_id.height),
'embryo_model_type_id': model_type.id, 'embryo_model_type_id': model_type.id,
'list_price': item['price'], 'list_price': item['price'],
'materials_id': materials_id.id, 'materials_id': materials_id.id,

View File

@@ -16,13 +16,13 @@ class sf_technology_design(models.Model):
is_auto = fields.Boolean('是否自动生成', default=False) is_auto = fields.Boolean('是否自动生成', default=False)
active = fields.Boolean('有效', default=True) active = fields.Boolean('有效', default=True)
def json_technology_design_str(self, k, route, i): def json_technology_design_str(self, k, route, i, process_parameter):
workorders_values_str = [0, '', { workorders_values_str = [0, '', {
'route_id': route.id, 'route_id': route.id,
'panel': k, 'panel': k,
'process_parameters_id': False if route.routing_type != '表面工艺' else self.env[ 'process_parameters_id': False if route.routing_type != '表面工艺' else self.env[
'sf.production.process.parameter'].search( 'sf.production.process.parameter'].search(
[('process_id', '=', route.surface_technics_id.id)]).id, [('id', '=', process_parameter.id)]).id,
'sequence': i, 'sequence': i,
'is_auto': True}] 'is_auto': True}]
return workorders_values_str return workorders_values_str

View File

@@ -66,75 +66,28 @@ class stockWarehouse(models.Model):
class StockRule(models.Model): class StockRule(models.Model):
_inherit = 'stock.rule' _inherit = 'stock.rule'
# @api.model @api.model
# def _run_pull(self, procurements): def _run_pull(self, procurements):
# logging.info(procurements) logging.info(procurements)
# moves_values_by_company = defaultdict(list) moves_values_by_company = defaultdict(list)
# mtso_products_by_locations = defaultdict(list) mtso_products_by_locations = defaultdict(list)
# # To handle the `mts_else_mto` procure method, we do a preliminary loop to # To handle the `mts_else_mto` procure method, we do a preliminary loop to
# # isolate the products we would need to read the forecasted quantity, # isolate the products we would need to read the forecasted quantity,
# # in order to to batch the read. We also make a sanitary check on the # in order to to batch the read. We also make a sanitary check on the
# # `location_src_id` field. # `location_src_id` field.
# # list1 = [] # list1 = []
# # for item in procurements:
# # num = int(item[0].product_qty)
# # if num > 1:
# # for no in range(1, num+1):
# #
# # Procurement = namedtuple('Procurement', ['product_id', 'product_qty',
# # 'product_uom', 'location_id', 'name', 'origin',
# # 'company_id',
# # 'values'])
# # s = Procurement(product_id=item[0].product_id,product_qty=1.0,product_uom=item[0].product_uom,
# # location_id=item[0].location_id,
# # name=item[0].name,
# # origin=item[0].origin,
# # company_id=item[0].company_id,
# # values=item[0].values,
# # )
# # item1 = list(item)
# # item1[0]=s
# #
# # list1.append(tuple(item1))
# # else:
# # list1.append(item)
# for procurement, rule in procurements:
# if not rule.location_src_id:
# msg = _('No source location defined on stock rule: %s!') % (rule.name,)
# raise ProcurementException([(procurement, msg)])
# if rule.procure_method == 'mts_else_mto':
# mtso_products_by_locations[rule.location_src_id].append(procurement.product_id.id)
# # Get the forecasted quantity for the `mts_else_mto` procurement.
# forecasted_qties_by_loc = {}
# for location, product_ids in mtso_products_by_locations.items():
# products = self.env['product.product'].browse(product_ids).with_context(location=location.id)
# forecasted_qties_by_loc[location] = {product.id: product.free_qty for product in products}
# # Prepare the move values, adapt the `procure_method` if needed.
# procurements = sorted(procurements, key=lambda proc: float_compare(proc[0].product_qty, 0.0,
# precision_rounding=proc[
# 0].product_uom.rounding) > 0)
# list2 = []
# for item in procurements: # for item in procurements:
# num = int(item[0].product_qty) # num = int(item[0].product_qty)
# product = self.env['product.product'].search(
# [("id", '=', item[0].product_id.id)])
# product_tmpl = self.env['product.template'].search(
# ["&", ("id", '=', product.product_tmpl_id.id), ('single_manufacturing', "!=", False)])
# if product_tmpl:
# if num > 1: # if num > 1:
# for no in range(1, num + 1): # for no in range(1, num+1):
#
# Procurement = namedtuple('Procurement', ['product_id', 'product_qty', # Procurement = namedtuple('Procurement', ['product_id', 'product_qty',
# 'product_uom', 'location_id', 'name', 'origin', # 'product_uom', 'location_id', 'name', 'origin',
# 'company_id', # 'company_id',
# 'values']) # 'values'])
# s = Procurement(product_id=item[0].product_id, product_qty=1.0, product_uom=item[0].product_uom, # s = Procurement(product_id=item[0].product_id,product_qty=1.0,product_uom=item[0].product_uom,
# location_id=item[0].location_id, # location_id=item[0].location_id,
# name=item[0].name, # name=item[0].name,
# origin=item[0].origin, # origin=item[0].origin,
@@ -142,282 +95,282 @@ class StockRule(models.Model):
# values=item[0].values, # values=item[0].values,
# ) # )
# item1 = list(item) # item1 = list(item)
# item1[0] = s # item1[0]=s
#
# list2.append(tuple(item1)) # list1.append(tuple(item1))
# else: # else:
# list2.append(item) # list1.append(item)
# else:
# list2.append(item)
# for procurement, rule in list2: for procurement, rule in procurements:
# procure_method = rule.procure_method if not rule.location_src_id:
# if rule.procure_method == 'mts_else_mto': msg = _('No source location defined on stock rule: %s!') % (rule.name,)
# qty_needed = procurement.product_uom._compute_quantity(procurement.product_qty, raise ProcurementException([(procurement, msg)])
# procurement.product_id.uom_id)
# if float_compare(qty_needed, 0, precision_rounding=procurement.product_id.uom_id.rounding) <= 0:
# procure_method = 'make_to_order'
# for move in procurement.values.get('group_id', self.env['procurement.group']).stock_move_ids:
# if move.rule_id == rule and float_compare(move.product_uom_qty, 0,
# precision_rounding=move.product_uom.rounding) > 0:
# procure_method = move.procure_method
# break
# forecasted_qties_by_loc[rule.location_src_id][procurement.product_id.id] -= qty_needed
# elif float_compare(qty_needed, forecasted_qties_by_loc[rule.location_src_id][procurement.product_id.id],
# precision_rounding=procurement.product_id.uom_id.rounding) > 0:
# procure_method = 'make_to_order'
# else:
# forecasted_qties_by_loc[rule.location_src_id][procurement.product_id.id] -= qty_needed
# procure_method = 'make_to_stock'
# move_values = rule._get_stock_move_values(*procurement)
# move_values['procure_method'] = procure_method
# moves_values_by_company[procurement.company_id.id].append(move_values)
# for company_id, moves_values in moves_values_by_company.items(): if rule.procure_method == 'mts_else_mto':
# # create the move as SUPERUSER because the current user may not have the rights to do it (mto product mtso_products_by_locations[rule.location_src_id].append(procurement.product_id.id)
# # launched by a sale for example)
# moves = self.env['stock.move'].with_user(SUPERUSER_ID).sudo().with_company(company_id).create( # Get the forecasted quantity for the `mts_else_mto` procurement.
# moves_values) forecasted_qties_by_loc = {}
# # Since action_confirm launch following procurement_group we should activate it. for location, product_ids in mtso_products_by_locations.items():
# moves._action_confirm() products = self.env['product.product'].browse(product_ids).with_context(location=location.id)
# return True forecasted_qties_by_loc[location] = {product.id: product.free_qty for product in products}
# Prepare the move values, adapt the `procure_method` if needed.
procurements = sorted(procurements, key=lambda proc: float_compare(proc[0].product_qty, 0.0,
precision_rounding=proc[
0].product_uom.rounding) > 0)
list2 = []
for item in procurements:
num = int(item[0].product_qty)
product = self.env['product.product'].search(
[("id", '=', item[0].product_id.id)])
product_tmpl = self.env['product.template'].search(
["&", ("id", '=', product.product_tmpl_id.id), ('single_manufacturing', "!=", False)])
if product_tmpl:
if num > 1:
for no in range(1, num + 1):
Procurement = namedtuple('Procurement', ['product_id', 'product_qty',
'product_uom', 'location_id', 'name', 'origin',
'company_id',
'values'])
s = Procurement(product_id=item[0].product_id, product_qty=1.0, product_uom=item[0].product_uom,
location_id=item[0].location_id,
name=item[0].name,
origin=item[0].origin,
company_id=item[0].company_id,
values=item[0].values,
)
item1 = list(item)
item1[0] = s
list2.append(tuple(item1))
else:
list2.append(item)
else:
list2.append(item)
for procurement, rule in list2:
procure_method = rule.procure_method
if rule.procure_method == 'mts_else_mto':
qty_needed = procurement.product_uom._compute_quantity(procurement.product_qty,
procurement.product_id.uom_id)
if float_compare(qty_needed, 0, precision_rounding=procurement.product_id.uom_id.rounding) <= 0:
procure_method = 'make_to_order'
for move in procurement.values.get('group_id', self.env['procurement.group']).stock_move_ids:
if move.rule_id == rule and float_compare(move.product_uom_qty, 0,
precision_rounding=move.product_uom.rounding) > 0:
procure_method = move.procure_method
break
forecasted_qties_by_loc[rule.location_src_id][procurement.product_id.id] -= qty_needed
elif float_compare(qty_needed, forecasted_qties_by_loc[rule.location_src_id][procurement.product_id.id],
precision_rounding=procurement.product_id.uom_id.rounding) > 0:
procure_method = 'make_to_order'
else:
forecasted_qties_by_loc[rule.location_src_id][procurement.product_id.id] -= qty_needed
procure_method = 'make_to_stock'
move_values = rule._get_stock_move_values(*procurement)
move_values['procure_method'] = procure_method
moves_values_by_company[procurement.company_id.id].append(move_values)
for company_id, moves_values in moves_values_by_company.items():
# create the move as SUPERUSER because the current user may not have the rights to do it (mto product
# launched by a sale for example)
moves = self.env['stock.move'].with_user(SUPERUSER_ID).sudo().with_company(company_id).create(
moves_values)
# Since action_confirm launch following procurement_group we should activate it.
moves._action_confirm()
return True
def attachment_update(self, name, res_id, res_field): def attachment_update(self, name, res_id, res_field):
attachment_info = self.env['ir.attachment'].sudo().search( attachment_info = self.env['ir.attachment'].sudo().search(
[('res_id', '=', res_id), ('res_field', '=', res_field)], limit=1) [('res_id', '=', res_id), ('res_field', '=', res_field)], limit=1)
attachment_info.write({'name': name}) attachment_info.write({'name': name})
# @api.model @api.model
# def _run_manufacture(self, procurements): def _run_manufacture(self, procurements):
# productions_values_by_company = defaultdict(list) productions_values_by_company = defaultdict(list)
# errors = [] errors = []
# for procurement, rule in procurements: for procurement, rule in procurements:
# if float_compare(procurement.product_qty, 0, precision_rounding=procurement.product_uom.rounding) <= 0: if float_compare(procurement.product_qty, 0, precision_rounding=procurement.product_uom.rounding) <= 0:
# # If procurement contains negative quantity, don't create a MO that would be for a negative value. # If procurement contains negative quantity, don't create a MO that would be for a negative value.
# continue continue
# bom = rule._get_matching_bom(procurement.product_id, procurement.company_id, procurement.values) bom = rule._get_matching_bom(procurement.product_id, procurement.company_id, procurement.values)
# productions_values_by_company[procurement.company_id.id].append(rule._prepare_mo_vals(*procurement, bom)) productions_values_by_company[procurement.company_id.id].append(rule._prepare_mo_vals(*procurement, bom))
# if errors: if errors:
# raise ProcurementException(errors) raise ProcurementException(errors)
# for company_id, productions_values in productions_values_by_company.items(): for company_id, productions_values in productions_values_by_company.items():
# # create the MO as SUPERUSER because the current user may not have the rights to do it # create the MO as SUPERUSER because the current user may not have the rights to do it
# # (mto product launched by a sale for example) # (mto product launched by a sale for example)
# '''创建制造订单''' '''创建制造订单'''
# productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company(company_id).create( productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company(company_id).create(
# productions_values) productions_values)
# # self.env['stock.move'].sudo().create(productions._get_moves_raw_values()) # self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
# # self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
# '''
# 创建工单
# '''
# # productions._create_workorder()
# #
# self.env['stock.move'].sudo().create(productions._get_moves_finished_values()) # self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
# productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \
# (
# p.move_dest_ids.procure_method != 'make_to_order' and not
# p.move_raw_ids and not p.workorder_ids)).action_confirm()
# # 处理 根据制造订单生成的采购单坯料入库时到原材料库,手动将原材料位置该为坯料存货区
# for production in productions:
# if production.picking_ids:
# product_type_id = production.picking_ids[0].move_ids[0].product_id.categ_id
# if product_type_id.name == '坯料':
# location_id = self.env['stock.location'].search([('name', '=', '坯料存货区')])
# if not location_id:
# logging.info(f'没有搜索到【坯料存货区】: {location_id}')
# break
# for picking_id in production.picking_ids:
# if picking_id.picking_type_id.name == '内部调拨':
# if picking_id.location_dest_id.product_type != product_type_id:
# picking_id.location_dest_id = location_id.id
# elif picking_id.picking_type_id.name == '生产发料':
# if picking_id.location_id.product_type != product_type_id:
# picking_id.location_id = location_id.id
# for production in productions: '''
# ''' 创建工单
# 创建制造订单时生成序列号 '''
# ''' # productions._create_workorder()
# production.action_generate_serial() #
# origin_production = production.move_dest_ids and production.move_dest_ids[ self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
# 0].raw_material_production_id or False productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \
# orderpoint = production.orderpoint_id (
# if orderpoint and orderpoint.create_uid.id == SUPERUSER_ID and orderpoint.trigger == 'manual': p.move_dest_ids.procure_method != 'make_to_order' and not
# production.message_post( p.move_raw_ids and not p.workorder_ids)).action_confirm()
# body=_('This production order has been created from Replenishment Report.'), # 处理 根据制造订单生成的采购单坯料入库时到原材料库,手动将原材料位置该为坯料存货区
# message_type='comment', for production in productions:
# subtype_xmlid='mail.mt_note') if production.picking_ids:
# elif orderpoint: product_type_id = production.picking_ids[0].move_ids[0].product_id.categ_id
# production.message_post_with_view( if product_type_id.name == '坯料':
# 'mail.message_origin_link', location_id = self.env['stock.location'].search([('name', '=', '坯料存货区')])
# values={'self': production, 'origin': orderpoint}, if not location_id:
# subtype_id=self.env.ref('mail.mt_note').id) logging.info(f'没有搜索到【坯料存货区】: {location_id}')
# elif origin_production: break
# production.message_post_with_view( for picking_id in production.picking_ids:
# 'mail.message_origin_link', if picking_id.picking_type_id.name == '内部调拨':
# values={'self': production, 'origin': origin_production}, if picking_id.location_dest_id.product_type != product_type_id:
# subtype_id=self.env.ref('mail.mt_note').id) picking_id.location_dest_id = location_id.id
elif picking_id.picking_type_id.name == '生产发料':
if picking_id.location_id.product_type != product_type_id:
picking_id.location_id = location_id.id
# ''' for production in productions:
# 创建生产计划 '''
# ''' 创建制造订单时生成序列号
# # 工单耗时 '''
# workorder_duration = 0 production.action_generate_serial()
# for workorder in production.workorder_ids: origin_production = production.move_dest_ids and production.move_dest_ids[
# workorder_duration += workorder.duration_expected 0].raw_material_production_id or False
orderpoint = production.orderpoint_id
if orderpoint and orderpoint.create_uid.id == SUPERUSER_ID and orderpoint.trigger == 'manual':
production.message_post(
body=_('This production order has been created from Replenishment Report.'),
message_type='comment',
subtype_xmlid='mail.mt_note')
elif orderpoint:
production.message_post_with_view(
'mail.message_origin_link',
values={'self': production, 'origin': orderpoint},
subtype_id=self.env.ref('mail.mt_note').id)
elif origin_production:
production.message_post_with_view(
'mail.message_origin_link',
values={'self': production, 'origin': origin_production},
subtype_id=self.env.ref('mail.mt_note').id)
# sale_order = self.env['sale.order'].sudo().search([('name', '=', production.origin)]) '''
# if sale_order: 创建生产计划
# # sale_order.write({'schedule_status': 'to schedule'}) '''
# self.env['sf.production.plan'].sudo().with_company(company_id).create({ # 工单耗时
# 'name': production.name, workorder_duration = 0
# 'order_deadline': sale_order.deadline_of_delivery, for workorder in production.workorder_ids:
# 'production_id': production.id, workorder_duration += workorder.duration_expected
# 'date_planned_start': production.date_planned_start,
# 'origin': production.origin,
# 'product_qty': production.product_qty,
# 'product_id': production.product_id.id,
# 'state': 'draft',
# })
# technology_design_values = []
# all_production = productions
# grouped_product_ids = {k: list(g) for k, g in groupby(all_production, key=lambda x: x.product_id.id)}
# # 初始化一个字典来存储每个product_id对应的生产订单名称列表
# product_id_to_production_names = {}
# # 对于每个product_id获取其所有生产订单的名称
# for product_id, all_production in grouped_product_ids.items():
# # 为同一个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)],
# # limit=1, order='id asc')
# if production_item.product_id.id in product_id_to_production_names:
# if production_item.product_id.model_process_parameters_ids:
# is_purchase = False
# sorted_process_parameters = sorted(production_item.product_id.model_process_parameters_ids,
# key=lambda w: w.id)
# consecutive_process_parameters = [] sale_order = self.env['sale.order'].sudo().search([('name', '=', production.origin)])
# m = 0 if sale_order:
# for i in range(len(sorted_process_parameters) - 1): # sale_order.write({'schedule_status': 'to schedule'})
# if m == 0: self.env['sf.production.plan'].sudo().with_company(company_id).create({
# is_purchase = False 'name': production.name,
# if self.env['product.template']._get_process_parameters_product( 'order_deadline': sale_order.deadline_of_delivery,
# sorted_process_parameters[i]).partner_id == self.env[ 'production_id': production.id,
# 'product.template']._get_process_parameters_product(sorted_process_parameters[ 'date_planned_start': production.date_planned_start,
# i + 1]).partner_id and \ 'origin': production.origin,
# sorted_process_parameters[i].gain_way == '外协': 'product_qty': production.product_qty,
# if sorted_process_parameters[i] not in consecutive_process_parameters: 'product_id': production.product_id.id,
# consecutive_process_parameters.append(sorted_process_parameters[i]) 'state': 'draft',
# consecutive_process_parameters.append(sorted_process_parameters[i + 1]) })
# m += 1 technology_design_values = []
# continue all_production = productions
# else: grouped_product_ids = {k: list(g) for k, g in groupby(all_production, key=lambda x: x.product_id.id)}
# if m == len(consecutive_process_parameters) - 1 and m != 0: # 初始化一个字典来存储每个product_id对应的生产订单名称列表
# self.env['purchase.order'].get_purchase_order(consecutive_process_parameters, product_id_to_production_names = {}
# production_item, # 对于每个product_id获取其所有生产订单的名称
# product_id_to_production_names) for product_id, all_production in grouped_product_ids.items():
# if sorted_process_parameters[i] in consecutive_process_parameters: # 为同一个product_id创建一个生产订单名称列表
# is_purchase = True product_id_to_production_names[product_id] = [production.name for production in all_production]
# consecutive_process_parameters = [] for production_item in productions:
# m = 0 production_programming = self.env['mrp.production'].search(
# # 当前面的连续外协采购单生成再生成当前外协采购单 [('product_id.id', '=', production_item.product_id.id),
# if is_purchase is False: ('origin', '=', production_item.origin)],
# self.env['purchase.order'].get_purchase_order(consecutive_process_parameters, limit=1, order='id asc')
# production_item, if production_item.product_id.id in product_id_to_production_names:
# product_id_to_production_names) # 同一个产品多个制造订单对应一个编程单和模型库
# if m == len(consecutive_process_parameters) - 1 and m != 0: # 只调用一次fetchCNC并将所有生产订单的名称作为字符串传递
# self.env['purchase.order'].get_purchase_order(consecutive_process_parameters, if not production_item.programming_no and production.production_type == '自动化产线加工':
# production_item, if not production_programming.programming_no:
# product_id_to_production_names) production_item.fetchCNC(
# if sorted_process_parameters[i] in consecutive_process_parameters: ', '.join(product_id_to_production_names[production_item.product_id.id]))
# is_purchase = True else:
# consecutive_process_parameters = [] production_item.write({'programming_no': production_programming.programming_no,
# m = 0 'programming_state': '编程中'})
# if m == len(consecutive_process_parameters) - 1 and m != 0: if not technology_design_values:
# self.env['purchase.order'].get_purchase_order(consecutive_process_parameters, i = 0
# production_item, if production_item.product_id.categ_id.type == '成品':
# product_id_to_production_names) # 根据加工面板的面数及成品工序模板生成工序设计
# if is_purchase is False and m == 0:
# if len(sorted_process_parameters) == 1:
# self.env['purchase.order'].get_purchase_order(sorted_process_parameters,
# production_item,
# product_id_to_production_names)
# else:
# self.env['purchase.order'].get_purchase_order(sorted_process_parameters[i],
# production_item,
# product_id_to_production_names)
# if not technology_design_values:
# if production.product_id.categ_id.type == '成品':
# production.product_id.model_processing_panel = 'ZM,FM'
# # 根据加工面板的面数及成品工序模板生成工序设计
# i = 0
# for k in (production.product_id.model_processing_panel.split(',')):
# product_routing_workcenter = self.env['sf.product.model.type.routing.sort'].search(
# [('product_model_type_id', '=', production.product_id.product_model_type_id.id)],
# order='sequence asc'
# )
# for route in product_routing_workcenter:
# i += 1
# technology_design_values.append(
# self.env['sf.technology.design'].json_technology_design_str(k, route, i))
# surface_technics_arr = []
# route_workcenter_arr = []
# for process_param in production.product_id.product_model_type_id.surface_technics_routing_tmpl_ids.filtered(
# lambda st: st.id in production.product_id.model_process_parameters_ids.ids):
# # if item.route_workcenter_id.surface_technics_id.id:
# # for process_param in production.product_id.model_process_parameters_ids:
# logging.info('process_param:%s%s' % (process_param.id, process_param.name))
# if item.route_workcenter_id.surface_technics_id == process_param.process_id:
# logging.info(
# 'surface_technics_id:%s%s' % (
# item.route_workcenter_id.surface_technics_id.id,
# item.route_workcenter_id.surface_technics_id.name))
# surface_technics_arr.append(
# item.route_workcenter_id.surface_technics_id.id)
# route_workcenter_arr.append(item.route_workcenter_id.id)
# if surface_technics_arr:
# production_process = self.env['sf.production.process'].search(
# [('id', 'in', surface_technics_arr)],
# order='sequence asc'
# )
# for p in production_process:
# logging.info('production_process:%s' % p.name)
# process_parameter = production.product_id.model_process_parameters_ids.filtered(
# lambda pm: pm.process_id.id == p.id)
# product_production_process = self.env['product.template'].search(
# [('server_product_process_parameters_id', '=',
# process_parameter.id)])
# if process_parameter:
# i += 1
# route_production_process = self.env[
# 'mrp.routing.workcenter'].search(
# [('surface_technics_id', '=', p.id),
# ('id', 'in', route_workcenter_arr)])
# technology_design_values.append(
# self.env['sf.technology.design'].json_technology_design_str(k,
# route_production_process,
# product_production_process,
# i))
# productions.technology_design_ids = technology_design_values
# # # 同一个产品多个制造订单对应一个编程单和模型库 for k in (production_item.product_id.model_processing_panel.split(',')):
# # # 只调用一次fetchCNC并将所有生产订单的名称作为字符串传递 if production_item.production_type == '自动化产线加工':
# # if not production_item.programming_no: product_routing_workcenter = self.env['sf.product.model.type.routing.sort'].search(
# # if not production_programming.programming_no: [('product_model_type_id', '=', production_item.product_id.product_model_type_id.id)],
# # production_item.fetchCNC( order='sequence asc'
# # ', '.join(product_id_to_production_names[production_item.product_id.id])) )
# # else: else:
# # production_item.write({'programming_no': production_programming.programming_no, product_routing_workcenter = self.env['sf.manual.product.model.type.routing.sort'].search(
# # 'programming_state': '编程中'}) [('manual_product_model_type_id', '=', production_item.product_id.product_model_type_id.id)],
# return True order='sequence asc'
)
for route in product_routing_workcenter:
i += 1
technology_design_values.append(
self.env['sf.technology.design'].json_technology_design_str(k, route, i, False))
elif production.product_id.categ_id.type == '坯料':
embryo_routing_workcenter = self.env['sf.embryo.model.type.routing.sort'].search(
[('embryo_model_type_id', '=', production_item.product_id.embryo_model_type_id.id)],
order='sequence asc'
)
for route_embryo in embryo_routing_workcenter:
i += 1
technology_design_values.append(
self.env['sf.technology.design'].json_technology_design_str(False, route_embryo, i,
False))
surface_technics_arr = []
route_workcenter_arr = []
for item in production_item.product_id.product_model_type_id.surface_technics_routing_tmpl_ids:
if item.route_workcenter_id.surface_technics_id.id:
for process_param in production_item.product_id.model_process_parameters_ids:
if item.route_workcenter_id.surface_technics_id == process_param.process_id:
surface_technics_arr.append(
item.route_workcenter_id.surface_technics_id.id)
route_workcenter_arr.append(item.route_workcenter_id.id)
if surface_technics_arr:
production_process = self.env['sf.production.process'].search(
[('id', 'in', surface_technics_arr)],
order='sequence asc'
)
for p in production_process:
logging.info('production_process:%s' % p.name)
process_parameter = production_item.product_id.model_process_parameters_ids.filtered(
lambda pm: pm.process_id.id == p.id)
if process_parameter:
i += 1
route_production_process = self.env[
'mrp.routing.workcenter'].search(
[('surface_technics_id', '=', p.id),
('id', 'in', route_workcenter_arr)])
technology_design_values.append(
self.env['sf.technology.design'].json_technology_design_str(False,
route_production_process,
i,
process_parameter))
productions.technology_design_ids = technology_design_values
return True
class ProductionLot(models.Model): class ProductionLot(models.Model):
@@ -659,17 +612,13 @@ class StockPicking(models.Model):
return '%s%s' % (rescode, num) return '%s%s' % (rescode, num)
def button_validate(self): def button_validate(self):
if self.picking_type_id.barcode == 'OCOUT':
move_out = self.env['stock.move'].search( move_out = self.env['stock.move'].search(
[('location_id', '=', self.env['stock.location'].search( [('location_id', '=', self.env['stock.location'].search(
[('barcode', 'ilike', 'WH-PREPRODUCTION')]).id), [('barcode', 'ilike', 'WH-PREPRODUCTION')]).id),
('location_dest_id', '=', self.env['stock.location'].search( ('location_dest_id', '=', self.env['stock.location'].search(
[('barcode', 'ilike', 'VL-SPOC')]).id), [('barcode', 'ilike', 'VL-SPOC')]).id),
('origin', '=', self.origin)]) ('origin', '=', self.origin)])
# if self.id == move_out.picking_id.id:
# if move_out.move_line_ids.workorder_id.state not in ['progress']:
# raise UserError(
# _('该出库单里源单据内的单号为%s的工单还未开始不能进行验证操作' % move_out.move_line_ids.workorder_id.name))
# 入库单验证
move_in = self.env['stock.move'].search( move_in = self.env['stock.move'].search(
[('location_dest_id', '=', self.env['stock.location'].search( [('location_dest_id', '=', self.env['stock.location'].search(
[('barcode', 'ilike', 'WH-PREPRODUCTION')]).id), [('barcode', 'ilike', 'WH-PREPRODUCTION')]).id),
@@ -683,7 +632,7 @@ class StockPicking(models.Model):
raise UserError( raise UserError(
_('该入库单对应的单号为%s的出库单还未完成,不能进行验证操作!' % move_out.picking_id.name)) _('该入库单对应的单号为%s的出库单还未完成,不能进行验证操作!' % move_out.picking_id.name))
res = super().button_validate() res = super().button_validate()
if res is True: if res is True and self.picking_type_id.barcode == 'OCIN':
if self.id == move_out.picking_id.id: if self.id == move_out.picking_id.id:
# if move_out.move_line_ids.workorder_id.state == 'progress': # if move_out.move_line_ids.workorder_id.state == 'progress':
move_in = self.env['stock.move'].search( move_in = self.env['stock.move'].search(
@@ -701,12 +650,15 @@ class StockPicking(models.Model):
# 创建 外协出库入单 # 创建 外协出库入单
def create_outcontract_picking(self, sorted_workorders_arr, item): def create_outcontract_picking(self, sorted_workorders_arr, item):
m = 0 if len(sorted_workorders_arr) > 1:
sorted_workorders_arr = sorted_workorders_arr[0]
stock_picking = self.env['stock.picking'].search(
[('origin', '=', sorted_workorders_arr.production_id.name), ('name', 'ilike', 'OCOUT')])
if not stock_picking:
for sorted_workorders in sorted_workorders_arr: for sorted_workorders in sorted_workorders_arr:
# pick_ids = [] # pick_ids = []
if m == 0: if not sorted_workorders.picking_ids:
outcontract_stock_move = self.env['stock.move'].search( outcontract_stock_move = self.env['stock.move'].search([('production_id', '=', item.id)])
[('workorder_id', '=', sorted_workorders.id), ('production_id', '=', item.id)])
if not outcontract_stock_move: if not outcontract_stock_move:
new_picking = True new_picking = True
location_id = self.env['stock.location'].search( location_id = self.env['stock.location'].search(
@@ -724,7 +676,7 @@ class StockPicking(models.Model):
moves_out._get_new_picking_values_Res(item, sorted_workorders, 'WH/OCOUT/')) moves_out._get_new_picking_values_Res(item, sorted_workorders, 'WH/OCOUT/'))
# pick_ids.append(picking_out.id) # pick_ids.append(picking_out.id)
moves_out.write( moves_out.write(
{'picking_id': picking_out.id, 'state': 'waiting', 'workorder_id': sorted_workorders.id}) {'picking_id': picking_out.id, 'state': 'waiting'})
moves_out._assign_picking_post_process(new=new_picking) moves_out._assign_picking_post_process(new=new_picking)
moves_in = self.env['stock.move'].sudo().create( moves_in = self.env['stock.move'].sudo().create(
self.env['stock.move']._get_stock_move_values_Res(item, location_id, location_dest_id, self.env['stock.move']._get_stock_move_values_Res(item, location_id, location_dest_id,
@@ -733,10 +685,8 @@ class StockPicking(models.Model):
moves_in._get_new_picking_values_Res(item, sorted_workorders, 'WH/OCIN/')) moves_in._get_new_picking_values_Res(item, sorted_workorders, 'WH/OCIN/'))
# pick_ids.append(picking_in.id) # pick_ids.append(picking_in.id)
moves_in.write( moves_in.write(
{'picking_id': picking_in.id, 'state': 'waiting', 'workorder_id': sorted_workorders.id}) {'picking_id': picking_in.id, 'state': 'waiting'})
moves_in._assign_picking_post_process(new=new_picking) moves_in._assign_picking_post_process(new=new_picking)
m += 1
# sorted_workorders.write({'picking_ids': [(6, 0, pick_ids)]})
class ReStockMove(models.Model): class ReStockMove(models.Model):
@@ -772,7 +722,7 @@ class ReStockMove(models.Model):
return { return {
'name': self.env['stock.picking']._get_name_Res(rescode), 'name': self.env['stock.picking']._get_name_Res(rescode),
'origin': item.name, 'origin': item.name,
'surface_technics_parameters_id': sorted_workorders.surface_technics_parameters_id.id, # 'surface_technics_parameters_id': sorted_workorders.surface_technics_parameters_id.id,
'company_id': self.mapped('company_id').id, 'company_id': self.mapped('company_id').id,
'user_id': False, 'user_id': False,
'move_type': self.mapped('group_id').move_type or 'direct', 'move_type': self.mapped('group_id').move_type or 'direct',
@@ -793,7 +743,7 @@ class ReStockMove(models.Model):
'picking_id': self.picking_id.id, 'picking_id': self.picking_id.id,
'reserved_uom_qty': 1.0, 'reserved_uom_qty': 1.0,
'lot_id': production_id.move_line_raw_ids.lot_id.id, 'lot_id': production_id.move_line_raw_ids.lot_id.id,
'company_id': self.company_id.id, 'company_id': self.env.company.id,
# 'workorder_id': '' if not sorted_workorders else sorted_workorders.id, # 'workorder_id': '' if not sorted_workorders else sorted_workorders.id,
# 'production_id': '' if not sorted_workorders else sorted_workorders.production_id.id, # 'production_id': '' if not sorted_workorders else sorted_workorders.production_id.id,
'state': 'assigned', 'state': 'assigned',
@@ -842,7 +792,6 @@ class ReStockMove(models.Model):
elif self.product_id.tracking == "lot": elif self.product_id.tracking == "lot":
self._put_tool_lot(self.company_id, self.product_id, self.origin) self._put_tool_lot(self.company_id, self.product_id, self.origin)
return { return {
'name': _('Detailed Operations'), 'name': _('Detailed Operations'),
'type': 'ir.actions.act_window', 'type': 'ir.actions.act_window',
@@ -992,6 +941,11 @@ class ReStockMove(models.Model):
qty_by_location[loc.id] += 1 qty_by_location[loc.id] += 1
return move_lines_commands 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): class ReStockQuant(models.Model):
_inherit = 'stock.quant' _inherit = 'stock.quant'

View File

@@ -171,6 +171,9 @@ access_sf_technology_design_group_production_engineer,sf_technology_design_group
access_sf_production_technology_wizard_group_plan_dispatch,sf_production_technology_wizard_group_plan_dispatch,model_sf_production_technology_wizard,sf_base.group_plan_dispatch,1,1,1,0 access_sf_production_technology_wizard_group_plan_dispatch,sf_production_technology_wizard_group_plan_dispatch,model_sf_production_technology_wizard,sf_base.group_plan_dispatch,1,1,1,0
access_sf_production_technology_wizard_group_sf_mrp_manager,sf_production_technology_wizard_group_sf_mrp_manager,model_sf_production_technology_wizard,sf_base.group_sf_mrp_manager,1,1,1,0 access_sf_production_technology_wizard_group_sf_mrp_manager,sf_production_technology_wizard_group_sf_mrp_manager,model_sf_production_technology_wizard,sf_base.group_sf_mrp_manager,1,1,1,0
access_sf_production_technology_wizard_group_production_engineer,sf_production_technology_wizard_group_production_engineer,model_sf_production_technology_wizard,sf_base.group_production_engineer,1,1,1,0 access_sf_production_technology_wizard_group_production_engineer,sf_production_technology_wizard_group_production_engineer,model_sf_production_technology_wizard,sf_base.group_production_engineer,1,1,1,0
access_sf_production_technology_re_adjust_wizard_group_plan_dispatch,sf_production_technology_re_adjust_wizard_group_plan_dispatch,model_sf_production_technology_re_adjust_wizard,sf_base.group_plan_dispatch,1,1,1,0
access_sf_production_technology_re_adjust_wizard_group_sf_mrp_manager,sf_production_technology_re_adjust_wizard_group_sf_mrp_manager,model_sf_production_technology_re_adjust_wizard,sf_base.group_sf_mrp_manager,1,1,1,0
access_sf_production_technology_re_adjust_wizard_group_production_engineer,sf_production_technology_re_adjust_wizard_group_production_engineer,model_sf_production_technology_re_adjust_wizard,sf_base.group_production_engineer,1,1,1,0
access_sf_manual_product_model_type_routing_sort_group_sf_mrp_user,sf_manual_product_model_type_routing_sort,model_sf_manual_product_model_type_routing_sort,sf_base.group_sf_mrp_user,1,0,0,0 access_sf_manual_product_model_type_routing_sort_group_sf_mrp_user,sf_manual_product_model_type_routing_sort,model_sf_manual_product_model_type_routing_sort,sf_base.group_sf_mrp_user,1,0,0,0
access_sf_manual_product_model_type_routing_sort_manager,sf_manual_product_model_type_routing_sort,model_sf_manual_product_model_type_routing_sort,sf_base.group_sf_mrp_manager,1,1,1,0 access_sf_manual_product_model_type_routing_sort_manager,sf_manual_product_model_type_routing_sort,model_sf_manual_product_model_type_routing_sort,sf_base.group_sf_mrp_manager,1,1,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
171
172
173
174
175
176
177
178
179

View File

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

View File

@@ -35,10 +35,10 @@
<field name="reservation_state" optional="hide" decoration-danger="reservation_state == 'confirmed'" <field name="reservation_state" optional="hide" decoration-danger="reservation_state == 'confirmed'"
decoration-success="reservation_state == 'assigned'"/> decoration-success="reservation_state == 'assigned'"/>
</xpath> </xpath>
<!-- <xpath expr="//field[@name='state']" position="before"> <xpath expr="//field[@name='state']" position="before">
<field name="production_type" widget="badge" decoration-warning="production_type == '人工线下加工'" <field name="production_type" widget="badge" decoration-warning="production_type == '人工线下加工'"
decoration-success="production_type == '自动化产线加工'" optional="show"/> decoration-success="production_type == '自动化产线加工'" optional="show"/>
</xpath> --> </xpath>
<xpath expr="//field[@name='activity_ids']" position="replace"> <xpath expr="//field[@name='activity_ids']" position="replace">
<field name="activity_ids" string="下一个活动" widget="list_activity" optional="hide"/> <field name="activity_ids" string="下一个活动" widget="list_activity" optional="hide"/>
</xpath> </xpath>
@@ -91,10 +91,13 @@
</xpath> </xpath>
<xpath expr="//sheet//group//group//div[3]" position="after"> <xpath expr="//sheet//group//group//div[3]" position="after">
<!-- <field name="production_type" readonly="1"/> --> <field name="production_type" readonly="1"/>
<field name="manual_quotation" readonly="1"/> <field name="manual_quotation" readonly="1"
<field name="programming_no" readonly="1"/> attrs="{'invisible': [('production_type', 'not in', ['自动化产线加工'])]}"/>
<field name="programming_no" readonly="1"
attrs="{'invisible': [('production_type', 'not in', ['自动化产线加工'])]}"/>
<field name="programming_state" readonly="1" <field name="programming_state" readonly="1"
attrs="{'invisible': [('production_type', 'not in', ['自动化产线加工'])]}"
decoration-success="programming_state == '已编程'" decoration-success="programming_state == '已编程'"
decoration-warning="programming_state =='编程中'" decoration-warning="programming_state =='编程中'"
decoration-danger="programming_state =='已编程未下发'"/> decoration-danger="programming_state =='已编程未下发'"/>
@@ -127,20 +130,18 @@
string="验证" type="object" class="oe_highlight" string="验证" type="object" class="oe_highlight"
confirm="There are no components to consume. Are you still sure you want to continue?" confirm="There are no components to consume. Are you still sure you want to continue?"
data-hotkey="g" groups="sf_base.group_sf_mrp_user"/> data-hotkey="g" groups="sf_base.group_sf_mrp_user"/>
<button name="technology_confirm" string="工艺确认" type="object" class="oe_highlight"
attrs="{'invisible': ['|', '|', ('state', 'in', ('draft', 'cancel', 'done', 'to_close')), ('qty_producing', '=', 0), ('move_raw_ids', '!=', [])]}"></button>
</xpath> </xpath>
<xpath expr="(//header//button[@name='button_mark_done'])[2]" position="replace"> <xpath expr="(//header//button[@name='button_mark_done'])[2]" position="replace">
<button name="button_mark_done" <button name="button_mark_done"
attrs="{'invisible': ['|', '|', ('state', 'in', ('draft', 'cancel', 'done', 'to_close')), ('qty_producing', '=', 0), ('move_raw_ids', '=', [])]}" attrs="{'invisible': ['|', '|', ('state', 'in', ('draft', 'cancel', 'done', 'to_close')), ('qty_producing', '=', 0), ('move_raw_ids', '=', [])]}"
string="验证" type="object" data-hotkey="g" string="验证" type="object" data-hotkey="g"
groups="sf_base.group_sf_mrp_user"/> groups="sf_base.group_sf_mrp_user"/>
<button name="technology_confirm" string="工艺确认" type="object" class="oe_highlight"
attrs="{'invisible': ['|', '|', ('state', 'in', ('draft', 'cancel', 'done', 'to_close')), ('qty_producing', '=', 0), ('move_raw_ids', '=', [])]}"
></button>
</xpath> </xpath>
<xpath expr="(//header//button[@name='button_scrap'])" position="replace"> <xpath expr="(//header//button[@name='button_scrap'])" position="replace">
<button name="technology_confirm" string="工艺确认" type="object" class="oe_highlight"
attrs="{'invisible': [('workorder_ids', '!=', [])]}"></button>
<button name="technology_back_adjust" string="退回调整" type="object" class="oe_highlight"
attrs="{'invisible': [('state', '!=', 'confirmed')]}"></button>
<button name="button_scrap" invisible="1"/> <button name="button_scrap" invisible="1"/>
<button name="do_update_program" string="更新程序" type="object" groups="sf_base.group_sf_mrp_user" <button name="do_update_program" string="更新程序" type="object" groups="sf_base.group_sf_mrp_user"
confirm="是否确认更新程序" confirm="是否确认更新程序"
@@ -310,8 +311,7 @@
</xpath> </xpath>
<xpath expr="//sheet//notebook//page[@name='operations']" position="attributes"> <xpath expr="//sheet//notebook//page[@name='operations']" position="attributes">
<attribute name="attrs">{'invisible': ['|',('schedule_state', '=', '未排'),('workorder_ids', '=', <attribute name="attrs">{'invisible': [('workorder_ids', '=', [])]}
[])]}
</attribute> </attribute>
</xpath> </xpath>
@@ -352,23 +352,20 @@
<field name="part_drawing" widget="adaptive_viewer"/> <field name="part_drawing" widget="adaptive_viewer"/>
</page> </page>
</xpath> </xpath>
<xpath expr="//sheet//notebook" position="inside"> <xpath expr="//sheet//notebook//page[@name='components']" position="before">
<page string="质检标准">
<field name="quality_standard" widget="adaptive_viewer"/>
</page>
<page string="工艺设计"> <page string="工艺设计">
<field name="technology_design_ids" widget="one2many"> <field name="technology_design_ids" widget="one2many">
<tree editable="bottom"> <tree editable="bottom">
<field name="sequence" widget="handle"/> <field name="sequence" widget="handle"/>
<field name="route_id" context="{'production_id': production_id}" <field name="route_id" context="{'production_id': production_id}"
attrs="{'readonly': [('is_auto', '=', True)]}" options="{'no_create': True}"/> attrs="{'readonly': [('id', '!=', False)]}" options="{'no_create': True}"/>
<field name="process_parameters_id" attrs="{'readonly': [('is_auto', '=', True)]}" <field name="process_parameters_id" attrs="{'readonly': [('id', '!=', False)]}"
string="参数" context="{'route_id':route_id}" options="{'no_create': True}"/> string="参数" context="{'route_id':route_id}" options="{'no_create': True}"/>
<field name="panel" readonly="1"/> <field name="panel" readonly="1"/>
<field name="routing_tag" readonly="1" widget="badge" <field name="routing_tag" readonly="1" widget="badge"
decoration-success="routing_tag == 'standard'" decoration-success="routing_tag == 'standard'"
decoration-warning="routing_tag == 'special'"/> decoration-warning="routing_tag == 'special'"/>
<field name="time_cycle_manual" attrs="{'readonly': [('is_auto', '=', True)]}"/> <field name="time_cycle_manual" attrs="{'readonly': [('id', '!=', False)]}"/>
<field name="is_auto" invisible="1"/> <field name="is_auto" invisible="1"/>
<field name="production_id" invisible="1"/> <field name="production_id" invisible="1"/>
<button name="unlink_technology_design" confirm="是否确认删除?" class="oe_highlight" <button name="unlink_technology_design" confirm="是否确认删除?" class="oe_highlight"
@@ -378,6 +375,12 @@
</field> </field>
</page> </page>
</xpath> </xpath>
<xpath expr="//sheet//notebook" position="inside">
<page string="质检标准">
<field name="quality_standard" widget="adaptive_viewer"/>
</page>
</xpath>
</field> </field>
</record> </record>

View File

@@ -2,3 +2,4 @@ from . import workpiece_delivery_wizard
from . import rework_wizard from . import rework_wizard
from . import production_wizard from . import production_wizard
from . import production_technology_wizard from . import production_technology_wizard
from . import production_technology_re_adjust_wizard

View File

@@ -0,0 +1,110 @@
# -*- coding: utf-8 -*-
import logging
from itertools import groupby
from odoo import models, api, fields, _
class ProductionTechnologyReAdjustWizard(models.TransientModel):
_name = 'sf.production.technology.re_adjust.wizard'
_description = '制造订单工艺调整'
production_id = fields.Many2one('mrp.production', string='制造订单号')
origin = fields.Char(string='源单据')
is_technology_re_adjust = fields.Boolean(default=False)
def confirm(self):
if self.is_technology_re_adjust is True:
domain = [('origin', '=', self.origin), ('state', '=', 'confirmed')]
else:
domain = [('id', '=', self.production_id.id)]
technology_designs = self.env['sf.technology.design'].sudo().search(
[('production_id', '=', self.production_id.id), ('active', 'in', [True, False])])
productions = self.env['mrp.production'].search(domain)
for production_item in productions:
# 该制造订单的其他同一销售订单的制造订单的工艺设计处理
if production_item != self.production_id:
for td_other in production_item.technology_design_ids:
if td_other.is_auto is False:
td_del = technology_designs.filtered(lambda tdo: tdo.route_id.id == td_other.route_id.id)
if not td_del or td_del.active is False:
td_other.write({'active': False})
for td_main in technology_designs:
route_other = production_item.technology_design_ids.filtered(
lambda td: td.route_id.id == td_main.route_id.id)
if not route_other and td_main.active is True:
production_item.write({'technology_design_ids': [(0, 0, {
'route_id': td_main.route_id.id,
'process_parameters_id': False if td_main.process_parameters_id is False else
self.env[
'sf.production.process.parameter'].search(
[('id', '=', td_main.process_parameters_id.id)]).id,
'sequence': td_main.sequence,
'is_auto': td_main.is_auto})]})
else:
for ro in route_other:
domain = [('production_id', '=', self.production_id.id), ('active', 'in', [True, False]),
('route_id', '=', ro.route_id.id)]
if ro.route_id.routing_type == '表面工艺':
domain += [('process_parameters_id', '=', ro.process_parameters_id.id)]
elif ro.route_id.routing_tag == 'special' and ro.is_auto is False:
display_name = ro.route_id.display_name
domain += [('name', 'ilike', display_name)]
elif ro.panel is not False:
domain += [('panel', '=', ro.panel)]
td_upd = self.env['sf.technology.design'].sudo().search(domain)
if td_upd:
ro.write({'sequence': td_upd.sequence, 'active': td_upd.active})
special_design = self.env['sf.technology.design'].sudo().search(
[('routing_tag', '=', 'special'), ('production_id', '=', production_item.id),
('is_auto', '=', False), ('active', 'in', [True, False])])
for special in special_design:
workorders_values = []
if special.active is False:
# 工单采购单外协出入库单皆需取消
domain = [('production_id', '=', special.production_id.id)]
if special.process_parameters_id:
domain += [('surface_technics_parameters_id', '=', special.process_parameters_id.id)]
else:
domain += [('name', '=', special.route_id.name)]
workorder = self.env['mrp.workorder'].search(domain)
if workorder.state != 'cancel':
workorder.write({'state': 'cancel'})
workorder.picking_ids.write({'state': 'cancel'})
workorder.picking_ids.move_ids.write({'state': 'cancel'})
purchase_order = self.env['purchase.order'].search(
[('origin', '=', workorder.production_id.origin)])
for line in purchase_order.order_line:
if line.product_id.server_product_process_parameters_id == workorder.surface_technics_parameters_id:
purchase_order.write({'state': 'cancel'})
else:
if special.route_id.routing_type == '表面工艺':
display_name = special.process_parameters_id.display_name
else:
display_name = special.route_id.display_name
workorder = self.env['mrp.workorder'].search(
[('name', '=', display_name), ('production_id', '=', special.production_id.id)])
if not workorder:
if special.route_id.routing_type == '表面工艺':
product_production_process = self.env['product.template'].search(
[('server_product_process_parameters_id', '=', special.process_parameters_id.id)])
workorders_values.append(
self.env[
'mrp.workorder']._json_workorder_surface_process_str(special.production_id, special,
product_production_process.seller_ids[
0].partner_id.id))
else:
workorders_values.append(
self.env['mrp.workorder'].json_workorder_str(special.production_id, special))
special.production_id.write({'workorder_ids': workorders_values})
else:
if len(workorder.blocked_by_workorder_ids) > 1:
if workorder.sequence == 1:
workorder.blocked_by_workorder_ids = None
else:
workorder.blocked_by_workorder_ids = blocked_by_workorder_ids[0]
productions._reset_work_order_sequence()
productions.get_subcontract_pick_purchase()
for item in productions:
workorders = item.workorder_ids.filtered(lambda wo: wo.state not in ('cancel')).sorted(
key=lambda a: a.sequence)
workorders[0].state = 'waiting'

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="ir.ui.view" id="sf_production_technology_re_adjust_wizard_form_view">
<field name="name">sf.production.technology.re_adjust.wizard.form.view</field>
<field name="model">sf.production.technology.re_adjust.wizard</field>
<field name="arch" type="xml">
<form>
<sheet>
<field name="production_id" invisible="1"/>
<field name="origin" invisible="1"/>
<div>
<field name="is_technology_re_adjust" force_save="1"/>
当前制造订单,同一销售订单相同产品所生成的制造订单是否统一进行退回调整操作
</div>
<footer>
<button string="确认" name="confirm" type="object" class="oe_highlight" confirm="是否确认退回调整"/>
<button string="取消" class="btn btn-secondary" special="cancel"/>
</footer>
</sheet>
</form>
</field>
</record>
<record id="action_sf_production_technology_re_adjust_wizard" model="ir.actions.act_window">
<field name="name">工艺退回调整</field>
<field name="res_model">sf.production.technology.re_adjust.wizard</field>
<field name="view_mode">form</field>
<!-- <field name="context">{-->
<!-- 'default_production_id': active_id}-->
<!-- </field>-->
<field name="target">new</field>
</record>
</odoo>

View File

@@ -1,10 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Part of YiZuo. See LICENSE file for full copyright and licensing details. # Part of YiZuo. See LICENSE file for full copyright and licensing details.
import logging import logging
from odoo.exceptions import UserError, ValidationError from itertools import groupby
from collections import defaultdict, namedtuple
from odoo.addons.stock.models.stock_rule import ProcurementException
from datetime import datetime
from odoo import models, api, fields, _ from odoo import models, api, fields, _
@@ -21,5 +18,47 @@ class ProductionTechnologyWizard(models.TransientModel):
domain = [('origin', '=', self.origin)] domain = [('origin', '=', self.origin)]
else: else:
domain = [('id', '=', self.production_id.id)] domain = [('id', '=', self.production_id.id)]
technology_designs = self.production_id.technology_design_ids
productions = self.env['mrp.production'].search(domain) productions = self.env['mrp.production'].search(domain)
productions._create_workorder(self.production_id) for production in productions:
if production != self.production_id:
for td_other in production.technology_design_ids:
if td_other.is_auto is False:
td_del = technology_designs.filtered(lambda tdo: tdo.route_id.id == td_other.route_id.id)
if not td_del or td_del.active is False:
td_other.write({'active': False})
for td_main in technology_designs:
route_other = production.technology_design_ids.filtered(
lambda td: td.route_id.id == td_main.route_id.id)
if not route_other and td_main.active is True:
production.write({'technology_design_ids': [(0, 0, {
'route_id': td_main.route_id.id,
'process_parameters_id': False if td_main.process_parameters_id is False else self.env[
'sf.production.process.parameter'].search(
[('id', '=', td_main.process_parameters_id.id)]).id,
'sequence': td_main.sequence})]})
else:
for ro in route_other:
domain = [('production_id', '=', self.production_id.id),
('active', 'in', [True, False]),
('route_id', '=', ro.route_id.id)]
if ro.route_id.routing_type == '表面工艺':
domain += [('process_parameters_id', '=', ro.process_parameters_id.id)]
elif ro.route_id.routing_tag == 'special' and ro.is_auto is False:
display_name = ro.route_id.display_name
domain += [('name', 'ilike', display_name)]
elif ro.panel is not False:
domain += [('panel', '=', ro.panel)]
td_upd = self.env['sf.technology.design'].sudo().search(domain)
if td_upd:
ro.write({'sequence': td_upd.sequence, 'active': td_upd.active})
# special = production.technology_design_ids.filtered(
# lambda td: td.is_auto is False and td.process_parameters_id is not False)
# # if special:
productions._create_workorder(False)
productions.get_subcontract_pick_purchase()
for item in productions:
workorder = item.workorder_ids.filtered(lambda wo: wo.state not in ('cancel')).sorted(
key=lambda a: a.sequence)
if workorder[0].state in ['pending']:
workorder[0].state = 'waiting'

View File

@@ -28,6 +28,8 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController):
domain = [('programming_no', '=', ret['programming_no'])] domain = [('programming_no', '=', ret['programming_no'])]
if ret['manufacturing_type'] in ('scrap', 'invalid_tool_rework'): if ret['manufacturing_type'] in ('scrap', 'invalid_tool_rework'):
domain += [('state', 'not in', ['done', 'scrap', 'cancel'])] domain += [('state', 'not in', ['done', 'scrap', 'cancel'])]
else:
domain += [('state', '=', 'confirmed')]
productions = request.env['mrp.production'].with_user( productions = request.env['mrp.production'].with_user(
request.env.ref("base.user_admin")).search(domain) request.env.ref("base.user_admin")).search(domain)
if productions: if productions:
@@ -48,11 +50,6 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController):
res['message'] = '编程单号为%s的CNC程序文件从FTP拉取失败' % (ret['programming_no']) res['message'] = '编程单号为%s的CNC程序文件从FTP拉取失败' % (ret['programming_no'])
return json.JSONEncoder().encode(res) return json.JSONEncoder().encode(res)
for production in productions: for production in productions:
if not production.workorder_ids:
production.product_id.model_processing_panel = ret['processing_panel']
production._create_workorder(ret)
productions.process_range_time()
else:
for panel in ret['processing_panel'].split(','): for panel in ret['processing_panel'].split(','):
# 查询状态为进行中且工序类型为CNC加工的工单 # 查询状态为进行中且工序类型为CNC加工的工单
cnc_workorder_has = production.workorder_ids.filtered( cnc_workorder_has = production.workorder_ids.filtered(
@@ -77,7 +74,6 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController):
# program_path_tmp_panel = os.path.join('C://Users//43484//Desktop//fsdownload//test', # program_path_tmp_panel = os.path.join('C://Users//43484//Desktop//fsdownload//test',
# panel) # panel)
program_path_tmp_panel = os.path.join('/tmp', ret['folder_name'], 'return', panel) program_path_tmp_panel = os.path.join('/tmp', ret['folder_name'], 'return', panel)
logging.info('program_path_tmp_panel:%s' % program_path_tmp_panel)
files_panel = os.listdir(program_path_tmp_panel) files_panel = os.listdir(program_path_tmp_panel)
if files_panel: if files_panel:
for file in files_panel: for file in files_panel:
@@ -85,17 +81,13 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController):
if file_extension.lower() == '.pdf': if file_extension.lower() == '.pdf':
panel_file_path = os.path.join(program_path_tmp_panel, file) panel_file_path = os.path.join(program_path_tmp_panel, file)
logging.info('panel_file_path:%s' % panel_file_path) logging.info('panel_file_path:%s' % panel_file_path)
logging.info('更新工作指令:%s' % cnc_workorder)
cnc_workorder.write({'cnc_worksheet': base64.b64encode(open(panel_file_path, 'rb').read())}) cnc_workorder.write({'cnc_worksheet': base64.b64encode(open(panel_file_path, 'rb').read())})
logging.info('更新工作指令完成:%s' % cnc_workorder)
pre_workorder = productions.workorder_ids.filtered( pre_workorder = productions.workorder_ids.filtered(
lambda ap: ap.routing_type == '装夹预调' and ap.state not in ['done', 'rework' lambda ap: ap.routing_type == '装夹预调' and ap.state not in ['done', 'rework'
'cancel'] and ap.processing_panel == panel) 'cancel'] and ap.processing_panel == panel)
if pre_workorder: if pre_workorder:
logging.info('更新加工图纸:%s' % pre_workorder)
pre_workorder.write( pre_workorder.write(
{'processing_drawing': base64.b64encode(open(panel_file_path, 'rb').read())}) {'processing_drawing': base64.b64encode(open(panel_file_path, 'rb').read())})
logging.info('更新加工图纸完成:%s' % pre_workorder)
productions.write({'programming_state': '已编程', 'work_state': '已编程'}) productions.write({'programming_state': '已编程', 'work_state': '已编程'})
logging.info('已更新制造订单编程状态:%s' % productions.ids) logging.info('已更新制造订单编程状态:%s' % productions.ids)
res.update({ res.update({

View File

@@ -86,6 +86,8 @@ class ResConfigSettings(models.TransientModel):
_logger.info("同步刀具物料每齿走刀量完成") _logger.info("同步刀具物料每齿走刀量完成")
self.env['sf.machining.accuracy'].sync_machining_accuracy_all() self.env['sf.machining.accuracy'].sync_machining_accuracy_all()
_logger.info("同步加工精度完成") _logger.info("同步加工精度完成")
self.env['sf.embryo.redundancy'].sync_embryo_redundancy_all()
_logger.info("同步坯料冗余完成")
except Exception as e: except Exception as e:
_logger.info("sf_all_sync error: %s" % e) _logger.info("sf_all_sync error: %s" % e)

View File

@@ -76,6 +76,8 @@ class MrStaticResourceDataSync(models.Model):
_logger.info("同步刀具物料每齿走刀量完成") _logger.info("同步刀具物料每齿走刀量完成")
self.env['sf.machining.accuracy'].sync_machining_accuracy_all() self.env['sf.machining.accuracy'].sync_machining_accuracy_all()
_logger.info("同步加工精度完成") _logger.info("同步加工精度完成")
self.env['sf.embryo.redundancy'].sync_embryo_redundancy_all()
_logger.info("同步坯料冗余完成")
except Exception as e: except Exception as e:
traceback_error = traceback.format_exc() traceback_error = traceback.format_exc()
logging.error("同步静态资源库失败:%s" % traceback_error) logging.error("同步静态资源库失败:%s" % traceback_error)
@@ -3149,7 +3151,7 @@ class MachiningAccuracySync(models.Model):
r = requests.post(strUrl, json={}, data=None, headers=headers) r = requests.post(strUrl, json={}, data=None, headers=headers)
r = r.json() r = r.json()
result = json.loads(r['result']) result = json.loads(r['result'])
_logger.info('加工精度:%s' % result) # _logger.info('加工精度:%s' % result)
if result['status'] == 1: if result['status'] == 1:
machining_accuracy_all_list = result['machining_accuracy_all_list'] machining_accuracy_all_list = result['machining_accuracy_all_list']
# 获取同步的id集合 # 获取同步的id集合
@@ -3168,3 +3170,42 @@ class MachiningAccuracySync(models.Model):
"name": time['name'], "name": time['name'],
"standard_tolerance": time['standard_tolerance'], "standard_tolerance": time['standard_tolerance'],
}) })
class EmbryoRedundancySync(models.Model):
_inherit = 'sf.embryo.redundancy'
_description = '坯料冗余'
url = '/api/embryo_redundancy/list'
def sync_embryo_redundancy_all(self):
config = self.env['res.config.settings'].get_values()
headers = Common.get_headers(self, config['token'], config['sf_secret_key'])
strUrl = config['sf_url'] + self.url
r = requests.post(strUrl, json={}, data=None, headers=headers)
r = r.json()
result = json.loads(r['result'])
# _logger.info('加工精度:%s' % result)
if result['status'] == 1:
embryo_redundancy_all_list = result['embryo_redundancy_all_list']
# 获取同步的id集合
codes = [obj['code'] for obj in embryo_redundancy_all_list]
self.env['sf.embryo.redundancy'].sudo().search(
[('code', 'not in', codes)]).unlink()
for item in embryo_redundancy_all_list:
embryo_redundancy = self.env['sf.embryo.redundancy'].sudo().search(
[('code', '=', item['code'])])
if embryo_redundancy:
embryo_redundancy.name = item['name']
embryo_redundancy.code = item['code']
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'],
"code": item['code'],
"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 @api.model
def search_read(self, domain=None, fields=None, offset=0, limit=None, order=None): 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) info = super(sf_production_plan, self).search_read(domain, fields, offset, limit, order)
return info return info
@@ -417,12 +421,12 @@ class sf_production_plan(models.Model):
raise UserError(e) raise UserError(e)
# 增加制造订单类型 # 增加制造订单类型
# production_type = fields.Selection( production_type = fields.Selection(
# [('自动化产线加工', '自动化产线加工'), ('人工线下加工', '人工线下加工')], [('自动化产线加工', '自动化产线加工'), ('人工线下加工', '人工线下加工')],
# string='制造类型', string='制造类型',
# related='production_id.production_type', related='production_id.production_type',
# store=True store=True
# ) )
# 机台作业计划 # 机台作业计划
@@ -446,8 +450,12 @@ class MrpProductionInheritForPlan(models.Model):
def toggle_active(self): def toggle_active(self):
# 调用父类方法切换 active 状态 # 调用父类方法切换 active 状态
res = super(MrpProductionInheritForPlan, self).toggle_active() res = super(MrpProductionInheritForPlan, self).toggle_active()
stage_active = self.filtered('active')
stage_inactive = self - stage_active
self.env['sf.production.plan'].search( self.env['sf.production.plan'].search(
[('production_id', '=', self.id), '|', ('active', '=', False), ('active', '=', True)]).write( [('production_id', 'in', stage_active.ids)]).write(
{'active': self.active}) {'active': True})
self.env['sf.production.plan'].search(
[('production_id', 'in', stage_inactive.ids)]).write(
{'active': False})
return res return res

View File

@@ -22,7 +22,7 @@
<field name="production_line_id"/> <field name="production_line_id"/>
<field name="date_planned_start"/> <field name="date_planned_start"/>
<field name="date_planned_finished"/> <field name="date_planned_finished"/>
<!-- <field name="production_type" widget="badge" decoration-warning="production_type == '人工线下加工'" decoration-success="production_type == '自动化产线加工'"/> --> <field name="production_type" widget="badge" decoration-warning="production_type == '人工线下加工'" decoration-success="production_type == '自动化产线加工'"/>
<field name="actual_start_time" optional='hide'/> <field name="actual_start_time" optional='hide'/>
<field name="actual_end_time" optional='hide'/> <field name="actual_end_time" optional='hide'/>
<field name="actual_process_time" optional='hide'/> <field name="actual_process_time" optional='hide'/>

View File

@@ -133,7 +133,7 @@ class ReSaleOrder(models.Model):
'product_uom_qty': item['number'], 'product_uom_qty': item['number'],
'model_glb_file': base64.b64decode(item['model_file']), 'model_glb_file': base64.b64decode(item['model_file']),
'remark': item.get('remark'), 'remark': item.get('remark'),
'is_incoming_material': item.get('is_incoming_material'), 'embryo_redundancy_id': item.get('embryo_redundancy_id'),
'manual_quotation': item.get('manual_quotation') 'manual_quotation': item.get('manual_quotation')
} }
return self.env['sale.order.line'].with_context(skip_procurement=True).create(vals) return self.env['sale.order.line'].with_context(skip_procurement=True).create(vals)
@@ -175,7 +175,8 @@ class ResaleOrderLine(models.Model):
check_status = fields.Selection(related='order_id.check_status') check_status = fields.Selection(related='order_id.check_status')
remark = fields.Char('备注') remark = fields.Char('备注')
is_incoming_material = fields.Boolean('客供料', default=False) # is_incoming_material = fields.Boolean('客供料', default=False)
embryo_redundancy_id = fields.Many2one('sf.embryo.redundancy', '坯料冗余')
manual_quotation = fields.Boolean('人工编程', default=False) manual_quotation = fields.Boolean('人工编程', default=False)
@api.depends('product_template_id') @api.depends('product_template_id')
@@ -244,9 +245,8 @@ class RePurchaseOrder(models.Model):
production_process = product_id_to_production_names.get( production_process = product_id_to_production_names.get(
production.product_id.id) production.product_id.id)
for pp in consecutive_process_parameters: for pp in consecutive_process_parameters:
if pp.gain_way == '外协':
server_template = self.env['product.template'].search( server_template = self.env['product.template'].search(
[('server_product_process_parameters_id', '=', pp.id), [('server_product_process_parameters_id', '=', pp.surface_technics_parameters_id.id),
('detailed_type', '=', 'service')]) ('detailed_type', '=', 'service')])
purchase_order_line = self.env['purchase.order.line'].search( purchase_order_line = self.env['purchase.order.line'].search(
[('product_id', '=', server_template.product_variant_id.id), [('product_id', '=', server_template.product_variant_id.id),
@@ -269,9 +269,10 @@ class RePurchaseOrder(models.Model):
'product_qty': len(production_process), 'product_qty': len(production_process),
'product_uom': server_template.uom_id.id 'product_uom': server_template.uom_id.id
})) }))
if server_product_process: if server_product_process:
self.env['purchase.order'].sudo().create({ self.env['purchase.order'].sudo().create({
'partner_id': server_template.seller_ids.partner_id.id, 'partner_id': server_template.seller_ids[0].partner_id.id,
'origin': ','.join(production_process), 'origin': ','.join(production_process),
'state': 'draft', 'state': 'draft',
'purchase_type': 'consignment', 'purchase_type': 'consignment',

View File

@@ -119,7 +119,7 @@
<field name="name" widget="section_and_note_text" optional="show" <field name="name" widget="section_and_note_text" optional="show"
string="参数说明(长/宽/高/体积/精度/材质)"/> string="参数说明(长/宽/高/体积/精度/材质)"/>
<field name="manual_quotation" readonly="1"/> <field name="manual_quotation" readonly="1"/>
<field name="is_incoming_material" readonly="1"/> <field name="embryo_redundancy_id" readonly="1"/>
</xpath> </xpath>
<field name="user_id" position="attributes"> <field name="user_id" position="attributes">
<attribute name="attrs">{'readonly': [('state', 'in', ['cancel','sale'])]}</attribute> <attribute name="attrs">{'readonly': [('state', 'in', ['cancel','sale'])]}</attribute>
@@ -167,7 +167,7 @@
<!--新增带料字段--> <!--新增带料字段-->
<xpath expr="//field[@name='order_line']/form//group//group//field[@name='analytic_distribution']" position="after"> <xpath expr="//field[@name='order_line']/form//group//group//field[@name='analytic_distribution']" position="after">
<field name="manual_quotation" /> <field name="manual_quotation" />
<field name="is_incoming_material"/> <field name="embryo_redundancy_id"/>
</xpath> </xpath>
</field> </field>
</record> </record>