Merge branch 'refs/heads/develop' into feature/customer_material_optimization
This commit is contained in:
5
jikimo_purchase_tier_validation/__init__.py
Normal file
5
jikimo_purchase_tier_validation/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from . import controllers
|
||||||
|
from . import models
|
||||||
|
from . import wizards
|
||||||
36
jikimo_purchase_tier_validation/__manifest__.py
Normal file
36
jikimo_purchase_tier_validation/__manifest__.py
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
{
|
||||||
|
'name': "机企猫 采购审批流程",
|
||||||
|
|
||||||
|
'summary': """
|
||||||
|
Short (1 phrase/line) summary of the module's purpose, used as
|
||||||
|
subtitle on modules listing or apps.openerp.com""",
|
||||||
|
|
||||||
|
'description': """
|
||||||
|
Long description of module's purpose
|
||||||
|
""",
|
||||||
|
|
||||||
|
'author': "My Company",
|
||||||
|
'website': "https://www.yourcompany.com",
|
||||||
|
|
||||||
|
# Categories can be used to filter modules in modules listing
|
||||||
|
# Check https://github.com/odoo/odoo/blob/16.0/odoo/addons/base/data/ir_module_category_data.xml
|
||||||
|
# for the full list
|
||||||
|
'category': 'Uncategorized',
|
||||||
|
'version': '0.1',
|
||||||
|
|
||||||
|
# any module necessary for this one to work correctly
|
||||||
|
'depends': ['purchase', 'base_tier_validation', 'documents'],
|
||||||
|
|
||||||
|
# always loaded
|
||||||
|
'data': [
|
||||||
|
'security/ir.model.access.csv',
|
||||||
|
'data/documents_data.xml',
|
||||||
|
'wizards/upload_file_wizard_view.xml',
|
||||||
|
'views/views.xml',
|
||||||
|
],
|
||||||
|
# only loaded in demonstration mode
|
||||||
|
'demo': [
|
||||||
|
'demo/demo.xml',
|
||||||
|
],
|
||||||
|
}
|
||||||
3
jikimo_purchase_tier_validation/controllers/__init__.py
Normal file
3
jikimo_purchase_tier_validation/controllers/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from . import controllers
|
||||||
21
jikimo_purchase_tier_validation/controllers/controllers.py
Normal file
21
jikimo_purchase_tier_validation/controllers/controllers.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# from odoo import http
|
||||||
|
|
||||||
|
|
||||||
|
# class JikimoPurchaseTierValidation(http.Controller):
|
||||||
|
# @http.route('/jikimo_purchase_tier_validation/jikimo_purchase_tier_validation', auth='public')
|
||||||
|
# def index(self, **kw):
|
||||||
|
# return "Hello, world"
|
||||||
|
|
||||||
|
# @http.route('/jikimo_purchase_tier_validation/jikimo_purchase_tier_validation/objects', auth='public')
|
||||||
|
# def list(self, **kw):
|
||||||
|
# return http.request.render('jikimo_purchase_tier_validation.listing', {
|
||||||
|
# 'root': '/jikimo_purchase_tier_validation/jikimo_purchase_tier_validation',
|
||||||
|
# 'objects': http.request.env['jikimo_purchase_tier_validation.jikimo_purchase_tier_validation'].search([]),
|
||||||
|
# })
|
||||||
|
|
||||||
|
# @http.route('/jikimo_purchase_tier_validation/jikimo_purchase_tier_validation/objects/<model("jikimo_purchase_tier_validation.jikimo_purchase_tier_validation"):obj>', auth='public')
|
||||||
|
# def object(self, obj, **kw):
|
||||||
|
# return http.request.render('jikimo_purchase_tier_validation.object', {
|
||||||
|
# 'object': obj
|
||||||
|
# })
|
||||||
11
jikimo_purchase_tier_validation/data/documents_data.xml
Normal file
11
jikimo_purchase_tier_validation/data/documents_data.xml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<data noupdate="1">
|
||||||
|
<!-- 创建采购合同文件夹 -->
|
||||||
|
<record id="documents_purchase_contracts_folder" model="documents.folder">
|
||||||
|
<field name="name">采购合同</field>
|
||||||
|
<field name="description">存放采购合同相关文件</field>
|
||||||
|
<field name="sequence">10</field>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
30
jikimo_purchase_tier_validation/demo/demo.xml
Normal file
30
jikimo_purchase_tier_validation/demo/demo.xml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<odoo>
|
||||||
|
<data>
|
||||||
|
<!--
|
||||||
|
<record id="object0" model="jikimo_purchase_tier_validation.jikimo_purchase_tier_validation">
|
||||||
|
<field name="name">Object 0</field>
|
||||||
|
<field name="value">0</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="object1" model="jikimo_purchase_tier_validation.jikimo_purchase_tier_validation">
|
||||||
|
<field name="name">Object 1</field>
|
||||||
|
<field name="value">10</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="object2" model="jikimo_purchase_tier_validation.jikimo_purchase_tier_validation">
|
||||||
|
<field name="name">Object 2</field>
|
||||||
|
<field name="value">20</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="object3" model="jikimo_purchase_tier_validation.jikimo_purchase_tier_validation">
|
||||||
|
<field name="name">Object 3</field>
|
||||||
|
<field name="value">30</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="object4" model="jikimo_purchase_tier_validation.jikimo_purchase_tier_validation">
|
||||||
|
<field name="name">Object 4</field>
|
||||||
|
<field name="value">40</field>
|
||||||
|
</record>
|
||||||
|
-->
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
3
jikimo_purchase_tier_validation/models/__init__.py
Normal file
3
jikimo_purchase_tier_validation/models/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from . import models
|
||||||
154
jikimo_purchase_tier_validation/models/models.py
Normal file
154
jikimo_purchase_tier_validation/models/models.py
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
from odoo import models, fields, api, _
|
||||||
|
from odoo.exceptions import ValidationError
|
||||||
|
import logging
|
||||||
|
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class jikimo_purchase_tier_validation(models.Model):
|
||||||
|
_name = 'purchase.order'
|
||||||
|
_inherit = ['purchase.order', 'tier.validation']
|
||||||
|
|
||||||
|
_tier_validation_buttons_xpath = "/form/header/button[@id='draft_confirm'][1]"
|
||||||
|
|
||||||
|
contract_document_id = fields.Many2one('documents.document', string='合同文件')
|
||||||
|
contract_file = fields.Binary(related='contract_document_id.datas', string='合同文件内容')
|
||||||
|
contract_file_name = fields.Char(related='contract_document_id.attachment_id.name', string='文件名')
|
||||||
|
|
||||||
|
# 是否已上传合同文件
|
||||||
|
is_upload_contract_file = fields.Boolean(string='是否已上传合同文件', default=False)
|
||||||
|
|
||||||
|
def button_confirm(self):
|
||||||
|
for record in self:
|
||||||
|
if record.need_validation and record.validation_status != 'validated':
|
||||||
|
raise ValidationError(_('请先完成审批!'))
|
||||||
|
return super().button_confirm()
|
||||||
|
|
||||||
|
# def button_confirm(self):
|
||||||
|
# self = self.with_context(skip_validation=True)
|
||||||
|
# return super().button_confirm()
|
||||||
|
#
|
||||||
|
# def _check_state_conditions(self, vals):
|
||||||
|
# self.ensure_one()
|
||||||
|
# if self._context.get('skip_validation'):
|
||||||
|
# return False
|
||||||
|
# return (
|
||||||
|
# self._check_state_from_condition()
|
||||||
|
# and vals.get(self._state_field) in self._state_to
|
||||||
|
# )
|
||||||
|
|
||||||
|
def request_validation(self):
|
||||||
|
for record in self:
|
||||||
|
error_messages = []
|
||||||
|
|
||||||
|
# 检查必填字段
|
||||||
|
required_fields = {
|
||||||
|
'partner_ref': '合同名称',
|
||||||
|
'contract_number': '合同编号'
|
||||||
|
}
|
||||||
|
|
||||||
|
missing_fields = [
|
||||||
|
name for field, name in required_fields.items()
|
||||||
|
if not record[field]
|
||||||
|
]
|
||||||
|
|
||||||
|
if missing_fields:
|
||||||
|
error_messages.append('* 如下字段要求必须填写:%s' % '、'.join(missing_fields))
|
||||||
|
|
||||||
|
# 检查合同文件
|
||||||
|
if not record.contract_document_id:
|
||||||
|
error_messages.append('* 必须点击上传合同文件')
|
||||||
|
|
||||||
|
# 如果有任何错误,一次性显示所有错误信息
|
||||||
|
if error_messages:
|
||||||
|
raise ValidationError('\n'.join(error_messages))
|
||||||
|
|
||||||
|
return super(jikimo_purchase_tier_validation, self).request_validation()
|
||||||
|
|
||||||
|
# 上传合同文件
|
||||||
|
def upload_contract_file(self):
|
||||||
|
print('upload_contract_file===========================')
|
||||||
|
# self.ensure_one()
|
||||||
|
# return {
|
||||||
|
# 'name': _('上传合同文件'),
|
||||||
|
# 'type': 'ir.actions.act_window',
|
||||||
|
# 'res_model': 'ir.attachment',
|
||||||
|
# 'view_mode': 'form',
|
||||||
|
# 'view_type': 'form',
|
||||||
|
# 'target': 'new',
|
||||||
|
# 'context': {
|
||||||
|
# 'default_res_model': self._name,
|
||||||
|
# 'default_res_id': self.id,
|
||||||
|
# 'default_type': 'binary',
|
||||||
|
# 'default_mimetype': 'application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,image/jpeg,image/png',
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
|
||||||
|
self.ensure_one()
|
||||||
|
action = {
|
||||||
|
'type': 'ir.actions.act_window',
|
||||||
|
'name': _('上传合同文件'),
|
||||||
|
'res_model': 'ir.attachment.wizard', # 我们需要创建一个新的向导模型
|
||||||
|
'view_mode': 'form',
|
||||||
|
'target': 'new',
|
||||||
|
'context': {
|
||||||
|
'default_res_model': self._name,
|
||||||
|
'default_res_id': self.id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return action
|
||||||
|
|
||||||
|
# 删除合同文件
|
||||||
|
def delete_contract_file(self):
|
||||||
|
self.ensure_one()
|
||||||
|
if self.contract_document_id:
|
||||||
|
try:
|
||||||
|
document = self.contract_document_id
|
||||||
|
|
||||||
|
# 清空关联
|
||||||
|
self.write({
|
||||||
|
'contract_document_id': False,
|
||||||
|
'contract_file': False,
|
||||||
|
'contract_file_name': False
|
||||||
|
})
|
||||||
|
|
||||||
|
# 删除文档
|
||||||
|
if document:
|
||||||
|
document.with_context(no_attachment=True).sudo().unlink()
|
||||||
|
|
||||||
|
self.is_upload_contract_file = False
|
||||||
|
|
||||||
|
# 返回视图动作来刷新当前表单
|
||||||
|
return {
|
||||||
|
'type': 'ir.actions.act_window',
|
||||||
|
'res_model': 'purchase.order',
|
||||||
|
'res_id': self.id,
|
||||||
|
'view_mode': 'form',
|
||||||
|
'view_type': 'form',
|
||||||
|
'target': 'current',
|
||||||
|
'flags': {'mode': 'readonly'},
|
||||||
|
}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
_logger.error('删除合同文件时出错: %s', str(e))
|
||||||
|
return {
|
||||||
|
'type': 'ir.actions.client',
|
||||||
|
'tag': 'display_notification',
|
||||||
|
'params': {
|
||||||
|
'title': _('错误'),
|
||||||
|
'message': _('删除文件时出现错误'),
|
||||||
|
'type': 'danger',
|
||||||
|
'sticky': True,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
'type': 'ir.actions.client',
|
||||||
|
'tag': 'display_notification',
|
||||||
|
'params': {
|
||||||
|
'title': _('提示'),
|
||||||
|
'message': _('没有需要删除的合同文件'),
|
||||||
|
'type': 'warning',
|
||||||
|
'sticky': False,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||||
|
access_ir_attachment_wizard,ir.attachment.wizard,model_ir_attachment_wizard,base.group_user,1,1,1,1
|
||||||
|
24
jikimo_purchase_tier_validation/views/templates.xml
Normal file
24
jikimo_purchase_tier_validation/views/templates.xml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<odoo>
|
||||||
|
<data>
|
||||||
|
<!--
|
||||||
|
<template id="listing">
|
||||||
|
<ul>
|
||||||
|
<li t-foreach="objects" t-as="object">
|
||||||
|
<a t-attf-href="#{ root }/objects/#{ object.id }">
|
||||||
|
<t t-esc="object.display_name"/>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
<template id="object">
|
||||||
|
<h1><t t-esc="object.display_name"/></h1>
|
||||||
|
<dl>
|
||||||
|
<t t-foreach="object._fields" t-as="field">
|
||||||
|
<dt><t t-esc="field"/></dt>
|
||||||
|
<dd><t t-esc="object[field]"/></dd>
|
||||||
|
</t>
|
||||||
|
</dl>
|
||||||
|
</template>
|
||||||
|
-->
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
82
jikimo_purchase_tier_validation/views/views.xml
Normal file
82
jikimo_purchase_tier_validation/views/views.xml
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<odoo>
|
||||||
|
<data>
|
||||||
|
<record model="ir.ui.view" id="tier_validation_view_purchase_order_form_inherit">
|
||||||
|
<field name="name">tier_validation_view_purchase_order_form_inherit</field>
|
||||||
|
<field name="model">purchase.order</field>
|
||||||
|
<field name="inherit_id" ref="purchase.purchase_order_form"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//header/button[@name='button_cancel']" position="replace">
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
<xpath expr="//header/button[last()]" position="after">
|
||||||
|
<button name="button_cancel" states="draft,to approve,sent,purchase" string="取消" type="object" data-hotkey="x" />
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
<xpath expr="//header/button[@name='action_rfq_send'][1]" position="before">
|
||||||
|
<field name="validation_status" invisible="1"/>
|
||||||
|
<field name="is_upload_contract_file" invisible="1"/>
|
||||||
|
<button name="upload_contract_file" string="上传合同" type="object" class="oe_highlight" attrs="{'invisible': ['|', ('validation_status', '!=', 'no'), ('is_upload_contract_file', '=', True)]}"/>
|
||||||
|
<button name="delete_contract_file" string="删除合同" type="object" class="oe_highlight" attrs="{'invisible': ['|', ('validation_status', '!=', 'no'), ('is_upload_contract_file', '=', False)]}"/>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//notebook/page[1]" position="before">
|
||||||
|
<page string="合同" name="contract_documents"
|
||||||
|
attrs="{'invisible': [('contract_document_id', '=', False)]}"
|
||||||
|
autofocus="autofocus">
|
||||||
|
<group>
|
||||||
|
<group>
|
||||||
|
<field name="contract_document_id" invisible="1"/>
|
||||||
|
<field name="contract_file_name" invisible="1"/>
|
||||||
|
<field name="contract_file"
|
||||||
|
widget="adaptive_viewer"
|
||||||
|
filename="contract_file_name"/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
</page>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- actions opening views on models -->
|
||||||
|
<!--
|
||||||
|
<record model="ir.actions.act_window" id="jikimo_purchase_tier_validation.action_window">
|
||||||
|
<field name="name">jikimo_purchase_tier_validation window</field>
|
||||||
|
<field name="res_model">jikimo_purchase_tier_validation.jikimo_purchase_tier_validation</field>
|
||||||
|
<field name="view_mode">tree,form</field>
|
||||||
|
</record>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- server action to the one above -->
|
||||||
|
<!--
|
||||||
|
<record model="ir.actions.server" id="jikimo_purchase_tier_validation.action_server">
|
||||||
|
<field name="name">jikimo_purchase_tier_validation server</field>
|
||||||
|
<field name="model_id" ref="model_jikimo_purchase_tier_validation_jikimo_purchase_tier_validation"/>
|
||||||
|
<field name="state">code</field>
|
||||||
|
<field name="code">
|
||||||
|
action = {
|
||||||
|
"type": "ir.actions.act_window",
|
||||||
|
"view_mode": "tree,form",
|
||||||
|
"res_model": model._name,
|
||||||
|
}
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Top menu item -->
|
||||||
|
<!--
|
||||||
|
<menuitem name="jikimo_purchase_tier_validation" id="jikimo_purchase_tier_validation.menu_root"/>
|
||||||
|
-->
|
||||||
|
<!-- menu categories -->
|
||||||
|
<!--
|
||||||
|
<menuitem name="Menu 1" id="jikimo_purchase_tier_validation.menu_1" parent="jikimo_purchase_tier_validation.menu_root"/>
|
||||||
|
<menuitem name="Menu 2" id="jikimo_purchase_tier_validation.menu_2" parent="jikimo_purchase_tier_validation.menu_root"/>
|
||||||
|
-->
|
||||||
|
<!-- actions -->
|
||||||
|
<!--
|
||||||
|
<menuitem name="List" id="jikimo_purchase_tier_validation.menu_1_list" parent="jikimo_purchase_tier_validation.menu_1"
|
||||||
|
action="jikimo_purchase_tier_validation.action_window"/>
|
||||||
|
<menuitem name="Server to list" id="jikimo_purchase_tier_validation" parent="jikimo_purchase_tier_validation.menu_2"
|
||||||
|
action="jikimo_purchase_tier_validation.action_server"/>
|
||||||
|
-->
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
1
jikimo_purchase_tier_validation/wizards/__init__.py
Normal file
1
jikimo_purchase_tier_validation/wizards/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from . import upload_file_wizard
|
||||||
114
jikimo_purchase_tier_validation/wizards/upload_file_wizard.py
Normal file
114
jikimo_purchase_tier_validation/wizards/upload_file_wizard.py
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
from odoo import models, fields, api, _
|
||||||
|
|
||||||
|
|
||||||
|
class IrAttachmentWizard(models.TransientModel):
|
||||||
|
_name = 'ir.attachment.wizard'
|
||||||
|
_description = '文件上传向导'
|
||||||
|
|
||||||
|
attachment = fields.Binary(string='选择文件', required=True)
|
||||||
|
filename = fields.Char(string='文件名')
|
||||||
|
res_model = fields.Char()
|
||||||
|
res_id = fields.Integer()
|
||||||
|
|
||||||
|
# def action_upload_file(self):
|
||||||
|
# self.ensure_one()
|
||||||
|
# # 首先创建 ir.attachment
|
||||||
|
# attachment = self.env['ir.attachment'].create({
|
||||||
|
# 'name': self.filename,
|
||||||
|
# 'type': 'binary',
|
||||||
|
# 'datas': self.attachment,
|
||||||
|
# 'res_model': self.res_model,
|
||||||
|
# 'res_id': self.res_id,
|
||||||
|
# })
|
||||||
|
#
|
||||||
|
# # 获取默认的文档文件夹
|
||||||
|
# workspace = self.env['documents.folder'].search([('name', '=', '采购合同')], limit=1)
|
||||||
|
#
|
||||||
|
# # 创建 documents.document 记录
|
||||||
|
# document = self.env['documents.document'].create({
|
||||||
|
# 'name': self.filename,
|
||||||
|
# 'attachment_id': attachment.id,
|
||||||
|
# 'folder_id': workspace.id,
|
||||||
|
# 'res_model': self.res_model,
|
||||||
|
# 'res_id': self.res_id,
|
||||||
|
# })
|
||||||
|
#
|
||||||
|
# return {
|
||||||
|
# 'type': 'ir.actions.client',
|
||||||
|
# 'tag': 'display_notification',
|
||||||
|
# 'params': {
|
||||||
|
# 'title': _('成功'),
|
||||||
|
# 'message': _('文件上传成功'),
|
||||||
|
# 'type': 'success',
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
|
||||||
|
def action_upload_file(self):
|
||||||
|
self.ensure_one()
|
||||||
|
# 获取当前用户的 partner_id
|
||||||
|
current_partner = self.env.user.partner_id
|
||||||
|
# 首先创建 ir.attachment
|
||||||
|
attachment = self.env['ir.attachment'].create({
|
||||||
|
'name': self.filename,
|
||||||
|
'type': 'binary',
|
||||||
|
'datas': self.attachment,
|
||||||
|
'res_model': self.res_model,
|
||||||
|
'res_id': self.res_id,
|
||||||
|
})
|
||||||
|
|
||||||
|
# 获取默认的文档文件夹
|
||||||
|
workspace = self.env['documents.folder'].search([('name', '=', '采购合同')], limit=1)
|
||||||
|
|
||||||
|
# 创建 documents.document 记录
|
||||||
|
document = self.env['documents.document'].create({
|
||||||
|
'name': self.filename,
|
||||||
|
'attachment_id': attachment.id,
|
||||||
|
'folder_id': workspace.id,
|
||||||
|
'res_model': self.res_model,
|
||||||
|
'res_id': self.res_id,
|
||||||
|
'partner_id': current_partner.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
# 更新采购订单的合同文档字段
|
||||||
|
purchase_order = self.env['purchase.order'].browse(self.res_id)
|
||||||
|
purchase_order.write({
|
||||||
|
'contract_document_id': document.id,
|
||||||
|
'is_upload_contract_file': True
|
||||||
|
})
|
||||||
|
|
||||||
|
# 显示成功消息并关闭向导
|
||||||
|
message = {
|
||||||
|
'type': 'ir.actions.client',
|
||||||
|
'tag': 'display_notification',
|
||||||
|
'params': {
|
||||||
|
'title': _('成功'),
|
||||||
|
'message': _('文件上传成功'),
|
||||||
|
'type': 'success',
|
||||||
|
'sticky': False, # 自动消失
|
||||||
|
'next': {
|
||||||
|
'type': 'ir.actions.act_window_close'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return message
|
||||||
|
|
||||||
|
|
||||||
|
# def action_upload_file(self):
|
||||||
|
# self.ensure_one()
|
||||||
|
# attachment = self.env['ir.attachment'].create({
|
||||||
|
# 'name': self.filename,
|
||||||
|
# 'type': 'binary',
|
||||||
|
# 'datas': self.attachment,
|
||||||
|
# 'res_model': self.res_model,
|
||||||
|
# 'res_id': self.res_id,
|
||||||
|
# })
|
||||||
|
# return {
|
||||||
|
# 'type': 'ir.actions.client',
|
||||||
|
# 'tag': 'display_notification',
|
||||||
|
# 'params': {
|
||||||
|
# 'title': _('成功'),
|
||||||
|
# 'message': _('文件上传成功'),
|
||||||
|
# 'type': 'success',
|
||||||
|
# }
|
||||||
|
# }
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<record id="view_upload_file_wizard_form" model="ir.ui.view">
|
||||||
|
<field name="name">ir.attachment.wizard.form</field>
|
||||||
|
<field name="model">ir.attachment.wizard</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form string="上传文件">
|
||||||
|
<group>
|
||||||
|
<field name="attachment" widget="binary" filename="filename" options="{'accepted_file_extensions': '.pdf,.doc,.docx,.jpg,.jpeg,.png'}"/>
|
||||||
|
<field name="filename" invisible="1"/>
|
||||||
|
<field name="res_model" invisible="1"/>
|
||||||
|
<field name="res_id" invisible="1"/>
|
||||||
|
</group>
|
||||||
|
<footer>
|
||||||
|
<button name="action_upload_file" string="确认上传" type="object" class="btn-primary"/>
|
||||||
|
<button string="取消" class="btn-secondary" special="cancel"/>
|
||||||
|
</footer>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</odoo>
|
||||||
@@ -51,11 +51,11 @@ class JikimoWorkorderException(models.Model):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
def _get_message(self, message_queue_ids):
|
def _get_message(self, message_queue_ids):
|
||||||
contents = super(JikimoWorkorderException, self)._get_message(message_queue_ids)
|
contents, _ = super(JikimoWorkorderException, self)._get_message(message_queue_ids)
|
||||||
url = self.env['ir.config_parameter'].get_param('web.base.url')
|
url = self.env['ir.config_parameter'].get_param('web.base.url')
|
||||||
action_id = self.env.ref('mrp.mrp_production_action').id
|
action_id = self.env.ref('mrp.mrp_production_action').id
|
||||||
for index, content in enumerate(contents):
|
for index, content in enumerate(contents):
|
||||||
exception_id = self.env['jikimo.workorder.exception'].browse(message_queue_ids[index].res_id)
|
exception_id = self.env['jikimo.workorder.exception'].browse(message_queue_ids[index].res_id)
|
||||||
url = url + '/web#id=%s&view_type=form&action=%s' % (exception_id.workorder_id.production_id.id, action_id)
|
url = url + '/web#id=%s&view_type=form&action=%s' % (exception_id.workorder_id.production_id.id, action_id)
|
||||||
contents[index] = content.replace('{{url}}', url)
|
contents[index] = content.replace('{{url}}', url)
|
||||||
return contents
|
return contents, message_queue_ids
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from datetime import datetime
|
|||||||
import random
|
import random
|
||||||
|
|
||||||
from odoo import api, models, fields, _
|
from odoo import api, models, fields, _
|
||||||
|
from odoo.api import depends
|
||||||
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, float_round
|
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, float_round
|
||||||
from odoo.osv.expression import OR
|
from odoo.osv.expression import OR
|
||||||
|
|
||||||
@@ -122,7 +123,13 @@ class QualityPoint(models.Model):
|
|||||||
|
|
||||||
class QualityCheck(models.Model):
|
class QualityCheck(models.Model):
|
||||||
_inherit = "quality.check"
|
_inherit = "quality.check"
|
||||||
|
part_name = fields.Char('零件名称', compute='_compute_part_name_number', readonly=True)
|
||||||
|
part_number = fields.Char('零件图号', compute='_compute_part_name_number', readonly=True)
|
||||||
|
@depends('product_id')
|
||||||
|
def _compute_part_name_number(self):
|
||||||
|
for record in self:
|
||||||
|
record.part_number = record.product_id.part_number
|
||||||
|
record.part_name = record.product_id.part_name
|
||||||
failure_message = fields.Html(related='point_id.failure_message', readonly=True)
|
failure_message = fields.Html(related='point_id.failure_message', readonly=True)
|
||||||
measure = fields.Float('Measure', default=0.0, digits='Quality Tests', tracking=True)
|
measure = fields.Float('Measure', default=0.0, digits='Quality Tests', tracking=True)
|
||||||
measure_success = fields.Selection([
|
measure_success = fields.Selection([
|
||||||
|
|||||||
@@ -389,6 +389,8 @@
|
|||||||
<field name="name" decoration-bf="1"/>
|
<field name="name" decoration-bf="1"/>
|
||||||
<field name="measure_on" optional="show"/>
|
<field name="measure_on" optional="show"/>
|
||||||
<field name='product_id' optional="show"/>
|
<field name='product_id' optional="show"/>
|
||||||
|
<field name="part_name" optional="hide"/>
|
||||||
|
<field name='part_number' optional="show"/>
|
||||||
<field name="lot_id" invisible="context.get('show_lots_text')"/>
|
<field name="lot_id" invisible="context.get('show_lots_text')"/>
|
||||||
<field name="lot_name" invisible="not context.get('show_lots_text')"/>
|
<field name="lot_name" invisible="not context.get('show_lots_text')"/>
|
||||||
<field name="picking_id" optional="hide" string="Transfer"/>
|
<field name="picking_id" optional="hide" string="Transfer"/>
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ class StockRuleInherit(models.Model):
|
|||||||
@api.model
|
@api.model
|
||||||
def _run_buy(self, procurements):
|
def _run_buy(self, procurements):
|
||||||
# 判断补货组的采购类型
|
# 判断补货组的采购类型
|
||||||
procurements_group = {'standard': [], 'consignment': []}
|
procurements_group = {'standard': [], 'outsourcing': []}
|
||||||
for procurement, rule in procurements:
|
for procurement, rule in procurements:
|
||||||
is_consignment = False
|
is_outsourcing = False
|
||||||
product = procurement.product_id
|
product = procurement.product_id
|
||||||
# 获取主 BOM
|
# 获取主 BOM
|
||||||
bom = self.env['mrp.bom'].search([('product_tmpl_id', '=', product.product_tmpl_id.id)], limit=1)
|
bom = self.env['mrp.bom'].search([('product_tmpl_id', '=', product.product_tmpl_id.id)], limit=1)
|
||||||
@@ -24,17 +24,17 @@ class StockRuleInherit(models.Model):
|
|||||||
for route in raw_material.route_ids:
|
for route in raw_material.route_ids:
|
||||||
# print('route.name:', route.name)
|
# print('route.name:', route.name)
|
||||||
if route.name == '按订单补给外包商':
|
if route.name == '按订单补给外包商':
|
||||||
is_consignment = True
|
is_outsourcing = True
|
||||||
|
|
||||||
if is_consignment:
|
if is_outsourcing:
|
||||||
procurements_group['consignment'].append((procurement, rule))
|
procurements_group['outsourcing'].append((procurement, rule))
|
||||||
else:
|
else:
|
||||||
procurements_group['standard'].append((procurement, rule))
|
procurements_group['standard'].append((procurement, rule))
|
||||||
|
|
||||||
for key, value in procurements_group.items():
|
for key, value in procurements_group.items():
|
||||||
super(StockRuleInherit, self)._run_buy(value)
|
super(StockRuleInherit, self)._run_buy(value)
|
||||||
|
|
||||||
if key == 'consignment':
|
if key == 'outsourcing':
|
||||||
for procurement, rule in value:
|
for procurement, rule in value:
|
||||||
supplier = procurement.values.get('supplier')
|
supplier = procurement.values.get('supplier')
|
||||||
if supplier:
|
if supplier:
|
||||||
@@ -49,7 +49,7 @@ class StockRuleInherit(models.Model):
|
|||||||
], limit=1)
|
], limit=1)
|
||||||
logging.info("po=: %s", po)
|
logging.info("po=: %s", po)
|
||||||
if po:
|
if po:
|
||||||
po.write({'purchase_type': 'consignment'})
|
po.write({'purchase_type': 'outsourcing'})
|
||||||
|
|
||||||
# # 首先调用父类的 _run_buy 方法,以保留原有逻辑
|
# # 首先调用父类的 _run_buy 方法,以保留原有逻辑
|
||||||
# super(StockRuleInherit, self)._run_buy(procurements)
|
# super(StockRuleInherit, self)._run_buy(procurements)
|
||||||
@@ -83,5 +83,5 @@ class StockRuleInherit(models.Model):
|
|||||||
# ], limit=1)
|
# ], limit=1)
|
||||||
# logging.info("po=: %s", po)
|
# logging.info("po=: %s", po)
|
||||||
# if po:
|
# if po:
|
||||||
# po.write({'purchase_type': 'consignment'})
|
# po.write({'purchase_type': 'outsourcing'})
|
||||||
# break
|
# break
|
||||||
|
|||||||
@@ -363,24 +363,18 @@ class MrpProduction(models.Model):
|
|||||||
# if production.state == 'pending_cam':
|
# if production.state == 'pending_cam':
|
||||||
# if all(wo_state in 'done' for wo_state in production.workorder_ids.mapped('state')):
|
# if all(wo_state in 'done' for wo_state in production.workorder_ids.mapped('state')):
|
||||||
# production.state = 'done'
|
# production.state = 'done'
|
||||||
if any(
|
if any((wo.test_results == '返工' and wo.state == 'done' and production.programming_state in ['已编程'])
|
||||||
(
|
or (wo.is_rework is True and wo.state == 'done' and production.programming_state in ['编程中', '已编程'])
|
||||||
wo.test_results == '返工' and wo.state == 'done' and production.programming_state in [
|
for wo in production.workorder_ids):
|
||||||
'已编程']) or (
|
|
||||||
wo.state == 'rework' and production.programming_state == '编程中') or (
|
|
||||||
wo.is_rework is True and wo.state == 'done' and production.programming_state in ['编程中',
|
|
||||||
'已编程'])
|
|
||||||
for wo in
|
|
||||||
production.workorder_ids):
|
|
||||||
production.state = 'rework'
|
production.state = 'rework'
|
||||||
if any(wo.test_results == '报废' and wo.state == 'done' for wo in production.workorder_ids):
|
if any(wo.test_results == '报废' and wo.state == 'done' for wo in production.workorder_ids):
|
||||||
production.state = 'scrap'
|
production.state = 'scrap'
|
||||||
if any(dr.test_results == '报废' and dr.handle_result == '已处理' for dr in
|
if any(dr.test_results == '报废' and dr.handle_result == '已处理' for dr in
|
||||||
production.detection_result_ids):
|
production.detection_result_ids):
|
||||||
production.state = 'cancel'
|
production.state = 'cancel'
|
||||||
# 如果制造订单的功能刀具为【无效刀】则制造订单状态改为返工
|
if production.workorder_ids and all(wo_state in ('done', 'rework', 'cancel') for wo_state in production.workorder_ids.mapped('state')):
|
||||||
if production.tool_state == '2':
|
if production.state not in ['scrap', 'rework', 'cancel']:
|
||||||
production.state = 'rework'
|
production.state = 'done'
|
||||||
|
|
||||||
# 退回调整
|
# 退回调整
|
||||||
def technology_back_adjust(self):
|
def technology_back_adjust(self):
|
||||||
@@ -809,45 +803,45 @@ class MrpProduction(models.Model):
|
|||||||
workorder.move_subcontract_workorder_ids.picking_id.write({'state': 'cancel'})
|
workorder.move_subcontract_workorder_ids.picking_id.write({'state': 'cancel'})
|
||||||
consecutive_workorders = []
|
consecutive_workorders = []
|
||||||
sorted_workorders = sorted(process_parameter_workorder, key=lambda w: w.sequence)
|
sorted_workorders = sorted(process_parameter_workorder, key=lambda w: w.sequence)
|
||||||
for i, workorder in enumerate(sorted_workorders):
|
# for i, workorder in enumerate(sorted_workorders):
|
||||||
# 检查当前工作订单和下一个工作订单是否连续,并且供应商相同
|
# # 检查当前工作订单和下一个工作订单是否连续,并且供应商相同
|
||||||
if i == 0:
|
# if i == 0:
|
||||||
consecutive_workorders.append(workorder)
|
# consecutive_workorders.append(workorder)
|
||||||
elif workorder.sequence == sorted_workorders[
|
# elif workorder.sequence == sorted_workorders[
|
||||||
i - 1].sequence + 1 and workorder.supplier_id.id == sorted_workorders[i - 1].supplier_id.id:
|
# i - 1].sequence + 1 and workorder.supplier_id.id == sorted_workorders[i - 1].supplier_id.id:
|
||||||
consecutive_workorders.append(workorder)
|
# consecutive_workorders.append(workorder)
|
||||||
else:
|
# else:
|
||||||
# 处理连续组,如果它不为空
|
# # 处理连续组,如果它不为空
|
||||||
if consecutive_workorders:
|
# if consecutive_workorders:
|
||||||
proc_workorders.append(consecutive_workorders)
|
# proc_workorders.append(consecutive_workorders)
|
||||||
# 创建外协出入库单和采购订单
|
# # 创建外协出入库单和采购订单
|
||||||
# self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production, sorted_workorders)
|
# # self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production, sorted_workorders)
|
||||||
# self.env['purchase.order'].get_purchase_order(consecutive_workorders, production,
|
# # self.env['purchase.order'].get_purchase_order(consecutive_workorders, production,
|
||||||
# product_id_to_production_names)
|
# # product_id_to_production_names)
|
||||||
if i < len(sorted_workorders) - 1:
|
# if i < len(sorted_workorders) - 1:
|
||||||
# 重置连续组,并添加当前工作订单
|
# # 重置连续组,并添加当前工作订单
|
||||||
consecutive_workorders = [workorder]
|
# consecutive_workorders = [workorder]
|
||||||
else:
|
# else:
|
||||||
# 判断最后一笔:
|
# # 判断最后一笔:
|
||||||
if workorder.sequence == sorted_workorders[
|
# if workorder.sequence == sorted_workorders[
|
||||||
i - 1].sequence and workorder.supplier_id.id == sorted_workorders[
|
# i - 1].sequence and workorder.supplier_id.id == sorted_workorders[
|
||||||
i - 1].supplier_id.id:
|
# i - 1].supplier_id.id:
|
||||||
consecutive_workorders = [workorder]
|
# consecutive_workorders = [workorder]
|
||||||
else:
|
# else:
|
||||||
proc_workorders.append([workorder])
|
# proc_workorders.append([workorder])
|
||||||
# 立即创建外协出入库单和采购订单
|
# # 立即创建外协出入库单和采购订单
|
||||||
# self.env['stock.picking'].create_outcontract_picking(workorder, production)
|
# # self.env['stock.picking'].create_outcontract_picking(workorder, production)
|
||||||
# self.env['purchase.order'].get_purchase_order(workorder, production,
|
# # self.env['purchase.order'].get_purchase_order(workorder, production,
|
||||||
# product_id_to_production_names)
|
# # product_id_to_production_names)
|
||||||
consecutive_workorders = []
|
# consecutive_workorders = []
|
||||||
|
#
|
||||||
# 处理最后一个组,即使它可能只有一个工作订单
|
# # 处理最后一个组,即使它可能只有一个工作订单
|
||||||
if consecutive_workorders:
|
# if consecutive_workorders:
|
||||||
proc_workorders.append(consecutive_workorders)
|
# proc_workorders.append(consecutive_workorders)
|
||||||
# self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production)
|
# self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production)
|
||||||
# self.env['purchase.order'].get_purchase_order(consecutive_workorders, production,
|
# self.env['purchase.order'].get_purchase_order(consecutive_workorders, production,
|
||||||
# product_id_to_production_names)
|
# product_id_to_production_names)
|
||||||
for workorders in reversed(proc_workorders):
|
for workorders in reversed(sorted_workorders):
|
||||||
self.env['stock.picking'].create_outcontract_picking(workorders, production, sorted_workorders)
|
self.env['stock.picking'].create_outcontract_picking(workorders, production, sorted_workorders)
|
||||||
self.env['purchase.order'].get_purchase_order(workorders, production, product_id_to_production_names)
|
self.env['purchase.order'].get_purchase_order(workorders, production, product_id_to_production_names)
|
||||||
|
|
||||||
|
|||||||
@@ -31,3 +31,13 @@ class PurchaseOrder(models.Model):
|
|||||||
class PurchaseOrderLine(models.Model):
|
class PurchaseOrderLine(models.Model):
|
||||||
_inherit = 'purchase.order.line'
|
_inherit = 'purchase.order.line'
|
||||||
part_number = fields.Char('零件图号', related='product_id.part_number', readonly=True)
|
part_number = fields.Char('零件图号', related='product_id.part_number', readonly=True)
|
||||||
|
related_product = fields.Many2one('product.product',compute='_compute_related_product', string='关联产品',help='经此产品工艺加工成的成品')
|
||||||
|
@api.depends('order_id.origin')
|
||||||
|
def _compute_related_product(self):
|
||||||
|
for record in self:
|
||||||
|
if record.product_id.detailed_type:
|
||||||
|
production_id = self.env['mrp.production'].search([('name', '=', record.order_id.origin)])
|
||||||
|
record.related_product = production_id.product_id if production_id else False
|
||||||
|
else:
|
||||||
|
record.related_product = False
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from collections import Counter
|
||||||
|
|
||||||
from odoo import fields, models, api, _
|
from odoo import fields, models, api, _
|
||||||
from odoo.exceptions import ValidationError
|
from odoo.exceptions import ValidationError
|
||||||
|
|
||||||
@@ -6,7 +8,7 @@ from odoo.exceptions import ValidationError
|
|||||||
class sf_technology_design(models.Model):
|
class sf_technology_design(models.Model):
|
||||||
_name = 'sf.technology.design'
|
_name = 'sf.technology.design'
|
||||||
_description = "工艺设计"
|
_description = "工艺设计"
|
||||||
|
group_uniq_id = fields.Integer('同一制造订单唯一id',default=0)
|
||||||
sequence = fields.Integer('序号')
|
sequence = fields.Integer('序号')
|
||||||
route_id = fields.Many2one('mrp.routing.workcenter', '工序')
|
route_id = fields.Many2one('mrp.routing.workcenter', '工序')
|
||||||
process_parameters_id = fields.Many2one('sf.production.process.parameter', string='表面工艺参数')
|
process_parameters_id = fields.Many2one('sf.production.process.parameter', string='表面工艺参数')
|
||||||
@@ -17,6 +19,11 @@ 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)
|
||||||
|
|
||||||
|
# @api.depends('production_id')
|
||||||
|
# def _compute_group_uniq_id(self):
|
||||||
|
# for record in self:
|
||||||
|
|
||||||
|
|
||||||
def json_technology_design_str(self, k, route, i, process_parameter):
|
def json_technology_design_str(self, k, route, i, process_parameter):
|
||||||
workorders_values_str = [0, '', {
|
workorders_values_str = [0, '', {
|
||||||
'route_id': route.id if route.routing_type in ['表面工艺'] else route.route_workcenter_id.id,
|
'route_id': route.id if route.routing_type in ['表面工艺'] else route.route_workcenter_id.id,
|
||||||
@@ -28,6 +35,9 @@ class sf_technology_design(models.Model):
|
|||||||
'is_auto': True}]
|
'is_auto': True}]
|
||||||
return workorders_values_str
|
return workorders_values_str
|
||||||
|
|
||||||
|
def write(self, vals):
|
||||||
|
print('qwfojkqwfkio')
|
||||||
|
return super(sf_technology_design, self).write(vals)
|
||||||
def unlink_technology_design(self):
|
def unlink_technology_design(self):
|
||||||
self.active = False
|
self.active = False
|
||||||
|
|
||||||
@@ -37,4 +47,64 @@ class sf_technology_design(models.Model):
|
|||||||
for vals in vals_list:
|
for vals in vals_list:
|
||||||
if not vals.get('route_id'):
|
if not vals.get('route_id'):
|
||||||
raise ValidationError(_("工序不能为空"))
|
raise ValidationError(_("工序不能为空"))
|
||||||
return super(sf_technology_design, self).create(vals_list)
|
result = super(sf_technology_design, self).create(vals_list)
|
||||||
|
for res in result:
|
||||||
|
record = self.search([('production_id', '=', res.production_id.id), ('active', 'in', [True, False])], order='group_uniq_id desc', limit=1)
|
||||||
|
res.group_uniq_id=record.group_uniq_id + 1
|
||||||
|
return result
|
||||||
|
def get_duplicates_with_inactive(self,technology_designs):
|
||||||
|
# 统计每个 'sequence' 出现的次数
|
||||||
|
sequence_count = Counter(technology_design.sequence for technology_design in technology_designs)
|
||||||
|
|
||||||
|
# 筛选出 'sequence' 重复且 'active' 为 False 的元素
|
||||||
|
result = [
|
||||||
|
technology_design for technology_design in technology_designs
|
||||||
|
if sequence_count[technology_design.sequence] > 1 and technology_design.active is False
|
||||||
|
]
|
||||||
|
|
||||||
|
return result
|
||||||
|
# def rearrange_numbering(self,self_technology_designs):
|
||||||
|
# inactive_designs = self.get_duplicates_with_inactive(self_technology_designs)
|
||||||
|
# if inactive_designs:
|
||||||
|
# max_design = max(self_technology_designs, key=lambda x: x.sequence)
|
||||||
|
# max_sequence = max_design.sequence if max_design else 0
|
||||||
|
# for designs in inactive_designs:
|
||||||
|
# max_sequence += 1
|
||||||
|
# designs.sequence = max_sequence
|
||||||
|
# self_technology_designs.sorted(key=lambda techology_design:techology_design.sequence)
|
||||||
|
# return self_technology_designs
|
||||||
|
|
||||||
|
def get_technology_design(self):
|
||||||
|
return {
|
||||||
|
'sequence':self.sequence,
|
||||||
|
'route_id': self.route_id.id,
|
||||||
|
'process_parameters_id': self.process_parameters_id.id,
|
||||||
|
'panel': self.panel,
|
||||||
|
'routing_tag': self.routing_tag,
|
||||||
|
'time_cycle_manual': self.time_cycle_manual,
|
||||||
|
'is_auto': self.is_auto,
|
||||||
|
'active': self.active,
|
||||||
|
'group_uniq_id':self.group_uniq_id,
|
||||||
|
}
|
||||||
|
def sync_technology_designs(self,production_technology_designs, self_technology_designs):
|
||||||
|
production_id = production_technology_designs[0].production_id.id
|
||||||
|
self_technology_design_dict = {item.group_uniq_id:item for item in self_technology_designs}
|
||||||
|
production_technology_designs_dict = {item.group_uniq_id:item for item in production_technology_designs}
|
||||||
|
for technology_design in production_technology_designs:
|
||||||
|
if not self_technology_design_dict.get(technology_design.group_uniq_id):
|
||||||
|
technology_design.write({'production_id': False})
|
||||||
|
else:
|
||||||
|
technology_design.write(self_technology_design_dict.get(technology_design.group_uniq_id).get_technology_design())
|
||||||
|
for technology_design in self_technology_designs:
|
||||||
|
if not production_technology_designs_dict.get(technology_design.group_uniq_id):
|
||||||
|
technology_design = technology_design.get_technology_design()
|
||||||
|
technology_design.update({'production_id': production_id})
|
||||||
|
technology_design.pop('group_uniq_id')
|
||||||
|
self.env['sf.technology.design'].create(technology_design)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def unified_procedure_multiple_work_orders(self,self_technology_designs,production_item):
|
||||||
|
technology_designs = self.env['sf.technology.design'].sudo().search(
|
||||||
|
[('production_id', '=', production_item.id), ('active', 'in', [True, False])])
|
||||||
|
self.sync_technology_designs(self_technology_designs=self_technology_designs,production_technology_designs=technology_designs)
|
||||||
@@ -684,14 +684,13 @@ class StockPicking(models.Model):
|
|||||||
'partner_id': self.partner_id.id,
|
'partner_id': self.partner_id.id,
|
||||||
})
|
})
|
||||||
move_dest_id = False
|
move_dest_id = False
|
||||||
# 如果当前工单是是制造订单的最后一个工单
|
# 如果当前工单是是制造订单的最后一个工艺外协工单
|
||||||
if workorder == item.workorder_ids[-1]:
|
if workorder == next((workorder for workorder in reversed(item.workorder_ids) if workorder.is_subcontract), None):
|
||||||
move_dest_id = item.move_raw_ids[0].id
|
move_dest_id = item.move_raw_ids[0].id
|
||||||
else:
|
else:
|
||||||
# 从sorted_workorders中找到上一工单的move
|
# 从sorted_workorders中找到上一工单的move
|
||||||
if sorted_workorders.index(workorder) > 0:
|
if len(sorted_workorders) > 1:
|
||||||
move_dest_id = \
|
move_dest_id = sorted_workorders[sorted_workorders.index(workorder)+1].move_subcontract_workorder_ids[1].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,
|
||||||
|
|||||||
@@ -131,11 +131,6 @@
|
|||||||
<field name="deadline_of_delivery" readonly="1"/>
|
<field name="deadline_of_delivery" readonly="1"/>
|
||||||
<field name="tool_state_remark2" invisible="1"/>
|
<field name="tool_state_remark2" invisible="1"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//header//button[@name='action_cancel']" position="replace">
|
|
||||||
<button name="action_cancel" type="object" string="取消" data-hotkey="z"
|
|
||||||
attrs="{'invisible': ['|', '|', ('id', '=', False), ('state', 'in', ('done', 'cancel')), ('confirm_cancel', '=', True)]}"
|
|
||||||
groups="sf_base.group_sf_mrp_user"/>
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="(//header//button[@name='button_mark_done'])[1]" position="replace">
|
<xpath expr="(//header//button[@name='button_mark_done'])[1]" 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', '!=', [])]}"
|
||||||
@@ -260,13 +255,6 @@
|
|||||||
type="object" groups="sf_base.group_sf_mrp_user"/>
|
type="object" groups="sf_base.group_sf_mrp_user"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
||||||
<xpath expr="//header//button[@name='action_cancel']" position="replace">
|
|
||||||
<button name="action_cancel" type="object" string="Cancel" data-hotkey="z"
|
|
||||||
attrs="{'invisible': ['|', '|', ('id', '=', False), ('state', 'in', ('done', 'cancel')), ('confirm_cancel', '=', False)]}"
|
|
||||||
confirm="Some product moves have already been confirmed, this manufacturing order can't be completely cancelled. Are you still sure you want to process ?"
|
|
||||||
groups="sf_base.group_sf_mrp_user"/>
|
|
||||||
</xpath>
|
|
||||||
|
|
||||||
<xpath expr="//header//button[@name='button_unbuild']" position="replace">
|
<xpath expr="//header//button[@name='button_unbuild']" position="replace">
|
||||||
<button name="button_unbuild" type="object" string="拆单"
|
<button name="button_unbuild" type="object" string="拆单"
|
||||||
attrs="{'invisible': [('state', '!=', 'done')]}" data-hotkey="shift+v"
|
attrs="{'invisible': [('state', '!=', 'done')]}" data-hotkey="shift+v"
|
||||||
@@ -310,12 +298,14 @@
|
|||||||
type="object" groups="sf_base.group_sf_mrp_user"/>
|
type="object" groups="sf_base.group_sf_mrp_user"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
||||||
<xpath expr="//header//button[@name='action_cancel']" position="replace">
|
<xpath expr="//header//button[@name='action_cancel'][2]" position="replace">
|
||||||
<button name="action_cancel" type="object" string="取消" data-hotkey="z"
|
<button name="action_cancel" type="object" string="取消" data-hotkey="z"
|
||||||
attrs="{'invisible': ['|', '|', ('id', '=', False), ('state', 'in', ('done', 'cancel')), ('confirm_cancel', '=', False)]}"
|
attrs="{'invisible': ['|', '|', ('id', '=', False), ('state', 'in', ('done', 'rework', 'cancel')), ('confirm_cancel', '=', False)]}"
|
||||||
confirm="Some product moves have already been confirmed, this manufacturing order can't be completely cancelled. Are you still sure you want to process ?"
|
confirm="Some product moves have already been confirmed, this manufacturing order can't be completely cancelled. Are you still sure you want to process ?"
|
||||||
groups="sf_base.group_sf_mrp_user"/>
|
groups="sf_base.group_sf_mrp_user"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
<xpath expr="//header//button[@name='action_cancel'][1]" position="replace"></xpath>
|
||||||
|
|
||||||
<xpath expr="//header//button[@name='button_unbuild']" position="replace">
|
<xpath expr="//header//button[@name='button_unbuild']" position="replace">
|
||||||
<button name="button_unbuild" type="object" string="拆单"
|
<button name="button_unbuild" type="object" string="拆单"
|
||||||
attrs="{'invisible': [('state', '!=', 'done')]}" data-hotkey="shift+v"
|
attrs="{'invisible': [('state', '!=', 'done')]}" data-hotkey="shift+v"
|
||||||
|
|||||||
@@ -174,8 +174,6 @@
|
|||||||
<!-- 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': [('state', '!=', 'ready')]}"/>
|
attrs="{'invisible': [('state', '!=', 'ready')]}"/>
|
||||||
<button name="button_start" type="object" string="开始" class="btn-success"
|
|
||||||
attrs="{'invisible': [('state', '!=', 'ready')]}"/>
|
|
||||||
<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="是否确认完工"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<field name="inherit_id" ref="purchase.purchase_order_form"/>
|
<field name="inherit_id" ref="purchase.purchase_order_form"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<xpath expr="//field[@name='order_line']/tree/field[@name='name']" position="after">
|
<xpath expr="//field[@name='order_line']/tree/field[@name='name']" position="after">
|
||||||
|
<field name="related_product" optional="show"/>
|
||||||
<field name="part_number" optional="show"/>
|
<field name="part_number" optional="show"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class ProductionTechnologyReAdjustWizard(models.TransientModel):
|
|||||||
|
|
||||||
production_id = fields.Many2one('mrp.production', string='制造订单号')
|
production_id = fields.Many2one('mrp.production', string='制造订单号')
|
||||||
origin = fields.Char(string='源单据')
|
origin = fields.Char(string='源单据')
|
||||||
is_technology_re_adjust = fields.Boolean(default=False)
|
is_technology_re_adjust = fields.Boolean(default=True)
|
||||||
|
|
||||||
def confirm(self):
|
def confirm(self):
|
||||||
if self.is_technology_re_adjust is True:
|
if self.is_technology_re_adjust is True:
|
||||||
@@ -24,38 +24,39 @@ class ProductionTechnologyReAdjustWizard(models.TransientModel):
|
|||||||
for production_item in productions:
|
for production_item in productions:
|
||||||
# 该制造订单的其他同一销售订单的制造订单的工艺设计处理
|
# 该制造订单的其他同一销售订单的制造订单的工艺设计处理
|
||||||
if production_item != self.production_id:
|
if production_item != self.production_id:
|
||||||
for td_other in production_item.technology_design_ids:
|
self.env['sf.technology.design'].sudo().unified_procedure_multiple_work_orders(technology_designs, production_item)
|
||||||
if td_other.is_auto is False:
|
# for td_other in production_item.technology_design_ids:
|
||||||
td_del = technology_designs.filtered(lambda tdo: tdo.route_id.id == td_other.route_id.id)
|
# # if td_other.is_auto is False:
|
||||||
if not td_del or td_del.active is False:
|
# # td_del = technology_designs.filtered(lambda tdo: tdo.route_id.id == td_other.route_id.id)
|
||||||
td_other.write({'active': False})
|
# # if not td_del or td_del.active is False:
|
||||||
for td_main in technology_designs:
|
# # td_other.write({'active': False})
|
||||||
route_other = production_item.technology_design_ids.filtered(
|
# for td_main in technology_designs:
|
||||||
lambda td: td.route_id.id == td_main.route_id.id)
|
# route_other = production_item.technology_design_ids.filtered(
|
||||||
if not route_other and td_main.active is True:
|
# lambda td: td.route_id.id == td_main.route_id.id)
|
||||||
production_item.write({'technology_design_ids': [(0, 0, {
|
# if not route_other and td_main.active is True:
|
||||||
'route_id': td_main.route_id.id,
|
# production_item.write({'technology_design_ids': [(0, 0, {
|
||||||
'process_parameters_id': False if td_main.process_parameters_id is False else
|
# 'route_id': td_main.route_id.id,
|
||||||
self.env[
|
# 'process_parameters_id': False if td_main.process_parameters_id is False else
|
||||||
'sf.production.process.parameter'].search(
|
# self.env[
|
||||||
[('id', '=', td_main.process_parameters_id.id)]).id,
|
# 'sf.production.process.parameter'].search(
|
||||||
'sequence': td_main.sequence,
|
# [('id', '=', td_main.process_parameters_id.id)]).id,
|
||||||
'is_auto': td_main.is_auto})]})
|
# 'sequence': td_main.sequence,
|
||||||
else:
|
# 'is_auto': td_main.is_auto})]})
|
||||||
for ro in route_other:
|
# else:
|
||||||
domain = [('production_id', '=', self.production_id.id),
|
# for ro in route_other:
|
||||||
('active', 'in', [True, False]),
|
# domain = [('production_id', '=', self.production_id.id),
|
||||||
('route_id', '=', ro.route_id.id)]
|
# ('active', 'in', [True, False]),
|
||||||
if ro.route_id.routing_type == '表面工艺':
|
# ('route_id', '=', ro.route_id.id)]
|
||||||
domain += [('process_parameters_id', '=', ro.process_parameters_id.id)]
|
# if ro.route_id.routing_type == '表面工艺':
|
||||||
elif ro.route_id.routing_tag == 'special' and ro.is_auto is False:
|
# domain += [('process_parameters_id', '=', ro.process_parameters_id.id)]
|
||||||
# display_name = ro.route_id.display_name
|
# elif ro.route_id.routing_tag == 'special' and ro.is_auto is False:
|
||||||
domain += [('id', '=', ro.id)]
|
# # display_name = ro.route_id.display_name
|
||||||
elif ro.panel is not False:
|
# domain += [('id', '=', ro.id)]
|
||||||
domain += [('panel', '=', ro.panel)]
|
# elif ro.panel is not False:
|
||||||
td_upd = self.env['sf.technology.design'].sudo().search(domain)
|
# domain += [('panel', '=', ro.panel)]
|
||||||
if td_upd:
|
# td_upd = self.env['sf.technology.design'].sudo().search(domain)
|
||||||
ro.write({'sequence': td_upd.sequence, 'active': td_upd.active})
|
# if td_upd:
|
||||||
|
# ro.write({'sequence': td_upd.sequence, 'active': td_upd.active})
|
||||||
special_design = self.env['sf.technology.design'].sudo().search(
|
special_design = self.env['sf.technology.design'].sudo().search(
|
||||||
[('routing_tag', '=', 'special'), ('production_id', '=', production_item.id),
|
[('routing_tag', '=', 'special'), ('production_id', '=', production_item.id),
|
||||||
('is_auto', '=', False), ('active', 'in', [True, False])])
|
('is_auto', '=', False), ('active', 'in', [True, False])])
|
||||||
@@ -124,3 +125,4 @@ class ProductionTechnologyReAdjustWizard(models.TransientModel):
|
|||||||
if workorders[
|
if workorders[
|
||||||
0].production_id.product_id.categ_id.type == '成品' and item.programming_state != '已编程':
|
0].production_id.product_id.categ_id.type == '成品' and item.programming_state != '已编程':
|
||||||
workorders[0].state = 'waiting'
|
workorders[0].state = 'waiting'
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class ProductionTechnologyWizard(models.TransientModel):
|
|||||||
|
|
||||||
production_id = fields.Many2one('mrp.production', string='制造订单号')
|
production_id = fields.Many2one('mrp.production', string='制造订单号')
|
||||||
origin = fields.Char(string='源单据')
|
origin = fields.Char(string='源单据')
|
||||||
is_technology_confirm = fields.Boolean(default=False)
|
is_technology_confirm = fields.Boolean(default=True)
|
||||||
|
|
||||||
def confirm(self):
|
def confirm(self):
|
||||||
if self.is_technology_confirm is True and self.production_id.product_id.categ_id.type in ['成品', '坯料']:
|
if self.is_technology_confirm is True and self.production_id.product_id.categ_id.type in ['成品', '坯料']:
|
||||||
@@ -19,40 +19,44 @@ class ProductionTechnologyWizard(models.TransientModel):
|
|||||||
('product_id', '=', self.production_id.product_id.id)]
|
('product_id', '=', self.production_id.product_id.id)]
|
||||||
else:
|
else:
|
||||||
domain = [('id', '=', self.production_id.id)]
|
domain = [('id', '=', self.production_id.id)]
|
||||||
technology_designs = self.production_id.technology_design_ids
|
technology_designs = self.env['sf.technology.design'].sudo().search(
|
||||||
|
[('production_id', '=', self.production_id.id), ('active', 'in', [True, False])])
|
||||||
|
# technology_designs = self.production_id.technology_design_ids
|
||||||
productions = self.env['mrp.production'].search(domain)
|
productions = self.env['mrp.production'].search(domain)
|
||||||
for production in productions:
|
for production in productions:
|
||||||
if production != self.production_id:
|
if production != self.production_id:
|
||||||
for td_other in production.technology_design_ids:
|
self.env['sf.technology.design'].sudo().unified_procedure_multiple_work_orders(technology_designs,
|
||||||
if td_other.is_auto is False:
|
production)
|
||||||
td_del = technology_designs.filtered(lambda tdo: tdo.route_id.id == td_other.route_id.id)
|
# for td_other in production.technology_design_ids:
|
||||||
if not td_del or td_del.active is False:
|
# if td_other.is_auto is False:
|
||||||
td_other.write({'active': False})
|
# td_del = technology_designs.filtered(lambda tdo: tdo.route_id.id == td_other.route_id.id)
|
||||||
for td_main in technology_designs:
|
# if not td_del or td_del.active is False:
|
||||||
route_other = production.technology_design_ids.filtered(
|
# td_other.write({'active': False})
|
||||||
lambda td: td.route_id.id == td_main.route_id.id)
|
# for td_main in technology_designs:
|
||||||
if not route_other and td_main.active is True:
|
# route_other = production.technology_design_ids.filtered(
|
||||||
production.write({'technology_design_ids': [(0, 0, {
|
# lambda td: td.route_id.id == td_main.route_id.id)
|
||||||
'route_id': td_main.route_id.id,
|
# if not route_other and td_main.active is True:
|
||||||
'process_parameters_id': False if td_main.process_parameters_id is False else self.env[
|
# production.write({'technology_design_ids': [(0, 0, {
|
||||||
'sf.production.process.parameter'].search(
|
# 'route_id': td_main.route_id.id,
|
||||||
[('id', '=', td_main.process_parameters_id.id)]).id,
|
# 'process_parameters_id': False if td_main.process_parameters_id is False else self.env[
|
||||||
'sequence': td_main.sequence})]})
|
# 'sf.production.process.parameter'].search(
|
||||||
else:
|
# [('id', '=', td_main.process_parameters_id.id)]).id,
|
||||||
for ro in route_other:
|
# 'sequence': td_main.sequence})]})
|
||||||
domain = [('production_id', '=', self.production_id.id),
|
# else:
|
||||||
('active', 'in', [True, False]),
|
# for ro in route_other:
|
||||||
('route_id', '=', ro.route_id.id)]
|
# domain = [('production_id', '=', self.production_id.id),
|
||||||
if ro.route_id.routing_type == '表面工艺':
|
# ('active', 'in', [True, False]),
|
||||||
domain += [('process_parameters_id', '=', ro.process_parameters_id.id)]
|
# ('route_id', '=', ro.route_id.id)]
|
||||||
elif ro.route_id.routing_tag == 'special' and ro.is_auto is False:
|
# if ro.route_id.routing_type == '表面工艺':
|
||||||
# display_name = ro.route_id.display_name
|
# domain += [('process_parameters_id', '=', ro.process_parameters_id.id)]
|
||||||
domain += [('id', '=', ro.id)]
|
# elif ro.route_id.routing_tag == 'special' and ro.is_auto is False:
|
||||||
elif ro.panel is not False:
|
# # display_name = ro.route_id.display_name
|
||||||
domain += [('panel', '=', ro.panel)]
|
# domain += [('id', '=', ro.id)]
|
||||||
td_upd = self.env['sf.technology.design'].sudo().search(domain)
|
# elif ro.panel is not False:
|
||||||
if td_upd:
|
# domain += [('panel', '=', ro.panel)]
|
||||||
ro.write({'sequence': td_upd.sequence, 'active': td_upd.active})
|
# 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(
|
special_design = self.env['sf.technology.design'].sudo().search(
|
||||||
[('routing_tag', '=', 'special'), ('production_id', '=', production.id),
|
[('routing_tag', '=', 'special'), ('production_id', '=', production.id),
|
||||||
('is_auto', '=', False), ('active', 'in', [True, False])])
|
('is_auto', '=', False), ('active', 'in', [True, False])])
|
||||||
|
|||||||
@@ -287,6 +287,8 @@ class ReworkWizard(models.TransientModel):
|
|||||||
self.production_id.update_programming_state()
|
self.production_id.update_programming_state()
|
||||||
self.production_id.write(
|
self.production_id.write(
|
||||||
{'programming_state': '编程中', 'work_state': '编程中', 'state': 'progress'})
|
{'programming_state': '编程中', 'work_state': '编程中', 'state': 'progress'})
|
||||||
|
# ================= 返工完成,制造订单状态置为加工中 ==============
|
||||||
|
self.production_id.write({'state': 'progress', 'is_rework': False})
|
||||||
|
|
||||||
@api.onchange('production_id')
|
@api.onchange('production_id')
|
||||||
def onchange_processing_panel_id(self):
|
def onchange_processing_panel_id(self):
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
'category': 'sf',
|
'category': 'sf',
|
||||||
'website': 'https://www.sf.jikimo.com',
|
'website': 'https://www.sf.jikimo.com',
|
||||||
'depends': ['sale', 'purchase', 'sf_plan', 'jikimo_message_notify', 'stock', 'sf_quality', 'mrp',
|
'depends': ['sale', 'purchase', 'sf_plan', 'jikimo_message_notify', 'stock', 'sf_quality', 'mrp',
|
||||||
'sf_manufacturing'],
|
'sf_manufacturing','product'],
|
||||||
'data': [
|
'data': [
|
||||||
'data/bussiness_node.xml',
|
'data/bussiness_node.xml',
|
||||||
'data/cron_data.xml',
|
'data/cron_data.xml',
|
||||||
|
|||||||
@@ -39,12 +39,6 @@ class MessageSfMrsConnect(Sf_Mrs_Connect):
|
|||||||
_logger.info('无效用刀异常消息推送接口:%s' % ret)
|
_logger.info('无效用刀异常消息推送接口:%s' % ret)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
_logger.info('无效用刀异常消息推送接口:%s' % e)
|
_logger.info('无效用刀异常消息推送接口:%s' % e)
|
||||||
|
|
||||||
try:
|
|
||||||
productions = request.env['mrp.production'].sudo().search([('id', '=', res.get('production_ids')[0])])
|
|
||||||
productions.add_queue('工单已下发通知')
|
|
||||||
except Exception as e:
|
|
||||||
_logger.info('工单已下发通知异常:%s' % e)
|
|
||||||
return json.JSONEncoder().encode(res)
|
return json.JSONEncoder().encode(res)
|
||||||
|
|
||||||
@http.route('/api/maintenance_logs/notify', type='json', auth='public', methods=['GET', 'POST'], csrf=False,
|
@http.route('/api/maintenance_logs/notify', type='json', auth='public', methods=['GET', 'POST'], csrf=False,
|
||||||
|
|||||||
@@ -56,7 +56,7 @@
|
|||||||
<!--工单-->
|
<!--工单-->
|
||||||
<record id="bussiness_mrp_workorder_remind" model="jikimo.message.bussiness.node">
|
<record id="bussiness_mrp_workorder_remind" model="jikimo.message.bussiness.node">
|
||||||
<field name="name">工单已下发通知</field>
|
<field name="name">工单已下发通知</field>
|
||||||
<field name="model">mrp.production</field>
|
<field name="model">product.product</field>
|
||||||
</record>
|
</record>
|
||||||
<!--发货调拨-->
|
<!--发货调拨-->
|
||||||
<record id="production_completed_warehouse_reminder" model="jikimo.message.bussiness.node">
|
<record id="production_completed_warehouse_reminder" model="jikimo.message.bussiness.node">
|
||||||
|
|||||||
@@ -78,8 +78,8 @@
|
|||||||
|
|
||||||
<record id="template_mrp_workorder_remind" model="jikimo.message.template">
|
<record id="template_mrp_workorder_remind" model="jikimo.message.template">
|
||||||
<field name="name">工单已下发通知</field>
|
<field name="name">工单已下发通知</field>
|
||||||
<field name="model_id" ref="mrp.model_mrp_production"/>
|
<field name="model_id" ref="product.model_product_product"/>
|
||||||
<field name="model">mrp.production</field>
|
<field name="model">product.product</field>
|
||||||
<field name="bussiness_node_id" ref="bussiness_mrp_workorder_remind"/>
|
<field name="bussiness_node_id" ref="bussiness_mrp_workorder_remind"/>
|
||||||
<field name="msgtype">markdown</field>
|
<field name="msgtype">markdown</field>
|
||||||
<field name="urgency">normal</field>
|
<field name="urgency">normal</field>
|
||||||
|
|||||||
@@ -12,3 +12,4 @@ from . import sf_message_quality_cnc_test
|
|||||||
from . import sf_message_maintenance_logs
|
from . import sf_message_maintenance_logs
|
||||||
from . import sf_message_mrp_production_wizard
|
from . import sf_message_mrp_production_wizard
|
||||||
from . import sf_message_mrp_production_adjust_wizard
|
from . import sf_message_mrp_production_adjust_wizard
|
||||||
|
from . import sf_message_product
|
||||||
|
|||||||
@@ -13,11 +13,11 @@ class SFMessageMaintenanceLogs(models.Model):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
def _get_message(self, message_queue_ids):
|
def _get_message(self, message_queue_ids):
|
||||||
contents = super(SFMessageMaintenanceLogs, self)._get_message(message_queue_ids)
|
contents, _ = super(SFMessageMaintenanceLogs, self)._get_message(message_queue_ids)
|
||||||
url = self.env['ir.config_parameter'].get_param('web.base.url')
|
url = self.env['ir.config_parameter'].get_param('web.base.url')
|
||||||
action_id = self.env.ref('sf_maintenance.action_maintenance_logs').id
|
action_id = self.env.ref('sf_maintenance.action_maintenance_logs').id
|
||||||
for index, content in enumerate(contents):
|
for index, content in enumerate(contents):
|
||||||
maintenance_logs_id = self.env['sf.maintenance.logs'].browse(message_queue_ids[index].res_id)
|
maintenance_logs_id = self.env['sf.maintenance.logs'].browse(message_queue_ids[index].res_id)
|
||||||
url = url + '/web#id=%s&view_type=form&action=%s' % (maintenance_logs_id.id, action_id)
|
url = url + '/web#id=%s&view_type=form&action=%s' % (maintenance_logs_id.id, action_id)
|
||||||
contents[index] = content.replace('{{url}}', url)
|
contents[index] = content.replace('{{url}}', url)
|
||||||
return contents
|
return contents, message_queue_ids
|
||||||
@@ -69,28 +69,19 @@ class SFMessageMrpProduction(models.Model):
|
|||||||
url_with_id).replace(
|
url_with_id).replace(
|
||||||
'{{num}}', str(stock_picking_num))
|
'{{num}}', str(stock_picking_num))
|
||||||
contents.append(content)
|
contents.append(content)
|
||||||
if message_queue_id.message_template_id.name == '工单已下发通知':
|
|
||||||
content = message_queue_id.message_template_id.content
|
|
||||||
mrp_production = self.env['mrp.production'].sudo().search([('id', '=', int(message_queue_id.res_id))])
|
|
||||||
production_num = self.env['mrp.production'].sudo().search_count(
|
|
||||||
[('product_id', '=', mrp_production.product_id.id)])
|
|
||||||
if production_num >= 1:
|
|
||||||
url = self.get_request_url()
|
|
||||||
content = content.replace('{{product_id}}', mrp_production.product_id.name).replace(
|
|
||||||
'{{number}}', str(production_num)).replace(
|
|
||||||
'{{request_url}}', url)
|
|
||||||
contents.append(content)
|
|
||||||
if unique_products:
|
if unique_products:
|
||||||
|
action_id = self.env.ref('sf_plan.sf_production_plan_action1').id
|
||||||
unique_products_contents = self.get_production_info(content, unique_products, 'confirmed',
|
unique_products_contents = self.get_production_info(content, unique_products, 'confirmed',
|
||||||
'sf_plan.sf_production_plan_action1')
|
action_id)
|
||||||
contents.extend(unique_products_contents)
|
contents.extend(unique_products_contents)
|
||||||
if technology_to_confirmed:
|
if technology_to_confirmed:
|
||||||
|
action_id = self.env.ref('mrp.mrp_production_action').id
|
||||||
technology_to_confirmed_contents = self.get_production_info(content, technology_to_confirmed,
|
technology_to_confirmed_contents = self.get_production_info(content, technology_to_confirmed,
|
||||||
'technology_to_confirmed',
|
'technology_to_confirmed',
|
||||||
'mrp.mrp_production_action')
|
action_id)
|
||||||
contents.extend(technology_to_confirmed_contents)
|
contents.extend(technology_to_confirmed_contents)
|
||||||
logging.info('生产完工入库提醒: %s' % contents)
|
logging.info('生产完工入库提醒: %s' % contents)
|
||||||
return contents
|
return contents, message_queue_ids
|
||||||
|
|
||||||
def get_production_info(self, content, product_ids, state, action_id):
|
def get_production_info(self, content, product_ids, state, action_id):
|
||||||
contents = []
|
contents = []
|
||||||
@@ -100,7 +91,6 @@ class SFMessageMrpProduction(models.Model):
|
|||||||
[('product_id', '=', products_id), ('state', '=', state)])
|
[('product_id', '=', products_id), ('state', '=', state)])
|
||||||
if production_num >= 1:
|
if production_num >= 1:
|
||||||
url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
||||||
action_id = self.env.ref(action_id).id
|
|
||||||
url_with_id = f"{url}/web#view_type=list&action={action_id}"
|
url_with_id = f"{url}/web#view_type=list&action={action_id}"
|
||||||
new_content = (content.replace('{{name}}', product_name)
|
new_content = (content.replace('{{name}}', product_name)
|
||||||
.replace('{{url}}', url_with_id)
|
.replace('{{url}}', url_with_id)
|
||||||
@@ -120,17 +110,3 @@ class SFMessageMrpProduction(models.Model):
|
|||||||
# 拼接URL
|
# 拼接URL
|
||||||
full_url = url + "/web#" + query_string
|
full_url = url + "/web#" + query_string
|
||||||
return full_url
|
return full_url
|
||||||
|
|
||||||
def get_request_url(self):
|
|
||||||
url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
|
||||||
action_id = self.env.ref('sf_message.mrp_workorder_issued_action').id
|
|
||||||
menu_id = self.env.ref('mrp.menu_mrp_root').id
|
|
||||||
active_id = self.env['mrp.workcenter'].sudo().search([('name', '=', '工件装夹中心')]).id
|
|
||||||
# 查询参数
|
|
||||||
params = {'menu_id': menu_id, 'action': action_id, 'model': 'mrp.workorder',
|
|
||||||
'view_type': 'list', 'active_id': active_id}
|
|
||||||
# 拼接查询参数
|
|
||||||
query_string = urlencode(params)
|
|
||||||
# 拼接URL
|
|
||||||
full_url = url + "/web#" + query_string
|
|
||||||
return full_url
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class SFMessageMrpProductionWizard(models.TransientModel):
|
|||||||
productions = super(SFMessageMrpProductionWizard, self).confirm()
|
productions = super(SFMessageMrpProductionWizard, self).confirm()
|
||||||
try:
|
try:
|
||||||
for production_info in self.production_id:
|
for production_info in self.production_id:
|
||||||
if production_info.state == 'confirmed':
|
if production_info.state == 'confirmed' and production_info.product_id.categ_id.type == '成品':
|
||||||
production_info.add_queue('待排程')
|
production_info.add_queue('待排程')
|
||||||
for production_id in productions:
|
for production_id in productions:
|
||||||
workorder_ids = production_id.workorder_ids.filtered(
|
workorder_ids = production_id.workorder_ids.filtered(
|
||||||
|
|||||||
45
sf_message/models/sf_message_product.py
Normal file
45
sf_message/models/sf_message_product.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from odoo import models, fields, api, _
|
||||||
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
|
|
||||||
|
class SFMessagePlan(models.Model):
|
||||||
|
_name = 'product.product'
|
||||||
|
_inherit = ['product.product', 'jikimo.message.dispatch']
|
||||||
|
|
||||||
|
def _get_message(self, message_queue_ids):
|
||||||
|
contents = []
|
||||||
|
for message_queue_id in message_queue_ids:
|
||||||
|
if message_queue_id.message_template_id.name == '工单已下发通知':
|
||||||
|
content = message_queue_id.message_template_id.content
|
||||||
|
product_product = self.env['product.product'].sudo().search([('id', '=', int(message_queue_id.res_id))])
|
||||||
|
mrp_production_list = self.env['mrp.production'].sudo().search(
|
||||||
|
[('product_id', '=', product_product.id)])
|
||||||
|
production_num = 0
|
||||||
|
for mrp_production_info in mrp_production_list:
|
||||||
|
routing_type = '人工线下加工' if mrp_production_info.production_type == '人工线下加工' else '装夹预调'
|
||||||
|
mrp_production_ready = mrp_production_info.workorder_ids.filtered(
|
||||||
|
lambda w: w.routing_type == routing_type and w.state == 'ready')
|
||||||
|
if mrp_production_ready:
|
||||||
|
production_num += 1
|
||||||
|
if production_num >= 1:
|
||||||
|
url = self.get_request_url()
|
||||||
|
content = content.replace('{{product_id}}', product_product.name).replace(
|
||||||
|
'{{number}}', str(production_num)).replace(
|
||||||
|
'{{request_url}}', url)
|
||||||
|
contents.append(content)
|
||||||
|
return contents
|
||||||
|
|
||||||
|
def get_request_url(self):
|
||||||
|
url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
||||||
|
action_id = self.env.ref('sf_message.mrp_workorder_issued_action').id
|
||||||
|
menu_id = self.env.ref('mrp.menu_mrp_root').id
|
||||||
|
active_id = self.env['mrp.workcenter'].sudo().search([('name', '=', '工件装夹中心')]).id
|
||||||
|
# 查询参数
|
||||||
|
params = {'menu_id': menu_id, 'action': action_id, 'model': 'mrp.workorder',
|
||||||
|
'view_type': 'list', 'active_id': active_id}
|
||||||
|
# 拼接查询参数
|
||||||
|
query_string = urlencode(params)
|
||||||
|
# 拼接URL
|
||||||
|
full_url = url + "/web#" + query_string
|
||||||
|
return full_url
|
||||||
@@ -58,7 +58,7 @@ class SFMessagePurchase(models.Model):
|
|||||||
.replace('{{url}}', url_with_id)
|
.replace('{{url}}', url_with_id)
|
||||||
.replace('{{num}}', str(production_num)))
|
.replace('{{num}}', str(production_num)))
|
||||||
contents.append(new_content)
|
contents.append(new_content)
|
||||||
return contents
|
return contents, message_queue_ids
|
||||||
|
|
||||||
def request_url(self, id):
|
def request_url(self, id):
|
||||||
url = self.env['ir.config_parameter'].get_param('web.base.url')
|
url = self.env['ir.config_parameter'].get_param('web.base.url')
|
||||||
|
|||||||
@@ -33,4 +33,4 @@ class SFMessageQualityCncTest(models.Model):
|
|||||||
content_template = content.replace('{{judge_num}}', str(i))
|
content_template = content.replace('{{judge_num}}', str(i))
|
||||||
content_template = content_template.replace('{{url}}', url_with_id)
|
content_template = content_template.replace('{{url}}', url_with_id)
|
||||||
contents.append(content_template)
|
contents.append(content_template)
|
||||||
return contents
|
return contents, message_queue_ids
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class SFMessageSale(models.Model):
|
|||||||
purchase_order_info.add_queue('坯料采购提醒')
|
purchase_order_info.add_queue('坯料采购提醒')
|
||||||
purchase_order_ids = self.order_line.purchase_line_ids.order_id | self.procurement_group_id.stock_move_ids.created_purchase_line_id.order_id | self.procurement_group_id.stock_move_ids.move_orig_ids.purchase_line_id.order_id
|
purchase_order_ids = self.order_line.purchase_line_ids.order_id | self.procurement_group_id.stock_move_ids.created_purchase_line_id.order_id | self.procurement_group_id.stock_move_ids.move_orig_ids.purchase_line_id.order_id
|
||||||
for purchase_order_id in purchase_order_ids:
|
for purchase_order_id in purchase_order_ids:
|
||||||
if purchase_order_id.purchase_type == 'consignment':
|
if purchase_order_id.purchase_type == 'outsourcing':
|
||||||
purchase_order_id.add_queue('委外加工采购单提醒')
|
purchase_order_id.add_queue('委外加工采购单提醒')
|
||||||
if purchase_order_id.purchase_type == 'standard':
|
if purchase_order_id.purchase_type == 'standard':
|
||||||
purchase_order_id.add_queue('外购订单采购单提醒')
|
purchase_order_id.add_queue('外购订单采购单提醒')
|
||||||
@@ -58,7 +58,7 @@ class SFMessageSale(models.Model):
|
|||||||
i = 0
|
i = 0
|
||||||
for item in message_queue_ids:
|
for item in message_queue_ids:
|
||||||
if item.message_template_id.bussiness_node_id.name in ('待接单', '待确认供货方式'):
|
if item.message_template_id.bussiness_node_id.name in ('待接单', '待确认供货方式'):
|
||||||
content = super(SFMessageSale, self)._get_message(item)
|
content, _ = super(SFMessageSale, self)._get_message(item)
|
||||||
action_id = self.env.ref('sale.action_quotations_with_onboarding').id \
|
action_id = self.env.ref('sale.action_quotations_with_onboarding').id \
|
||||||
if item.message_template_id.bussiness_node_id.name == '待接单' \
|
if item.message_template_id.bussiness_node_id.name == '待接单' \
|
||||||
else self.env.ref('sale.action_orders').id
|
else self.env.ref('sale.action_orders').id
|
||||||
@@ -66,7 +66,7 @@ class SFMessageSale(models.Model):
|
|||||||
content = content[0].replace('{{url}}', url_with_id)
|
content = content[0].replace('{{url}}', url_with_id)
|
||||||
contents.append(content)
|
contents.append(content)
|
||||||
elif item.message_template_id.bussiness_node_id.name == '确认接单':
|
elif item.message_template_id.bussiness_node_id.name == '确认接单':
|
||||||
content = super(SFMessageSale, self)._get_message(item)
|
content, _ = super(SFMessageSale, self)._get_message(item)
|
||||||
sale_order_line = self.env['sale.order.line'].sudo().search([('order_id', '=', int(item.res_id))])
|
sale_order_line = self.env['sale.order.line'].sudo().search([('order_id', '=', int(item.res_id))])
|
||||||
product = sale_order_line[0].product_id.name if len(sale_order_line) == 1 else '%s...' % \
|
product = sale_order_line[0].product_id.name if len(sale_order_line) == 1 else '%s...' % \
|
||||||
sale_order_line[
|
sale_order_line[
|
||||||
@@ -103,7 +103,7 @@ class SFMessageSale(models.Model):
|
|||||||
elif bussiness_node == '销售订单已逾期':
|
elif bussiness_node == '销售订单已逾期':
|
||||||
content = content_template.replace('{{overdue_num}}', str(i))
|
content = content_template.replace('{{overdue_num}}', str(i))
|
||||||
contents.append(content)
|
contents.append(content)
|
||||||
return contents
|
return contents, message_queue_ids
|
||||||
|
|
||||||
# # 销售订单逾期预警和已逾期
|
# # 销售订单逾期预警和已逾期
|
||||||
def _overdue_or_warning_func(self):
|
def _overdue_or_warning_func(self):
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ class SFMessageStockPicking(models.Model):
|
|||||||
super(SFMessageStockPicking, self)._compute_state()
|
super(SFMessageStockPicking, self)._compute_state()
|
||||||
try:
|
try:
|
||||||
for record in self:
|
for record in self:
|
||||||
if record.state == 'assigned' and record.picking_type_id.sequence_code == 'PC':
|
if (record.state == 'assigned' and record.picking_type_id.sequence_code == 'PC'
|
||||||
|
and record.product_id.categ_id.type == '坯料'):
|
||||||
record.add_queue('坯料发料提醒')
|
record.add_queue('坯料发料提醒')
|
||||||
|
|
||||||
if record.picking_type_id.sequence_code == 'SFP' and record.state == 'done':
|
if record.picking_type_id.sequence_code == 'SFP' and record.state == 'done':
|
||||||
@@ -71,19 +72,18 @@ class SFMessageStockPicking(models.Model):
|
|||||||
content = message_queue_id.message_template_id.content
|
content = message_queue_id.message_template_id.content
|
||||||
stock_picking_line = self.env['stock.picking'].sudo().search(
|
stock_picking_line = self.env['stock.picking'].sudo().search(
|
||||||
[('id', '=', int(message_queue_id.res_id))])
|
[('id', '=', int(message_queue_id.res_id))])
|
||||||
if stock_picking_line.state == 'assigned':
|
url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
||||||
url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
action_id = self.env.ref('stock.action_picking_tree_ready').id
|
||||||
action_id = self.env.ref('stock.action_picking_tree_ready').id
|
menu_id = self.env.ref('stock.menu_stock_root').id
|
||||||
menu_id = self.env.ref('stock.menu_stock_root').id
|
url_with_id = f"{url}/web#view_type=form&action={action_id}&menu_id={menu_id}&id={stock_picking_line.id}"
|
||||||
url_with_id = f"{url}/web#view_type=form&action={action_id}&menu_id={menu_id}&id={stock_picking_line.id}"
|
content = content.replace('{{name}}', stock_picking_line.name).replace(
|
||||||
content = content.replace('{{name}}', stock_picking_line.name).replace(
|
|
||||||
'{{request_url}}', url_with_id)
|
'{{request_url}}', url_with_id)
|
||||||
contents.append(content)
|
contents.append(content)
|
||||||
elif message_queue_id.message_template_id.name == '订单发货提醒':
|
elif message_queue_id.message_template_id.name == '订单发货提醒':
|
||||||
content = self.deal_stock_picking_sfp(message_queue_id)
|
content = self.deal_stock_picking_sfp(message_queue_id)
|
||||||
if content:
|
if content:
|
||||||
contents.append(content)
|
contents.append(content)
|
||||||
return contents
|
return contents, message_queue_ids
|
||||||
|
|
||||||
def get_special_url(self, id, tmplate_name, special_name, model_id):
|
def get_special_url(self, id, tmplate_name, special_name, model_id):
|
||||||
menu_id = 0
|
menu_id = 0
|
||||||
|
|||||||
@@ -17,4 +17,5 @@ class SfMessageTemplate(models.Model):
|
|||||||
res.append('sf.maintenance.logs')
|
res.append('sf.maintenance.logs')
|
||||||
res.append('quality.cnc.test')
|
res.append('quality.cnc.test')
|
||||||
res.append('mrp.production')
|
res.append('mrp.production')
|
||||||
|
res.append('product.product')
|
||||||
return res
|
return res
|
||||||
|
|||||||
@@ -12,6 +12,28 @@ class SFMessageWork(models.Model):
|
|||||||
_name = 'mrp.workorder'
|
_name = 'mrp.workorder'
|
||||||
_inherit = ['mrp.workorder', 'jikimo.message.dispatch']
|
_inherit = ['mrp.workorder', 'jikimo.message.dispatch']
|
||||||
|
|
||||||
|
@api.depends('production_availability', 'blocked_by_workorder_ids', 'blocked_by_workorder_ids.state',
|
||||||
|
'production_id.tool_state', 'production_id.schedule_state', 'sequence',
|
||||||
|
'production_id.programming_state')
|
||||||
|
def _compute_state(self):
|
||||||
|
super(SFMessageWork, self)._compute_state()
|
||||||
|
for workorder in self:
|
||||||
|
min_sequence_wk = None
|
||||||
|
work_ids = workorder.production_id.workorder_ids.filtered(lambda w: w.routing_type == '装夹预调')
|
||||||
|
if work_ids:
|
||||||
|
min_sequence_wk = work_ids.sorted(key=lambda w: w.sequence)[0]
|
||||||
|
if (
|
||||||
|
workorder.state == 'ready' and workorder.routing_type == '装夹预调' and workorder.id == min_sequence_wk.id) or (
|
||||||
|
workorder.state == 'ready' and workorder.routing_type == '人工线下加工'):
|
||||||
|
message_template = self.env["jikimo.message.template"].sudo().search(
|
||||||
|
[("name", "=", '工单已下发通知')], limit=1)
|
||||||
|
jikimo_message_queue = self.env['jikimo.message.queue'].sudo().search(
|
||||||
|
[('res_id', '=', workorder.production_id.product_id.id),
|
||||||
|
("message_status", "in", ("pending", "sent")),
|
||||||
|
('message_template_id', '=', message_template.id)])
|
||||||
|
if not jikimo_message_queue:
|
||||||
|
workorder.production_id.product_id.add_queue('工单已下发通知')
|
||||||
|
|
||||||
def _get_message(self, message_queue_ids):
|
def _get_message(self, message_queue_ids):
|
||||||
contents = []
|
contents = []
|
||||||
bussiness_node = None
|
bussiness_node = None
|
||||||
@@ -69,7 +91,7 @@ class SFMessageWork(models.Model):
|
|||||||
elif bussiness_node in template_names['已逾期']:
|
elif bussiness_node in template_names['已逾期']:
|
||||||
content = content_template.replace('{{overdue_num}}', str(i))
|
content = content_template.replace('{{overdue_num}}', str(i))
|
||||||
contents.append(content)
|
contents.append(content)
|
||||||
return contents
|
return contents, message_queue_ids
|
||||||
|
|
||||||
def _overdue_or_warning_func(self):
|
def _overdue_or_warning_func(self):
|
||||||
workorders = self.env['mrp.workorder'].search(
|
workorders = self.env['mrp.workorder'].search(
|
||||||
|
|||||||
@@ -6678,7 +6678,7 @@ msgstr "账单状态"
|
|||||||
#: model_terms:ir.ui.view,arch_db:account.account_journal_dashboard_kanban_view
|
#: model_terms:ir.ui.view,arch_db:account.account_journal_dashboard_kanban_view
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Bills"
|
msgid "Bills"
|
||||||
msgstr "账单"
|
msgstr "发票账单"
|
||||||
|
|
||||||
#. module: account
|
#. module: account
|
||||||
#: model_terms:ir.ui.view,arch_db:account.account_journal_dashboard_kanban_view
|
#: model_terms:ir.ui.view,arch_db:account.account_journal_dashboard_kanban_view
|
||||||
@@ -23023,7 +23023,7 @@ msgstr "支付:支付收据"
|
|||||||
#: model_terms:ir.ui.view,arch_db:account.view_account_payment_search
|
#: model_terms:ir.ui.view,arch_db:account.view_account_payment_search
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Payments"
|
msgid "Payments"
|
||||||
msgstr "支付"
|
msgstr "付款单"
|
||||||
|
|
||||||
#. module: account
|
#. module: account
|
||||||
#: model_terms:ir.actions.act_window,help:account.action_account_payments
|
#: model_terms:ir.actions.act_window,help:account.action_account_payments
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class SfQualityCncTest(models.Model):
|
|||||||
equipment_id = fields.Many2one(related='workorder_id.equipment_id', string='加工设备')
|
equipment_id = fields.Many2one(related='workorder_id.equipment_id', string='加工设备')
|
||||||
production_line_id = fields.Many2one(related='workorder_id.production_line_id',
|
production_line_id = fields.Many2one(related='workorder_id.production_line_id',
|
||||||
string='生产线')
|
string='生产线')
|
||||||
part_number = fields.Char(related='workorder_id.part_number', string='成品零件图号')
|
part_number = fields.Char(related='workorder_id.part_number', string='零件图号')
|
||||||
detection_report = fields.Binary(related='workorder_id.detection_report', readonly=True, string='检测报告')
|
detection_report = fields.Binary(related='workorder_id.detection_report', readonly=True, string='检测报告')
|
||||||
state = fields.Selection([
|
state = fields.Selection([
|
||||||
('waiting', '待判定'),
|
('waiting', '待判定'),
|
||||||
|
|||||||
@@ -170,9 +170,9 @@ class ReSaleOrder(models.Model):
|
|||||||
def _compute_purchase_order_count(self):
|
def _compute_purchase_order_count(self):
|
||||||
for order in self:
|
for order in self:
|
||||||
order.purchase_order_count = len(order._get_purchase_orders().filtered(
|
order.purchase_order_count = len(order._get_purchase_orders().filtered(
|
||||||
lambda po: po.purchase_type not in ['consignment']))
|
lambda po: po.purchase_type not in ['outsourcing']))
|
||||||
order.consignment_purchase_order_count = len(order._get_purchase_orders().filtered(
|
order.consignment_purchase_order_count = len(order._get_purchase_orders().filtered(
|
||||||
lambda po: po.purchase_type in ['consignment']))
|
lambda po: po.purchase_type in ['outsourcing']))
|
||||||
|
|
||||||
def action_view_purchase_orders(self):
|
def action_view_purchase_orders(self):
|
||||||
"""
|
"""
|
||||||
@@ -180,7 +180,7 @@ class ReSaleOrder(models.Model):
|
|||||||
"""
|
"""
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
purchase_order_ids = self._get_purchase_orders().filtered(
|
purchase_order_ids = self._get_purchase_orders().filtered(
|
||||||
lambda po: po.purchase_type not in ['consignment']).ids
|
lambda po: po.purchase_type not in ['outsourcing']).ids
|
||||||
action = {
|
action = {
|
||||||
'res_model': 'purchase.order',
|
'res_model': 'purchase.order',
|
||||||
'type': 'ir.actions.act_window',
|
'type': 'ir.actions.act_window',
|
||||||
@@ -203,21 +203,21 @@ class ReSaleOrder(models.Model):
|
|||||||
委外加工
|
委外加工
|
||||||
"""
|
"""
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
consignment_purchase_order_ids = self._get_purchase_orders().filtered(
|
outsourcing_purchase_order_ids = self._get_purchase_orders().filtered(
|
||||||
lambda po: po.purchase_type in ['consignment']).ids
|
lambda po: po.purchase_type in ['outsourcing']).ids
|
||||||
action = {
|
action = {
|
||||||
'res_model': 'purchase.order',
|
'res_model': 'purchase.order',
|
||||||
'type': 'ir.actions.act_window',
|
'type': 'ir.actions.act_window',
|
||||||
}
|
}
|
||||||
if len(consignment_purchase_order_ids) == 1:
|
if len(outsourcing_purchase_order_ids) == 1:
|
||||||
action.update({
|
action.update({
|
||||||
'view_mode': 'form',
|
'view_mode': 'form',
|
||||||
'res_id': consignment_purchase_order_ids[0],
|
'res_id': outsourcing_purchase_order_ids[0],
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
action.update({
|
action.update({
|
||||||
'name': _("从 %s生成委外加工订单", self.name),
|
'name': _("从 %s生成委外加工订单", self.name),
|
||||||
'domain': [('id', 'in', consignment_purchase_order_ids)],
|
'domain': [('id', 'in', outsourcing_purchase_order_ids)],
|
||||||
'view_mode': 'tree,form',
|
'view_mode': 'tree,form',
|
||||||
})
|
})
|
||||||
return action
|
return action
|
||||||
@@ -287,6 +287,11 @@ class RePurchaseOrder(models.Model):
|
|||||||
|
|
||||||
origin_sale_id = fields.Many2one('sale.order', string='销售订单号', compute='_compute_origin_sale_id')
|
origin_sale_id = fields.Many2one('sale.order', string='销售订单号', compute='_compute_origin_sale_id')
|
||||||
|
|
||||||
|
# 合同编号
|
||||||
|
contract_number = fields.Char(string='合同编号', size=20)
|
||||||
|
# 合同概况
|
||||||
|
contract_summary = fields.Text(string='合同概况')
|
||||||
|
|
||||||
@api.depends('origin')
|
@api.depends('origin')
|
||||||
def _compute_purchase_type(self):
|
def _compute_purchase_type(self):
|
||||||
for purchase in self:
|
for purchase in self:
|
||||||
@@ -319,7 +324,7 @@ class RePurchaseOrder(models.Model):
|
|||||||
purchase.origin_sale_id = False
|
purchase.origin_sale_id = False
|
||||||
|
|
||||||
delivery_warning = fields.Selection([('normal', '正常'), ('warning', '预警'), ('overdue', '已逾期')],
|
delivery_warning = fields.Selection([('normal', '正常'), ('warning', '预警'), ('overdue', '已逾期')],
|
||||||
string='交期状态',
|
string='交期状态', default='normal',
|
||||||
tracking=True)
|
tracking=True)
|
||||||
|
|
||||||
@api.depends('partner_id')
|
@api.depends('partner_id')
|
||||||
@@ -395,11 +400,12 @@ class RePurchaseOrder(models.Model):
|
|||||||
move_id.put_move_line()
|
move_id.put_move_line()
|
||||||
for line in item.order_line:
|
for line in item.order_line:
|
||||||
if line.product_id.categ_type == '表面工艺':
|
if line.product_id.categ_type == '表面工艺':
|
||||||
for production_name in item.origin.split(','):
|
if item.origin:
|
||||||
production = self.env['mrp.production'].search([('name', '=', production_name)])
|
for production_name in item.origin.split(','):
|
||||||
for workorder in production.workorder_ids.filtered(
|
production = self.env['mrp.production'].search([('name', '=', production_name)])
|
||||||
lambda wd: wd.routing_type == '表面工艺' and wd.state == 'waiting' and line.product_id.server_product_process_parameters_id == wd.surface_technics_parameters_id):
|
for workorder in production.workorder_ids.filtered(
|
||||||
workorder.state = 'ready'
|
lambda wd: wd.routing_type == '表面工艺' and wd.state == 'waiting' and line.product_id.server_product_process_parameters_id == wd.surface_technics_parameters_id):
|
||||||
|
workorder.state = 'ready'
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@@ -411,7 +417,7 @@ class RePurchaseOrder(models.Model):
|
|||||||
last_overdue_order = None
|
last_overdue_order = None
|
||||||
last_warning_order = None
|
last_warning_order = None
|
||||||
for item in purchase_order:
|
for item in purchase_order:
|
||||||
current_time = datetime.now()
|
current_time = datetime.datetime.now()
|
||||||
if item.date_planned <= current_time: # 已逾期
|
if item.date_planned <= current_time: # 已逾期
|
||||||
item.delivery_warning = 'overdue'
|
item.delivery_warning = 'overdue'
|
||||||
last_overdue_order = item
|
last_overdue_order = item
|
||||||
|
|||||||
@@ -36,13 +36,13 @@
|
|||||||
<field name="partner_id" widget="res_partner_many2one" context="{'is_supplier': True }"/>
|
<field name="partner_id" widget="res_partner_many2one" context="{'is_supplier': True }"/>
|
||||||
</field>
|
</field>
|
||||||
<field name="currency_id" position="after">
|
<field name="currency_id" position="after">
|
||||||
<field name="remark" attrs="{'readonly': [('state', 'in', ['purchase'])]}"/>
|
<field name="remark" attrs="{'readonly': [('state', 'in', ['purchase'])]}" string="订单备注"/>
|
||||||
</field>
|
</field>
|
||||||
<xpath expr="//form/header/button[@name='button_confirm'][2]" position="replace">
|
<xpath expr="//form/header/button[@name='button_confirm'][2]" position="replace">
|
||||||
<button name="button_confirm" type="object" context="{'validate_analytic': True}"
|
<button name="button_confirm" type="object" context="{'validate_analytic': True}"
|
||||||
string="确认订单" id="draft_confirm"
|
string="确认订单" id="draft_confirm"
|
||||||
groups="sf_base.group_purchase,sf_base.group_purchase_director"
|
groups="sf_base.group_purchase,sf_base.group_purchase_director"
|
||||||
attrs="{'invisible': [('state', 'in', ['purchase'])]}"
|
attrs="{'invisible': [('state', 'in', ['purchase', 'cancel'])]}"
|
||||||
/>
|
/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//form/header/button[@name='action_rfq_send'][1]" position="replace">
|
<xpath expr="//form/header/button[@name='action_rfq_send'][1]" position="replace">
|
||||||
@@ -139,7 +139,14 @@
|
|||||||
<!-- <field name="part_number" optional="show"/>-->
|
<!-- <field name="part_number" optional="show"/>-->
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='date_order']" position="attributes">
|
<xpath expr="//field[@name='date_order']" position="attributes">
|
||||||
<attribute name="string">报价截止日期</attribute>
|
<attribute name="string">签约日期</attribute>
|
||||||
|
</xpath>
|
||||||
|
<field name="payment_term_id" position="attributes">
|
||||||
|
<attribute name="invisible">1</attribute>
|
||||||
|
</field>
|
||||||
|
<xpath expr="//field[@name='date_order']" position="after">
|
||||||
|
<field name="payment_term_id" attrs="{'readonly': ['|', ('invoice_status','=', 'invoiced'), ('state', '=', 'done')]}" options="{'no_create': True}"/>
|
||||||
|
<field name="contract_summary"/>
|
||||||
</xpath>
|
</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'])]}
|
||||||
@@ -171,13 +178,49 @@
|
|||||||
</field>
|
</field>
|
||||||
|
|
||||||
<!-- 添加采购类型字段 -->
|
<!-- 添加采购类型字段 -->
|
||||||
<field name="partner_ref" position="after">
|
<field name="partner_id" position="after">
|
||||||
<field name="purchase_type" string="采购类型" readonly="1"/>
|
<field name="purchase_type" string="采购类型" readonly="1"/>
|
||||||
|
<field name="picking_type_id" string="作业类型" domain="[('code','=','incoming'), '|', ('warehouse_id', '=', False), ('warehouse_id.company_id', '=', company_id)]" options="{'no_create': True}" groups="stock.group_stock_multi_locations"/>
|
||||||
|
<label for="date_planned" string="最近交货日期"/>
|
||||||
|
<div name="date_planned_div" class="o_row">
|
||||||
|
<field name="date_planned" attrs="{'readonly': [('state', 'not in', ('draft', 'sent', 'to approve', 'purchase'))]}"/>
|
||||||
|
<field name="mail_reminder_confirmed" invisible="1"/>
|
||||||
|
<span class="text-muted" attrs="{'invisible': [('mail_reminder_confirmed', '=', False)]}">(confirmed by vendor)</span>
|
||||||
|
</div>
|
||||||
|
<field name="effective_date" attrs="{'invisible': [('effective_date', '=', False)]}" string="到货时间"/>
|
||||||
</field>
|
</field>
|
||||||
|
<field name="partner_ref" position="attributes">
|
||||||
|
<attribute name="invisible">1</attribute>
|
||||||
|
</field>
|
||||||
|
<xpath expr="//sheet/group/group[2]/field[1]" position="before">
|
||||||
|
<field name="partner_ref" string="合同名称"/>
|
||||||
|
<field name="contract_number"/>
|
||||||
|
</xpath>
|
||||||
<!-- 添加销售订单号字段-->
|
<!-- 添加销售订单号字段-->
|
||||||
<field name="effective_date" position="after">
|
<xpath expr="//sheet/group/group[2]/div[@name='date_approve']" position="after">
|
||||||
<field name="origin_sale_id" readonly="1" attrs="{'invisible': [('origin_sale_id', '=', False)]}"/>
|
<!-- <field name="origin_sale_id" readonly="1" attrs="{'invisible': [('origin_sale_id', '=', False)]}" string="参考销售订单"/> -->
|
||||||
</field>
|
<field name="origin_sale_id" readonly="1" string="参考销售订单"/>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//sheet/group/group[2]/field[@name='effective_date']" position="attributes">
|
||||||
|
<attribute name="invisible">1</attribute>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
<!-- 隐藏 label -->
|
||||||
|
<xpath expr="//label[@for='receipt_reminder_email']" position="attributes">
|
||||||
|
<attribute name="invisible">1</attribute>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
<!-- 隐藏整个 reminder div -->
|
||||||
|
<xpath expr="//div[@name='reminder']" position="attributes">
|
||||||
|
<attribute name="invisible">1</attribute>
|
||||||
|
</xpath>
|
||||||
|
<!-- 使用更精确的路径定位原始元素 -->
|
||||||
|
<xpath expr="//sheet/group/group[2]/label[@for='date_planned']" position="attributes">
|
||||||
|
<attribute name="invisible">1</attribute>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//sheet/group/group[2]/div[@name='date_planned_div']" position="attributes">
|
||||||
|
<attribute name="invisible">1</attribute>
|
||||||
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
@@ -196,11 +239,13 @@
|
|||||||
<attribute name="optional">hide</attribute>
|
<attribute name="optional">hide</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='date_order']" position="attributes">
|
<xpath expr="//field[@name='date_order']" position="attributes">
|
||||||
<attribute name="string">报价截止日期</attribute>
|
<attribute name="string">签约日期</attribute>
|
||||||
<attribute name="widget">''</attribute>
|
<attribute name="widget">''</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
<xpath expr="//field[@name='date_planned']" position="replace">
|
||||||
|
</xpath>
|
||||||
<xpath expr="//field[@name='date_order']" position="after">
|
<xpath expr="//field[@name='date_order']" position="after">
|
||||||
<field name="date_planned"/>
|
<field name="date_planned" string="最近交货日期"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='name']" position="after">
|
<xpath expr="//field[@name='name']" position="after">
|
||||||
<field name="purchase_type"/>
|
<field name="purchase_type"/>
|
||||||
@@ -224,6 +269,8 @@
|
|||||||
<attribute name="attrs">{'readonly': [('state', 'in', ['purchase'])]}
|
<attribute name="attrs">{'readonly': [('state', 'in', ['purchase'])]}
|
||||||
</attribute>
|
</attribute>
|
||||||
</field>
|
</field>
|
||||||
|
<xpath expr="//field[@name='picking_type_id'][1]" position="replace">
|
||||||
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
@@ -246,7 +293,8 @@
|
|||||||
<attribute name="string">采购员</attribute>
|
<attribute name="string">采购员</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='user_id']" position="after">
|
<xpath expr="//field[@name='user_id']" position="after">
|
||||||
<field name="date_planned" string="预计到货日期" optional="show"/>
|
<field name="delivery_warning" optional="show"/>
|
||||||
|
<field name="date_planned" string="最近交货日期" optional="show" widget="date"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='name']" position="after">
|
<xpath expr="//field[@name='name']" position="after">
|
||||||
<field name="purchase_type"/>
|
<field name="purchase_type"/>
|
||||||
@@ -298,7 +346,7 @@
|
|||||||
<xpath expr="//search" position="inside">
|
<xpath expr="//search" position="inside">
|
||||||
<searchpanel>
|
<searchpanel>
|
||||||
<field name="purchase_type" icon="fa-filter" enable_counters="1"/>
|
<field name="purchase_type" icon="fa-filter" enable_counters="1"/>
|
||||||
<field name="state" icon="fa-filter" enable_counters="1"/>
|
<field name="delivery_warning" icon="fa-filter" enable_counters="1"/>
|
||||||
</searchpanel>
|
</searchpanel>
|
||||||
</xpath>
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
|
|||||||
@@ -170,8 +170,14 @@
|
|||||||
<field name="manual_quotation" />
|
<field name="manual_quotation" />
|
||||||
<field name="is_incoming_material"/>
|
<field name="is_incoming_material"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//sheet//group//group[@name='order_details']//div[@class='o_td_label'][2]//label[@for='date_order']" position="attributes">
|
<xpath expr="//div[@class='o_td_label'][2]" position="replace"></xpath>
|
||||||
<attribute name="string">下单日期</attribute>
|
<xpath expr="//field[@name='date_order'][1]" position="replace"></xpath>
|
||||||
|
<xpath expr="//field[@name='date_order']" position="replace"></xpath>
|
||||||
|
<xpath expr="//div[@class='o_td_label'][1]" position="replace">
|
||||||
|
<div class="o_td_label" attrs="{'invisible': [('state', 'in', ['done', 'cancel'])]}">
|
||||||
|
<label for="date_order" string="下单日期"/>
|
||||||
|
</div>
|
||||||
|
<field name="date_order" attrs="{'invisible': [('state', 'in', ['done', 'cancel'])], 'required': True}" nolabel="1"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
||||||
</field>
|
</field>
|
||||||
|
|||||||
@@ -45,7 +45,8 @@ class FunctionalCuttingToolEntity(models.Model):
|
|||||||
string='状态', store=True, default='正常')
|
string='状态', store=True, default='正常')
|
||||||
current_location_id = fields.Many2one('stock.location', string='当前位置', compute='_compute_current_location_id',
|
current_location_id = fields.Many2one('stock.location', string='当前位置', compute='_compute_current_location_id',
|
||||||
store=True)
|
store=True)
|
||||||
current_shelf_location_id = fields.Many2one('sf.shelf.location', string='当前货位', readonly=True)
|
current_shelf_location_id = fields.Many2one('sf.shelf.location', string='当前货位',
|
||||||
|
compute='_compute_current_location_id', store=True)
|
||||||
current_location = fields.Selection(
|
current_location = fields.Selection(
|
||||||
[('组装后', '组装后'), ('刀具房', '刀具房'), ('线边刀库', '线边刀库'), ('机内刀库', '机内刀库')],
|
[('组装后', '组装后'), ('刀具房', '刀具房'), ('线边刀库', '线边刀库'), ('机内刀库', '机内刀库')],
|
||||||
string='位置', compute='_compute_current_location_id', store=True)
|
string='位置', compute='_compute_current_location_id', store=True)
|
||||||
@@ -85,6 +86,10 @@ class FunctionalCuttingToolEntity(models.Model):
|
|||||||
if quant_id.inventory_quantity_auto_apply > 0:
|
if quant_id.inventory_quantity_auto_apply > 0:
|
||||||
record.current_location_id = quant_id.location_id
|
record.current_location_id = quant_id.location_id
|
||||||
if quant_id.location_id.name == '制造前':
|
if quant_id.location_id.name == '制造前':
|
||||||
|
shelf_location_id = self.env['sf.shelf.location'].sudo().search([
|
||||||
|
('product_sn_id', '=', record.barcode_id.id)])
|
||||||
|
if shelf_location_id:
|
||||||
|
record.current_shelf_location_id = shelf_location_id.id
|
||||||
if not record.current_shelf_location_id:
|
if not record.current_shelf_location_id:
|
||||||
record.current_location = '机内刀库'
|
record.current_location = '机内刀库'
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -198,8 +198,8 @@ class MrpProduction(models.Model):
|
|||||||
logging.info('cnc用刀校验到无效刀自动调用重新编程方法:update_programming_state()')
|
logging.info('cnc用刀校验到无效刀自动调用重新编程方法:update_programming_state()')
|
||||||
self[0].update_programming_state()
|
self[0].update_programming_state()
|
||||||
self[0].write({'is_rework': False})
|
self[0].write({'is_rework': False})
|
||||||
# 修改制造订单 编程状态变为“编程中” 制造订单状态为‘返工’
|
# 修改制造订单 编程状态变为“编程中”
|
||||||
self.write({'programming_state': '编程中', 'work_state': '编程中', 'state': 'rework'})
|
self.write({'programming_state': '编程中', 'work_state': '编程中'})
|
||||||
self[0].workorder_ids.filtered(
|
self[0].workorder_ids.filtered(
|
||||||
lambda a: a.name == '装夹预调' and a.state not in ['rework', 'done', 'cancel'])._compute_state()
|
lambda a: a.name == '装夹预调' and a.state not in ['rework', 'done', 'cancel'])._compute_state()
|
||||||
if missing_tool_1:
|
if missing_tool_1:
|
||||||
|
|||||||
@@ -888,12 +888,11 @@ class SfStockMoveLine(models.Model):
|
|||||||
def _check_destination_location_id(self):
|
def _check_destination_location_id(self):
|
||||||
for item in self:
|
for item in self:
|
||||||
if item:
|
if item:
|
||||||
i = 0
|
|
||||||
barcode = item.destination_location_id.barcode
|
barcode = item.destination_location_id.barcode
|
||||||
for line in item.picking_id.move_line_ids_without_package:
|
for line in item.picking_id.move_line_ids_without_package:
|
||||||
if barcode and barcode == line.destination_location_id.barcode:
|
if line.destination_location_id:
|
||||||
i += 1
|
if (barcode and barcode == line.destination_location_id.barcode
|
||||||
if i > 1:
|
and item.product_id != line.product_id):
|
||||||
raise ValidationError(
|
raise ValidationError(
|
||||||
'【%s】货位已经被占用,请重新选择!!!' % item.destination_location_id.barcode)
|
'【%s】货位已经被占用,请重新选择!!!' % item.destination_location_id.barcode)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user