Merge remote-tracking branch 'refs/remotes/origin/develop' into feature/消息提醒优化
# Conflicts: # sf_sale/views/purchase_order_view.xml
This commit is contained in:
@@ -138,7 +138,7 @@ if env.user.has_group('mrp.group_mrp_workorder_dependencies'):
|
|||||||
<button name="openMenuPopup" t-att-disabled="isBlocked" class="btn btn-secondary o_workorder_icon_btn fa fa-bars" type="workorder_event" title="menu"/>
|
<button name="openMenuPopup" t-att-disabled="isBlocked" class="btn btn-secondary o_workorder_icon_btn fa fa-bars" type="workorder_event" title="menu"/>
|
||||||
<span groups="mrp_workorder.group_mrp_wo_tablet_timer">
|
<span groups="mrp_workorder.group_mrp_wo_tablet_timer">
|
||||||
<button name="button_pending" type="object" class="btn btn-secondary" attrs="{'invisible': ['|', ('is_user_working', '=', False), ('working_state', '=', 'blocked')]}" barcode_trigger="pause" string="PAUSE"/>
|
<button name="button_pending" type="object" class="btn btn-secondary" attrs="{'invisible': ['|', ('is_user_working', '=', False), ('working_state', '=', 'blocked')]}" barcode_trigger="pause" string="PAUSE"/>
|
||||||
<button name="button_start" type="object" class="btn btn-warning" attrs="{'invisible': ['|', '|', ('is_user_working', '=', True), ('working_state', '=', 'blocked'), ('state', '=', ('done', 'cancel'))]}" barcode_trigger="pause" string="CONTINUE"/>
|
<button name="button_start" type="object" class="btn btn-warning" attrs="{'invisible': ['|', '|', ('is_user_working', '=', True), ('working_state', '=', 'blocked'), ('state', '=', ('done','rework', 'cancel'))]}" barcode_trigger="pause" string="CONTINUE"/>
|
||||||
<button name="button_unblock" type="object" class="btn btn-secondary btn-danger o_unblock" attrs="{'invisible': [('working_state', '!=', 'blocked')]}">Unblock</button>
|
<button name="button_unblock" type="object" class="btn btn-secondary btn-danger o_unblock" attrs="{'invisible': [('working_state', '!=', 'blocked')]}">Unblock</button>
|
||||||
<field name="duration" widget="mrp_timer" class="ms-1" readonly="1"/>
|
<field name="duration" widget="mrp_timer" class="ms-1" readonly="1"/>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -151,6 +151,12 @@ class JdEclp(models.Model):
|
|||||||
_logger.info('准备调接口1')
|
_logger.info('准备调接口1')
|
||||||
url1 = config['bfm_url_new'] + '/api/create/jd/order'
|
url1 = config['bfm_url_new'] + '/api/create/jd/order'
|
||||||
requests.post(url1, json=json1, data=None)
|
requests.post(url1, json=json1, data=None)
|
||||||
|
# ===============修改销售订单状态为【物流中】===================
|
||||||
|
item = self.env['sale.order'].sudo().search([('name', '=', self.origin)])
|
||||||
|
if not item:
|
||||||
|
raise ValidationError('没有查询到订单号为【%s】的销售订单!' % self.origin)
|
||||||
|
else:
|
||||||
|
item.write({'state': 'physical_distribution'})
|
||||||
_logger.info('调用成功1')
|
_logger.info('调用成功1')
|
||||||
_logger.info('准备调接口2')
|
_logger.info('准备调接口2')
|
||||||
json2 = {
|
json2 = {
|
||||||
|
|||||||
@@ -23,6 +23,16 @@ class JkmPracticeEmployee(models.Model):
|
|||||||
vals["we_id"] = self._get_we_id(vals.get('work_email'))
|
vals["we_id"] = self._get_we_id(vals.get('work_email'))
|
||||||
return super(JkmPracticeEmployee, self).write(vals)
|
return super(JkmPracticeEmployee, self).write(vals)
|
||||||
|
|
||||||
|
def unlink(self):
|
||||||
|
for record in self:
|
||||||
|
res_partner_obj = record.env['res.partner'].sudo().search([('email', '=', record.work_email)])
|
||||||
|
if res_partner_obj:
|
||||||
|
res_partner_obj.unlink()
|
||||||
|
res = super(JkmPracticeEmployee, self).unlink()
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
@api.depends('work_contact_id', 'work_contact_id.mobile', 'work_contact_id.email')
|
@api.depends('work_contact_id', 'work_contact_id.mobile', 'work_contact_id.email')
|
||||||
def _compute_work_contact_details(self):
|
def _compute_work_contact_details(self):
|
||||||
for employee in self:
|
for employee in self:
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
'views/res_config_settings_views.xml',
|
'views/res_config_settings_views.xml',
|
||||||
'views/sale_order_views.xml',
|
'views/sale_order_views.xml',
|
||||||
'views/mrp_workorder_batch_replan.xml',
|
'views/mrp_workorder_batch_replan.xml',
|
||||||
|
'views/purchase_order_view.xml',
|
||||||
],
|
],
|
||||||
'assets': {
|
'assets': {
|
||||||
|
|
||||||
@@ -52,6 +53,8 @@
|
|||||||
'sf_manufacturing/static/src/scss/kanban_change.scss',
|
'sf_manufacturing/static/src/scss/kanban_change.scss',
|
||||||
'sf_manufacturing/static/src/xml/button_show_on_tree.xml',
|
'sf_manufacturing/static/src/xml/button_show_on_tree.xml',
|
||||||
'sf_manufacturing/static/src/js/workpiece_delivery_wizard_confirm.js',
|
'sf_manufacturing/static/src/js/workpiece_delivery_wizard_confirm.js',
|
||||||
|
'sf_manufacturing/static/src/js/agv_scheduling_resend_confirm.js',
|
||||||
|
'sf_manufacturing/static/src/js/agv_scheduling_cancel_confirm.js',
|
||||||
'sf_manufacturing/static/src/js/qr.js',
|
'sf_manufacturing/static/src/js/qr.js',
|
||||||
'sf_manufacturing/static/src/xml/qr.xml',
|
'sf_manufacturing/static/src/xml/qr.xml',
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class JikimoSaleRoutePicking(Sf_Bf_Connect):
|
|||||||
bfm_process_order_list = json.loads(kw['bfm_process_order_list'])
|
bfm_process_order_list = json.loads(kw['bfm_process_order_list'])
|
||||||
order_id = request.env['sale.order'].with_user(request.env.ref("base.user_admin")).sale_order_create(
|
order_id = request.env['sale.order'].with_user(request.env.ref("base.user_admin")).sale_order_create(
|
||||||
company_id, kw['delivery_name'], kw['delivery_telephone'], kw['delivery_address'],
|
company_id, kw['delivery_name'], kw['delivery_telephone'], kw['delivery_address'],
|
||||||
kw['delivery_end_date'], kw['payments_way'], kw['pay_way'], state='draft')
|
kw['delivery_end_date'], kw['payments_way'], kw['pay_way'], kw['order_number'], state='draft')
|
||||||
i = 1
|
i = 1
|
||||||
# 给sale_order的default_code字段赋值
|
# 给sale_order的default_code字段赋值
|
||||||
# aa = request.env['sale.order'].sudo().search([('name', '=', order_id.name)])
|
# aa = request.env['sale.order'].sudo().search([('name', '=', order_id.name)])
|
||||||
|
|||||||
@@ -15,3 +15,4 @@ from . import sf_technology_design
|
|||||||
from . import sf_production_common
|
from . import sf_production_common
|
||||||
from . import sale_order
|
from . import sale_order
|
||||||
from . import quick_easy_order
|
from . import quick_easy_order
|
||||||
|
from . import purchase_order
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import requests
|
import requests
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
from odoo import models, fields, api, _
|
from odoo import models, fields, api, _
|
||||||
from odoo.exceptions import UserError
|
from odoo.exceptions import UserError
|
||||||
@@ -210,9 +211,18 @@ class AgvScheduling(models.Model):
|
|||||||
def button_cancel(self):
|
def button_cancel(self):
|
||||||
# 弹出二次确认窗口后执行
|
# 弹出二次确认窗口后执行
|
||||||
for rec in self:
|
for rec in self:
|
||||||
if rec.state != '待下发':
|
|
||||||
raise UserError('只有待下发状态的AGV调度任务才能取消!')
|
|
||||||
rec.state = '已取消'
|
rec.state = '已取消'
|
||||||
|
return {
|
||||||
|
'type': 'ir.actions.client',
|
||||||
|
'tag': 'display_notification',
|
||||||
|
'target': 'new',
|
||||||
|
'params': {
|
||||||
|
'message': '任务取消成功!',
|
||||||
|
'type': 'success',
|
||||||
|
'sticky': False,
|
||||||
|
'next': {'type': 'ir.actions.act_window_close'},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def finish_scheduling(self):
|
def finish_scheduling(self):
|
||||||
"""
|
"""
|
||||||
@@ -232,7 +242,7 @@ class AgvScheduling(models.Model):
|
|||||||
agv_route sf.agv.task.route对象
|
agv_route sf.agv.task.route对象
|
||||||
"""
|
"""
|
||||||
for rec in self:
|
for rec in self:
|
||||||
if rec.state != '待下发':
|
if rec.state not in ['待下发', '配送中']:
|
||||||
return False
|
return False
|
||||||
_logger.info('AGV任务调度:下发调度任务,路线为%s' % agv_task_route)
|
_logger.info('AGV任务调度:下发调度任务,路线为%s' % agv_task_route)
|
||||||
rec.state = '配送中'
|
rec.state = '配送中'
|
||||||
@@ -264,7 +274,45 @@ class AgvScheduling(models.Model):
|
|||||||
'task_delivery_time': fields.Datetime.now()
|
'task_delivery_time': fields.Datetime.now()
|
||||||
})
|
})
|
||||||
return super().write(vals)
|
return super().write(vals)
|
||||||
|
|
||||||
|
def button_cancel_confirm(self):
|
||||||
|
if self.task_delivery_time > fields.Datetime.now() - timedelta(minutes=10):
|
||||||
|
return {
|
||||||
|
'type': 'ir.actions.client',
|
||||||
|
'tag': 'agv_scheduling_cancel_confirm',
|
||||||
|
'params': {
|
||||||
|
'agv_scheduling_id': self.id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
return self.button_cancel()
|
||||||
|
|
||||||
|
def button_resend_confirm(self):
|
||||||
|
if self.task_delivery_time > fields.Datetime.now() - timedelta(minutes=10):
|
||||||
|
return {
|
||||||
|
'type': 'ir.actions.client',
|
||||||
|
'tag': 'agv_scheduling_resend_confirm',
|
||||||
|
'params': {
|
||||||
|
'agv_scheduling_id': self.id,
|
||||||
|
'context': self.env.context,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
return self.button_resend()
|
||||||
|
|
||||||
|
def button_resend(self):
|
||||||
|
self.dispatch_scheduling(self.agv_route_id)
|
||||||
|
return {
|
||||||
|
'type': 'ir.actions.client',
|
||||||
|
'tag': 'display_notification',
|
||||||
|
'target': 'new',
|
||||||
|
'params': {
|
||||||
|
'message': '任务重新下发成功!',
|
||||||
|
'type': 'success',
|
||||||
|
'sticky': False,
|
||||||
|
'next': {'type': 'ir.actions.act_window_close'},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class ResMrpWorkOrder(models.Model):
|
class ResMrpWorkOrder(models.Model):
|
||||||
_inherit = 'mrp.workorder'
|
_inherit = 'mrp.workorder'
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ class ManualProductModelTypeRoutingSort(models.Model):
|
|||||||
_description = '成品工序排序(人工线下加工)'
|
_description = '成品工序排序(人工线下加工)'
|
||||||
|
|
||||||
sequence = fields.Integer('Sequence')
|
sequence = fields.Integer('Sequence')
|
||||||
route_workcenter_id = fields.Many2one('mrp.routing.workcenter')
|
route_workcenter_id = fields.Many2one('mrp.routing.workcenter', domain=[('routing_type', 'in', ['人工线下加工'])])
|
||||||
is_repeat = fields.Boolean('重复', related='route_workcenter_id.is_repeat')
|
is_repeat = fields.Boolean('重复', related='route_workcenter_id.is_repeat')
|
||||||
routing_type = fields.Selection(string="工序类型", related='route_workcenter_id.routing_type')
|
routing_type = fields.Selection(string="工序类型", related='route_workcenter_id.routing_type')
|
||||||
workcenter_ids = fields.Many2many('mrp.workcenter', required=False, related='route_workcenter_id.workcenter_ids')
|
workcenter_ids = fields.Many2many('mrp.workcenter', required=False, related='route_workcenter_id.workcenter_ids')
|
||||||
|
|||||||
@@ -440,6 +440,18 @@ class MrpProduction(models.Model):
|
|||||||
process_parameters = []
|
process_parameters = []
|
||||||
account_moves = []
|
account_moves = []
|
||||||
parameters_not = []
|
parameters_not = []
|
||||||
|
# 获取原有的工单对应的工序
|
||||||
|
origin_designs = self.workorder_ids.technology_design_id
|
||||||
|
# 获取已删除的工序
|
||||||
|
deleted_designs = origin_designs - self.technology_design_ids
|
||||||
|
if deleted_designs:
|
||||||
|
for deleted_design in deleted_designs:
|
||||||
|
workorder = self.env['mrp.workorder'].search([('technology_design_id', '=', deleted_design.id)])
|
||||||
|
purchase = workorder._get_surface_technics_purchase_ids()
|
||||||
|
account = self.env['account.move'].search([('id', 'in', purchase.invoice_ids.ids)])
|
||||||
|
if account.state not in ['cancel', False]:
|
||||||
|
if purchase.name not in account_moves:
|
||||||
|
account_moves.append(purchase.name)
|
||||||
special_design = self.technology_design_ids.filtered(
|
special_design = self.technology_design_ids.filtered(
|
||||||
lambda a: a.routing_tag == 'special' and a.is_auto is False)
|
lambda a: a.routing_tag == 'special' and a.is_auto is False)
|
||||||
for special in special_design:
|
for special in special_design:
|
||||||
@@ -451,11 +463,7 @@ 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:
|
if account_moves:
|
||||||
raise UserError(_("请联系工厂生产经理对采购订单为%s生成的账单进行取消", ", ".join(account_moves)))
|
raise UserError(_("请联系工厂生产经理对采购订单为%s生成的账单进行取消", ", ".join(account_moves)))
|
||||||
if parameters_not:
|
if parameters_not:
|
||||||
|
|||||||
@@ -94,4 +94,10 @@ class ResMrpRoutingWorkcenter(models.Model):
|
|||||||
route_ids.append(t.route_id.surface_technics_id.id)
|
route_ids.append(t.route_id.surface_technics_id.id)
|
||||||
domain = [('id', 'not in', route_ids), ('routing_tag', '=', 'special')]
|
domain = [('id', 'not in', route_ids), ('routing_tag', '=', 'special')]
|
||||||
return self._search(domain, limit=limit, access_rights_uid=name_get_uid)
|
return self._search(domain, limit=limit, access_rights_uid=name_get_uid)
|
||||||
|
if self._context.get('is_duplicate') and self._context.get('model_name'):
|
||||||
|
# 查询出已经选择的工序
|
||||||
|
model_type = self.env[self._context.get('model_name')].search_read([],['route_workcenter_id'])
|
||||||
|
route_workcenter_ids = [item['route_workcenter_id'][0] if item['route_workcenter_id'] else False for item in model_type]
|
||||||
|
domain = args + [('id', 'not in', route_workcenter_ids)]
|
||||||
|
return self._search(domain, limit=limit, access_rights_uid=name_get_uid)
|
||||||
return super()._name_search(name, args, operator, limit, name_get_uid)
|
return super()._name_search(name, args, operator, limit, name_get_uid)
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
store=True, check_company=True, string="材料")
|
store=True, check_company=True, string="材料")
|
||||||
product_tmpl_id_materials_type_id = fields.Many2one(related='production_id.product_tmpl_id.materials_type_id',
|
product_tmpl_id_materials_type_id = fields.Many2one(related='production_id.product_tmpl_id.materials_type_id',
|
||||||
readonly=True, store=True, check_company=True, string="型号")
|
readonly=True, store=True, check_company=True, string="型号")
|
||||||
workcenter_id = fields.Many2one('mrp.workcenter', string='工作中心', required=False)
|
# workcenter_id = fields.Many2one('mrp.workcenter', string='工作中心', required=False)
|
||||||
users_ids = fields.Many2many("res.users", 'users_workorder', related="workcenter_id.users_ids")
|
users_ids = fields.Many2many("res.users", 'users_workorder', related="workcenter_id.users_ids")
|
||||||
processing_panel = fields.Char('加工面')
|
processing_panel = fields.Char('加工面')
|
||||||
sequence = fields.Integer(string='工序')
|
sequence = fields.Integer(string='工序')
|
||||||
@@ -1114,9 +1114,7 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
# ================= 如果制造订单刀具状态为[无效刀、缺刀] 或者 制造订单状态为[返工]==========================
|
# ================= 如果制造订单刀具状态为[无效刀、缺刀] 或者 制造订单状态为[返工]==========================
|
||||||
if (workorder.production_id.tool_state in ['1', '2'] or workorder.production_id.state == 'rework'
|
if (workorder.production_id.tool_state in ['1', '2'] or workorder.production_id.state == 'rework'
|
||||||
or workorder.production_id.schedule_state != '已排'
|
or workorder.production_id.schedule_state != '已排'
|
||||||
or workorder.production_id.reservation_state not in ['assigned']
|
or workorder.production_id.reservation_state not in ['assigned']):
|
||||||
or workorder.production_id.workorder_ids.filtered(
|
|
||||||
lambda wk: wk.sequence == workorder.sequence - 1).test_results in ['报废', '返工']):
|
|
||||||
if workorder.state != 'waiting':
|
if workorder.state != 'waiting':
|
||||||
workorder.state = 'waiting'
|
workorder.state = 'waiting'
|
||||||
continue
|
continue
|
||||||
@@ -1425,8 +1423,7 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
len(done_workorder) == len(record.production_id.workorder_ids)):
|
len(done_workorder) == len(record.production_id.workorder_ids)):
|
||||||
is_production_id = True
|
is_production_id = True
|
||||||
if record.routing_type in ['解除装夹'] or (
|
if record.routing_type in ['解除装夹'] or (
|
||||||
record.is_rework is True and record.routing_type in ['装夹预调']) or (
|
record.is_rework is True and record.routing_type in ['装夹预调']):
|
||||||
record.test_results in ['返工', '报废'] and record.routing_type in ['CNC加工']):
|
|
||||||
for workorder in record.production_id.workorder_ids:
|
for workorder in record.production_id.workorder_ids:
|
||||||
if workorder.processing_panel == record.processing_panel:
|
if workorder.processing_panel == record.processing_panel:
|
||||||
rfid_code = workorder.rfid_code
|
rfid_code = workorder.rfid_code
|
||||||
|
|||||||
@@ -774,11 +774,10 @@ class ResProductMo(models.Model):
|
|||||||
|
|
||||||
# bfm下单
|
# bfm下单
|
||||||
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
|
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
|
||||||
part_number = fields.Char(string='零件图号', readonly=True)
|
|
||||||
machining_drawings = fields.Binary('2D加工图纸', readonly=True)
|
machining_drawings = fields.Binary('2D加工图纸', readonly=True)
|
||||||
quality_standard = fields.Binary('质检标准', readonly=True)
|
quality_standard = fields.Binary('质检标准', readonly=True)
|
||||||
part_name = fields.Char(string='零件名称', readonly=True)
|
part_name = fields.Char(string='零件名称', readonly=True)
|
||||||
|
part_number = fields.Char(string='零件图号', readonly=True)
|
||||||
@api.constrains('tool_length')
|
@api.constrains('tool_length')
|
||||||
def _check_tool_length_size(self):
|
def _check_tool_length_size(self):
|
||||||
if self.tool_length > 1000000:
|
if self.tool_length > 1000000:
|
||||||
@@ -892,7 +891,7 @@ class ResProductMo(models.Model):
|
|||||||
'machining_drawings': '' if not item['machining_drawings'] else base64.b64decode(
|
'machining_drawings': '' if not item['machining_drawings'] else base64.b64decode(
|
||||||
item['machining_drawings']),
|
item['machining_drawings']),
|
||||||
'quality_standard': '' if not item['quality_standard'] else base64.b64decode(item['quality_standard']),
|
'quality_standard': '' if not item['quality_standard'] else base64.b64decode(item['quality_standard']),
|
||||||
'part_name': item['part_name'],
|
'part_name': item.get('part_name') or '',
|
||||||
}
|
}
|
||||||
tax_id = self.env['account.tax'].sudo().search(
|
tax_id = self.env['account.tax'].sudo().search(
|
||||||
[('type_tax_use', '=', 'sale'), ('amount', '=', item.get('tax')), ('price_include', '=', 'True')])
|
[('type_tax_use', '=', 'sale'), ('amount', '=', item.get('tax')), ('price_include', '=', 'True')])
|
||||||
|
|||||||
33
sf_manufacturing/models/purchase_order.py
Normal file
33
sf_manufacturing/models/purchase_order.py
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
|
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
from odoo import api, fields, models, _
|
||||||
|
from odoo.tools import OrderedSet
|
||||||
|
|
||||||
|
|
||||||
|
# _get_surface_technics_purchase_ids
|
||||||
|
class PurchaseOrder(models.Model):
|
||||||
|
_inherit = 'purchase.order'
|
||||||
|
def button_confirm(self):
|
||||||
|
super().button_confirm()
|
||||||
|
workorders = self.env['mrp.workorder'].search([('purchase_id', '=', self.id)])
|
||||||
|
for workorder in workorders:
|
||||||
|
if workorder.routing_type == '表面工艺' and workorder.is_subcontract is True:
|
||||||
|
move_out = workorder.move_subcontract_workorder_ids[1]
|
||||||
|
# move_out = self.env['stock.move'].search(
|
||||||
|
# [('location_id', '=', self.env['stock.location'].search(
|
||||||
|
# [('barcode', 'ilike', 'WH-PREPRODUCTION')]).id),
|
||||||
|
# ('location_dest_id', '=', self.env['stock.location'].search(
|
||||||
|
# [('barcode', 'ilike', 'VL-SPOC')]).id),
|
||||||
|
# ('origin', '=', self.production_id.name), ('state', 'not in', ['cancel', 'done'])])
|
||||||
|
for mo in move_out:
|
||||||
|
if mo.state != 'done':
|
||||||
|
mo.write({'state': 'assigned', 'production_id': False})
|
||||||
|
if not mo.move_line_ids:
|
||||||
|
self.env['stock.move.line'].create(mo.get_move_line(workorder.production_id, workorder))
|
||||||
|
return True
|
||||||
|
class PurchaseOrderLine(models.Model):
|
||||||
|
_inherit = 'purchase.order.line'
|
||||||
|
part_number = fields.Char('零件图号', related='product_id.part_number', readonly=True)
|
||||||
@@ -13,6 +13,9 @@ class SaleOrder(models.Model):
|
|||||||
('sent', "报价已发送"),
|
('sent', "报价已发送"),
|
||||||
('supply method', "供货方式待确认"),
|
('supply method', "供货方式待确认"),
|
||||||
('sale', "销售订单"),
|
('sale', "销售订单"),
|
||||||
|
('processing', "加工中"),
|
||||||
|
('physical_distribution', "物流中"),
|
||||||
|
('delivered', "已交付"),
|
||||||
('done', "已锁定"),
|
('done', "已锁定"),
|
||||||
('cancel', "已取消"),
|
('cancel', "已取消"),
|
||||||
])
|
])
|
||||||
@@ -149,7 +152,7 @@ class SaleOrder(models.Model):
|
|||||||
|
|
||||||
class SaleOrderLine(models.Model):
|
class SaleOrderLine(models.Model):
|
||||||
_inherit = 'sale.order.line'
|
_inherit = 'sale.order.line'
|
||||||
|
part_number = fields.Char('零件图号', related='product_id.part_number', readonly=True)
|
||||||
# 供货方式
|
# 供货方式
|
||||||
supply_method = fields.Selection([
|
supply_method = fields.Selection([
|
||||||
('automation', "自动化产线加工"),
|
('automation', "自动化产线加工"),
|
||||||
|
|||||||
@@ -644,12 +644,19 @@ class StockPicking(models.Model):
|
|||||||
workorder = move_in.subcontract_workorder_id
|
workorder = move_in.subcontract_workorder_id
|
||||||
workorders = workorder.production_id.workorder_ids
|
workorders = workorder.production_id.workorder_ids
|
||||||
subcontract_workorders = workorders.filtered(lambda wo: wo.is_subcontract == True).sorted('sequence')
|
subcontract_workorders = workorders.filtered(lambda wo: wo.is_subcontract == True).sorted('sequence')
|
||||||
if workorder == subcontract_workorders[-1]:
|
if workorder == subcontract_workorders[-1]:
|
||||||
self.env['stock.quant']._update_reserved_quantity(
|
self.env['stock.quant']._update_reserved_quantity(
|
||||||
move_in.product_id, move_in.location_dest_id, move_in.product_uom_qty, lot_id=move_in.move_line_ids.lot_id,
|
move_in.product_id, move_in.location_dest_id, move_in.product_uom_qty,
|
||||||
|
lot_id=move_in.move_line_ids.lot_id,
|
||||||
package_id=False, owner_id=False, strict=False
|
package_id=False, owner_id=False, strict=False
|
||||||
)
|
)
|
||||||
|
workorder.button_finish()
|
||||||
|
picking_type_out = self.env.ref('sf_manufacturing.outcontract_picking_out').id
|
||||||
|
if res and self.picking_type_id.id == picking_type_out:
|
||||||
|
move_out = self.move_ids
|
||||||
|
if move_out:
|
||||||
|
workorder = move_out.subcontract_workorder_id
|
||||||
|
workorder.button_start()
|
||||||
return res
|
return res
|
||||||
|
|
||||||
# 创建 外协出库入单
|
# 创建 外协出库入单
|
||||||
@@ -671,14 +678,16 @@ class StockPicking(models.Model):
|
|||||||
else:
|
else:
|
||||||
# 从sorted_workorders中找到上一工单的move
|
# 从sorted_workorders中找到上一工单的move
|
||||||
if sorted_workorders.index(workorder) > 0:
|
if sorted_workorders.index(workorder) > 0:
|
||||||
move_dest_id = sorted_workorders[sorted_workorders.index(workorder) - 1].move_subcontract_workorder_ids[1].id
|
move_dest_id = \
|
||||||
|
sorted_workorders[sorted_workorders.index(workorder) - 1].move_subcontract_workorder_ids[1].id
|
||||||
new_picking = True
|
new_picking = True
|
||||||
outcontract_picking_type_in = self.env.ref(
|
outcontract_picking_type_in = self.env.ref(
|
||||||
'sf_manufacturing.outcontract_picking_in').id,
|
'sf_manufacturing.outcontract_picking_in').id,
|
||||||
outcontract_picking_type_out = self.env.ref(
|
outcontract_picking_type_out = self.env.ref(
|
||||||
'sf_manufacturing.outcontract_picking_out').id,
|
'sf_manufacturing.outcontract_picking_out').id,
|
||||||
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, outcontract_picking_type_in, procurement_group_id.id, move_dest_id))
|
self.env['stock.move']._get_stock_move_values_Res(item, outcontract_picking_type_in,
|
||||||
|
procurement_group_id.id, move_dest_id))
|
||||||
picking_in = self.create(
|
picking_in = self.create(
|
||||||
moves_in._get_new_picking_values_Res(item, workorder, 'WH/OCIN/'))
|
moves_in._get_new_picking_values_Res(item, workorder, 'WH/OCIN/'))
|
||||||
# pick_ids.append(picking_in.id)
|
# pick_ids.append(picking_in.id)
|
||||||
@@ -686,7 +695,8 @@ class StockPicking(models.Model):
|
|||||||
{'picking_id': picking_in.id, 'state': 'waiting'})
|
{'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)
|
||||||
moves_out = self.env['stock.move'].sudo().create(
|
moves_out = self.env['stock.move'].sudo().create(
|
||||||
self.env['stock.move']._get_stock_move_values_Res(item, outcontract_picking_type_out, procurement_group_id.id, moves_in.id))
|
self.env['stock.move']._get_stock_move_values_Res(item, outcontract_picking_type_out,
|
||||||
|
procurement_group_id.id, moves_in.id))
|
||||||
workorder.write({'move_subcontract_workorder_ids': [(6, 0, [moves_in.id, moves_out.id])]})
|
workorder.write({'move_subcontract_workorder_ids': [(6, 0, [moves_in.id, moves_out.id])]})
|
||||||
picking_out = self.create(
|
picking_out = self.create(
|
||||||
moves_out._get_new_picking_values_Res(item, workorder, 'WH/OCOUT/'))
|
moves_out._get_new_picking_values_Res(item, workorder, 'WH/OCOUT/'))
|
||||||
@@ -694,8 +704,7 @@ class StockPicking(models.Model):
|
|||||||
moves_out.write(
|
moves_out.write(
|
||||||
{'picking_id': picking_out.id, 'state': 'waiting'})
|
{'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)
|
||||||
|
|
||||||
|
|
||||||
@api.depends('move_type', 'immediate_transfer', 'move_ids.state', 'move_ids.picking_id')
|
@api.depends('move_type', 'immediate_transfer', 'move_ids.state', 'move_ids.picking_id')
|
||||||
def _compute_state(self):
|
def _compute_state(self):
|
||||||
super(StockPicking, self)._compute_state()
|
super(StockPicking, self)._compute_state()
|
||||||
@@ -706,7 +715,9 @@ class StockPicking(models.Model):
|
|||||||
if picking.move_ids:
|
if picking.move_ids:
|
||||||
workorder = picking.move_ids[0].subcontract_workorder_id
|
workorder = picking.move_ids[0].subcontract_workorder_id
|
||||||
if picking.state == 'assigned':
|
if picking.state == 'assigned':
|
||||||
if workorder.state in ['pending', 'waiting'] or workorder._get_surface_technics_purchase_ids().state in ['draft', 'sent']:
|
if workorder.state in ['pending',
|
||||||
|
'waiting'] or workorder._get_surface_technics_purchase_ids().state in [
|
||||||
|
'draft', 'sent']:
|
||||||
picking.state = 'waiting'
|
picking.state = 'waiting'
|
||||||
|
|
||||||
|
|
||||||
@@ -719,7 +730,8 @@ class ReStockMove(models.Model):
|
|||||||
|
|
||||||
def _get_stock_move_values_Res(self, item, picking_type_id, group_id, move_dest_ids=False):
|
def _get_stock_move_values_Res(self, item, picking_type_id, group_id, move_dest_ids=False):
|
||||||
route_id = self.env.ref('sf_manufacturing.route_surface_technology_outsourcing').id
|
route_id = self.env.ref('sf_manufacturing.route_surface_technology_outsourcing').id
|
||||||
stock_rule = self.env['stock.rule'].sudo().search([('route_id', '=', route_id), ('picking_type_id', '=', picking_type_id)])
|
stock_rule = self.env['stock.rule'].sudo().search(
|
||||||
|
[('route_id', '=', route_id), ('picking_type_id', '=', picking_type_id)])
|
||||||
move_values = {
|
move_values = {
|
||||||
'name': '推',
|
'name': '推',
|
||||||
'company_id': item.company_id.id,
|
'company_id': item.company_id.id,
|
||||||
@@ -997,8 +1009,9 @@ class ReStockMove(models.Model):
|
|||||||
res['origin'] = ','.join(productions.mapped('name'))
|
res['origin'] = ','.join(productions.mapped('name'))
|
||||||
res['retrospect_ref'] = production.product_id.name
|
res['retrospect_ref'] = production.product_id.name
|
||||||
return res
|
return res
|
||||||
|
|
||||||
subcontract_workorder_id = fields.Many2one('mrp.workorder', '外协工单组件', check_company=True, index='btree_not_null')
|
subcontract_workorder_id = fields.Many2one('mrp.workorder', '外协工单组件', check_company=True,
|
||||||
|
index='btree_not_null')
|
||||||
|
|
||||||
|
|
||||||
class ReStockQuant(models.Model):
|
class ReStockQuant(models.Model):
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
odoo.define('sf_manufacturing.agv_scheduling_button_confirm', function (require) {
|
||||||
|
const core = require('web.core');
|
||||||
|
const ajax = require('web.ajax');
|
||||||
|
const Dialog = require('web.Dialog');
|
||||||
|
var rpc = require('web.rpc');
|
||||||
|
var _t = core._t;
|
||||||
|
|
||||||
|
async function agv_scheduling_cancel_confirm(parent, {params}) {
|
||||||
|
const dialog = new Dialog(parent, {
|
||||||
|
title: "确认",
|
||||||
|
$content: $('<div>').append("工件正在配送中,确定取消"),
|
||||||
|
buttons: [
|
||||||
|
{ text: "确认", classes: 'btn-primary', close: true, click: () => dispatchConfirmed(parent, params) },
|
||||||
|
{ text: "取消", close: true },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
dialog.open();
|
||||||
|
|
||||||
|
|
||||||
|
async function dispatchConfirmed(parent, params) {
|
||||||
|
rpc.query({
|
||||||
|
model: 'sf.agv.scheduling',
|
||||||
|
method: 'button_cancel',
|
||||||
|
args: [params.agv_scheduling_id],
|
||||||
|
kwargs: {
|
||||||
|
context: params.context,
|
||||||
|
}
|
||||||
|
}).then(res => {
|
||||||
|
parent.services.action.doAction({
|
||||||
|
'type': 'ir.actions.client',
|
||||||
|
'tag': 'display_notification',
|
||||||
|
'target': 'new',
|
||||||
|
'params': {
|
||||||
|
'message': '取消成功!',
|
||||||
|
'type': 'success',
|
||||||
|
'sticky': false,
|
||||||
|
'next': {'type': 'ir.actions.act_window_close'},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
parent.services.action.doAction({
|
||||||
|
'type': 'ir.actions.client',
|
||||||
|
'tag': 'reload',
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
core.action_registry.add('agv_scheduling_cancel_confirm', agv_scheduling_cancel_confirm);
|
||||||
|
return agv_scheduling_cancel_confirm;
|
||||||
|
});
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
odoo.define('sf_manufacturing.agv_scheduling_resend_confirm', function (require) {
|
||||||
|
const core = require('web.core');
|
||||||
|
const ajax = require('web.ajax');
|
||||||
|
const Dialog = require('web.Dialog');
|
||||||
|
var rpc = require('web.rpc');
|
||||||
|
var _t = core._t;
|
||||||
|
|
||||||
|
async function agv_scheduling_resend_confirm(parent, {params}) {
|
||||||
|
const dialog = new Dialog(parent, {
|
||||||
|
title: "确认",
|
||||||
|
$content: $('<div>').append("工件正在配送中,确定重新下发"),
|
||||||
|
buttons: [
|
||||||
|
{ text: "确认", classes: 'btn-primary', close: true, click: () => dispatchConfirmed(parent, params) },
|
||||||
|
{ text: "取消", close: true },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
dialog.open();
|
||||||
|
|
||||||
|
|
||||||
|
async function dispatchConfirmed(parent, params) {
|
||||||
|
rpc.query({
|
||||||
|
model: 'sf.agv.scheduling',
|
||||||
|
method: 'button_resend',
|
||||||
|
args: [params.agv_scheduling_id],
|
||||||
|
kwargs: {
|
||||||
|
context: params.context,
|
||||||
|
}
|
||||||
|
}).then(res => {
|
||||||
|
parent.services.action.doAction({
|
||||||
|
'type': 'ir.actions.client',
|
||||||
|
'tag': 'display_notification',
|
||||||
|
'target': 'new',
|
||||||
|
'params': {
|
||||||
|
'message': '重新下发成功!',
|
||||||
|
'type': 'success',
|
||||||
|
'sticky': false,
|
||||||
|
'next': {'type': 'ir.actions.act_window_close'},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
parent.services.action.doAction({
|
||||||
|
'type': 'ir.actions.client',
|
||||||
|
'tag': 'reload',
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
core.action_registry.add('agv_scheduling_resend_confirm', agv_scheduling_resend_confirm );
|
||||||
|
return agv_scheduling_resend_confirm;
|
||||||
|
});
|
||||||
@@ -22,8 +22,7 @@ odoo.define('sf_manufacturing.action_dispatch_confirm', function (require) {
|
|||||||
rpc.query({
|
rpc.query({
|
||||||
model: 'sf.workpiece.delivery.wizard',
|
model: 'sf.workpiece.delivery.wizard',
|
||||||
method: 'confirm',
|
method: 'confirm',
|
||||||
args: [params.active_id]
|
args: [params.active_id],
|
||||||
,
|
|
||||||
kwargs: {
|
kwargs: {
|
||||||
context: params.context,
|
context: params.context,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,20 @@
|
|||||||
class="btn-danger"
|
class="btn-danger"
|
||||||
confirm="你确定要取消这条记录吗?"
|
confirm="你确定要取消这条记录吗?"
|
||||||
/>
|
/>
|
||||||
|
<button
|
||||||
|
name="button_cancel_confirm"
|
||||||
|
string="取消" type="object"
|
||||||
|
attrs="{'invisible': [('state', '!=', '配送中')]}"
|
||||||
|
icon="fa-times"
|
||||||
|
class="btn-danger"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
name="button_resend_confirm"
|
||||||
|
string="重新下发" type="object"
|
||||||
|
attrs="{'invisible': [('state', '!=', '配送中')]}"
|
||||||
|
icon="fa-circle-o-notch"
|
||||||
|
class="btn-success "
|
||||||
|
/>
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<data>
|
<data>
|
||||||
#------------------模型类型------------------
|
#------------------模型类型------------------
|
||||||
|
|
||||||
<record model="ir.ui.view" id="search_sf_model_type_view">
|
<record model="ir.ui.view" id="search_sf_model_name_view">
|
||||||
<field name="name">search.sf.model.type</field>
|
<field name="name">search.sf.model.type</field>
|
||||||
<field name="model">sf.model.type</field>
|
<field name="model">sf.model.type</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="ir.ui.view" id="tree_sf_model_type_view">
|
<record model="ir.ui.view" id="tree_sf_model_name_view">
|
||||||
<field name="name">tree.sf.model.type</field>
|
<field name="name">tree.sf.model.type</field>
|
||||||
<field name="model">sf.model.type</field>
|
<field name="model">sf.model.type</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="ir.ui.view" id="form_sf_model_type">
|
<record model="ir.ui.view" id="form_sf_model_name">
|
||||||
<field name="name">form.sf.model.type</field>
|
<field name="name">form.sf.model.type</field>
|
||||||
<field name="model">sf.model.type</field>
|
<field name="model">sf.model.type</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
<field name='product_routing_tmpl_ids'>
|
<field name='product_routing_tmpl_ids'>
|
||||||
<tree editable='bottom'>
|
<tree editable='bottom'>
|
||||||
<field name="sequence" widget="handle" string="序号"/>
|
<field name="sequence" widget="handle" string="序号"/>
|
||||||
<field name="route_workcenter_id" string="工序" options="{'no_create': True}"/>
|
<field name="route_workcenter_id" string="工序" options="{'no_create': True}" context="{'is_duplicate': True, 'model_name': 'sf.product.model.type.routing.sort'}"/>
|
||||||
<field name="routing_type" string="类型"/>
|
<field name="routing_type" string="类型"/>
|
||||||
<field name="is_repeat" string="重复"/>
|
<field name="is_repeat" string="重复"/>
|
||||||
<field name="workcenter_ids" string="工作中心" widget="many2many_tags"/>
|
<field name="workcenter_ids" string="工作中心" widget="many2many_tags"/>
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
<field name='manual_product_routing_tmpl_ids'>
|
<field name='manual_product_routing_tmpl_ids'>
|
||||||
<tree editable='bottom'>
|
<tree editable='bottom'>
|
||||||
<field name="sequence" widget="handle" string="序号"/>
|
<field name="sequence" widget="handle" string="序号"/>
|
||||||
<field name="route_workcenter_id" string="工序" options="{'no_create': True}"/>
|
<field name="route_workcenter_id" string="工序" options="{'no_create': True}" context="{'is_duplicate': True, 'model_name': 'sf.manual.product.model.type.routing.sort'}"/>
|
||||||
<field name="routing_type" string="类型"/>
|
<field name="routing_type" string="类型"/>
|
||||||
<field name="is_repeat" string="重复"/>
|
<field name="is_repeat" string="重复"/>
|
||||||
<field name="workcenter_ids" string="工作中心" widget="many2many_tags"/>
|
<field name="workcenter_ids" string="工作中心" widget="many2many_tags"/>
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
<field name='embryo_routing_tmpl_ids'>
|
<field name='embryo_routing_tmpl_ids'>
|
||||||
<tree editable='bottom'>
|
<tree editable='bottom'>
|
||||||
<field name="sequence" widget="handle" string="序号"/>
|
<field name="sequence" widget="handle" string="序号"/>
|
||||||
<field name="route_workcenter_id" string="工序" options="{'no_create': True}"/>
|
<field name="route_workcenter_id" string="工序" options="{'no_create': True}" context="{'is_duplicate': True, 'model_name': 'sf.embryo.model.type.routing.sort'}"/>
|
||||||
<field name="routing_type" string="类型"/>
|
<field name="routing_type" string="类型"/>
|
||||||
<field name="is_repeat" string="重复"/>
|
<field name="is_repeat" string="重复"/>
|
||||||
<field name="workcenter_ids" string="工作中心" widget="many2many_tags"/>
|
<field name="workcenter_ids" string="工作中心" widget="many2many_tags"/>
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
<field name='surface_technics_routing_tmpl_ids' style="white-space: pre-wrap;">
|
<field name='surface_technics_routing_tmpl_ids' style="white-space: pre-wrap;">
|
||||||
<tree editable='bottom'>
|
<tree editable='bottom'>
|
||||||
<field name="sequence" widget="handle" string="序号"/>
|
<field name="sequence" widget="handle" string="序号"/>
|
||||||
<field name="route_workcenter_id" string="工序" options="{'no_create': True}"/>
|
<field name="route_workcenter_id" string="工序" options="{'no_create': True}" context="{'is_duplicate': True, 'model_name': 'sf.surface_technics.model.type.routing.sort'}"/>
|
||||||
<field name="routing_type" string="类型"/>
|
<field name="routing_type" string="类型"/>
|
||||||
<field name="is_repeat" string="重复"/>
|
<field name="is_repeat" string="重复"/>
|
||||||
<field name="workcenter_ids" string="工作中心" widget="many2many_tags"/>
|
<field name="workcenter_ids" string="工作中心" widget="many2many_tags"/>
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="action_sf_model_type" model="ir.actions.act_window">
|
<record id="action_sf_model_name" model="ir.actions.act_window">
|
||||||
<field name="name">模型类型</field>
|
<field name="name">模型类型</field>
|
||||||
<field name="type">ir.actions.act_window</field>
|
<field name="type">ir.actions.act_window</field>
|
||||||
<field name="res_model">sf.model.type</field>
|
<field name="res_model">sf.model.type</field>
|
||||||
@@ -96,11 +96,11 @@
|
|||||||
</record>
|
</record>
|
||||||
|
|
||||||
<menuitem
|
<menuitem
|
||||||
id="menu_sf_model_type"
|
id="menu_sf_model_name"
|
||||||
name="模型类型"
|
name="模型类型"
|
||||||
parent="mrp.menu_mrp_configuration"
|
parent="mrp.menu_mrp_configuration"
|
||||||
sequence="9"
|
sequence="9"
|
||||||
action="action_sf_model_type"
|
action="action_sf_model_name"
|
||||||
/>
|
/>
|
||||||
</data>
|
</data>
|
||||||
</odoo>
|
</odoo>
|
||||||
@@ -18,9 +18,12 @@
|
|||||||
<xpath expr="//field[@name='date_deadline']" position="replace"/>
|
<xpath expr="//field[@name='date_deadline']" position="replace"/>
|
||||||
<xpath expr="//field[@name='name']" position="after">
|
<xpath expr="//field[@name='name']" position="after">
|
||||||
<field name="product_id" readonly="1" optional="show"/>
|
<field name="product_id" readonly="1" optional="show"/>
|
||||||
|
<field name="part_name" readonly="1" optional="hide"/>
|
||||||
|
<field name="part_number" readonly="1" optional="show"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='product_id']" position="after">
|
<xpath expr="//field[@name='product_id']" position="after">
|
||||||
<field name="product_qty" sum="Total Qty" string="数量" readonly="1" optional="show"/>
|
<field name="product_qty" sum="Total Qty" string="数量" readonly="1" optional="show"/>
|
||||||
|
<field name="deadline_of_delivery" optional="show"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='product_qty']" position="after">
|
<xpath expr="//field[@name='product_qty']" position="after">
|
||||||
<field name="product_uom_id" string="计量单位" options="{'no_open':True,'no_create':True}"
|
<field name="product_uom_id" string="计量单位" options="{'no_open':True,'no_create':True}"
|
||||||
@@ -442,7 +445,7 @@
|
|||||||
<field name="routing_type" invisible="True"/>
|
<field name="routing_type" invisible="True"/>
|
||||||
<button name="button_start" type="object" string="开始" class="btn-success" confirm="是否确认开始?"
|
<button name="button_start" type="object" string="开始" class="btn-success" confirm="是否确认开始?"
|
||||||
attrs="{'invisible': ['|', '|', '|','|', ('production_state','in', ('draft', 'done', 'cancel')),
|
attrs="{'invisible': ['|', '|', '|','|', ('production_state','in', ('draft', 'done', 'cancel')),
|
||||||
('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel')), ('is_user_working', '!=',
|
('working_state', '=', 'blocked'), ('state', 'in', ('done','rework', 'cancel')), ('is_user_working', '!=',
|
||||||
False), ('routing_type', '=', 'CNC加工')]}"
|
False), ('routing_type', '=', 'CNC加工')]}"
|
||||||
groups="sf_base.group_sf_mrp_user"/>
|
groups="sf_base.group_sf_mrp_user"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|||||||
@@ -29,6 +29,8 @@
|
|||||||
</field>
|
</field>
|
||||||
<field name="product_id" position="after">
|
<field name="product_id" position="after">
|
||||||
<field name="equipment_id" optional="hide"/>
|
<field name="equipment_id" optional="hide"/>
|
||||||
|
<field name="part_name" optional="hide"/>
|
||||||
|
<field name="part_number" optional="show"/>
|
||||||
</field>
|
</field>
|
||||||
<xpath expr="//field[@name='qty_remaining']" position="after">
|
<xpath expr="//field[@name='qty_remaining']" position="after">
|
||||||
<field name="manual_quotation" optional="show"/>
|
<field name="manual_quotation" optional="show"/>
|
||||||
@@ -55,7 +57,7 @@
|
|||||||
<!-- </attribute>-->
|
<!-- </attribute>-->
|
||||||
<attribute name="attrs">{'invisible': ['|', '|', '|','|','|', ('production_state','in', ('draft',
|
<attribute name="attrs">{'invisible': ['|', '|', '|','|','|', ('production_state','in', ('draft',
|
||||||
'done',
|
'done',
|
||||||
'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel')),
|
'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done','rework', 'cancel')),
|
||||||
('is_user_working', '!=', False),("user_permissions","=",False),("name","in",("CNC加工","解除装夹"))]}
|
('is_user_working', '!=', False),("user_permissions","=",False),("name","in",("CNC加工","解除装夹"))]}
|
||||||
</attribute>
|
</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
@@ -174,9 +176,9 @@
|
|||||||
<!-- <button name="button_start" type="object" string="开始" class="btn-success" confirm="是否确认开始"-->
|
<!-- <button name="button_start" type="object" string="开始" class="btn-success" confirm="是否确认开始"-->
|
||||||
<!-- attrs="{'invisible': ['|', '|', '|', ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel','to be detected')), ('is_user_working', '!=', False)]}"/>-->
|
<!-- attrs="{'invisible': ['|', '|', '|', ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel','to be detected')), ('is_user_working', '!=', False)]}"/>-->
|
||||||
<button name="button_start" type="object" string="开始" class="btn-success" confirm="是否确认开始"
|
<button name="button_start" type="object" string="开始" class="btn-success" confirm="是否确认开始"
|
||||||
attrs="{'invisible': ['|', '|', '|', '|', '|', ('routing_type', '=', '装夹预调'), ('routing_type', '=', '解除装夹'), ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel','to be detected')), ('is_user_working', '!=', False)]}"/>
|
attrs="{'invisible': ['|', '|', '|', '|', '|', ('routing_type', '=', '装夹预调'), ('routing_type', '=', '解除装夹'), ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done','rework', 'cancel','to be detected')), ('is_user_working', '!=', False)]}"/>
|
||||||
<button name="button_start" type="object" string="开始" class="btn-success"
|
<button name="button_start" type="object" string="开始" class="btn-success"
|
||||||
attrs="{'invisible': ['|', '|', '|', '|', ('routing_type', '!=', '装夹预调'), ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel','to be detected')), ('is_user_working', '!=', False)]}"/>
|
attrs="{'invisible': ['|', '|', '|', '|', ('routing_type', '!=', '装夹预调'), ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done','rework', 'cancel','to be detected')), ('is_user_working', '!=', False)]}"/>
|
||||||
<button name="button_pending" type="object" string="暂停" class="btn-warning"
|
<button name="button_pending" type="object" string="暂停" class="btn-warning"
|
||||||
attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False)]}"/>
|
attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False)]}"/>
|
||||||
<button name="button_finish" type="object" string="完成" class="btn-success" confirm="是否确认完工"
|
<button name="button_finish" type="object" string="完成" class="btn-success" confirm="是否确认完工"
|
||||||
|
|||||||
15
sf_manufacturing/views/purchase_order_view.xml
Normal file
15
sf_manufacturing/views/purchase_order_view.xml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<odoo>
|
||||||
|
<data>
|
||||||
|
<record model="ir.ui.view" id="view_purchase_order_line_form_inherit_sf1">
|
||||||
|
<field name="name">purchase.order.form.inherit.sf</field>
|
||||||
|
<field name="model">purchase.order</field>
|
||||||
|
<field name="inherit_id" ref="purchase.purchase_order_form"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//field[@name='order_line']/tree/field[@name='name']" position="after">
|
||||||
|
<field name="part_number" optional="show"/>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
@@ -13,11 +13,15 @@
|
|||||||
<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">supply method,sale,processing,physical_distribution,delivered</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//page/field[@name='order_line']/tree/field[@name='remark']" position="before">
|
<xpath expr="//page/field[@name='order_line']/tree/field[@name='remark']" position="before">
|
||||||
<field name="supply_method" attrs="{'invisible': [('state', '=', 'draft')], 'required': [('state', '=', 'supply method')]}" />
|
<field name="supply_method" attrs="{'invisible': [('state', '=', 'draft')], 'required': [('state', '=', 'supply method')]}" />
|
||||||
</xpath>
|
</xpath>
|
||||||
|
<xpath expr="//field[@name='order_line']/tree/field[@name='model_glb_file']" position="before">
|
||||||
|
<field name="part_number" optional="show"/>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
<xpath expr="//header/button[@name='action_cancel']" position="attributes">
|
<xpath expr="//header/button[@name='action_cancel']" position="attributes">
|
||||||
<attribute name="attrs">{'invisible': [('state', '!=', 'draft')]}</attribute>
|
<attribute name="attrs">{'invisible': [('state', '!=', 'draft')]}</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|||||||
@@ -85,7 +85,8 @@ class ReworkWizard(models.TransientModel):
|
|||||||
# 2、当FM工单在CNC工单进行选择返工,并将已全部完成的ZM面工序全部勾选上时,FM工单上所有的已完成的工单(装夹预调工单)也必须进行勾选
|
# 2、当FM工单在CNC工单进行选择返工,并将已全部完成的ZM面工序全部勾选上时,FM工单上所有的已完成的工单(装夹预调工单)也必须进行勾选
|
||||||
if not wk_ids.filtered(lambda wk: wk.name == '装夹预调' and wk.processing_panel == panel):
|
if not wk_ids.filtered(lambda wk: wk.name == '装夹预调' and wk.processing_panel == panel):
|
||||||
if wk_ids.filtered(lambda wk: wk.name == 'CNC加工' and wk.processing_panel == panel):
|
if wk_ids.filtered(lambda wk: wk.name == 'CNC加工' and wk.processing_panel == panel):
|
||||||
sequence_max = wk_ids.filtered(lambda wk: wk.name == 'CNC加工' and wk.processing_panel == panel).sequence
|
sequence_max = wk_ids.filtered(
|
||||||
|
lambda wk: wk.name == 'CNC加工' and wk.processing_panel == panel).sequence
|
||||||
for wk_id in wk_ids.filtered(lambda wk: wk.sequence < sequence_max):
|
for wk_id in wk_ids.filtered(lambda wk: wk.sequence < sequence_max):
|
||||||
if len(wk_ids.filtered(lambda wk: wk.processing_panel == wk_id.processing_panel)) == 3:
|
if len(wk_ids.filtered(lambda wk: wk.processing_panel == wk_id.processing_panel)) == 3:
|
||||||
raise ValidationError(
|
raise ValidationError(
|
||||||
@@ -114,19 +115,17 @@ class ReworkWizard(models.TransientModel):
|
|||||||
else:
|
else:
|
||||||
raise ValidationError('请选择返工工单!!!')
|
raise ValidationError('请选择返工工单!!!')
|
||||||
if rework_workorder_ids:
|
if rework_workorder_ids:
|
||||||
clamp_workorder_ids = None
|
# 限制
|
||||||
if rework_workorder_ids:
|
# 1、单独返工CNC工单则不解绑托盘RFID,如单独返工装夹预调工单,则自动解绑托盘RFID;
|
||||||
# 限制
|
# 2、返工CNC工单和装夹预调工单则自动解绑RFID
|
||||||
# 1、单独返工CNC工单则不解绑托盘RFID,如单独返工装夹预调工单,则自动解绑托盘RFID;
|
clamp_workorder_ids = rework_workorder_ids.filtered(lambda rp: rp.routing_type == '装夹预调')
|
||||||
# 2、返工CNC工单和装夹预调工单则自动解绑RFID
|
if clamp_workorder_ids:
|
||||||
clamp_workorder_ids = rework_workorder_ids.filtered(lambda rp: rp.routing_type == '装夹预调')
|
for clamp_workorder_id in clamp_workorder_ids:
|
||||||
if clamp_workorder_ids:
|
self.production_id.workorder_ids.filtered(
|
||||||
for clamp_workorder_id in clamp_workorder_ids:
|
lambda wk: wk.processing_panel == clamp_workorder_id.processing_panel).write(
|
||||||
self.production_id.workorder_ids.filtered(
|
{'rfid_code': None})
|
||||||
lambda wk: wk.processing_panel == clamp_workorder_id.processing_panel).write(
|
# 返工工单状态设置为【返工】
|
||||||
{'rfid_code': None})
|
rework_workorder_ids.write({'state': 'rework'})
|
||||||
# 返工工单状态设置为【返工】
|
|
||||||
rework_workorder_ids.write({'state': 'rework'})
|
|
||||||
# 查询返工工单对应的工艺设计记录,并调用方法拼接数据,用于创建新的工单
|
# 查询返工工单对应的工艺设计记录,并调用方法拼接数据,用于创建新的工单
|
||||||
workorders_values = []
|
workorders_values = []
|
||||||
for work in rework_workorder_ids:
|
for work in rework_workorder_ids:
|
||||||
@@ -147,6 +146,11 @@ class ReworkWizard(models.TransientModel):
|
|||||||
new_pre_workorder_ids = self.production_id.workorder_ids.filtered(
|
new_pre_workorder_ids = self.production_id.workorder_ids.filtered(
|
||||||
lambda kw: kw.routing_type == '装夹预调' and kw.sequence == 0)
|
lambda kw: kw.routing_type == '装夹预调' and kw.sequence == 0)
|
||||||
self.production_id._reset_work_order_sequence()
|
self.production_id._reset_work_order_sequence()
|
||||||
|
# ====新工单绑定rfid===
|
||||||
|
for new_work_id in new_work_ids:
|
||||||
|
if new_work_id.routing_type in ['CNC加工', '解除装夹']:
|
||||||
|
new_work_id.write({'rfid_code': self.production_id.workorder_ids.filtered(
|
||||||
|
lambda wk: wk.sequence == new_work_id.sequence - 1).rfid_code})
|
||||||
self.production_id.detection_result_ids.filtered(
|
self.production_id.detection_result_ids.filtered(
|
||||||
lambda ap1: ap1.handle_result == '待处理').write({'handle_result': '已处理'})
|
lambda ap1: ap1.handle_result == '待处理').write({'handle_result': '已处理'})
|
||||||
panels = [] # 返工的加工面
|
panels = [] # 返工的加工面
|
||||||
@@ -267,11 +271,7 @@ class ReworkWizard(models.TransientModel):
|
|||||||
elif self.programming_state in ['待编程', '编程中']:
|
elif self.programming_state in ['待编程', '编程中']:
|
||||||
self.production_id.write(
|
self.production_id.write(
|
||||||
{'programming_state': '编程中', 'work_state': '编程中', 'is_rework': True})
|
{'programming_state': '编程中', 'work_state': '编程中', 'is_rework': True})
|
||||||
# ==================申请重新编程=======================
|
# =================================================
|
||||||
if self.is_reprogramming is True:
|
|
||||||
self.production_id.update_programming_state()
|
|
||||||
self.production_id.write(
|
|
||||||
{'programming_state': '编程中', 'work_state': '编程中'})
|
|
||||||
if self.production_id.state == 'progress':
|
if self.production_id.state == 'progress':
|
||||||
self.production_id.write({'programming_state': '已编程', 'work_state': '已编程'})
|
self.production_id.write({'programming_state': '已编程', 'work_state': '已编程'})
|
||||||
if self.reprogramming_num >= 1 and self.programming_state == '已编程':
|
if self.reprogramming_num >= 1 and self.programming_state == '已编程':
|
||||||
@@ -282,6 +282,11 @@ class ReworkWizard(models.TransientModel):
|
|||||||
productions_not_delivered.write(
|
productions_not_delivered.write(
|
||||||
{'state': 'progress', 'programming_state': '已编程', 'work_state': '已编程',
|
{'state': 'progress', 'programming_state': '已编程', 'work_state': '已编程',
|
||||||
'is_rework': False})
|
'is_rework': False})
|
||||||
|
# ==================申请重新编程=======================
|
||||||
|
if self.is_reprogramming is True:
|
||||||
|
self.production_id.update_programming_state()
|
||||||
|
self.production_id.write(
|
||||||
|
{'programming_state': '编程中', 'work_state': '编程中', 'state': 'progress'})
|
||||||
|
|
||||||
@api.onchange('production_id')
|
@api.onchange('production_id')
|
||||||
def onchange_processing_panel_id(self):
|
def onchange_processing_panel_id(self):
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController):
|
|||||||
ret = json.loads(ret['result'])
|
ret = json.loads(ret['result'])
|
||||||
logging.info('下发编程单:%s' % ret)
|
logging.info('下发编程单:%s' % ret)
|
||||||
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', 'rework'):
|
||||||
domain += [('state', 'not in', ['done', 'scrap', 'cancel'])]
|
domain += [('state', 'not in', ['done', 'scrap', 'cancel'])]
|
||||||
else:
|
else:
|
||||||
domain += [('state', 'in', ['confirmed', 'pending_cam'])]
|
domain += [('state', 'in', ['confirmed', 'pending_cam'])]
|
||||||
@@ -56,7 +56,7 @@ 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:
|
||||||
production.write({'programming_state': '已编程', 'work_state': '已编程'})
|
production.write({'programming_state': '已编程', 'work_state': '已编程', 'is_rework': False})
|
||||||
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(
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ class sf_production_plan(models.Model):
|
|||||||
_description = 'sf_production_plan'
|
_description = 'sf_production_plan'
|
||||||
_inherit = ['mail.thread']
|
_inherit = ['mail.thread']
|
||||||
# _order = 'state desc, write_date desc'
|
# _order = 'state desc, write_date desc'
|
||||||
|
part_name = fields.Char('零件名称', related='product_id.part_name', readonly=True)
|
||||||
|
part_number = fields.Char('零件图号', related='product_id.part_number', readonly=True)
|
||||||
state = fields.Selection([
|
state = fields.Selection([
|
||||||
('draft', '待排程'),
|
('draft', '待排程'),
|
||||||
('done', '已排程'),
|
('done', '已排程'),
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
decoration-danger="state == 'finished'"/>
|
decoration-danger="state == 'finished'"/>
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
<field name="origin"/>
|
<field name="origin"/>
|
||||||
|
<field name="part_number" optional="show"/>
|
||||||
|
<field name="part_name" optional="hide"/>
|
||||||
<field name="order_deadline" widget="date"/>
|
<field name="order_deadline" widget="date"/>
|
||||||
<field name="product_qty"/>
|
<field name="product_qty"/>
|
||||||
<field name="production_line_id"/>
|
<field name="production_line_id"/>
|
||||||
|
|||||||
@@ -18,7 +18,8 @@
|
|||||||
<field name="production_id"/>
|
<field name="production_id"/>
|
||||||
<field name="processing_panel"/>
|
<field name="processing_panel"/>
|
||||||
<field name="product_id"/>
|
<field name="product_id"/>
|
||||||
<field name="part_number"/>
|
<field name="part_number" optional="show"/>
|
||||||
|
<field name="part_name" optional="hide"/>
|
||||||
<field name="number"/>
|
<field name="number"/>
|
||||||
<field name="state" widget="badge"
|
<field name="state" widget="badge"
|
||||||
decoration-success="state == 'done'"
|
decoration-success="state == 'done'"
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
'assets': {
|
'assets': {
|
||||||
'web.assets_backend': [
|
'web.assets_backend': [
|
||||||
'sf_sale/static/js/setTableWidth.js',
|
'sf_sale/static/js/setTableWidth.js',
|
||||||
|
'sf_sale/static/src/css/purchase_list.css',
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
'demo': [
|
'demo': [
|
||||||
|
|||||||
@@ -55,12 +55,15 @@ class ReSaleOrder(models.Model):
|
|||||||
store=True, readonly=False, copy=False, precompute=True,
|
store=True, readonly=False, copy=False, precompute=True,
|
||||||
states=READONLY_FIELD_STATES, default=fields.Datetime.now)
|
states=READONLY_FIELD_STATES, default=fields.Datetime.now)
|
||||||
|
|
||||||
delivery_warning = fields.Selection([('normal', '正常'), ('warning', '告警'), ('overdue', '逾期')], string='时效',
|
delivery_warning = fields.Selection([('normal', '正常'), ('warning', '告警'), ('overdue', '逾期')],
|
||||||
tracking=True)
|
default='normal',
|
||||||
|
string='时效', tracking=True)
|
||||||
|
|
||||||
|
order_code = fields.Char('平台订单号', readonly=True)
|
||||||
|
|
||||||
# 业务平台分配工厂后在智能工厂先创建销售订单
|
# 业务平台分配工厂后在智能工厂先创建销售订单
|
||||||
def sale_order_create(self, company_id, delivery_name, delivery_telephone, delivery_address,
|
def sale_order_create(self, company_id, delivery_name, delivery_telephone, delivery_address,
|
||||||
deadline_of_delivery, payments_way, pay_way, state='sale'):
|
deadline_of_delivery, payments_way, pay_way, order_number, state='sale'):
|
||||||
now_time = datetime.datetime.now()
|
now_time = datetime.datetime.now()
|
||||||
partner = self.get_customer()
|
partner = self.get_customer()
|
||||||
data = {
|
data = {
|
||||||
@@ -76,6 +79,7 @@ class ReSaleOrder(models.Model):
|
|||||||
'address_of_delivery': delivery_address,
|
'address_of_delivery': delivery_address,
|
||||||
'payments_way': payments_way,
|
'payments_way': payments_way,
|
||||||
'pay_way': pay_way,
|
'pay_way': pay_way,
|
||||||
|
'order_code': order_number,
|
||||||
}
|
}
|
||||||
if deadline_of_delivery:
|
if deadline_of_delivery:
|
||||||
# deadline_of_delivery字段存在为false字符串情况
|
# deadline_of_delivery字段存在为false字符串情况
|
||||||
@@ -158,10 +162,71 @@ class ReSaleOrder(models.Model):
|
|||||||
if not line.tax_id:
|
if not line.tax_id:
|
||||||
raise UserError('请对【订单行】中的【税】进行选择')
|
raise UserError('请对【订单行】中的【税】进行选择')
|
||||||
|
|
||||||
|
consignment_purchase_order_count = fields.Integer(
|
||||||
|
"Number of consignment Purchase Order Generated",
|
||||||
|
compute='_compute_purchase_order_count')
|
||||||
|
|
||||||
|
@api.depends('order_line.purchase_line_ids.order_id')
|
||||||
|
def _compute_purchase_order_count(self):
|
||||||
|
for order in self:
|
||||||
|
order.purchase_order_count = len(order._get_purchase_orders().filtered(
|
||||||
|
lambda po: po.purchase_type not in ['consignment']))
|
||||||
|
order.consignment_purchase_order_count = len(order._get_purchase_orders().filtered(
|
||||||
|
lambda po: po.purchase_type in ['consignment']))
|
||||||
|
|
||||||
|
def action_view_purchase_orders(self):
|
||||||
|
"""
|
||||||
|
采购
|
||||||
|
"""
|
||||||
|
self.ensure_one()
|
||||||
|
purchase_order_ids = self._get_purchase_orders().filtered(
|
||||||
|
lambda po: po.purchase_type not in ['consignment']).ids
|
||||||
|
action = {
|
||||||
|
'res_model': 'purchase.order',
|
||||||
|
'type': 'ir.actions.act_window',
|
||||||
|
}
|
||||||
|
if len(purchase_order_ids) == 1:
|
||||||
|
action.update({
|
||||||
|
'view_mode': 'form',
|
||||||
|
'res_id': purchase_order_ids[0],
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
action.update({
|
||||||
|
'name': _("从 %s生成采购订单", self.name),
|
||||||
|
'domain': [('id', 'in', purchase_order_ids)],
|
||||||
|
'view_mode': 'tree,form',
|
||||||
|
})
|
||||||
|
return action
|
||||||
|
|
||||||
|
def action_view_consignment_purchase_orders(self):
|
||||||
|
"""
|
||||||
|
委外加工
|
||||||
|
"""
|
||||||
|
self.ensure_one()
|
||||||
|
consignment_purchase_order_ids = self._get_purchase_orders().filtered(
|
||||||
|
lambda po: po.purchase_type in ['consignment']).ids
|
||||||
|
action = {
|
||||||
|
'res_model': 'purchase.order',
|
||||||
|
'type': 'ir.actions.act_window',
|
||||||
|
}
|
||||||
|
if len(consignment_purchase_order_ids) == 1:
|
||||||
|
action.update({
|
||||||
|
'view_mode': 'form',
|
||||||
|
'res_id': consignment_purchase_order_ids[0],
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
action.update({
|
||||||
|
'name': _("从 %s生成委外加工订单", self.name),
|
||||||
|
'domain': [('id', 'in', consignment_purchase_order_ids)],
|
||||||
|
'view_mode': 'tree,form',
|
||||||
|
})
|
||||||
|
return action
|
||||||
|
|
||||||
|
|
||||||
class ResaleOrderLine(models.Model):
|
class ResaleOrderLine(models.Model):
|
||||||
_inherit = 'sale.order.line'
|
_inherit = 'sale.order.line'
|
||||||
|
# part_number = fields.Char('零件图号', related='product_id.part_number', readonly=True)
|
||||||
|
part_name = fields.Char('零件名称', related='product_id.part_name', readonly=True)
|
||||||
model_glb_file = fields.Binary('模型的glb文件', compute='_compute_model_glb_file', store=True)
|
model_glb_file = fields.Binary('模型的glb文件', compute='_compute_model_glb_file', store=True)
|
||||||
# product_template_id = fields.Many2one(
|
# product_template_id = fields.Many2one(
|
||||||
# string="产品",
|
# string="产品",
|
||||||
@@ -199,6 +264,7 @@ class ProductTemplate(models.Model):
|
|||||||
_inherit = 'product.template'
|
_inherit = 'product.template'
|
||||||
|
|
||||||
manual_quotation = fields.Boolean('人工编程', default=False)
|
manual_quotation = fields.Boolean('人工编程', default=False)
|
||||||
|
part_name = fields.Char(string='零件名称', readonly=True)
|
||||||
|
|
||||||
|
|
||||||
class RePurchaseOrder(models.Model):
|
class RePurchaseOrder(models.Model):
|
||||||
@@ -215,8 +281,22 @@ class RePurchaseOrder(models.Model):
|
|||||||
compute='_compute_user_id',
|
compute='_compute_user_id',
|
||||||
store=True)
|
store=True)
|
||||||
|
|
||||||
purchase_type = fields.Selection([('standard', '标准采购'), ('consignment', '委外加工')], string='采购类型',
|
purchase_type = fields.Selection(
|
||||||
default='standard')
|
[('standard', '标准采购'), ('consignment', '委外加工'), ('outsourcing', '工序外协'), ('outside', '外购订单')],
|
||||||
|
string='采购类型', default='standard')
|
||||||
|
|
||||||
|
origin_sale_id = fields.Many2one('sale.order', string='销售订单号', compute='_compute_origin_sale_id')
|
||||||
|
|
||||||
|
@api.depends('order_line.move_dest_ids.group_id.mrp_production_ids',
|
||||||
|
'order_line.move_ids.move_dest_ids.group_id.mrp_production_ids')
|
||||||
|
def _compute_origin_sale_id(self):
|
||||||
|
for purchase in self:
|
||||||
|
productions_ids = purchase._get_mrp_productions()
|
||||||
|
if productions_ids:
|
||||||
|
if productions_ids[0].sale_order_id:
|
||||||
|
purchase.origin_sale_id = productions_ids[0].sale_order_id.id
|
||||||
|
continue
|
||||||
|
purchase.origin_sale_id = False
|
||||||
|
|
||||||
delivery_warning = fields.Selection([('normal', '正常'), ('warning', '预警'), ('overdue', '已逾期')],
|
delivery_warning = fields.Selection([('normal', '正常'), ('warning', '预警'), ('overdue', '已逾期')],
|
||||||
string='交期状态',
|
string='交期状态',
|
||||||
@@ -259,7 +339,7 @@ class RePurchaseOrder(models.Model):
|
|||||||
else:
|
else:
|
||||||
server_template = self.env['product.template'].search(
|
server_template = self.env['product.template'].search(
|
||||||
[('server_product_process_parameters_id', '=', pp.surface_technics_parameters_id.id),
|
[('server_product_process_parameters_id', '=', pp.surface_technics_parameters_id.id),
|
||||||
('detailed_type', '=', 'service')])
|
('detailed_type', '=', 'service')])
|
||||||
server_product_process.append((0, 0, {
|
server_product_process.append((0, 0, {
|
||||||
'product_id': server_template.product_variant_id.id,
|
'product_id': server_template.product_variant_id.id,
|
||||||
'product_qty': 1,
|
'product_qty': 1,
|
||||||
@@ -325,6 +405,12 @@ class RePurchaseOrder(models.Model):
|
|||||||
return last_overdue_order, last_warning_order
|
return last_overdue_order, last_warning_order
|
||||||
|
|
||||||
|
|
||||||
|
class PurchaseOrderLine(models.Model):
|
||||||
|
_inherit = 'purchase.order.line'
|
||||||
|
|
||||||
|
part_name = fields.Char('零件名称', related='product_id.part_name', readonly=True)
|
||||||
|
# part_number = fields.Char('零件图号',related='product_id.part_number', readonly=True)
|
||||||
|
|
||||||
class ResPartnerToSale(models.Model):
|
class ResPartnerToSale(models.Model):
|
||||||
_inherit = 'res.partner'
|
_inherit = 'res.partner'
|
||||||
|
|
||||||
|
|||||||
3
sf_sale/static/src/css/purchase_list.css
Normal file
3
sf_sale/static/src/css/purchase_list.css
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.purchase_order_list_name {
|
||||||
|
min-width: 62px !important;
|
||||||
|
}
|
||||||
@@ -16,10 +16,11 @@
|
|||||||
<button name="button_confirm" type="object" states="draft" context="{'validate_analytic': True}"
|
<button name="button_confirm" type="object" states="draft" context="{'validate_analytic': True}"
|
||||||
string="Confirm Order" id="draft_confirm"/>
|
string="Confirm Order" id="draft_confirm"/>
|
||||||
<button name="action_view_picking"
|
<button name="action_view_picking"
|
||||||
string="接收产品" class="oe_highlight" type="object"
|
string="接收产品" class="oe_highlight" type="object"
|
||||||
attrs="{'invisible': ['|', '|' , ('is_shipped', '=', True), ('state','not in', ('purchase','done')), ('incoming_picking_count', '=', 0)]}"
|
attrs="{'invisible': ['|', '|' , ('is_shipped', '=', True), ('state','not in', ('purchase','done')), ('incoming_picking_count', '=', 0)]}"
|
||||||
data-hotkey="y" groups="stock.group_stock_user"/>
|
data-hotkey="y" groups="stock.group_stock_user"/>
|
||||||
<button name="button_cancel" states="draft,to approve,sent,purchase" string="取消" type="object" data-hotkey="x" />
|
<button name="button_cancel" states="draft,to approve,sent,purchase" string="取消" type="object"
|
||||||
|
data-hotkey="x"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//header/button[@name='button_cancel'][2]" position="attributes">
|
<xpath expr="//header/button[@name='button_cancel'][2]" position="attributes">
|
||||||
<attribute name="invisible">1</attribute>
|
<attribute name="invisible">1</attribute>
|
||||||
@@ -130,6 +131,16 @@
|
|||||||
<xpath expr="//field[@name='order_line']/tree/field[@name='product_id']" position="attributes">
|
<xpath expr="//field[@name='order_line']/tree/field[@name='product_id']" position="attributes">
|
||||||
<attribute name="options">{'no_create': True}</attribute>
|
<attribute name="options">{'no_create': True}</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
<xpath expr="//field[@name='order_line']/tree/field[@name='name']" position="attributes">
|
||||||
|
<attribute name="optional">hide</attribute>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//field[@name='order_line']/tree/field[@name='name']" position="after">
|
||||||
|
<field name="part_name" optional="hide"/>
|
||||||
|
<!-- <field name="part_number" optional="show"/>-->
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//field[@name='date_order']" position="attributes">
|
||||||
|
<attribute name="string">报价截止日期</attribute>
|
||||||
|
</xpath>
|
||||||
<field name="partner_ref" position="attributes">
|
<field name="partner_ref" position="attributes">
|
||||||
<attribute name="attrs">{'readonly': [('state', 'in', ['purchase'])]}
|
<attribute name="attrs">{'readonly': [('state', 'in', ['purchase'])]}
|
||||||
</attribute>
|
</attribute>
|
||||||
@@ -159,10 +170,14 @@
|
|||||||
</attribute>
|
</attribute>
|
||||||
</field>
|
</field>
|
||||||
|
|
||||||
<!-- 添加采购类型字段 -->
|
<!-- 添加采购类型字段 -->
|
||||||
<field name="partner_ref" position="after">
|
<field name="partner_ref" position="after">
|
||||||
<field name="purchase_type" string="采购类型" readonly="1"/>
|
<field name="purchase_type" string="采购类型" readonly="1"/>
|
||||||
</field>
|
</field>
|
||||||
|
<!-- 添加销售订单号字段-->
|
||||||
|
<field name="effective_date" position="after">
|
||||||
|
<field name="origin_sale_id" readonly="1" attrs="{'invisible': [('origin_sale_id', '=', False)]}"/>
|
||||||
|
</field>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
@@ -174,6 +189,25 @@
|
|||||||
<xpath expr="//tree//header//button[@name='action_create_invoice']" position="attributes">
|
<xpath expr="//tree//header//button[@name='action_create_invoice']" position="attributes">
|
||||||
<attribute name="groups">sf_base.group_purchase,sf_base.group_purchase_director</attribute>
|
<attribute name="groups">sf_base.group_purchase,sf_base.group_purchase_director</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
<xpath expr="//field[@name='user_id']" position="attributes">
|
||||||
|
<attribute name="string">采购员</attribute>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//field[@name='activity_ids']" position="attributes">
|
||||||
|
<attribute name="optional">hide</attribute>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//field[@name='date_order']" position="attributes">
|
||||||
|
<attribute name="string">报价截止日期</attribute>
|
||||||
|
<attribute name="widget">''</attribute>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//field[@name='date_order']" position="after">
|
||||||
|
<field name="date_planned"/>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//field[@name='name']" position="after">
|
||||||
|
<field name="purchase_type"/>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//field[@name='name']" position="attributes">
|
||||||
|
<attribute name="class">purchase_order_list_name</attribute>
|
||||||
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
@@ -203,9 +237,24 @@
|
|||||||
<attribute name="decoration-warning">delivery_warning == 'warning'</attribute>
|
<attribute name="decoration-warning">delivery_warning == 'warning'</attribute>
|
||||||
<attribute name="decoration-danger">delivery_warning == 'overdue'</attribute>
|
<attribute name="decoration-danger">delivery_warning == 'overdue'</attribute>
|
||||||
</tree>
|
</tree>
|
||||||
<field name="name" position="after">
|
<xpath expr="//field[@name='activity_ids']" position="attributes">
|
||||||
<field name="delivery_warning" invisible="1"/>
|
<attribute name="optional">hide</attribute>
|
||||||
</field>
|
</xpath>
|
||||||
|
<xpath expr="//field[@name='date_planned']" position="replace">
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//field[@name='user_id']" position="attributes">
|
||||||
|
<attribute name="string">采购员</attribute>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//field[@name='user_id']" position="after">
|
||||||
|
<field name="date_planned" string="预计到货日期" optional="show"/>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//field[@name='name']" position="after">
|
||||||
|
<field name="purchase_type"/>
|
||||||
|
<field name="delivery_warning" invisible="1"/>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//field[@name='name']" position="attributes">
|
||||||
|
<attribute name="class">purchase_order_list_name</attribute>
|
||||||
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
@@ -232,8 +281,29 @@
|
|||||||
<xpath expr="//field[@name='name']" position="replace">
|
<xpath expr="//field[@name='name']" position="replace">
|
||||||
<field name="name" string="单据编码" filter_domain="[('name', 'ilike', self)]"/>
|
<field name="name" string="单据编码" filter_domain="[('name', 'ilike', self)]"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
<!-- <xpath expr="//search" position="inside">-->
|
||||||
|
<!-- <searchpanel>-->
|
||||||
|
<!-- <field name="purchase_type" icon="fa-filter"/>-->
|
||||||
|
<!-- <field name="state" icon="fa-filter"/>-->
|
||||||
|
<!-- </searchpanel>-->
|
||||||
|
<!-- </xpath>-->
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<record id="purchase_order_view_search_sf" model="ir.ui.view">
|
||||||
|
<field name="name">purchase.order.list.select.sf</field>
|
||||||
|
<field name="model">purchase.order</field>
|
||||||
|
<field name="inherit_id" ref="purchase.purchase_order_view_search"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//search" position="inside">
|
||||||
|
<searchpanel>
|
||||||
|
<field name="purchase_type" icon="fa-filter" enable_counters="1"/>
|
||||||
|
<field name="state" icon="fa-filter" enable_counters="1"/>
|
||||||
|
</searchpanel>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
<record id="purchase.product_normal_action_puchased" model="ir.actions.act_window">
|
<record id="purchase.product_normal_action_puchased" model="ir.actions.act_window">
|
||||||
<field name="context">
|
<field name="context">
|
||||||
{"search_default_categ_id":1,"search_default_filter_to_purchase":1, "purchase_product_template": 1}
|
{"search_default_categ_id":1,"search_default_filter_to_purchase":1, "purchase_product_template": 1}
|
||||||
|
|||||||
@@ -103,6 +103,7 @@
|
|||||||
<xpath expr="//field[@name='order_line']/tree/field[@name='name']" position="before">
|
<xpath expr="//field[@name='order_line']/tree/field[@name='name']" position="before">
|
||||||
<field name="model_glb_file" widget="Viewer3D" optional="show"
|
<field name="model_glb_file" widget="Viewer3D" optional="show"
|
||||||
string="模型文件" attrs="{'readonly': [('state', 'in', ['draft'])]}"/>
|
string="模型文件" attrs="{'readonly': [('state', 'in', ['draft'])]}"/>
|
||||||
|
<field name="part_name" optional="hide"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='order_line']/tree/field[@name='price_subtotal']" position="after">
|
<xpath expr="//field[@name='order_line']/tree/field[@name='price_subtotal']" position="after">
|
||||||
<field name="remark"/>
|
<field name="remark"/>
|
||||||
@@ -169,20 +170,36 @@
|
|||||||
<field name="manual_quotation" />
|
<field name="manual_quotation" />
|
||||||
<field name="is_incoming_material"/>
|
<field name="is_incoming_material"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='date_order']" position="attributes">
|
<xpath expr="//sheet//group//group[@name='order_details']//div[@class='o_td_label'][2]//label[@for='date_order']" position="attributes">
|
||||||
<attribute name="string">下单时间</attribute>
|
<attribute name="string">下单日期</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<record id="sale_order_inherited_form_purchase_sf" model="ir.ui.view">
|
||||||
|
<field name="name">sale.order.inherited.form.purchase</field>
|
||||||
|
<field name="model">sale.order</field>
|
||||||
|
<field name="inherit_id" ref="sale_purchase.sale_order_inherited_form_purchase"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//button[@name='action_view_purchase_orders']" position="before">
|
||||||
|
<button class="oe_stat_button" name="action_view_consignment_purchase_orders" type="object" icon="fa-credit-card"
|
||||||
|
groups='purchase.group_purchase_user'
|
||||||
|
attrs="{'invisible': [('consignment_purchase_order_count', '=', 0)]}">
|
||||||
|
<div class="o_field_widget o_stat_info">
|
||||||
|
<span class="o_stat_value"><field name="consignment_purchase_order_count"/></span>
|
||||||
|
<span class="o_stat_text">委外加工</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
<record model="ir.ui.view" id="view_sale_management_order_form_quote_inherit_sf">
|
<record model="ir.ui.view" id="view_sale_management_order_form_quote_inherit_sf">
|
||||||
<field name="name">sale.management.order.form.quote.inherit.sf</field>
|
<field name="name">sale.management.order.form.quote.inherit.sf</field>
|
||||||
<field name="model">sale.order</field>
|
<field name="model">sale.order</field>
|
||||||
<field name="inherit_id" ref="sale_management.sale_order_form_quote"/>
|
<field name="inherit_id" ref="sale_management.sale_order_form_quote"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<field name="date_order" position="attributes">
|
|
||||||
<attribute name="string">下单日期</attribute>
|
|
||||||
</field>
|
|
||||||
<field name="sale_order_template_id" position="after">
|
<field name="sale_order_template_id" position="after">
|
||||||
<field name="remark" attrs="{'readonly': [('state', 'in', ('sale','cancel'))]}"/>
|
<field name="remark" attrs="{'readonly': [('state', 'in', ('sale','cancel'))]}"/>
|
||||||
</field>
|
</field>
|
||||||
@@ -224,6 +241,7 @@
|
|||||||
<attribute name="optional">hide</attribute>
|
<attribute name="optional">hide</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='create_date']" position="after">
|
<xpath expr="//field[@name='create_date']" position="after">
|
||||||
|
<field name="order_code"/>
|
||||||
<field name="deadline_of_delivery"/>
|
<field name="deadline_of_delivery"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<!-- <field name="state" position="after">
|
<!-- <field name="state" position="after">
|
||||||
@@ -245,6 +263,10 @@
|
|||||||
<separator/>
|
<separator/>
|
||||||
<filter string="预警" name="filter_order_warning" domain="[('delivery_warning', '=', 'warning')]"/>
|
<filter string="预警" name="filter_order_warning" domain="[('delivery_warning', '=', 'warning')]"/>
|
||||||
<filter string="逾期" name="filter_order_overdue" domain="[('delivery_warning', '=', 'overdue')]"/>
|
<filter string="逾期" name="filter_order_overdue" domain="[('delivery_warning', '=', 'overdue')]"/>
|
||||||
|
<searchpanel>
|
||||||
|
<field name="delivery_warning" string="交期状态" icon="fa-filter" enable_counters="1"/>
|
||||||
|
<field name="state" icon="fa-filter" enable_counters="1"/>
|
||||||
|
</searchpanel>
|
||||||
</xpath>
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
@@ -267,7 +289,11 @@
|
|||||||
<field name="amount_total" position="after">
|
<field name="amount_total" position="after">
|
||||||
<field name="delivery_warning" invisible="1"/>
|
<field name="delivery_warning" invisible="1"/>
|
||||||
</field>
|
</field>
|
||||||
|
<field name="date_order" position="attributes">
|
||||||
|
<attribute name="string">下单日期</attribute>
|
||||||
|
</field>
|
||||||
<xpath expr="//field[@name='date_order']" position="after">
|
<xpath expr="//field[@name='date_order']" position="after">
|
||||||
|
<field name="order_code"/>
|
||||||
<field name="deadline_of_delivery"/>
|
<field name="deadline_of_delivery"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='activity_ids']" position="attributes">
|
<xpath expr="//field[@name='activity_ids']" position="attributes">
|
||||||
@@ -276,6 +302,9 @@
|
|||||||
<xpath expr="//field[@name='invoice_status']" position="after">
|
<xpath expr="//field[@name='invoice_status']" position="after">
|
||||||
<field name="state"/>
|
<field name="state"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
<xpath expr="//field[@name='user_id']" position="after">
|
||||||
|
<field name="delivery_warning" string="交期状态"/>
|
||||||
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user