Compare commits
1 Commits
feature/10
...
release_1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
609e65e36f |
@@ -1,4 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import controllers
|
||||
from . import models
|
||||
@@ -1,35 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
{
|
||||
'name': "jikimo_account_process",
|
||||
|
||||
'summary': """
|
||||
处理会计凭证生成重复名称报错问题
|
||||
""",
|
||||
|
||||
'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': ['base', 'account'],
|
||||
|
||||
# always loaded
|
||||
'data': [
|
||||
# 'security/ir.model.access.csv',
|
||||
# 'views/views.xml',
|
||||
# 'views/templates.xml',
|
||||
],
|
||||
# only loaded in demonstration mode
|
||||
'demo': [
|
||||
# 'demo/demo.xml',
|
||||
],
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import controllers
|
||||
@@ -1,21 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# from odoo import http
|
||||
|
||||
|
||||
# class JikimoAccountProcess(http.Controller):
|
||||
# @http.route('/jikimo_account_process/jikimo_account_process', auth='public')
|
||||
# def index(self, **kw):
|
||||
# return "Hello, world"
|
||||
|
||||
# @http.route('/jikimo_account_process/jikimo_account_process/objects', auth='public')
|
||||
# def list(self, **kw):
|
||||
# return http.request.render('jikimo_account_process.listing', {
|
||||
# 'root': '/jikimo_account_process/jikimo_account_process',
|
||||
# 'objects': http.request.env['jikimo_account_process.jikimo_account_process'].search([]),
|
||||
# })
|
||||
|
||||
# @http.route('/jikimo_account_process/jikimo_account_process/objects/<model("jikimo_account_process.jikimo_account_process"):obj>', auth='public')
|
||||
# def object(self, obj, **kw):
|
||||
# return http.request.render('jikimo_account_process.object', {
|
||||
# 'object': obj
|
||||
# })
|
||||
@@ -1,4 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import models
|
||||
from . import account_move
|
||||
@@ -1,15 +0,0 @@
|
||||
from odoo import models, fields, api
|
||||
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class CustomAccountMoveLine(models.Model):
|
||||
_inherit = 'account.move'
|
||||
_description = "account move line"
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals):
|
||||
for val in vals:
|
||||
val['name'] = self.env['ir.sequence'].next_by_code('account.move') or '/'
|
||||
# 因为供应商与客户支付创建流程是先创建move line在修改来填充account_payment与move line的关联
|
||||
return super(CustomAccountMoveLine, self).create(vals)
|
||||
@@ -1,18 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# from odoo import models, fields, api
|
||||
|
||||
|
||||
# class jikimo_account_process(models.Model):
|
||||
# _name = 'jikimo_account_process.jikimo_account_process'
|
||||
# _description = 'jikimo_account_process.jikimo_account_process'
|
||||
|
||||
# name = fields.Char()
|
||||
# value = fields.Integer()
|
||||
# value2 = fields.Float(compute="_value_pc", store=True)
|
||||
# description = fields.Text()
|
||||
#
|
||||
# @api.depends('value')
|
||||
# def _value_pc(self):
|
||||
# for record in self:
|
||||
# record.value2 = float(record.value) / 100
|
||||
@@ -6,6 +6,6 @@ import { patch } from "web.utils";
|
||||
patch(WebClient.prototype, "kolpolok_custom_title_and_favicon.WebClient", {
|
||||
setup() {
|
||||
this._super();
|
||||
// this.title.setParts({ zopenerp: "JIKIMO" });
|
||||
this.title.setParts({ zopenerp: "JIKIMO" });
|
||||
},
|
||||
});
|
||||
@@ -1,99 +1,41 @@
|
||||
|
||||
.processing-capabilities-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(6, 1fr);
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
.zoomed {
|
||||
position: fixed !important;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%) scale(10);
|
||||
}
|
||||
|
||||
.grid-item {
|
||||
.many2many_flex {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.item-content {
|
||||
.many2many_flex>div {
|
||||
margin-right: 15px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
/*控制图片大小*/
|
||||
.item-icon {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.item-label {
|
||||
font-size: 12px;
|
||||
word-break: break-word;
|
||||
.many2many_flex>div>:nth-child(2) {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.processing-capabilities-grid {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.processing-capabilities-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.processing-capabilities-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
.image-preview-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.9);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 1000;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.image-preview-container.show {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.image-preview {
|
||||
max-width: 90%;
|
||||
max-height: 90%;
|
||||
object-fit: contain;
|
||||
box-shadow: 0 0 20px rgba(255, 255, 255, 0.2);
|
||||
border-radius: 5px;
|
||||
transform: scale(0.9);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.image-preview-container.show .image-preview {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
.image-preview-close {
|
||||
.close {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 30px;
|
||||
top: -8.8px;
|
||||
right: -8.8px;
|
||||
color: #fff;
|
||||
font-size: 40px;
|
||||
font-weight: bold;
|
||||
transition: 0.3s;
|
||||
cursor: pointer;
|
||||
opacity: 0.7;
|
||||
background-color: #000;
|
||||
opacity: 0;
|
||||
text-align: center;
|
||||
line-height: 20px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.image-preview-close:hover,
|
||||
.image-preview-close:focus {
|
||||
.img_close {
|
||||
opacity: 1;
|
||||
text-decoration: none;
|
||||
transform: scale(0.1);
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -4,57 +4,35 @@ import {Many2ManyCheckboxesField} from "@web/views/fields/many2many_checkboxes/m
|
||||
import {registry} from "@web/core/registry";
|
||||
|
||||
export class MyCustomWidget extends Many2ManyCheckboxesField {
|
||||
// 你可以重写或者添加一些方法和属性
|
||||
// 例如,你可以重写setup方法来添加一些事件监听器或者初始化一些变量
|
||||
setup() {
|
||||
super.setup();
|
||||
super.setup(); // 调用父类的setup方法
|
||||
// 你自己的代码
|
||||
}
|
||||
|
||||
onImageClick(event, src) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
onImageClick(event) {
|
||||
// 放大图片逻辑
|
||||
// 获取图片元素
|
||||
const img = event.target;
|
||||
const close = img.nextSibling;
|
||||
|
||||
// 创建预览框
|
||||
const previewContainer = document.createElement('div');
|
||||
previewContainer.className = 'image-preview-container';
|
||||
|
||||
const previewImg = document.createElement('img');
|
||||
previewImg.src = src;
|
||||
previewImg.className = 'image-preview';
|
||||
// 设置放大的预览图片大小
|
||||
previewImg.style.width = '600px';
|
||||
previewImg.style.height = 'auto'; // 保持宽高比
|
||||
|
||||
const closeButton = document.createElement('span');
|
||||
closeButton.innerHTML = '×';
|
||||
closeButton.className = 'image-preview-close';
|
||||
|
||||
previewContainer.appendChild(previewImg);
|
||||
previewContainer.appendChild(closeButton);
|
||||
document.body.appendChild(previewContainer);
|
||||
|
||||
// 添加关闭预览的事件监听器
|
||||
const closePreview = () => {
|
||||
previewContainer.classList.remove('show');
|
||||
setTimeout(() => {
|
||||
document.body.removeChild(previewContainer);
|
||||
}, 300);
|
||||
};
|
||||
|
||||
closeButton.addEventListener('click', closePreview);
|
||||
|
||||
// 点击预览框外部也可以关闭
|
||||
previewContainer.addEventListener('click', (e) => {
|
||||
if (e.target === previewContainer) {
|
||||
closePreview();
|
||||
// 实现放大图片逻辑
|
||||
// 比如使用 CSS 放大
|
||||
img.parentElement.classList.add('zoomed');
|
||||
close.classList.add('img_close');
|
||||
}
|
||||
});
|
||||
|
||||
// 使用 setTimeout 来触发过渡效果
|
||||
setTimeout(() => {
|
||||
previewContainer.classList.add('show');
|
||||
}, 10);
|
||||
onCloseClick(event) {
|
||||
const close = event.target;
|
||||
const img = close.previousSibling;
|
||||
img.parentElement.classList.remove('zoomed');
|
||||
close.classList.remove('img_close');
|
||||
}
|
||||
}
|
||||
|
||||
MyCustomWidget.template = "jikimo_frontend.MyCustomWidget";
|
||||
// MyCustomWidget.supportedTypes = ['many2many'];
|
||||
|
||||
registry.category("fields").add("custom_many2many_checkboxes", MyCustomWidget);
|
||||
|
||||
|
||||
@@ -2,20 +2,25 @@
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="jikimo_frontend.MyCustomWidget" owl="1">
|
||||
<div aria-atomic="true" class="many2many_flex processing-capabilities-grid">
|
||||
<div aria-atomic="true" class="many2many_flex">
|
||||
<t t-foreach="items" t-as="item" t-key="item[0]">
|
||||
<div class="grid-item">
|
||||
<div>
|
||||
<CheckBox
|
||||
value="isSelected(item)"
|
||||
disabled="props.readonly"
|
||||
onChange="(ev) => this.onChange(item[0], ev)"
|
||||
>
|
||||
<div class="item-content">
|
||||
<img t-att-src="item[2]" class="item-icon" t-on-click="(ev) => this.onImageClick(ev, item[2])"/>
|
||||
<span class="item-label"><t t-esc="item[1]"/></span>
|
||||
</div>
|
||||
<t t-esc="item[1]"/>
|
||||
|
||||
</CheckBox>
|
||||
<div t-on-dblclick="onImageClick">
|
||||
<t>
|
||||
<img t-att-src="item[2]" width="50" height="50"/>
|
||||
<div class="close" t-on-click="onCloseClick">×</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
@@ -5,7 +5,7 @@ import {patch} from '@web/core/utils/patch';
|
||||
import {_t} from "@web/core/l10n/translation";
|
||||
import {FormStatusIndicator} from "@web/views/form/form_status_indicator/form_status_indicator";
|
||||
import {ListRenderer} from "@web/views/list/list_renderer";
|
||||
// import {StatusBarField} from "@web/views/fields/statusbar/statusbar_field";
|
||||
import {StatusBarField} from "@web/views/fields/statusbar/statusbar_field";
|
||||
|
||||
import {Field} from "@web/views/fields/field";
|
||||
|
||||
@@ -53,23 +53,6 @@ const tableRequiredList = [
|
||||
]
|
||||
|
||||
patch(FormStatusIndicator.prototype, 'jikimo_frontend.FormStatusIndicator', {
|
||||
setup() {
|
||||
owl.onMounted(() => {
|
||||
try {
|
||||
const dom = this.__owl__.bdom.el
|
||||
const buttonsDom = $(dom).find('.o_form_status_indicator_buttons ')
|
||||
if (buttonsDom) {
|
||||
const dom1 = buttonsDom.children('.o_form_button_save')
|
||||
const dom2 = buttonsDom.children('.o_form_button_cancel')
|
||||
dom1.append('保存')
|
||||
dom2.append('取消')
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
|
||||
});
|
||||
},
|
||||
// 你可以重写或者添加一些方法和属性
|
||||
async _onDiscardChanges() {
|
||||
// var self = this;
|
||||
@@ -170,36 +153,47 @@ patch(ListRenderer.prototype, 'jikimo_frontend.ListRenderer', {
|
||||
|
||||
|
||||
// 根据进度条设置水印
|
||||
// const statusbar_params = {
|
||||
// '已完工': 'bg-primary',
|
||||
// '完成': 'bg-primary',
|
||||
// '采购订单': 'bg-primary',
|
||||
// '作废': 'bg-danger',
|
||||
// '封存(报废)': 'bg-danger',
|
||||
// }
|
||||
// patch(StatusBarField.prototype, 'jikimo_frontend.StatusBarField', {
|
||||
// setup() {
|
||||
// owl.onMounted(this.ribbons);
|
||||
// return this._super(...arguments);
|
||||
// },
|
||||
// ribbons() {
|
||||
// try {
|
||||
// const dom = $('.o_form_sheet.position-relative')
|
||||
// const status = statusbar_params[this.currentName]
|
||||
// if(status && dom.length) {
|
||||
// dom.prepend(`<div class="o_widget o_widget_web_ribbon">
|
||||
// <div class="ribbon ribbon-top-right">
|
||||
// <span class="bg-opacity-75 ${status}" title="">${this.currentName}</span>
|
||||
// </div>
|
||||
// </div>`)
|
||||
// }
|
||||
// } catch (e) {
|
||||
// console.log(e)
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
const statusbar_params = {
|
||||
'已完工': 'bg-primary',
|
||||
'完成': 'bg-primary',
|
||||
'采购订单': 'bg-primary',
|
||||
'作废': 'bg-danger',
|
||||
'封存(报废)': 'bg-danger',
|
||||
}
|
||||
patch(StatusBarField.prototype, 'jikimo_frontend.StatusBarField', {
|
||||
setup() {
|
||||
owl.onMounted(this.ribbons);
|
||||
return this._super(...arguments);
|
||||
},
|
||||
ribbons() {
|
||||
try {
|
||||
const dom = $('.o_form_sheet.position-relative')
|
||||
const status = statusbar_params[this.currentName]
|
||||
if(status && dom.length) {
|
||||
dom.prepend(`<div class="o_widget o_widget_web_ribbon">
|
||||
<div class="ribbon ribbon-top-right">
|
||||
<span class="bg-opacity-75 ${status}" title="">${this.currentName}</span>
|
||||
</div>
|
||||
</div>`)
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
$(function () {
|
||||
document.addEventListener('click', function () {
|
||||
const dom = $('.o_form_status_indicator_buttons ')
|
||||
if (dom) {
|
||||
const dom1 = dom.children().eq(0)
|
||||
const dom2 = dom.children().eq(1)
|
||||
if (!dom1.text()) {
|
||||
dom1.append('保存')
|
||||
dom2.append('取消')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
function customRequired() {
|
||||
let timer = null
|
||||
|
||||
@@ -108,10 +108,6 @@ td.o_required_modifier {
|
||||
}
|
||||
|
||||
.color_3 {
|
||||
background-color: #808080;
|
||||
}
|
||||
|
||||
.color_4 {
|
||||
background-color: rgb(255, 150, 0);
|
||||
}
|
||||
|
||||
@@ -526,13 +522,3 @@ div:has(.o_required_modifier) > label::before {
|
||||
max-width: 100%;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
// 设置表单页面label文本不换行
|
||||
.o_form_view .o_group .o_wrap_label .o_form_label {
|
||||
white-space: nowrap;
|
||||
}
|
||||
// 修复表格内容覆盖表头bug
|
||||
.o_list_renderer .o_list_table tbody th {
|
||||
position: unset;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
<!-- 修改页面头部图标及文字 -->
|
||||
<template id="favicon_icon" inherit_id="web.layout" name="Web layout">
|
||||
<!-- change the title with reliance partner -->
|
||||
<!-- <xpath expr="//head//title" position="before">
|
||||
<xpath expr="//head//title" position="before">
|
||||
<title t-esc="'JIKIMO'"/>
|
||||
</xpath> -->
|
||||
</xpath>
|
||||
<!-- change the default favicon icon with -->
|
||||
<xpath expr="//head//link[@rel='shortcut icon']" position="replace">
|
||||
<link type="image/x-icon" rel="shortcut icon" href="/jikimo_frontend/static/src/img/jikimo-logo.ico"/>
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- hide 登录页面 powerd by odoo 及管理数据库 -->
|
||||
<template id="login_page_layout" inherit_id="web.login_layout" name="Login Page Layout">
|
||||
<!-- <xpath expr="//div[@class='card-body']/div[last()]" position="replace"></xpath> -->
|
||||
<xpath expr="//div[@class='card-body']//div[last()]" position="replace"></xpath>
|
||||
</template>
|
||||
|
||||
<!-- 隐藏odoo版本信息 -->
|
||||
|
||||
@@ -301,27 +301,53 @@ def unlink(self):
|
||||
# This is used to restrict the access right to unlink a record
|
||||
current_model_id = self.env['ir.model'].sudo().search(
|
||||
[('model', '=', self._name)]).id
|
||||
# access_right_rec = self.env['access.right'].sudo().search_read(
|
||||
# [('model_id', '=', current_model_id)], ['model_id', 'is_delete',
|
||||
# 'groups_id'])
|
||||
# if access_right_rec and not self.env.is_admin():
|
||||
# for rec in access_right_rec:
|
||||
# group_name = self.env['ir.model.data'].sudo().search([
|
||||
# ('model', '=', 'res.groups'),
|
||||
# ('res_id', '=', rec['groups_id'][0])
|
||||
# ]).name
|
||||
# module_name = self.env['ir.model.data'].sudo().search([
|
||||
# ('model', '=', 'res.groups'),
|
||||
# ('res_id', '=', rec['groups_id'][0])
|
||||
# ]).module
|
||||
# group = module_name + "." + group_name
|
||||
# if self.env.user.has_group(group):
|
||||
# if rec['is_delete']:
|
||||
# raise UserError(_('You are restricted from performing this'
|
||||
# ' operation. Please contact the'
|
||||
# ' administrator.'))
|
||||
# 检查 'access.right' 模型是否存在于环境中
|
||||
if 'access.right' in self.env:
|
||||
# current_model_id = self.env['ir.model'].sudo().search([('model', '=', self._name)]).id
|
||||
access_right_rec = self.env['access.right'].sudo().search_read(
|
||||
[('model_id', '=', current_model_id)], ['model_id', 'is_delete',
|
||||
'groups_id'])
|
||||
[('model_id', '=', current_model_id)], ['model_id', 'is_delete', 'groups_id']
|
||||
)
|
||||
|
||||
if access_right_rec and not self.env.is_admin():
|
||||
for rec in access_right_rec:
|
||||
group_name = self.env['ir.model.data'].sudo().search([
|
||||
('model', '=', 'res.groups'),
|
||||
('res_id', '=', rec['groups_id'][0])
|
||||
]).name
|
||||
module_name = self.env['ir.model.data'].sudo().search([
|
||||
('model', '=', 'res.groups'),
|
||||
('res_id', '=', rec['groups_id'][0])
|
||||
]).module
|
||||
group = module_name + "." + group_name
|
||||
if self.env.user.has_group(group):
|
||||
if rec['is_delete']:
|
||||
raise UserError(_('You are restricted from performing this'
|
||||
' operation. Please contact the'
|
||||
' administrator.'))
|
||||
group_data = self.env['ir.model.data'].sudo().search_read(
|
||||
[('model', '=', 'res.groups'), ('res_id', '=', rec['groups_id'][0])],
|
||||
['name', 'module']
|
||||
)
|
||||
|
||||
if group_data:
|
||||
group_name = group_data[0]['name']
|
||||
module_name = group_data[0]['module']
|
||||
group_xml_id = f"{module_name}.{group_name}"
|
||||
|
||||
if self.env.user.has_group(group_xml_id) and rec['is_delete']:
|
||||
raise UserError(
|
||||
_('You are restricted from performing this operation. Please contact the administrator.'))
|
||||
else:
|
||||
# 如果 'access.right' 模型不存在,可以在这里定义备选逻辑
|
||||
pass
|
||||
|
||||
return True
|
||||
|
||||
|
||||
BaseModel._create = _create
|
||||
# BaseModel.unlink = unlink
|
||||
BaseModel.unlink = unlink
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import controllers
|
||||
from . import models
|
||||
from . import wizard
|
||||
@@ -1,39 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
{
|
||||
'name': "jikimo_system_order",
|
||||
|
||||
'summary': """
|
||||
系统工单""",
|
||||
|
||||
'description': """
|
||||
用于处理针对系统的工作任务;
|
||||
员工可以通过系统工单发起申请,由维护人员处理以后,填写处理结果。
|
||||
""",
|
||||
|
||||
'author': "机企猫",
|
||||
'website': "http://www.jikimo.com",
|
||||
|
||||
# Categories can be used to filter modules in modules listing
|
||||
# Check https://github.com/odoo/odoo/blob/master/odoo/addons/base/module/module_data.xml
|
||||
# for the full list
|
||||
'category': 'Uncategorized',
|
||||
'version': '0.1',
|
||||
|
||||
# any module necessary for this one to work correctly
|
||||
'depends': ['base','mail'],
|
||||
|
||||
# always loaded
|
||||
'data': [
|
||||
'security/account_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'wizard/order_wizard.xml',
|
||||
'views/notice_user_config.xml',
|
||||
'views/yizuo_system_order_view.xml',
|
||||
'views/work_order_number.xml',
|
||||
'views/res_config_settings_views.xml',
|
||||
],
|
||||
# only loaded in demonstration mode
|
||||
'demo': [
|
||||
'demo/demo.xml',
|
||||
],
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import controllers
|
||||
@@ -1,20 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import http
|
||||
|
||||
# class TopSystemOrder(http.Controller):
|
||||
# @http.route('/jikimo_system_order/jikimo_system_order/', auth='public')
|
||||
# def index(self, **kw):
|
||||
# return "Hello, world"
|
||||
|
||||
# @http.route('/jikimo_system_order/jikimo_system_order/objects/', auth='public')
|
||||
# def list(self, **kw):
|
||||
# return http.request.render('jikimo_system_order.listing', {
|
||||
# 'root': '/jikimo_system_order/jikimo_system_order',
|
||||
# 'objects': http.request.env['jikimo_system_order.jikimo_system_order'].search([]),
|
||||
# })
|
||||
|
||||
# @http.route('/jikimo_system_order/jikimo_system_order/objects/<model("jikimo_system_order.jikimo_system_order"):obj>/', auth='public')
|
||||
# def object(self, obj, **kw):
|
||||
# return http.request.render('jikimo_system_order.object', {
|
||||
# 'object': obj
|
||||
# })
|
||||
@@ -1,30 +0,0 @@
|
||||
<odoo>
|
||||
<data>
|
||||
<!-- -->
|
||||
<!-- <record id="object0" model="jikimo_system_order.jikimo_system_order"> -->
|
||||
<!-- <field name="name">Object 0</field> -->
|
||||
<!-- <field name="value">0</field> -->
|
||||
<!-- </record> -->
|
||||
<!-- -->
|
||||
<!-- <record id="object1" model="jikimo_system_order.jikimo_system_order"> -->
|
||||
<!-- <field name="name">Object 1</field> -->
|
||||
<!-- <field name="value">10</field> -->
|
||||
<!-- </record> -->
|
||||
<!-- -->
|
||||
<!-- <record id="object2" model="jikimo_system_order.jikimo_system_order"> -->
|
||||
<!-- <field name="name">Object 2</field> -->
|
||||
<!-- <field name="value">20</field> -->
|
||||
<!-- </record> -->
|
||||
<!-- -->
|
||||
<!-- <record id="object3" model="jikimo_system_order.jikimo_system_order"> -->
|
||||
<!-- <field name="name">Object 3</field> -->
|
||||
<!-- <field name="value">30</field> -->
|
||||
<!-- </record> -->
|
||||
<!-- -->
|
||||
<!-- <record id="object4" model="jikimo_system_order.jikimo_system_order"> -->
|
||||
<!-- <field name="name">Object 4</field> -->
|
||||
<!-- <field name="value">40</field> -->
|
||||
<!-- </record> -->
|
||||
<!-- -->
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,7 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import constant
|
||||
from . import order_classify
|
||||
from . import system_work_order
|
||||
from . import work_order_template
|
||||
from . import res_config_setting
|
||||
@@ -1,7 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# 工单状态
|
||||
STATE_SELECTION = [('draft', u'草稿'), ('unconfirmed', u'待确认'), ('pending', u'待处理'),
|
||||
('processed', u'已处理待评分'), ('completed', u'已完成'), ('closed', u'已关闭')]
|
||||
|
||||
GRADE = [('1', '1非常不满意'), ('2', '2不满意'), ('3', '3一般'), ('4', '4满意'), ('5', '5非常满意')]
|
||||
@@ -1,25 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import models, fields, api
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class OrderClassify(models.Model):
|
||||
_name = 'order.classify'
|
||||
_order = 'sequence, name'
|
||||
|
||||
|
||||
@api.constrains('name')
|
||||
def check_base_name(self):
|
||||
"""类型名称唯一"""
|
||||
name_obj = self.env['order.classify'].search([('name', '=', self.name)])
|
||||
if len(name_obj) >= 2:
|
||||
raise ValidationError(u'该类型已存在')
|
||||
|
||||
# 名称
|
||||
name = fields.Char(string=u'名称', size=20)
|
||||
# 排序
|
||||
sequence = fields.Integer(default=10)
|
||||
# 是否有效
|
||||
state = fields.Boolean(default=True, string='是否有效')
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
from odoo import api, fields, models, _
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ResModelWeConfigSettings(models.TransientModel):
|
||||
_inherit = 'res.config.settings'
|
||||
|
||||
lost_agent_id = fields.Char('企微通知应用ID')
|
||||
|
||||
@api.model
|
||||
def get_values(self):
|
||||
"""
|
||||
重载获取参数的方法,参数都存在系统参数中
|
||||
:return:
|
||||
"""
|
||||
values = super(ResModelWeConfigSettings, self).get_values()
|
||||
config = self.env['ir.config_parameter'].sudo()
|
||||
lost_agent_id = config.get_param('lost_agent_id', default='')
|
||||
values.update(
|
||||
lost_agent_id=lost_agent_id,
|
||||
)
|
||||
return values
|
||||
|
||||
def set_values(self):
|
||||
super(ResModelWeConfigSettings, self).set_values()
|
||||
ir_config = self.env['ir.config_parameter'].sudo()
|
||||
ir_config.set_param("lost_agent_id", self.lost_agent_id or "")
|
||||
|
||||
@@ -1,183 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import models, fields, api
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo import exceptions
|
||||
from .constant import STATE_SELECTION, GRADE
|
||||
import datetime
|
||||
import logging
|
||||
|
||||
|
||||
class SystemWorkOrder(models.Model):
|
||||
_name = 'system.work.order'
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_order = 'date desc'
|
||||
_description = u'系统工单'
|
||||
_rec_name = 'order_number'
|
||||
|
||||
def get_is_technicist(self):
|
||||
self._cr.execute(
|
||||
"select u.id from res_users u left join res_groups_users_rel r on r.uid = u.id where r.gid in (select g.id from res_groups g where g.name = '技术员权限') and u.id ='%s'",
|
||||
(self.env.user.id,))
|
||||
hr = self._cr.dictfetchall()
|
||||
if len(hr) > 0:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
# def get_user_department_id(self):
|
||||
# """根据用户id系统员工id"""
|
||||
# employee = self.env['hr.employee'].sudo().search([('user_id', '=', self.env.uid)], limit=1)
|
||||
# if employee:
|
||||
# if len(employee) > 0:
|
||||
# if not employee.department_id:
|
||||
# raise exceptions.Warning(u'您当前使用的用户没有所属部门')
|
||||
# return employee.department_id
|
||||
# else:
|
||||
# return False
|
||||
# else:
|
||||
# raise exceptions.Warning(u'您当前使用的用户没有关联员工')
|
||||
|
||||
@api.onchange('order_template_id')
|
||||
def get_title(self):
|
||||
"""选择模板自动填充"""
|
||||
if self.order_template_id:
|
||||
self.title = self.order_template_id.title_template
|
||||
self.text = self.order_template_id.text_template
|
||||
|
||||
# 工单编号
|
||||
order_number = fields.Char(string=u'工单编号', default='/')
|
||||
# 紧急程度
|
||||
urgency_degree = fields.Selection([('0', u'0星'), ('1', u'一星'), ('2', u'二星'), ('3', u'三星'), ('4', u'四星'),
|
||||
('5', u'五星')], string=u'紧急程度', help='五星为最紧急!', default='5')
|
||||
# 工单分类(可以配置,并调整优先级)
|
||||
order_type = fields.Many2one('order.classify', string=u'工单分类', domain=[('state', '=', True)])
|
||||
# 发起人所属公司(res.company)
|
||||
initiator_company_id = fields.Many2one('res.company', string=u'发起人所属公司', default=lambda self: self.env.user.company_id)
|
||||
# 发起人部门(hr.department)
|
||||
# initiator_department_id = fields.Many2one('hr.department', string=u'发起人部门', default=get_user_department_id)
|
||||
# 发起人(hr.employee)
|
||||
initiator_id = fields.Many2one('res.users', string=u'发起人', default=lambda self: self.env.user)
|
||||
# 发起时间
|
||||
date = fields.Datetime(string=u'发起时间', default=lambda self: fields.datetime.now())
|
||||
# 确认人
|
||||
confirm_id = fields.Many2one('res.users', string=u'确认人')
|
||||
# 确认日期
|
||||
confirmation_date = fields.Datetime(string=u'确认时间')
|
||||
# 模板
|
||||
order_template_id = fields.Many2one('work.order.template', string=u'模板', domain=[('state', '=', True)])
|
||||
# 标题
|
||||
title = fields.Char(string=u'标题')
|
||||
# 正文
|
||||
text = fields.Html(string=u'正文')
|
||||
# 状态[草稿\待确认\待处理\已处理\已关闭]
|
||||
state = fields.Selection(STATE_SELECTION, default='draft', string=u'状态')
|
||||
# 关闭原因
|
||||
close_cause = fields.Text(string=u'关闭问题原因')
|
||||
# 关闭时间
|
||||
close_time = fields.Datetime(string=u'关闭问题时间')
|
||||
# 关闭人
|
||||
close_user_id = fields.Many2one('res.users', string=u'关闭人')
|
||||
# 解决人
|
||||
solve_people_id = fields.Many2one('res.users', string=u'解决人')
|
||||
# 用户实际问题
|
||||
users_problem = fields.Text(string=u'用户实际问题')
|
||||
# 最终解决方案
|
||||
solution = fields.Text(string=u'最终解决方案')
|
||||
# 判断是否为技术人员
|
||||
# is_technicist = fields.Boolean(string=u'是否为技术人员', default=get_is_technicist)
|
||||
# 打分
|
||||
grade = fields.Selection(GRADE, string=u'评分')
|
||||
# 评价按钮的显示
|
||||
is_display = fields.Boolean('控制显示评价按钮', compute='compute_is_display')
|
||||
|
||||
def compute_is_display(self):
|
||||
for item in self:
|
||||
if item.state == 'processed' and self.env.user.id == item.initiator_id.id:
|
||||
item.is_display = True
|
||||
else:
|
||||
item.is_display = False
|
||||
|
||||
@api.onchange('order_type')
|
||||
def _onchange_order_type(self):
|
||||
self.order_template_id = None
|
||||
self.title = None
|
||||
self.text = None
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
# 创建编号
|
||||
if vals.get('order_number', '/') == '/':
|
||||
vals['order_number'] = self.env['ir.sequence'].get('system.work.order') or '/'
|
||||
return super(SystemWorkOrder, self).create(vals)
|
||||
|
||||
def do_draft(self, order=None):
|
||||
"""状态草稿"""
|
||||
bill = self
|
||||
if order:
|
||||
bill = order
|
||||
if bill.state == 'unconfirmed':
|
||||
state_remark = u'待确认 --> 草稿'
|
||||
# bill.message_post(u'操作人:%s,操作时间:%s,状态变更过程:%s' % (self.env.user.name,
|
||||
# (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), state_remark))
|
||||
bill.state = 'draft'
|
||||
|
||||
def do_unconfirmed(self):
|
||||
"""状态待确认"""
|
||||
if self.state == 'draft':
|
||||
state_remark = u'草稿 --> 待确认'
|
||||
# self.message_post(u'操作人:%s,操作时间:%s,状态变更过程:%s' % (
|
||||
# self.env.user.name,
|
||||
# (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), state_remark))
|
||||
self.state = 'unconfirmed'
|
||||
# 获取通知人
|
||||
objs = self.env['system.order.notice'].search([])
|
||||
user_ids = objs.notice_user_ids.filtered(lambda item: item.we_employee_id not in ['', False])
|
||||
we_employee_ids = user_ids.mapped('we_employee_id')
|
||||
lost_agent_id = self.env['ir.config_parameter'].sudo().get_param('lost_agent_id')
|
||||
wechat = self.env['we.config'].sudo().get_wechat(agent_id=lost_agent_id)
|
||||
# agent_id, user_ids, content
|
||||
content = """您有一张工单<font color=\"warning\">待处理</font>:**工单标题:{2}**
|
||||
>创建人:{1}
|
||||
>提交时间:{3}
|
||||
>紧急程度:{0}星
|
||||
请查看工单消息,并及时处理!
|
||||
""".format(self.urgency_degree,
|
||||
self.initiator_id.name, self.title, (self.date + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M'))
|
||||
for we_employee_id in we_employee_ids:
|
||||
try:
|
||||
wechat.message.send_markdown(agent_id=lost_agent_id, user_ids=we_employee_id, content=content)
|
||||
except Exception as e:
|
||||
logging.error('工单处理发送消息异常%s' % str(e))
|
||||
|
||||
return True
|
||||
|
||||
def do_pending(self):
|
||||
"""状态待处理"""
|
||||
if self.state == 'unconfirmed':
|
||||
state_remark = u'待确认 --> 待处理'
|
||||
# self.message_post(u'操作人:%s,操作时间:%s,状态变更过程:%s' % (
|
||||
# self.env.user.name,
|
||||
# (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), state_remark))
|
||||
self.state = 'pending'
|
||||
self.confirm_id = self.env.user
|
||||
self.confirmation_date = fields.datetime.now()
|
||||
return True
|
||||
|
||||
def urned_off(self):
|
||||
"""状态关闭"""
|
||||
if self.close_cause:
|
||||
self.state = 'closed'
|
||||
self.close_time = fields.datetime.now()
|
||||
else:
|
||||
raise ValidationError(u'请注明关闭原因')
|
||||
return True
|
||||
|
||||
def unlink(self):
|
||||
for item in self:
|
||||
if item.state != "draft":
|
||||
raise ValidationError(u'只能删除状态为【草稿】的工单。')
|
||||
elif item.env.uid != item.initiator_id.id:
|
||||
raise ValidationError(u'非本人不能删除')
|
||||
else:
|
||||
super(SystemWorkOrder, item).unlink()
|
||||
@@ -1,38 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import models, fields, api
|
||||
|
||||
|
||||
class WorkOrderTemplate(models.Model):
|
||||
_name = 'work.order.template'
|
||||
_order = 'num'
|
||||
|
||||
# 编号
|
||||
num = fields.Char(string=u'编号', default='/')
|
||||
# 名称
|
||||
name = fields.Char(string=u'模板名称', required="1")
|
||||
# 分类
|
||||
work_order_type = fields.Many2one('order.classify', string=u'系统工单分类', domain=[('state', '=', True)])
|
||||
# 模板标题
|
||||
title_template = fields.Char(string=u'模板标题')
|
||||
# 模板正文
|
||||
text_template = fields.Html(string=u'模板正文')
|
||||
# 模板说明
|
||||
template_explain = fields.Text(string=u'模板说明')
|
||||
# 是否有效
|
||||
state = fields.Boolean(default=True, string=u'是否有效')
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
# 创建编号
|
||||
if vals.get('num', '/') == '/':
|
||||
vals['num'] = self.env['ir.sequence'].get('work.order.template') or '/'
|
||||
return super(WorkOrderTemplate, self).create(vals)
|
||||
|
||||
|
||||
class SystemOrderNotice(models.Model):
|
||||
_name = 'system.order.notice'
|
||||
_description = '工单处理人设置'
|
||||
|
||||
notice_user_ids = fields.Many2many('res.users', string='工单处理人')
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="0"> <!-- noupdate表示,当模块升级时是否更新本条数据-->
|
||||
<!--运维权限组-->
|
||||
<record id="group_operations_permissions_rwc" model="res.groups">
|
||||
<field name="name">运维权限</field>
|
||||
</record>
|
||||
|
||||
<record id="system_order_user_rule" model="ir.rule">
|
||||
<field name="name">用户访问工单信息</field>
|
||||
<field name="model_id" ref="model_system_work_order"/>
|
||||
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
|
||||
<field name="domain_force">[('initiator_id', '=', user.id)]</field>
|
||||
</record>
|
||||
|
||||
<record id="system_order_group_operations_rule" model="ir.rule">
|
||||
<field name="name">运维访问工单信息</field>
|
||||
<field name="model_id" ref="model_system_work_order"/>
|
||||
<field name="groups" eval="[(4, ref('jikimo_system_order.group_operations_permissions_rwc'))]"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,16 +0,0 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
|
||||
inside_system_order_classify_r,jikimo_system_order.order_classify,model_order_classify,,1,1,1,1
|
||||
inside_system_work_order_rc,jikimo_system_order.system_work_order,model_system_work_order,,1,1,1,1
|
||||
inside_work_order_template_r,jikimo_system_order.work_order_template,model_work_order_template,,1,1,1,1
|
||||
|
||||
inside_system_order_classify_rwc,jikimo_system_order.order_classify,model_order_classify,group_operations_permissions_rwc,1,1,1,0
|
||||
inside_system_work_order_rwc,jikimo_system_order.system_work_order,model_system_work_order,group_operations_permissions_rwc,1,1,1,0
|
||||
inside_work_order_template_rwc,jikimo_system_order.work_order_template,model_work_order_template,group_operations_permissions_rwc,1,1,1,0
|
||||
|
||||
order_close_wizard_group_user,jikimo_system_order.order_close_wizard,model_order_close_wizard,base.group_user,1,1,1,1
|
||||
order_other_wizard_group_user,jikimo_system_order.order_other_wizard,model_order_other_wizard,base.group_user,1,1,1,1
|
||||
order_technician_wizard_group_user,jikimo_system_order.order_technician_wizard,model_order_technician_wizard,base.group_user,1,1,1,1
|
||||
system_work_order_wizard_group_user,jikimo_system_order.system_work_order_wizard,model_system_work_order_wizard,base.group_user,1,1,1,1
|
||||
|
||||
system_order_notice_group_user,jikimo_system_order.system_order_notice,model_system_order_notice,base.group_user,1,1,1,1
|
||||
|
Binary file not shown.
|
Before Width: | Height: | Size: 2.7 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 533 B |
@@ -1,58 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<data>
|
||||
# ---------- 工单通知处理人设置 ------------
|
||||
|
||||
<record model="ir.ui.view" id="tree_system_order_notice_view">
|
||||
<field name="name">tree.system.order.notice</field>
|
||||
<field name="model">system.order.notice</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="工单处理人设置" editable="top">
|
||||
<field name="notice_user_ids" widget="many2many_tags" required="1" options="{'no_create': True, 'no_edit': True}"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record model="ir.ui.view" id="search_system_order_notice_view">
|
||||
<field name="name">search.system.order.notice</field>
|
||||
<field name="model">system.order.notice</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="工单处理人设置">
|
||||
<field name="notice_user_ids" string="模糊搜索"
|
||||
filter_domain="[('notice_user_ids', 'ilike', self)]"/>
|
||||
<separator></separator>
|
||||
|
||||
<field name="notice_user_ids" string="处理人"/>
|
||||
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record model="ir.actions.act_window" id="action_system_order_notice_view">
|
||||
<field name="name">工单处理人</field>
|
||||
<field name="res_model">system.order.notice</field>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="domain">[]</field>
|
||||
<field name="context">{}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
[工单处理人] 还没有哦!点左上角的[创建]按钮,沙发归你了!
|
||||
</p>
|
||||
<p>
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,28 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="res_config_settings_we_view_form_inherit" model="ir.ui.view">
|
||||
<field name="name">res.config.settings.we.view.form.inherit.bpm</field>
|
||||
<field name="model">res.config.settings</field>
|
||||
<field name="inherit_id" ref="base.res_config_settings_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[hasclass('app_settings_block')]/div[6]" position="after">
|
||||
<div>
|
||||
<h2>企微通知应用ID</h2>
|
||||
<div class="row mt16 o_settings_container" id="jd_api">
|
||||
<div class="col-12 col-lg-6 o_setting_box">
|
||||
<div class="o_setting_left_pane"/>
|
||||
<div class="o_setting_right_pane">
|
||||
<div class="text-muted">
|
||||
<label for="lost_agent_id"/>
|
||||
<field name="lost_agent_id"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<odoo>
|
||||
<data noupdate="True">
|
||||
<!-- 工单流水号 -->
|
||||
<record id="seq_work_order" model="ir.sequence">
|
||||
<field name="name">seq_work_order</field>
|
||||
<field name="company_id"/>
|
||||
<field name="code">system.work.order</field>
|
||||
<field name="prefix">SO%(year)s%(month)s%(day)s</field>
|
||||
<field name="padding">1</field>
|
||||
</record>
|
||||
|
||||
<!-- 模板编号 -->
|
||||
<record id="seq_order_template" model="ir.sequence">
|
||||
<field name="name">seq_order_template</field>
|
||||
<field name="company_id"/>
|
||||
<field name="code">work.order.template</field>
|
||||
<field name="prefix">TL</field>
|
||||
<field name="padding">1</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,243 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<odoo>
|
||||
<data>
|
||||
<!--工单信息-->
|
||||
<record model="ir.ui.view" id="work_order_tree">
|
||||
<field name="name">工单信息</field>
|
||||
<field name="model">system.work.order</field><!--对应表单名称-->
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="state" widget="badge" decoration-primary="state == 'draft'"
|
||||
decoration-success="state in ('processed', 'completed')"
|
||||
decoration-danger="state == 'pending'" decoration-warning="state in ('unconfirmed')"/>
|
||||
<field name="order_number"/>
|
||||
<field name="title"/>
|
||||
<field name="initiator_id"/>
|
||||
<field name="date"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!--新建系统工单-->
|
||||
<record model="ir.ui.view" id="ork_order_form">
|
||||
<field name="name">新建系统工单</field>
|
||||
<field name="model">system.work.order</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<header>
|
||||
<field name="is_display" invisible="1"/>
|
||||
<button string='提交' class="oe_highlight" states="draft"
|
||||
type="object" name="do_unconfirmed"
|
||||
attrs="{'invisible': [('state', '!=', 'draft')]}"/>
|
||||
<button string='追回编辑' states="unconfirmed"
|
||||
type="action" name="%(system_work_order_wizard_view_act_window)d"
|
||||
context="{'explain':'确认要执行此操作吗?','object_name':'system.work.order','function_name':'do_draft','object_id':id}"/>
|
||||
|
||||
<button name="do_pending" states="unconfirmed"
|
||||
string="确认可处理" type="object" class="oe_highlight"
|
||||
groups="jikimo_system_order.group_operations_permissions_rwc"/>
|
||||
|
||||
<button string='处理工单' class="oe_highlight" states="pending"
|
||||
type="action" name="%(launch_order_technician_wizard)d"
|
||||
groups="jikimo_system_order.group_operations_permissions_rwc"/>
|
||||
<button string='评价' class="oe_highlight" attrs="{'invisible': [('is_display', '=', False)]}"
|
||||
type="action" name="%(launch_order_other_wizard)d" context="{'active_id':id}"/>
|
||||
<button name="%(launch_order_close_wizard)d" string="关闭该工单"
|
||||
attrs="{'invisible': ['|',('state', '=', 'draft'),'|',('state','=','completed'),('state','=','closed')]}"
|
||||
type="action" context="{'active_id':id}"/>
|
||||
|
||||
<field name="state" widget="statusbar"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<group>
|
||||
<!-- <label for="order_number" class="oe_edit_only"/>-->
|
||||
<group>
|
||||
<field name="order_number" required="True" readonly="1"/>
|
||||
<field name="order_type" required="True" attrs="{'readonly': [('state', '!=', 'draft')]}" options="{'no_create': True}"/>
|
||||
<field name="date" required="True" readonly="True"/>
|
||||
<field name="order_template_id" attrs="{'readonly': [('state', '!=', 'draft')]}"
|
||||
domain="[('work_order_type','=',order_type),('state','=',True)]" options="{'no_create': True}"/>
|
||||
<field name="confirmation_date" readonly="True"/>
|
||||
<field name="urgency_degree" required="True" attrs="{'readonly': [('state','!=','draft')]}" widget="priority"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="initiator_company_id" required="True" readonly="True"/>
|
||||
<!-- <field name="initiator_department_id" required="True" readonly="True"/>-->
|
||||
<field name="initiator_id" required="True" readonly="True"/>
|
||||
<field name="confirm_id" readonly="True"/>
|
||||
<field name="solve_people_id" readonly="True"/>
|
||||
<field name="close_user_id" readonly="True"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="title" attrs="{'readonly': [('state', '!=', 'draft')]}" required="True"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="工单内容">
|
||||
<field name="text" attrs="{'readonly': [('state','!=','draft')]}" required="True"/>
|
||||
</page>
|
||||
<page string="解决方案">
|
||||
<group>
|
||||
<field name="users_problem" readonly="True"/>
|
||||
<field name="solution" readonly="True"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="其他">
|
||||
<group>
|
||||
<field name="close_cause" readonly="True"/>
|
||||
<field name="close_time" readonly="True"/>
|
||||
<field name="grade" readonly="True"/>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<!-- <div class="oe_chatter">-->
|
||||
<!-- <field name="message_follower_ids" widget="mail_followers"/>-->
|
||||
<!-- <field name="message_ids" widget="mail_thread"/>-->
|
||||
<!-- </div>-->
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- 搜索工单 -->
|
||||
<record model="ir.ui.view" id="restaurant_search">
|
||||
<field name="name">搜索工单</field>
|
||||
<field name="model">system.work.order</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field string='发起人' name="initiator_id" widget="char" required="True"/>
|
||||
<field string='标题' name="title" widget="char"/>
|
||||
<field string='正文' name="text" widget="html"/>
|
||||
<field string='实际问题' name="users_problem" widget="text"/>
|
||||
<field string='解决方案' name="solution" widget="text"/>
|
||||
<filter name="today" string="今日工单" domain="[('date','=',time.strftime('%%Y-%%m-%%d'))]"/>
|
||||
<filter name="yesterday" string="昨日工单"
|
||||
domain="[('date', '=', (context_today() - relativedelta(days=1)).strftime('%Y-%m-%d'))]"/>
|
||||
<filter name="month" string="本月工单"
|
||||
domain="[('date','>=', time.strftime('%Y-%m-01')),('date','<', (context_today() + relativedelta(months=1)).strftime('%Y-%m-01'))]"/>
|
||||
<filter name="last_month" string="上月工单"
|
||||
domain="[('date','<', time.strftime('%Y-%m-01')),('date','>=', (context_today() - relativedelta(months=1)).strftime('%Y-%m-01'))]"/>
|
||||
<filter name="unconfirmed" string="待确认" domain="[('state','=','unconfirmed')]"/>
|
||||
<filter name="pending" string="待处理" domain="[('state','=','pending')]"/>
|
||||
<filter name="processed" string="已处理"
|
||||
domain="['|', ('state','=','processed'), ('state','=','closed')]"/>
|
||||
<group>
|
||||
<filter string='发起人' name="initiator_id" context='{"group_by":"initiator_id"}'/>
|
||||
<filter string='工单分类' name="order_type" context='{"group_by":"order_type"}'/>
|
||||
<filter string='模板' name="order_template_id" context='{"group_by":"order_template_id"}'/>
|
||||
<filter string='状态' name="state" context='{"group_by":"state"}'/>
|
||||
<filter string='紧急情况' name="state" context='{"group_by":"urgency_degree"}'/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="graph_tree">
|
||||
<field name="name">工单图表</field>
|
||||
<field name="model">system.work.order</field><!--对应表单名称-->
|
||||
<field name="arch" type="xml">
|
||||
<pivot>
|
||||
<field name="date" type="row" interval="day"/>
|
||||
<field name="order_type" type="col"/>
|
||||
<field name="state" type="row"/>
|
||||
</pivot>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- 工单 -->
|
||||
<record model="ir.actions.act_window" id="system_order">
|
||||
<field name="name">工单</field>
|
||||
<field name="res_model">system.work.order</field>
|
||||
<field name="view_mode">tree,form,search,graph,pivot</field>
|
||||
</record>
|
||||
|
||||
<!--工单模板信息-->
|
||||
<record model="ir.ui.view" id="order_template_tree">
|
||||
<field name="name">工单模板信息</field>
|
||||
<field name="model">work.order.template</field><!--对应表单名称-->
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="num"/>
|
||||
<field name="name"/>
|
||||
<field name="work_order_type"/>
|
||||
<field name="title_template"/>
|
||||
<field name="template_explain"/>
|
||||
<field name="state"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!--新建系统工单模板-->
|
||||
<record model="ir.ui.view" id="order_template_form">
|
||||
<field name="name">新建系统工单模板</field>
|
||||
<field name="model">work.order.template</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="num" required="True" readonly="True"/>
|
||||
<field name="name" required="True"/>
|
||||
<field name="work_order_type" required="True"/>
|
||||
<field name="template_explain" required="True" style="height: 50px;"/>
|
||||
<field name="title_template" required="True"/>
|
||||
<field name="state"/>
|
||||
<field name="text_template" required="True"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- 工单模板 -->
|
||||
<record model="ir.actions.act_window" id="work_template">
|
||||
<field name="name">工单模板</field>
|
||||
<field name="res_model">work.order.template</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
<!--工单分类信息-->
|
||||
<record model="ir.ui.view" id="order_type_tree">
|
||||
<field name="name">工单分类信息</field>
|
||||
<field name="model">order.classify</field><!--对应表单名称-->
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="state"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!--新建系统分类信息-->
|
||||
<record model="ir.ui.view" id="order_type_form">
|
||||
<field name="name">新建系统分类信息</field>
|
||||
<field name="model">order.classify</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="name" required="True"/>
|
||||
<field name="sequence" invisible="True"/>
|
||||
<field name="state"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- 工单分类 -->
|
||||
<record model="ir.actions.act_window" id="classify">
|
||||
<field name="name">工单分类</field>
|
||||
<field name="res_model">order.classify</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
|
||||
<menuitem name="系统工单" id="work_order_1_list" web_icon="jikimo_system_order,static/description/系统工单.png"/>
|
||||
<menuitem name="工单" id="work_order" parent="work_order_1_list" action="system_order"/>
|
||||
<menuitem name="工单模板" id="work_order_template" parent="work_order_1_list" action="work_template" groups="jikimo_system_order.group_operations_permissions_rwc"/>
|
||||
<menuitem name="工单分类" id="work_order_type" parent="work_order_1_list" action="classify" groups="jikimo_system_order.group_operations_permissions_rwc"/>
|
||||
<menuitem name="工单设置" id="system_order_notice_user_config" parent="work_order_1_list" action="action_system_order_notice_view" groups="jikimo_system_order.group_operations_permissions_rwc"/>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,6 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import order_other_wizard
|
||||
from . import order_technician_wizard
|
||||
from . import order_close_wizard
|
||||
from . import system_work_order_wizard
|
||||
@@ -1,79 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import models, fields, api
|
||||
from odoo.addons.jikimo_system_order.models.constant import STATE_SELECTION
|
||||
from odoo.exceptions import ValidationError
|
||||
import datetime, logging
|
||||
|
||||
|
||||
class OrderCloseWizard(models.TransientModel):
|
||||
_name = 'order.close.wizard'
|
||||
|
||||
|
||||
def get_context(self):
|
||||
if self._context.get('active_id'):
|
||||
obj = self.env['system.work.order'].browse(self._context.get('active_id'))
|
||||
if obj.initiator_id.id != self.env.user.id:
|
||||
raise ValidationError(u'非本人无法操作')
|
||||
return obj
|
||||
|
||||
order_id = fields.Many2one('system.work.order', string=u'工单ID',
|
||||
default=lambda self: self.get_context().id)
|
||||
# 关闭原因
|
||||
close_cause = fields.Text(string=u'关闭问题原因', default=lambda self: self.get_context().close_cause)
|
||||
# 关闭时间
|
||||
close_time = fields.Datetime(string=u'关闭问题时间', default=fields.datetime.now())
|
||||
# 状态
|
||||
state = fields.Selection(STATE_SELECTION, default='closed', string=u'状态')
|
||||
# 关闭人
|
||||
close_user_id = fields.Many2one('res.users', string=u'关闭人', default=lambda self: self.env.user)
|
||||
|
||||
|
||||
def sure(self):
|
||||
self.order_id.close_cause = self.close_cause
|
||||
self.order_id.close_time = self.close_time
|
||||
if self.order_id.state == 'unconfirmed':
|
||||
state_remark = u'待确认 --> 已关闭'
|
||||
if self.order_id.state == 'pending':
|
||||
state_remark = u'待处理 --> 已关闭'
|
||||
if self.order_id.state == 'processed':
|
||||
state_remark = u'已处理待评分 --> 已关闭'
|
||||
# self.order_id.message_post(u'操作人:%s,操作时间:%s,状态变更过程:%s' % (
|
||||
# self.env.user.name,
|
||||
# (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), state_remark))
|
||||
self.order_id.state = self.state
|
||||
self.order_id.close_user_id = self.close_user_id
|
||||
we_employee_ids = []
|
||||
if self.order_id.initiator_id.we_employee_id:
|
||||
we_employee_ids.append(self.order_id.initiator_id.we_employee_id)
|
||||
lost_agent_id = self.env['ir.config_parameter'].sudo().get_param('lost_agent_id')
|
||||
wechat = self.env['we.config'].sudo().get_wechat(agent_id=lost_agent_id)
|
||||
# agent_id, user_ids, content
|
||||
content = """您提交的工单-**工单标题:{0}**-<font color=\"#FF0000\">**已关闭**</font>
|
||||
>提交时间:{1}
|
||||
>处理时间:{2}
|
||||
>处理人:{3}
|
||||
如有问题,请联系系统管理员!
|
||||
""".format(self.order_id.title,
|
||||
(self.order_id.date + datetime.timedelta(hours=8)).strftime(
|
||||
'%Y-%m-%d %H:%M'), (datetime.datetime.now() + datetime.timedelta(
|
||||
hours=8)).strftime('%Y-%m-%d %H:%M'), self.env.user.name or '')
|
||||
# wechat.message.send_markdown(agent_id=lost_agent_id, user_ids=we_employee_ids, content=content)
|
||||
for we_employee_id in we_employee_ids:
|
||||
try:
|
||||
wechat.message.send_markdown(agent_id=lost_agent_id, user_ids=we_employee_id, content=content)
|
||||
except Exception as e:
|
||||
logging.error('工单关闭发送消息异常%s' % str(e))
|
||||
return {}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import models, fields, api
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.addons.jikimo_system_order.models.constant import STATE_SELECTION, GRADE
|
||||
import datetime
|
||||
|
||||
|
||||
class OrderOtherWizard(models.TransientModel):
|
||||
_name = 'order.other.wizard'
|
||||
|
||||
|
||||
def get_context(self):
|
||||
if self._context.get('active_id'):
|
||||
obj = self.env['system.work.order'].browse(self._context.get('active_id'))
|
||||
if obj.initiator_id.id != self.env.user.id:
|
||||
raise ValidationError(u'非本人无法操作')
|
||||
return obj
|
||||
|
||||
order_id = fields.Many2one('system.work.order', string=u'工单ID',
|
||||
default=lambda self: self.get_context().id)
|
||||
# 关闭时间
|
||||
close_time = fields.Datetime(string=u'关闭时间', default=fields.datetime.now())
|
||||
# 状态
|
||||
state = fields.Selection(STATE_SELECTION, default='completed', string=u'状态')
|
||||
# 打分
|
||||
grade = fields.Selection(GRADE, string=u'评分')
|
||||
# 关闭人
|
||||
close_user_id = fields.Many2one('res.users', string=u'关闭人', default=lambda self: self.env.user)
|
||||
|
||||
|
||||
def sure(self):
|
||||
self.order_id.close_time = self.close_time
|
||||
self.order_id.grade = self.grade
|
||||
if self.order_id.state == 'processed':
|
||||
state_remark = u'已处理待评分 --> 已完成'
|
||||
# self.order_id.message_post(u'操作人:%s,操作时间:%s,状态变更过程:%s' % (
|
||||
# self.env.user.name,
|
||||
# (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), state_remark))
|
||||
self.order_id.state = self.state
|
||||
self.order_id.close_user_id = self.close_user_id
|
||||
return {}
|
||||
@@ -1,59 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import models, fields, api
|
||||
from odoo.addons.jikimo_system_order.models.constant import STATE_SELECTION
|
||||
import datetime
|
||||
import logging
|
||||
|
||||
|
||||
class OrderTechnicianWizard(models.TransientModel):
|
||||
_name = 'order.technician.wizard'
|
||||
|
||||
order_id = fields.Many2one('system.work.order', string=u'工单ID',
|
||||
default=lambda self: self.env.context.get('active_id'))
|
||||
# 解决人
|
||||
solve_people_id = fields.Many2one('res.users', string=u'解决人', default=lambda self: self.env.user)
|
||||
# 用户实际问题
|
||||
users_problem = fields.Text(string=u'用户实际问题')
|
||||
# 最终解决方案
|
||||
solution = fields.Text(string=u'最终解决方案')
|
||||
# 状态
|
||||
state = fields.Selection(STATE_SELECTION, default='processed', string=u'状态')
|
||||
|
||||
def sure(self):
|
||||
self.order_id.solve_people_id = self.solve_people_id
|
||||
self.order_id.users_problem = self.users_problem
|
||||
self.order_id.solution = self.solution
|
||||
if self.order_id.state == 'pending':
|
||||
state_remark = u'待处理 --> 已处理待评分'
|
||||
# self.order_id.message_post(u'操作人:%s,操作时间:%s,状态变更过程:%s' % (
|
||||
# self.env.user.name,
|
||||
# (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), state_remark))
|
||||
self.order_id.state = self.state
|
||||
# 获取通知人
|
||||
# objs = self.env['system.order.notice'].search([])
|
||||
# user_ids = objs.notice_user_ids.filtered(lambda item: item.we_employee_id not in ['', False])
|
||||
# we_employee_ids = user_ids.mapped('we_employee_id')
|
||||
we_employee_ids = []
|
||||
if self.order_id.initiator_id.we_employee_id:
|
||||
we_employee_ids.append(self.order_id.initiator_id.we_employee_id)
|
||||
print(we_employee_ids)
|
||||
lost_agent_id = self.env['ir.config_parameter'].sudo().get_param('lost_agent_id')
|
||||
wechat = self.env['we.config'].sudo().get_wechat(agent_id=lost_agent_id)
|
||||
# agent_id, user_ids, content
|
||||
content = """您提交的工单-**工单标题:{0}**-<font color=\"info\">**已处理**</font>
|
||||
>提交时间:{1}
|
||||
>处理反馈:{4}
|
||||
>处理时间:{2}
|
||||
>处理人:{3}
|
||||
如有问题,请联系系统管理员!
|
||||
""".format(self.order_id.title,
|
||||
(self.order_id.date + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M'), (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M'), self.env.user.name or '', self.solution or '')
|
||||
# wechat.message.send_markdown(agent_id=lost_agent_id, user_ids=we_employee_ids, content=content)
|
||||
for we_employee_id in we_employee_ids:
|
||||
try:
|
||||
wechat.message.send_markdown(agent_id=lost_agent_id, user_ids=we_employee_id, content=content)
|
||||
except Exception as e:
|
||||
logging.error('工单处理发送消息异常%s' % str(e))
|
||||
|
||||
return {}
|
||||
@@ -1,122 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<!-- 技术员向导form-->
|
||||
<record model="ir.ui.view" id="wizard_technician_form_view">
|
||||
<field name="name">技术员向导</field>
|
||||
<field name="model">order.technician.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="技术员编辑">
|
||||
<group>
|
||||
<field name="order_id" required="1" readonly="1"/>
|
||||
<field name="solve_people_id" required="1"/>
|
||||
<field name="users_problem" required="1" style="height: 50px;"/>
|
||||
<field name="solution" required="1" style="height: 50px;"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="sure" string="确定" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button string="取消" class="oe_link" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="launch_order_technician_wizard">
|
||||
<field name="name">技术员编辑</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">order.technician.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="wizard_technician_form_view"/>
|
||||
<field name="context">{'display_default_code':False}</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
<!-- 其它向导form-->
|
||||
<record model="ir.ui.view" id="wizard_other_form_view">
|
||||
<field name="name">其它向导</field>
|
||||
<field name="model">order.other.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="其它编辑">
|
||||
<group>
|
||||
<field name="order_id" required="1" readonly="1"/>
|
||||
<field name="close_time" required="1" readonly="1"/>
|
||||
<field name="grade" required="1"/>
|
||||
<field name="close_user_id" required="1" readonly="1"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="sure" string="确定" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button string="取消" class="oe_link" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="launch_order_other_wizard">
|
||||
<field name="name">其它编辑</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">order.other.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="wizard_other_form_view"/>
|
||||
<field name="context">{'display_default_code':False}</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<!--关闭向导form-->
|
||||
<record model="ir.ui.view" id="wizard_close_form_view">
|
||||
<field name="name">关闭向导</field>
|
||||
<field name="model">order.close.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="关闭工单">
|
||||
<group>
|
||||
<field name="order_id" required="1" readonly="1"/>
|
||||
<field name="close_cause" required="1" style="height: 50px;"/>
|
||||
<field name="close_time" required="1" readonly="1"/>
|
||||
<field name="close_user_id" required="1" readonly="1"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="sure" string="确定" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button string="取消" class="oe_link" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="launch_order_close_wizard">
|
||||
<field name="name">关闭工单</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">order.close.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="wizard_close_form_view"/>
|
||||
<field name="context">{'display_default_code':False}</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<record id="system_work_order_wizard_view" model="ir.ui.view">
|
||||
<field name="name">system_work_order_wizard_view</field>
|
||||
<field name="model">system.work.order.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="二次确认">
|
||||
<field name="explain" readonly="1"/>
|
||||
<footer>
|
||||
<button name="sure" string="确定" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button string="取消" class="oe_link" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="system_work_order_wizard_view_act_window">
|
||||
<field name="name">二次确认</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">system.work.order.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,42 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2017/12/12 9:46
|
||||
# @Author : GuoXiang
|
||||
# @Site :
|
||||
# @File : system_work_order_wizard.py
|
||||
# @Software: PyCharm
|
||||
# @Desc :
|
||||
# @license : Copyright©2018 www.dasmaster.com All Rights Reserved.
|
||||
# @Contact : xg1230205321@163.com
|
||||
from odoo import models, api, fields
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class SystemWorkOrderWizard(models.TransientModel):
|
||||
_name = "system.work.order.wizard"
|
||||
_description = u"追回确认"
|
||||
|
||||
|
||||
def _get_explain(self):
|
||||
if self._context.get('object_id'):
|
||||
obj = self.env['system.work.order'].browse(self._context.get('object_id'))
|
||||
if obj.initiator_id.id != self.env.user.id:
|
||||
raise ValidationError(u'非本人无法操作')
|
||||
if self._context.get('explain'):
|
||||
return self._context["explain"]
|
||||
|
||||
explain = fields.Char(default=_get_explain)
|
||||
|
||||
|
||||
def sure(self):
|
||||
"""
|
||||
确认
|
||||
:return:
|
||||
"""
|
||||
if self._context.get('object_id') and self._context.get('object_name') and self._context.get(
|
||||
'explain') and self._context.get('function_name'):
|
||||
work_sheet_obj = self.env[self._context["object_name"]].search([('id', '=', int(self._context["object_id"]))])
|
||||
class_name = self._context.get('object_name') # 获得对象类名
|
||||
method_name = self._context.get('function_name') # 获得对象的方法
|
||||
obj_function = getattr(self.env[class_name], method_name)
|
||||
obj_function(work_sheet_obj)
|
||||
@@ -1,4 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import models
|
||||
from . import controllers
|
||||
@@ -1,21 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
{
|
||||
'name': '机企猫 工单异常记录',
|
||||
'version': '1.0',
|
||||
'summary': '记录工单的异常日志',
|
||||
'sequence': 1,
|
||||
'category': 'sf',
|
||||
'website': 'https://www.sf.jikimo.com',
|
||||
'depends': ['sf_manufacturing', 'sf_mrs_connect'],
|
||||
'data': [
|
||||
'views/mrp_workorder_views.xml',
|
||||
'security/ir.model.access.csv',
|
||||
],
|
||||
'demo': [
|
||||
],
|
||||
'license': 'LGPL-3',
|
||||
'installable': True,
|
||||
'application': False,
|
||||
'auto_install': False,
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
from . import main
|
||||
@@ -1,89 +0,0 @@
|
||||
from odoo import http, fields
|
||||
from odoo.http import request
|
||||
import json
|
||||
import logging
|
||||
from odoo.addons.sf_mrs_connect.controllers.controllers import Sf_Mrs_Connect
|
||||
from odoo.addons.sf_manufacturing.controllers.controllers import Manufacturing_Connect
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class WorkorderExceptionConroller(http.Controller):
|
||||
|
||||
@http.route('/AutoDeviceApi/BillError', type='json', auth='public', methods=['GET', 'POST'], csrf=False,
|
||||
cors="*")
|
||||
def workder_exception(self, **kw):
|
||||
"""
|
||||
记录工单异常
|
||||
:param kw:
|
||||
:return:
|
||||
"""
|
||||
_logger.info('workder_exception:%s' % kw)
|
||||
try:
|
||||
res = {'Succeed': True, 'ErrorCode': 0, 'Error': ''}
|
||||
datas = request.httprequest.data
|
||||
ret = json.loads(datas)
|
||||
if not ret.get('RfidCode') or not ret.get('coding'):
|
||||
res = {'Succeed': False, 'ErrorCode': 400, 'Error': '参数错误'}
|
||||
return json.JSONEncoder().encode(res)
|
||||
|
||||
# 通过RfidCode获取就绪的CNC工单
|
||||
workorder = request.env['mrp.workorder'].sudo().search([
|
||||
('rfid_code', '=', ret['RfidCode']),
|
||||
('routing_type', '=', 'CNC加工'),
|
||||
])
|
||||
if not workorder:
|
||||
res = {'Succeed': False, 'ErrorCode': 401, 'Error': '无效的工单'}
|
||||
return json.JSONEncoder().encode(res)
|
||||
|
||||
# 创建工单异常记录,关联工单
|
||||
request.env['jikimo.workorder.exception'].sudo().create({
|
||||
'workorder_id': workorder.id,
|
||||
'exception_code': ret.get('coding'),
|
||||
'exception_content': ret.get('Error', '')
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
|
||||
_logger.info('workder_exception error:%s' % e)
|
||||
return json.JSONEncoder().encode(res)
|
||||
|
||||
|
||||
class SfMrsConnectController(Sf_Mrs_Connect):
|
||||
|
||||
@http.route('/api/cnc_processing/create', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
|
||||
cors="*")
|
||||
def get_cnc_processing_create(self, **kw):
|
||||
"""
|
||||
更新工单异常记录【'YC001', 'YC004'】
|
||||
"""
|
||||
res = super(SfMrsConnectController, self).get_cnc_processing_create(**kw)
|
||||
# 如果有未完成的YC0001、YC0004异常记录,则标记为完成
|
||||
res = json.loads(res)
|
||||
_logger.info('已进入工单异常:%s' % res)
|
||||
if res.get('production_ids'):
|
||||
try:
|
||||
productions = request.env['mrp.production'].sudo().search([('id', 'in', res.get('production_ids'))])
|
||||
if productions.workorder_ids:
|
||||
productions.workorder_ids.handle_exception(['YC0001', 'YC0004'])
|
||||
except Exception as e:
|
||||
_logger.info('更新工单异常记录失败:%s' % e)
|
||||
return json.JSONEncoder().encode(res)
|
||||
|
||||
class ManufactruingController(Manufacturing_Connect):
|
||||
|
||||
@http.route('/AutoDeviceApi/FeedBackStart', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
|
||||
cors="*")
|
||||
def button_Work_START(self, **kw):
|
||||
"""
|
||||
更新工单异常记录【'YC0002', 'YC0003'】
|
||||
"""
|
||||
res = super(ManufactruingController, self).button_Work_START(**kw)
|
||||
res = json.loads(res)
|
||||
_logger.info('已进入工单异常:%s' % res)
|
||||
if res.get('workorder_id'):
|
||||
try:
|
||||
workorder = request.env['mrp.workorder'].sudo().browse(int(res.get('workorder_id')))
|
||||
workorder.handle_exception(['YC0002', 'YC0003'])
|
||||
except Exception as e:
|
||||
_logger.info('更新工单异常记录失败:%s' % e)
|
||||
return json.JSONEncoder().encode(res)
|
||||
@@ -1,3 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from . import jikimo_workorder_exception
|
||||
from . import mrp_workorder
|
||||
@@ -1,14 +0,0 @@
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
class JikimoWorkorderException(models.Model):
|
||||
_name = 'jikimo.workorder.exception'
|
||||
_description = '工单异常记录'
|
||||
_order = 'id desc'
|
||||
|
||||
workorder_id = fields.Many2one('mrp.workorder', string='工单')
|
||||
exception_code = fields.Char('异常编码')
|
||||
exception_content = fields.Char('反馈的异常/问题信息')
|
||||
completion_time = fields.Datetime('处理完成时间')
|
||||
state = fields.Selection([('pending', '进行中'), ('done', '已处理')], string='状态', default='pending')
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
from odoo import models, fields
|
||||
import logging
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class MrpWorkorder(models.Model):
|
||||
_inherit = 'mrp.workorder'
|
||||
|
||||
exception_ids = fields.One2many('jikimo.workorder.exception', 'workorder_id', string='工单异常记录')
|
||||
|
||||
def write(self, values):
|
||||
if values.get('test_results') and self.exception_ids:
|
||||
pending_exception = self.exception_ids.filtered(
|
||||
lambda exc: exc.state == 'pending' and exc.exception_code == 'YC0005'
|
||||
)
|
||||
if pending_exception:
|
||||
pending_exception.write({
|
||||
'completion_time': fields.Datetime.now(),
|
||||
'state': 'done'
|
||||
})
|
||||
return super(MrpWorkorder, self).write(values)
|
||||
|
||||
def handle_exception(self, exception_codes):
|
||||
"""
|
||||
处理异常
|
||||
:param exception_codes: 需要处理的异常编码列表
|
||||
"""
|
||||
if not isinstance(exception_codes, list):
|
||||
exception_codes = [exception_codes]
|
||||
if self.exception_ids:
|
||||
_logger.info('workorder.exception_ids:%s' % self.exception_ids)
|
||||
pending_exception = self.exception_ids.filtered(
|
||||
lambda exc: exc.state == 'pending' and exc.exception_code in exception_codes
|
||||
)
|
||||
_logger.info('pending_exception:%s' % pending_exception)
|
||||
if pending_exception:
|
||||
pending_exception.write({
|
||||
'completion_time': fields.Datetime.now(),
|
||||
'state': 'done'
|
||||
})
|
||||
@@ -1,5 +0,0 @@
|
||||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
||||
"access_jikimo_workorder_exception","access.jikimo.workorder.exception","model_jikimo_workorder_exception","mrp.group_mrp_user",1,1,1,0
|
||||
"access_jikimo_workorder_exception_group_quality","access.jikimo.workorder.exception.group_quality","model_jikimo_workorder_exception","sf_base.group_quality",1,1,1,0
|
||||
"access_jikimo_workorder_exception_group_quality_director","access.jikimo.workorder.exception.group_quality_director","model_jikimo_workorder_exception","sf_base.group_quality_director",1,1,1,0
|
||||
|
||||
|
@@ -1,2 +0,0 @@
|
||||
from . import common
|
||||
from . import test_jikimo_workorder_exception
|
||||
@@ -1,48 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
from odoo import fields, Command
|
||||
from odoo.tests.common import TransactionCase, HttpCase, tagged, Form
|
||||
|
||||
import json
|
||||
import time
|
||||
import base64
|
||||
from lxml import etree
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestJikimoWorkorderExceptionCommon(TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestJikimoWorkorderExceptionCommon, self).setUp()
|
||||
# 获取名字为“1#自动生产线”的制造中心
|
||||
workcenter = self.env['mrp.workcenter'].search([('name', '=', '1#自动生产线')], limit=1)
|
||||
# 创建一个产品
|
||||
product_product = self.env['product.product'].create({
|
||||
'name': '测试产品',
|
||||
'type': 'product',
|
||||
})
|
||||
uom_unit = self.env.ref('uom.product_uom_unit')
|
||||
# 创建一个bom
|
||||
self.bom = self.env['mrp.bom'].create({
|
||||
'product_id': product_product.id,
|
||||
'product_tmpl_id': product_product.product_tmpl_id.id,
|
||||
'product_uom_id': uom_unit.id,
|
||||
'product_qty': 1.0,
|
||||
'type': 'normal',
|
||||
})
|
||||
# 创建一个制造订单
|
||||
self.production = self.env['mrp.production'].create({
|
||||
'name': 'Test Production',
|
||||
'product_id': product_product.id,
|
||||
'bom_id': self.bom.id,
|
||||
'company_id': self.env.ref('base.main_company').id,
|
||||
})
|
||||
# 创建一个测试工单
|
||||
self.workorder = self.env['mrp.workorder'].create({
|
||||
'name': 'Test order',
|
||||
'workcenter_id': workcenter.id,
|
||||
'product_uom_id': self.bom.product_uom_id.id,
|
||||
'production_id': self.production.id,
|
||||
'duration_expected': 1.0,
|
||||
'rfid_code': 'test-123456',
|
||||
'routing_type': 'CNC加工'
|
||||
})
|
||||
@@ -1,53 +0,0 @@
|
||||
import json
|
||||
from datetime import datetime
|
||||
from odoo.addons.jikimo_workorder_exception.tests.common import TestJikimoWorkorderExceptionCommon
|
||||
|
||||
class TestJikimoWorkorderException(TestJikimoWorkorderExceptionCommon):
|
||||
|
||||
def test_create_exception_record(self):
|
||||
exception_record = self.env['jikimo.workorder.exception'].create({
|
||||
'workorder_id': self.workorder.id,
|
||||
'exception_code': 'YC0001',
|
||||
'exception_content': '无CNC编程'
|
||||
})
|
||||
|
||||
self.assertTrue(exception_record)
|
||||
self.assertEqual(exception_record.exception_content, '无CNC编程')
|
||||
self.assertEqual(exception_record.workorder_id.id, self.workorder.id)
|
||||
self.assertEqual(exception_record.exception_code, 'YC0001')
|
||||
|
||||
def test_handle_exception(self):
|
||||
exception_record = self.env['jikimo.workorder.exception'].create({
|
||||
'workorder_id': self.workorder.id,
|
||||
'exception_code': 'YC0001',
|
||||
'exception_content': '无CNC编程'
|
||||
})
|
||||
self.workorder.handle_exception('YC0001')
|
||||
self.assertEqual(exception_record.state, 'done')
|
||||
# 判断完成时间是否为当前分钟
|
||||
self.assertEqual(exception_record.completion_time.minute, datetime.now().minute)
|
||||
|
||||
def test_handle_exception_with_invalid_code(self):
|
||||
exception_record = self.env['jikimo.workorder.exception'].create({
|
||||
'workorder_id': self.workorder.id,
|
||||
'exception_code': 'YC0001',
|
||||
'exception_content': '无CNC编程'
|
||||
})
|
||||
self.workorder.handle_exception(['YC0002', 'YC0004'])
|
||||
self.assertEqual(exception_record.state, 'pending')
|
||||
self.assertEqual(exception_record.completion_time, False)
|
||||
|
||||
|
||||
def test_handle_exception_with_test_results(self):
|
||||
exception_record = self.env['jikimo.workorder.exception'].create({
|
||||
'workorder_id': self.workorder.id,
|
||||
'exception_code': 'YC0005',
|
||||
'exception_content': '工单加工失败'
|
||||
})
|
||||
self.workorder.write({
|
||||
'test_results': '返工',
|
||||
'reason': 'cutter',
|
||||
'detailed_reason': '刀坏了',
|
||||
})
|
||||
self.assertEqual(exception_record.state, 'done')
|
||||
self.assertEqual(exception_record.completion_time.minute, datetime.now().minute)
|
||||
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="jikimo_workorder_exception_form_view_inherit" model="ir.ui.view">
|
||||
<field name="name">mrp.workorder.form</field>
|
||||
<field name="model">mrp.workorder</field>
|
||||
<field name="inherit_id" ref="mrp.mrp_production_workorder_form_view_inherit"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//notebook/page[last()]" position="after">
|
||||
<page string="异常记录" name="workorder_exception" attrs="{'invisible': [('routing_type', '!=', 'CNC加工')]}">
|
||||
<field name="exception_ids" nolabel="1" readonly="1">
|
||||
<tree create="false" delete="false" edit="false">
|
||||
<field name="exception_content" string="反馈的异常/问题信息"/>
|
||||
<field name="create_date" string="时间"/>
|
||||
<field name="completion_time"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,4 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import models
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
{
|
||||
'name': '机企猫 工单异常消息通知',
|
||||
'version': '1.0',
|
||||
'summary': '当产生工单异常时,发送消息通知',
|
||||
'sequence': 1,
|
||||
'category': 'sf',
|
||||
'website': 'https://www.sf.jikimo.com',
|
||||
'depends': ['jikimo_workorder_exception', 'jikimo_message_notify'],
|
||||
'data': [
|
||||
'data/bussiness_node.xml',
|
||||
'data/template_data.xml',
|
||||
# 'security/ir.model.access.csv',
|
||||
],
|
||||
'demo': [
|
||||
],
|
||||
'license': 'LGPL-3',
|
||||
'installable': True,
|
||||
'application': False,
|
||||
'auto_install': False,
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record id="bussiness_no_functional_tool" model="jikimo.message.bussiness.node">
|
||||
<field name="name">无功能刀具</field>
|
||||
<field name="model">jikimo.workorder.exception</field>
|
||||
</record>
|
||||
<record id="bussiness_no_position_data" model="jikimo.message.bussiness.node">
|
||||
<field name="name">无定位数据</field>
|
||||
<field name="model">jikimo.workorder.exception</field>
|
||||
</record>
|
||||
<record id="bussiness_processing_failure" model="jikimo.message.bussiness.node">
|
||||
<field name="name">加工失败</field>
|
||||
<field name="model">jikimo.workorder.exception</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,38 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record id="template_no_function_tool" model="jikimo.message.template">
|
||||
<field name="name">生产线无功能刀具提醒</field>
|
||||
<field name="model_id" ref="jikimo_workorder_exception_notify.model_jikimo_workorder_exception"/>
|
||||
<field name="model">jikimo.workorder.exception</field>
|
||||
<field name="bussiness_node_id" ref="bussiness_no_functional_tool"/>
|
||||
<field name="msgtype">markdown</field>
|
||||
<field name="urgency">urgent</field>
|
||||
<field name="content">### 生产线无功能刀具提醒
|
||||
单号:工单[{{workorder_id.production_id.name}}]({{url}})
|
||||
原因:生产线无加工程序要用的功能刀具</field>
|
||||
</record>
|
||||
<record id="template_no_position_data" model="jikimo.message.template">
|
||||
<field name="name">工单无定位数据提醒</field>
|
||||
<field name="model_id" ref="jikimo_workorder_exception_notify.model_jikimo_workorder_exception"/>
|
||||
<field name="model">jikimo.workorder.exception</field>
|
||||
<field name="bussiness_node_id" ref="bussiness_no_position_data"/>
|
||||
<field name="msgtype">markdown</field>
|
||||
<field name="urgency">urgent</field>
|
||||
<field name="content">### 工单无定位数据提醒
|
||||
单号:工单[{{workorder_id.production_id.name}}]({{url}})
|
||||
原因:无装夹定位测量数据</field>
|
||||
</record>
|
||||
<record id="template_processing_failure" model="jikimo.message.template">
|
||||
<field name="name">工单加工失败提醒</field>
|
||||
<field name="model_id" ref="jikimo_workorder_exception_notify.model_jikimo_workorder_exception"/>
|
||||
<field name="model">jikimo.workorder.exception</field>
|
||||
<field name="bussiness_node_id" ref="bussiness_processing_failure"/>
|
||||
<field name="msgtype">markdown</field>
|
||||
<field name="urgency">urgent</field>
|
||||
<field name="content">### 工单加工失败提醒
|
||||
单号:工单[{{workorder_id.production_id.name}}]({{url}})
|
||||
原因:加工失败,工件下产线处理</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1,3 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from . import jikimo_message_template
|
||||
from . import jikimo_workorder_exception
|
||||
@@ -1,10 +0,0 @@
|
||||
from odoo import models
|
||||
|
||||
|
||||
class JikimoMessageTemplate(models.Model):
|
||||
_inherit = "jikimo.message.template"
|
||||
|
||||
def _get_message_model(self):
|
||||
res = super(JikimoMessageTemplate, self)._get_message_model()
|
||||
res.append('jikimo.workorder.exception')
|
||||
return res
|
||||
@@ -1,61 +0,0 @@
|
||||
from odoo import models, api
|
||||
from odoo.addons.sf_base.commons.common import Common
|
||||
import requests, logging
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class JikimoWorkorderException(models.Model):
|
||||
_name = 'jikimo.workorder.exception'
|
||||
_inherit = ['jikimo.workorder.exception', 'jikimo.message.dispatch']
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
res = super(JikimoWorkorderException, self).create(vals_list)
|
||||
# 根据异常编码发送消息提醒
|
||||
try:
|
||||
for rec in res:
|
||||
if rec.exception_code == 'YC0001':
|
||||
# 无CNC程序,调用cloud接口
|
||||
data = {'name': rec.workorder_id.production_id.programming_no, 'exception_code': 'YC0001'}
|
||||
configsettings = self.env['res.config.settings'].sudo().get_values()
|
||||
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
|
||||
url = '/api/message/workorder_exception'
|
||||
config_url = configsettings['sf_url'] + url
|
||||
data['token'] = configsettings['token']
|
||||
ret = requests.post(config_url, json=data, headers=config_header)
|
||||
ret = ret.json()
|
||||
_logger.info('无CNC程序异常消息推送接口:%s' % ret)
|
||||
elif rec.exception_code == 'YC0002':
|
||||
# 无功能刀具
|
||||
rec.add_queue('无功能刀具')
|
||||
elif rec.exception_code == 'YC0003':
|
||||
# 无定位数据
|
||||
rec.add_queue('无定位数据')
|
||||
elif rec.exception_code == 'YC0004':
|
||||
# 无FTP文件,调用cloud接口
|
||||
data = {'name': rec.workorder_id.production_id.programming_no, 'exception_code': 'YC0004'}
|
||||
configsettings = self.env['res.config.settings'].sudo().get_values()
|
||||
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
|
||||
url = '/api/message/workorder_exception'
|
||||
config_url = configsettings['sf_url'] + url
|
||||
data['token'] = configsettings['token']
|
||||
ret = requests.post(config_url, json=data, headers=config_header)
|
||||
ret = ret.json()
|
||||
_logger.info('无FTP文件异常消息推送接口:%s' % ret)
|
||||
elif rec.exception_code == 'YC0005':
|
||||
# 加工失败
|
||||
rec.add_queue('加工失败')
|
||||
except Exception as e:
|
||||
_logger.error('异常编码发送消息提醒失败:%s' % e)
|
||||
return res
|
||||
|
||||
def _get_message(self, message_queue_ids):
|
||||
contents = super(JikimoWorkorderException, self)._get_message(message_queue_ids)
|
||||
url = self.env['ir.config_parameter'].get_param('web.base.url')
|
||||
action_id = self.env.ref('mrp.mrp_production_action').id
|
||||
for index, content in enumerate(contents):
|
||||
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)
|
||||
contents[index] = content.replace('{{url}}', url)
|
||||
return contents
|
||||
@@ -1,2 +0,0 @@
|
||||
from . import common
|
||||
from . import test_jikimo_workorder_exception_notify
|
||||
@@ -1,18 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
from odoo import fields, Command
|
||||
from odoo.tests.common import TransactionCase, HttpCase, tagged, Form
|
||||
|
||||
import json
|
||||
import time
|
||||
import base64
|
||||
from lxml import etree
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestJikimoWorkorderExceptionNotifyCommonNotify(TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestJikimoWorkorderExceptionNotifyCommonNotify, self).setUp()
|
||||
# 获取最后一个工单
|
||||
self.workorder = self.env['mrp.workorder'].search([], order='id desc', limit=1)
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
import json
|
||||
from datetime import datetime
|
||||
from odoo.addons.jikimo_workorder_exception_notify.tests.common import TestJikimoWorkorderExceptionNotifyCommonNotify
|
||||
|
||||
class TestJikimoWorkorderExceptionNotify(TestJikimoWorkorderExceptionNotifyCommonNotify):
|
||||
|
||||
def test_create_message_template(self):
|
||||
self.assertTrue(self.env['jikimo.message.template'].search([
|
||||
('name', '=', '生产线无功能刀具提醒'),
|
||||
('model', '=', 'jikimo.workorder.exception')
|
||||
]))
|
||||
self.assertTrue(self.env['jikimo.message.template'].search([
|
||||
('name', '=', '工单无定位数据提醒'),
|
||||
('model', '=', 'jikimo.workorder.exception')
|
||||
]))
|
||||
self.assertTrue(self.env['jikimo.message.template'].search([
|
||||
('name', '=', '工单加工失败提醒'),
|
||||
('model', '=', 'jikimo.workorder.exception')
|
||||
]))
|
||||
|
||||
def test_create_message_queue_yc0001(self):
|
||||
exception_record = self.env['jikimo.workorder.exception'].create({
|
||||
'workorder_id': self.workorder.id,
|
||||
'exception_code': 'YC0001',
|
||||
'exception_content': '无CNC程序'
|
||||
})
|
||||
|
||||
message_record = self.env['jikimo.message.queue'].search([
|
||||
('res_id', '=', exception_record.id),
|
||||
('model', '=', 'jikimo.workorder.exception'),
|
||||
('message_status', '=', 'pending')
|
||||
])
|
||||
self.assertFalse(message_record)
|
||||
|
||||
def test_create_message_queue_yc0002(self):
|
||||
exception_record = self.env['jikimo.workorder.exception'].create({
|
||||
'workorder_id': self.workorder.id,
|
||||
'exception_code': 'YC0002',
|
||||
'exception_content': '无功能刀具'
|
||||
})
|
||||
|
||||
bussiness_node = self.env['jikimo.message.bussiness.node'].search([
|
||||
('name', '=', '无功能刀具'),
|
||||
('model', '=', 'jikimo.workorder.exception')
|
||||
])
|
||||
|
||||
message_template = self.env['jikimo.message.template'].search([
|
||||
('bussiness_node_id', '=', bussiness_node.id),
|
||||
('model', '=', 'jikimo.workorder.exception')
|
||||
])
|
||||
|
||||
message_record = self.env['jikimo.message.queue'].search([
|
||||
('res_id', '=', exception_record.id),
|
||||
('model', '=', 'jikimo.workorder.exception'),
|
||||
('message_status', '=', 'pending'),
|
||||
('message_template_id', '=', message_template.id)
|
||||
])
|
||||
self.assertTrue(message_record)
|
||||
|
||||
def test_create_message_queue_yc0003(self):
|
||||
exception_record = self.env['jikimo.workorder.exception'].create({
|
||||
'workorder_id': self.workorder.id,
|
||||
'exception_code': 'YC0003',
|
||||
'exception_content': '无定位数据'
|
||||
})
|
||||
|
||||
bussiness_node = self.env['jikimo.message.bussiness.node'].search([
|
||||
('name', '=', '无定位数据'),
|
||||
('model', '=', 'jikimo.workorder.exception')
|
||||
])
|
||||
|
||||
message_template = self.env['jikimo.message.template'].search([
|
||||
('bussiness_node_id', '=', bussiness_node.id),
|
||||
('model', '=', 'jikimo.workorder.exception')
|
||||
])
|
||||
|
||||
message_record = self.env['jikimo.message.queue'].search([
|
||||
('res_id', '=', exception_record.id),
|
||||
('model', '=', 'jikimo.workorder.exception'),
|
||||
('message_status', '=', 'pending'),
|
||||
('message_template_id', '=', message_template.id)
|
||||
])
|
||||
self.assertTrue(message_record)
|
||||
|
||||
def test_create_message_queue_yc0004(self):
|
||||
exception_record = self.env['jikimo.workorder.exception'].create({
|
||||
'workorder_id': self.workorder.id,
|
||||
'exception_code': 'YC0004',
|
||||
'exception_content': '无CNC程序'
|
||||
})
|
||||
|
||||
message_record = self.env['jikimo.message.queue'].search([
|
||||
('res_id', '=', exception_record.id),
|
||||
('model', '=', 'jikimo.workorder.exception'),
|
||||
('message_status', '=', 'pending')
|
||||
])
|
||||
self.assertFalse(message_record)
|
||||
|
||||
def test_get_message(self):
|
||||
exception_record = self.env['jikimo.workorder.exception'].create({
|
||||
'workorder_id': self.workorder.id,
|
||||
'exception_code': 'YC0002',
|
||||
'exception_content': '无功能刀具'
|
||||
})
|
||||
message_queue_ids = self.env['jikimo.message.queue'].search([
|
||||
('res_id', '=', exception_record.id),
|
||||
('model', '=', 'jikimo.workorder.exception'),
|
||||
('message_status', '=', 'pending')
|
||||
])
|
||||
message = self.env['jikimo.workorder.exception']._get_message(message_queue_ids)
|
||||
self.assertTrue(message)
|
||||
|
||||
|
||||
@@ -1273,18 +1273,3 @@ msgstr ""
|
||||
#: model:product.template,description_sale:mrp_workorder.product_template_stool_top
|
||||
msgid "wooden stool top"
|
||||
msgstr ""
|
||||
|
||||
#. module: mrp_workorder
|
||||
#: model:quality.point.test_type,name:mrp_workorder.test_type_register_consumed_materials
|
||||
msgid "Register Consumed Materials"
|
||||
msgstr "登记消耗材料"
|
||||
|
||||
#. module: mrp_workorder
|
||||
#: model:quality.point.test_type,name:mrp_workorder.test_type_register_byproducts
|
||||
msgid "Register By-products"
|
||||
msgstr "按产品注册"
|
||||
|
||||
#. module: mrp_workorder
|
||||
#: model:quality.point.test_type,name:mrp_workorder.test_type_print_label
|
||||
msgid "Print label"
|
||||
msgstr "打印标签"
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import fields, models, api
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class MrpProduction(models.Model):
|
||||
@@ -12,8 +12,7 @@ class MrpProduction(models.Model):
|
||||
check_ids = fields.One2many('quality.check', 'production_id', string="Checks")
|
||||
|
||||
def _split_productions(self, amounts=False, cancel_remaining_qty=False, set_consumed_qty=False):
|
||||
productions = super()._split_productions(amounts=amounts, cancel_remaining_qty=cancel_remaining_qty,
|
||||
set_consumed_qty=set_consumed_qty)
|
||||
productions = super()._split_productions(amounts=amounts, cancel_remaining_qty=cancel_remaining_qty, set_consumed_qty=set_consumed_qty)
|
||||
backorders = productions[1:]
|
||||
if not backorders:
|
||||
return productions
|
||||
@@ -21,4 +20,3 @@ class MrpProduction(models.Model):
|
||||
if wo.current_quality_check_id.component_id:
|
||||
wo.current_quality_check_id._update_component_quantity()
|
||||
return productions
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ class MrpWorkcenter(models.Model):
|
||||
|
||||
class MrpProductionWorkcenterLine(models.Model):
|
||||
_name = 'mrp.workorder'
|
||||
_inherit = ['mrp.workorder', 'barcodes.barcode_events_mixin', 'mail.thread', 'mail.activity.mixin']
|
||||
_inherit = ['mrp.workorder', 'barcodes.barcode_events_mixin']
|
||||
|
||||
quality_point_ids = fields.Many2many('quality.point', compute='_compute_quality_point_ids', store=True)
|
||||
quality_point_count = fields.Integer('Steps', compute='_compute_quality_point_count')
|
||||
@@ -47,17 +47,14 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
|
||||
is_last_lot = fields.Boolean('Is Last lot', compute='_compute_is_last_lot')
|
||||
is_first_started_wo = fields.Boolean('Is The first Work Order', compute='_compute_is_last_unfinished_wo')
|
||||
is_last_unfinished_wo = fields.Boolean('Is Last Work Order To Process', compute='_compute_is_last_unfinished_wo',
|
||||
store=False)
|
||||
is_last_unfinished_wo = fields.Boolean('Is Last Work Order To Process', compute='_compute_is_last_unfinished_wo', store=False)
|
||||
lot_id = fields.Many2one(related='current_quality_check_id.lot_id', readonly=False)
|
||||
move_id = fields.Many2one(related='current_quality_check_id.move_id', readonly=False)
|
||||
move_line_id = fields.Many2one(related='current_quality_check_id.move_line_id', readonly=False)
|
||||
move_line_ids = fields.One2many(related='move_id.move_line_ids')
|
||||
quality_state = fields.Selection(related='current_quality_check_id.quality_state', string="Quality State",
|
||||
readonly=False)
|
||||
quality_state = fields.Selection(related='current_quality_check_id.quality_state', string="Quality State", readonly=False)
|
||||
qty_done = fields.Float(related='current_quality_check_id.qty_done', readonly=False)
|
||||
test_type_id = fields.Many2one('quality.point.test_type', 'Test Type',
|
||||
related='current_quality_check_id.test_type_id')
|
||||
test_type_id = fields.Many2one('quality.point.test_type', 'Test Type', related='current_quality_check_id.test_type_id')
|
||||
test_type = fields.Char(related='test_type_id.technical_name')
|
||||
user_id = fields.Many2one(related='current_quality_check_id.user_id', readonly=False)
|
||||
worksheet_page = fields.Integer('Worksheet page')
|
||||
@@ -68,8 +65,7 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
def _compute_quality_point_ids(self):
|
||||
for workorder in self:
|
||||
quality_points = workorder.operation_id.quality_point_ids
|
||||
quality_points = quality_points.filtered(
|
||||
lambda qp: not qp.product_ids or workorder.production_id.product_id in qp.product_ids)
|
||||
quality_points = quality_points.filtered(lambda qp: not qp.product_ids or workorder.production_id.product_id in qp.product_ids)
|
||||
workorder.quality_point_ids = quality_points
|
||||
|
||||
@api.depends('operation_id')
|
||||
@@ -95,8 +91,7 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
@api.depends('check_ids')
|
||||
def _compute_finished_product_check_ids(self):
|
||||
for wo in self:
|
||||
wo.finished_product_check_ids = wo.check_ids.filtered(
|
||||
lambda c: c.finished_product_sequence == wo.qty_produced)
|
||||
wo.finished_product_check_ids = wo.check_ids.filtered(lambda c: c.finished_product_sequence == wo.qty_produced)
|
||||
|
||||
def write(self, values):
|
||||
res = super().write(values)
|
||||
@@ -143,8 +138,7 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
self.finished_lot_id = self.env['stock.lot'].create({
|
||||
'product_id': self.product_id.id,
|
||||
'company_id': self.company_id.id,
|
||||
'name': self.env['stock.lot']._get_next_serial(self.company_id, self.product_id) or self.env[
|
||||
'ir.sequence'].next_by_code('stock.lot.serial'),
|
||||
'name': self.env['stock.lot']._get_next_serial(self.company_id, self.product_id) or self.env['ir.sequence'].next_by_code('stock.lot.serial'),
|
||||
})
|
||||
|
||||
def _create_subsequent_checks(self):
|
||||
@@ -285,8 +279,7 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
if self.current_quality_check_id:
|
||||
team = self.current_quality_check_id.team_id
|
||||
else:
|
||||
team = self.env['quality.alert.team'].search(
|
||||
['|', ('company_id', '=', self.company_id.id), ('company_id', '=', False)], limit=1)
|
||||
team = self.env['quality.alert.team'].search(['|', ('company_id', '=', self.company_id.id), ('company_id', '=', False)], limit=1)
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'quality.check',
|
||||
@@ -327,8 +320,7 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
production = wo.production_id
|
||||
|
||||
move_raw_ids = wo.move_raw_ids.filtered(lambda m: m.state not in ('done', 'cancel'))
|
||||
move_finished_ids = wo.move_finished_ids.filtered(
|
||||
lambda m: m.state not in ('done', 'cancel') and m.product_id != wo.production_id.product_id)
|
||||
move_finished_ids = wo.move_finished_ids.filtered(lambda m: m.state not in ('done', 'cancel') and m.product_id != wo.production_id.product_id)
|
||||
previous_check = self.env['quality.check']
|
||||
for point in wo.quality_point_ids:
|
||||
# Check if we need a quality control for this point
|
||||
@@ -350,13 +342,11 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
if point.test_type == 'register_byproducts':
|
||||
moves = move_finished_ids.filtered(lambda m: m.product_id == point.component_id)
|
||||
if not moves:
|
||||
moves = production.move_finished_ids.filtered(
|
||||
lambda m: not m.operation_id and m.product_id == point.component_id)
|
||||
moves = production.move_finished_ids.filtered(lambda m: not m.operation_id and m.product_id == point.component_id)
|
||||
elif point.test_type == 'register_consumed_materials':
|
||||
moves = move_raw_ids.filtered(lambda m: m.product_id == point.component_id)
|
||||
if not moves:
|
||||
moves = production.move_raw_ids.filtered(
|
||||
lambda m: not m.operation_id and m.product_id == point.component_id)
|
||||
moves = production.move_raw_ids.filtered(lambda m: not m.operation_id and m.product_id == point.component_id)
|
||||
else:
|
||||
check = self.env['quality.check'].create(values)
|
||||
previous_check.next_check_id = check
|
||||
@@ -373,10 +363,8 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
processed_move |= moves
|
||||
|
||||
# Generate quality checks associated with unreferenced components
|
||||
moves_without_check = ((move_raw_ids | move_finished_ids) - processed_move).filtered(lambda move: (
|
||||
move.has_tracking != 'none' and not move.raw_material_production_id.use_auto_consume_components_lots) or move.operation_id)
|
||||
quality_team_id = self.env['quality.alert.team'].search(
|
||||
['|', ('company_id', '=', wo.company_id.id), ('company_id', '=', False)], limit=1).id
|
||||
moves_without_check = ((move_raw_ids | move_finished_ids) - processed_move).filtered(lambda move: (move.has_tracking != 'none' and not move.raw_material_production_id.use_auto_consume_components_lots) or move.operation_id)
|
||||
quality_team_id = self.env['quality.alert.team'].search(['|', ('company_id', '=', wo.company_id.id), ('company_id', '=', False)], limit=1).id
|
||||
for move in moves_without_check:
|
||||
values = {
|
||||
'production_id': production.id,
|
||||
@@ -424,8 +412,7 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
|
||||
backorder = False
|
||||
# Trigger the backorder process if we produce less than expected
|
||||
if float_compare(self.qty_producing, self.qty_remaining,
|
||||
precision_rounding=self.product_uom_id.rounding) == -1 and self.is_first_started_wo:
|
||||
if float_compare(self.qty_producing, self.qty_remaining, precision_rounding=self.product_uom_id.rounding) == -1 and self.is_first_started_wo:
|
||||
backorder = self.production_id._split_productions()[1:]
|
||||
for workorder in backorder.workorder_ids:
|
||||
if workorder.product_tracking == 'serial':
|
||||
@@ -436,8 +423,7 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
else:
|
||||
if self.operation_id:
|
||||
backorder = (self.production_id.procurement_group_id.mrp_production_ids - self.production_id).filtered(
|
||||
lambda p: p.workorder_ids.filtered(lambda wo: wo.operation_id == self.operation_id).state not in (
|
||||
'cancel', 'done')
|
||||
lambda p: p.workorder_ids.filtered(lambda wo: wo.operation_id == self.operation_id).state not in ('cancel', 'done')
|
||||
)[:1]
|
||||
else:
|
||||
index = list(self.production_id.workorder_ids).index(self)
|
||||
@@ -456,8 +442,7 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
wo.current_quality_check_id._update_component_quantity()
|
||||
if not self.env.context.get('no_start_next'):
|
||||
if self.operation_id:
|
||||
return backorder.workorder_ids.filtered(
|
||||
lambda wo: wo.operation_id == self.operation_id).open_tablet_view()
|
||||
return backorder.workorder_ids.filtered(lambda wo: wo.operation_id == self.operation_id).open_tablet_view()
|
||||
else:
|
||||
index = list(self.production_id.workorder_ids).index(self)
|
||||
return backorder.workorder_ids[index].open_tablet_view()
|
||||
@@ -481,8 +466,7 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
|
||||
def open_tablet_view(self):
|
||||
self.ensure_one()
|
||||
if not self.is_user_working and self.working_state != 'blocked' and self.state in (
|
||||
'ready', 'waiting', 'progress', 'pending'):
|
||||
if not self.is_user_working and self.working_state != 'blocked' and self.state in ('ready', 'waiting', 'progress', 'pending'):
|
||||
self.button_start()
|
||||
action = self.env["ir.actions.actions"]._for_xml_id("mrp_workorder.tablet_client_action")
|
||||
action['target'] = 'fullscreen'
|
||||
@@ -537,8 +521,7 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
data = {
|
||||
'mrp.workorder': self.read(self._get_fields_for_tablet(), load=False)[0],
|
||||
'quality.check': self.check_ids._get_fields_for_tablet(sorted_check_list),
|
||||
'operation': self.operation_id.read(self.operation_id._get_fields_for_tablet())[
|
||||
0] if self.operation_id else {},
|
||||
'operation': self.operation_id.read(self.operation_id._get_fields_for_tablet())[0] if self.operation_id else {},
|
||||
'working_state': self.workcenter_id.working_state,
|
||||
'views': {
|
||||
'workorder': self.env.ref('mrp_workorder.mrp_workorder_view_form_tablet').id,
|
||||
@@ -570,8 +553,7 @@ class MrpProductionWorkcenterLine(models.Model):
|
||||
|
||||
return {
|
||||
'duration': self.duration,
|
||||
'position': bisect_left(last30op, self.duration),
|
||||
# which position regarded other workorders ranked by duration
|
||||
'position': bisect_left(last30op, self.duration), # which position regarded other workorders ranked by duration
|
||||
'quality_score': score,
|
||||
'show_rainbow': show_rainbow,
|
||||
}
|
||||
|
||||
@@ -5,16 +5,13 @@
|
||||
<field name="name">mrp.production.tree.inherit.planning</field>
|
||||
<field name="model">mrp.production</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree default_order="date_planned_start asc" decoration-info="state=='confirmed'"
|
||||
decoration-danger="date_planned_start<current_date and state not in ('done','cancel')"
|
||||
decoration-muted="state in ('done','cancel')" string="Manufacturing Orders" name="Production">
|
||||
<tree default_order="date_planned_start asc" decoration-info="state=='confirmed'" decoration-danger="date_planned_start<current_date and state not in ('done','cancel')" decoration-muted="state in ('done','cancel')" string="Manufacturing Orders" name="Production">
|
||||
<field name="message_needaction" invisible="1"/>
|
||||
<field name="name"/>
|
||||
<field name="date_planned_start"/>
|
||||
<field name="product_id"/>
|
||||
<field name="product_qty" sum="Total Qty" string="Quantity"/>
|
||||
<field name="product_uom_id" string="Unit of Measure" options="{'no_open':True,'no_create':True}"
|
||||
groups="uom.group_uom"/>
|
||||
<field name="product_uom_id" string="Unit of Measure" options="{'no_open':True,'no_create':True}" groups="uom.group_uom"/>
|
||||
<field name="reservation_state" string="Availability"/>
|
||||
<field name="origin"/>
|
||||
<field name="state"/>
|
||||
@@ -46,9 +43,7 @@
|
||||
<field name="inherit_id" ref="mrp.view_mrp_production_filter"/>
|
||||
<field name="arch" type="xml">
|
||||
<filter name="filter_planned" position="attributes">
|
||||
<attribute name="domain">[('is_planned', '=', True), ('date_planned_start', '!=', False),
|
||||
('date_planned_finished', '!=', False)]
|
||||
</attribute>
|
||||
<attribute name="domain">[('is_planned', '=', True), ('date_planned_start', '!=', False), ('date_planned_finished', '!=', False)]</attribute>
|
||||
</filter>
|
||||
</field>
|
||||
</record>
|
||||
@@ -63,13 +58,10 @@
|
||||
</record>
|
||||
|
||||
<record id="mrp.act_product_mrp_production_workcenter" model="ir.actions.act_window">
|
||||
<field name="domain">[('bom_id', '!=', False), ('bom_id.operation_ids.workcenter_id', '=', active_id),
|
||||
('date_planned_start', '!=', False), ('date_planned_finished', '!=', False)]
|
||||
</field>
|
||||
<field name="domain">[('bom_id', '!=', False), ('bom_id.operation_ids.workcenter_id', '=', active_id), ('date_planned_start', '!=', False), ('date_planned_finished', '!=', False)]</field>
|
||||
<field name="view_id" ref="mrp_production_tree_view_planning"/>
|
||||
</record>
|
||||
|
||||
|
||||
<menuitem id="mrp_workorder_menu_planning"
|
||||
name="Work Orders"
|
||||
sequence="2"
|
||||
|
||||
@@ -27,13 +27,6 @@
|
||||
</field>
|
||||
</page>
|
||||
</page>
|
||||
<xpath expr="//sheet" position="after">
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids"/>
|
||||
<field name="activity_ids"/>
|
||||
<field name="message_ids" options="{'post_refresh': 'recipients'}"/>
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -1050,13 +1050,3 @@ msgstr "工作中心故障"
|
||||
#: model:ir.model.fields,field_description:quality.field_quality_point_test_type__active
|
||||
msgid "active"
|
||||
msgstr "有效"
|
||||
|
||||
#. module: quality
|
||||
#: model:quality.point.test_type,name:quality.test_type_instructions
|
||||
msgid "Instructions"
|
||||
msgstr "使用说明"
|
||||
|
||||
#. module: quality
|
||||
#: model:quality.point.test_type,name:quality.test_type_picture
|
||||
msgid "Take a Picture"
|
||||
msgstr "照片"
|
||||
@@ -15,7 +15,7 @@ class TestType(models.Model):
|
||||
_description = "Quality Control Test Type"
|
||||
|
||||
# Used instead of selection field in order to hide a choice depending on the view.
|
||||
name = fields.Char('Name', required=True,translate=True)
|
||||
name = fields.Char('Name', required=True)
|
||||
technical_name = fields.Char('Technical name', required=True)
|
||||
active = fields.Boolean('active', default=True)
|
||||
|
||||
|
||||
@@ -1185,14 +1185,3 @@ msgstr "请先进行质量检查!"
|
||||
#: model_terms:ir.ui.view,arch_db:quality_control.quality_alert_team_view_form
|
||||
msgid "e.g. The QA Masters"
|
||||
msgstr "例如:QA大师"
|
||||
|
||||
|
||||
#. module: quality_control
|
||||
#: model:quality.point.test_type,name:quality_control.test_type_passfail
|
||||
msgid "Pass - Fail"
|
||||
msgstr "通过-失败"
|
||||
|
||||
#. module: quality_control
|
||||
#: model:quality.point.test_type,name:quality_control.test_type_measure
|
||||
msgid "Measure"
|
||||
msgstr "测量"
|
||||
@@ -6,4 +6,3 @@ from . import stock_move
|
||||
from . import stock_move_line
|
||||
from . import stock_picking
|
||||
from . import stock_lot
|
||||
from . import product_category
|
||||
@@ -1,32 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
from math import sqrt
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from datetime import datetime
|
||||
|
||||
import random
|
||||
|
||||
from odoo import api, models, fields, _
|
||||
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, float_round
|
||||
from odoo.osv.expression import OR
|
||||
|
||||
|
||||
class ProductCategory(models.Model):
|
||||
_inherit = 'product.category'
|
||||
@api.model
|
||||
def name_search(self, name='', args=None, operator='ilike', limit=100):
|
||||
if args is None:
|
||||
args = []
|
||||
# 添加过滤条件,确保只返回名称为 'abc' 的记录
|
||||
args += [('name', 'not in', ['Saleable', 'Expenses', 'Deliveries'])]
|
||||
|
||||
# 调用父类的 name_search 方法
|
||||
return super(ProductCategory, self).name_search(name, args=args, operator=operator, limit=limit)
|
||||
|
||||
@api.model
|
||||
def search(self, args, limit=100, offset=0, order=None, count=False):
|
||||
# 添加过滤条件,确保只返回名称不在指定列表中的记录
|
||||
args += [('name', 'not in', ['Saleable', 'Expenses', 'Deliveries'])]
|
||||
|
||||
# 调用父类的 search 方法
|
||||
return super(ProductCategory, self).search(args, limit=limit, offset=offset, order=order, count=count)
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 702 B |
@@ -1024,7 +1024,7 @@
|
||||
<menuitem
|
||||
id="menu_quality_root"
|
||||
name="Quality"
|
||||
web_icon="quality_control,static/description/质量.png"
|
||||
web_icon="quality_control,static/description/icon.svg"
|
||||
sequence="150"
|
||||
groups="quality.group_quality_user"/>
|
||||
|
||||
@@ -1033,7 +1033,7 @@
|
||||
name="Overview"
|
||||
action="quality_alert_team_action"
|
||||
parent="menu_quality_root"
|
||||
sequence="5" active="False"/>
|
||||
sequence="5"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_quality_control"
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
pystrich
|
||||
cpca
|
||||
pycryptodome==3.20
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
],
|
||||
'web.assets_backend': [
|
||||
'sf_base/static/src/scss/*.scss',
|
||||
'sf_base/static/src/js/*.js',
|
||||
],
|
||||
|
||||
},
|
||||
|
||||
@@ -38,17 +38,3 @@ class Manufacturing_Connect(http.Controller):
|
||||
res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
|
||||
logging.info('get_maintenance_tool_groups_Info error:%s' % e)
|
||||
return json.JSONEncoder().encode(res)
|
||||
|
||||
|
||||
class MultiInheritController():
|
||||
_sub_classes = []
|
||||
|
||||
def __init_subclass__(cls):
|
||||
"""
|
||||
多继承,解决多个字类时方法调用super的问题
|
||||
"""
|
||||
super().__init_subclass__()
|
||||
if len(cls._sub_classes) > 0 and cls not in cls._sub_classes:
|
||||
cls.__bases__ = (cls._sub_classes[-1],)
|
||||
if cls not in cls._sub_classes:
|
||||
cls._sub_classes.append(cls)
|
||||
|
||||
@@ -5,4 +5,3 @@ from . import fixture
|
||||
from . import functional_fixture
|
||||
from . import tool_other_features
|
||||
from . import basic_parameters_fixture
|
||||
from . import ir_sequence
|
||||
|
||||
@@ -394,19 +394,3 @@ class MachineToolCategory(models.Model):
|
||||
active = fields.Boolean('有效', default=True)
|
||||
category = fields.Selection([('shukong', u'数控'), ('putong', u'普通')], string=u'机床类别',
|
||||
default='shukong')
|
||||
|
||||
|
||||
class MachiningAccuracy(models.Model):
|
||||
_name = 'sf.machining.accuracy'
|
||||
_description = '加工精度'
|
||||
name = fields.Char('一般公差', index=True)
|
||||
standard_tolerance = fields.Char(string="标准公差")
|
||||
sync_id = fields.Char('同步ID')
|
||||
|
||||
|
||||
class ReSaleOrder(models.Model):
|
||||
_inherit = 'sale.order'
|
||||
|
||||
person_of_delivery = fields.Char('收货人')
|
||||
telephone_of_delivery = fields.Char('电话号码')
|
||||
address_of_delivery = fields.Char('联系地址')
|
||||
|
||||
@@ -13,7 +13,7 @@ class BasicParametersFixture(models.Model):
|
||||
diameter = fields.Float('直径(mm)', digits=(16, 2))
|
||||
|
||||
# '零点卡盘' 字段
|
||||
weight = fields.Float('重量(kg)', digits=(16, 2))
|
||||
weight = fields.Float('重量(mm)', digits=(16, 2))
|
||||
orientation_dish_diameter = fields.Float('定位盘直径(mm)', digits=(16, 2))
|
||||
clamping_diameter = fields.Float('装夹直径(mm)', digits=(16, 2))
|
||||
clamping_num = fields.Selection([('1', '1'), ('2', '2'), ('4', '4'), ('6', '6'), ('8', '8')], string='装夹单元数')
|
||||
|
||||
@@ -61,10 +61,12 @@ class MrsMaterialModel(models.Model):
|
||||
supplier_ids = fields.One2many('sf.supplier.sort', 'materials_model_id', string='供应商')
|
||||
active = fields.Boolean('有效', default=True)
|
||||
|
||||
@api.constrains("gain_way")
|
||||
def _check_supplier_ids(self):
|
||||
for item in self:
|
||||
if item.gain_way in ('外协', '采购') and not item.supplier_ids:
|
||||
@api.onchange('gain_way')
|
||||
def _check_gain_way(self):
|
||||
if not self.gain_way:
|
||||
raise UserError("请选择获取方式")
|
||||
if self.gain_way in ['外协', '采购']:
|
||||
if not self.supplier_ids:
|
||||
raise UserError("请添加供应商")
|
||||
|
||||
|
||||
@@ -84,21 +86,17 @@ class MrsProductionProcessCategory(models.Model):
|
||||
class MrsProductionProcess(models.Model):
|
||||
_name = 'sf.production.process'
|
||||
_description = '表面工艺'
|
||||
order = 'sequence asc'
|
||||
|
||||
code = fields.Char("编码")
|
||||
name = fields.Char('名称')
|
||||
remark = fields.Text("备注")
|
||||
sequence = fields.Integer('排序')
|
||||
# processing_order_ids = fields.One2many('sf.processing.order', 'production_process_id', string='工序')
|
||||
partner_process_ids = fields.Many2many('res.partner', 'process_ids', '加工工厂')
|
||||
active = fields.Boolean('有效', default=True)
|
||||
parameter_ids = fields.One2many('sf.production.process.parameter', 'process_id', string='可选参数')
|
||||
category_id = fields.Many2one('sf.production.process.category', string='表面工艺类别')
|
||||
category_id = fields.Many2one('sf.production.process.category')
|
||||
# workcenter_ids = fields.Many2many('mrp.workcenter', 'rel_workcenter_process', required=True)
|
||||
processing_day = fields.Float('加工天数/d')
|
||||
travel_day = fields.Float('路途天数/d')
|
||||
sequence = fields.Integer('排序')
|
||||
|
||||
|
||||
# class MrsProcessingTechnology(models.Model):
|
||||
# _name = 'sf.processing.technology'
|
||||
@@ -145,12 +143,8 @@ class MrsProductionProcessParameter(models.Model):
|
||||
is_check = fields.Boolean(default=False)
|
||||
# price = fields.Float('单价')
|
||||
process_id = fields.Many2one('sf.production.process', string='表面工艺')
|
||||
process_description = fields.Char(string='工艺描述')
|
||||
materials_model_ids = fields.Many2many('sf.materials.model', 'applicable_material', string='适用材料')
|
||||
processing_day = fields.Float('加工天数/d')
|
||||
travel_day = fields.Float('路途天数/d')
|
||||
active = fields.Boolean('有效', default=True)
|
||||
processing_mm = fields.Char('加工厚度/mm')
|
||||
|
||||
def name_get(self):
|
||||
result = []
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
import calendar
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
class IrSequence(models.Model):
|
||||
_inherit = 'ir.sequence'
|
||||
|
||||
date_range_period = fields.Selection(
|
||||
[('day', '每日'), ('month', '每月'), ('year', '每年')],
|
||||
string='日期期间',
|
||||
)
|
||||
|
||||
def _next(self, sequence_date=None):
|
||||
""" Returns the next number in the preferred sequence in all the ones given in self."""
|
||||
if not self.use_date_range:
|
||||
return self._next_do()
|
||||
# date mode
|
||||
dt = sequence_date or self._context.get('ir_sequence_date', fields.Date.today())
|
||||
seq_date = self.env['ir.sequence.date_range'].search(
|
||||
[
|
||||
('sequence_id', '=', self.id),
|
||||
('date_from', '<=', dt),
|
||||
('date_to', '>=', dt),
|
||||
('date_range_period', '=', self.date_range_period)
|
||||
], limit=1)
|
||||
if not seq_date:
|
||||
if self.date_range_period:
|
||||
seq_date = self._create_date_range_seq_by_period(dt, self.date_range_period)
|
||||
else:
|
||||
seq_date = self._create_date_range_seq(dt)
|
||||
return seq_date.with_context(ir_sequence_date_range=seq_date.date_from)._next()
|
||||
|
||||
def _create_date_range_seq_by_period(self, date, period):
|
||||
if period == 'year':
|
||||
year = fields.Date.from_string(date).strftime('%Y')
|
||||
date_from = '{}-01-01'.format(year)
|
||||
date_to = '{}-12-31'.format(year)
|
||||
if period == 'month':
|
||||
# 计算当前月份的第一天和最后一天
|
||||
year = fields.Date.from_string(date).strftime('%Y')
|
||||
month = fields.Date.from_string(date).strftime('%m')
|
||||
date_from = fields.Date.from_string(date).strftime('%Y-%m-01')
|
||||
date_to = '{}-{}-{}'.format(year, month, calendar.monthrange(int(year), int(month))[1])
|
||||
if period == 'day':
|
||||
date_from = date
|
||||
date_to = date
|
||||
date_range = self.env['ir.sequence.date_range'].search(
|
||||
[
|
||||
('sequence_id', '=', self.id),
|
||||
('date_to', '>=', date_from),
|
||||
('date_to', '<=', date),
|
||||
('date_range_period', '=', period)
|
||||
],
|
||||
order='date_to desc', limit=1)
|
||||
if date_range:
|
||||
date_from = date_range.date_to + timedelta(days=1)
|
||||
seq_date_range = self.env['ir.sequence.date_range'].sudo().create({
|
||||
'date_from': date_from,
|
||||
'date_to': date_to,
|
||||
'sequence_id': self.id,
|
||||
'date_range_period': period,
|
||||
})
|
||||
return seq_date_range
|
||||
|
||||
|
||||
class IrSequenceDateRange(models.Model):
|
||||
_inherit = 'ir.sequence.date_range'
|
||||
|
||||
date_range_period = fields.Selection(
|
||||
[('day', '每日'), ('month', '每月'), ('year', '每年')],
|
||||
string='日期期间',
|
||||
)
|
||||
@@ -321,7 +321,7 @@ class ToolInventory(models.Model):
|
||||
prefix = fields.Char('前缀')
|
||||
postfix = fields.Char('后缀')
|
||||
diameter = fields.Float('直径(mm)')
|
||||
angle = fields.Float('R角(mm)',default=0)
|
||||
angle = fields.Float('R角(mm)')
|
||||
tool_length = fields.Float('刀具总长(mm)')
|
||||
blade_length = fields.Float('避空长/刃长(mm)')
|
||||
knife_head_name = fields.Char('刀头名称')
|
||||
@@ -331,7 +331,7 @@ class ToolInventory(models.Model):
|
||||
work_material = fields.Selection([('钢', '钢'), ('铝', '铝')], string='加工材料')
|
||||
life_span = fields.Float('寿命(min)')
|
||||
|
||||
tool_groups_id = fields.Many2one('sf.tool.groups', string='刀具组', required=True)
|
||||
tool_groups_id = fields.Many2one('sf.tool.groups', string='刀具组')
|
||||
|
||||
active = fields.Boolean('已归档', default=True)
|
||||
|
||||
|
||||
10
sf_base/models/tool_base_new.py.rej
Normal file
10
sf_base/models/tool_base_new.py.rej
Normal file
@@ -0,0 +1,10 @@
|
||||
diff a/sf_base/models/tool_base_new.py b/sf_base/models/tool_base_new.py (rejected hunks)
|
||||
@@ -108,6 +108,4 @@
|
||||
cutting_speed_ids = fields.One2many('sf.cutting.speed', 'standard_library_id', string='切削速度Vc')
|
||||
- feed_per_tooth_ids = fields.One2many('sf.feed.per.tooth', 'standard_library_id', '每齿走刀量fz',
|
||||
- domain=[('cutting_speed', '!=', False)])
|
||||
- feed_per_tooth_ids_3 = fields.One2many('sf.feed.per.tooth', 'standard_library_id', '每齿走刀量fz',
|
||||
- domain=[('cutting_speed', '!=', False)])
|
||||
+ feed_per_tooth_ids = fields.One2many('sf.feed.per.tooth', 'standard_library_id', '每齿走刀量fz')
|
||||
+ feed_per_tooth_ids_3 = fields.One2many('sf.feed.per.tooth', 'standard_library_id', '每齿走刀量fz')
|
||||
|
||||
@@ -21,9 +21,8 @@ class ToolMaterialsBasicParameters(models.Model):
|
||||
neck_length = fields.Float('颈部长度(mm)')
|
||||
handle_diameter = fields.Float('柄部直径(mm)')
|
||||
handle_length = fields.Float('柄部长度(mm)')
|
||||
blade_tip_diameter = fields.Float('刀尖直径(mm)')
|
||||
blade_tip_working_size = fields.Char('刀尖倒角度(°)', size=20)
|
||||
tip_r_size = fields.Float('刀尖R角(mm)',default=0)
|
||||
blade_tip_diameter = fields.Integer('刀尖直径(mm)')
|
||||
blade_tip_working_size = fields.Char('刀尖处理尺寸(R半径mm/倒角度)', size=20)
|
||||
blade_tip_taper = fields.Integer('刀尖锥度(°)')
|
||||
blade_diameter = fields.Float('刃部直径(mm)')
|
||||
blade_length = fields.Float('刃部长度(mm)')
|
||||
@@ -38,7 +37,7 @@ class ToolMaterialsBasicParameters(models.Model):
|
||||
width = fields.Float('宽度(mm)')
|
||||
cutting_blade_length = fields.Float('切削刃长(mm)')
|
||||
relief_angle = fields.Integer('后角(°)')
|
||||
blade_tip_circular_arc_radius = fields.Char('刀尖圆弧半径(mm)', size=20,default='0')
|
||||
blade_tip_circular_arc_radius = fields.Char('刀尖圆弧半径(mm)', size=20)
|
||||
inscribed_circle_diameter = fields.Float('内接圆直径IC/D(mm)')
|
||||
install_aperture_diameter = fields.Float('安装孔直径(mm)')
|
||||
chip_breaker_groove = fields.Selection([('无', '无'), ('单面', '单面'), ('双面', '双面')],
|
||||
|
||||
@@ -46,11 +46,6 @@
|
||||
<field name="category_id" ref="base.module_category_manufacturing_manufacturing"/>
|
||||
</record>
|
||||
|
||||
<record id="group_production_engineer" model="res.groups">
|
||||
<field name="name">工艺工程师</field>
|
||||
<field name="implied_ids" eval="[(4, ref('group_sf_mrp_user'))]"/>
|
||||
<field name="category_id" ref="base.module_category_manufacturing_manufacturing"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.module.category" id="module_category_plan">
|
||||
<field name="name">计划</field>
|
||||
|
||||
@@ -11,8 +11,8 @@ access_sf_machine_control_system,sf_machine_control_system,model_sf_machine_cont
|
||||
access_sf_machine_control_system_admin,sf_machine_control_system_admin,model_sf_machine_control_system,base.group_system,1,1,1,0
|
||||
access_sf_production_process_group_sale_director,sf_production_process_group_sale_director,model_sf_production_process,sf_base.group_sale_director,1,0,0,0
|
||||
access_sf_production_process_group_sale_salemanager,sf_production_process_group_sale_salemanager,model_sf_production_process,sf_base.group_sale_salemanager,1,0,0,0
|
||||
access_res_partner_category_group_sale_salemanager,res_partner_category_group_sale_salemanager,base.model_res_partner_category,sf_base.group_sale_salemanager,1,1,1,0
|
||||
access_res_partner_category_group_sale_director,res_partner_category_group_sale_director,base.model_res_partner_category,sf_base.group_sale_director,1,1,1,0
|
||||
access_res_partner_category_group_sale_salemanager,res_partner_category_group_sale_salemanager,base.model_res_partner_category,sf_base.group_sale_salemanager,1,0,1,0
|
||||
access_res_partner_category_group_sale_director,res_partner_category_group_sale_director,base.model_res_partner_category,sf_base.group_sale_director,1,0,1,0
|
||||
access_sf_production_process,sf_production_process,model_sf_production_process,base.group_user,1,1,1,0
|
||||
access_sf_production_process_admin,sf_production_process_admin,model_sf_production_process,base.group_system,1,1,1,0
|
||||
access_sf_production_materials,sf_production_materials,model_sf_production_materials,base.group_user,1,1,1,0
|
||||
@@ -242,12 +242,3 @@ access_sf_fixture_materials_basic_parameters_group_sf_stock_manager,sf_fixture_m
|
||||
access_sf_multi_mounting_type_group_sf_stock_manager,sf_multi_mounting_type_group_sf_stock_manager,model_sf_multi_mounting_type,sf_base.group_sf_stock_manager,1,0,0,0
|
||||
access_sf_machine_brand_group_sf_stock_manager,sf_machine_brand_group_sf_stock_manager,model_sf_machine_brand,sf_base.group_sf_stock_manager,1,0,0,0
|
||||
access_sf_cutting_tool_type_group_sf_stock_manager,sf_cutting_tool_type_group_sf_stock_manager,model_sf_cutting_tool_type,sf_base.group_sf_stock_manager,1,0,0,0
|
||||
|
||||
|
||||
access_sf_cutting_tool_material_group_plan_dispatch,sf_cutting_tool_material_group_plan_dispatch,model_sf_cutting_tool_material,sf_base.group_plan_dispatch,1,0,0,0
|
||||
access_sf_functional_cutting_tool_model_group_plan_dispatch,sf_functional_cutting_tool_model_group_plan_dispatch,model_sf_functional_cutting_tool_model,sf_base.group_plan_dispatch,1,0,0,0
|
||||
access_sf_cutting_tool_type_group_plan_dispatch,sf_cutting_tool_type_group_plan_dispatch,model_sf_cutting_tool_type,sf_base.group_plan_dispatch,1,0,0,0
|
||||
|
||||
|
||||
access_sf_machining_accuracy,sf_machining_accuracy,model_sf_machining_accuracy,base.group_user,1,0,0,0
|
||||
access_sf_machining_accuracy_admin,sf_machining_accuracy_admin,model_sf_machining_accuracy,base.group_system,1,0,0,0
|
||||
|
||||
|
@@ -1,125 +0,0 @@
|
||||
// 获取表格数据
|
||||
function getDomData() {
|
||||
const dom = $('div[name=cutting_speed_ids]')
|
||||
if (!dom.length) return
|
||||
const table = dom.find('.o_list_table')
|
||||
const thead = table.children('thead')
|
||||
const tbody = table.children('tbody')
|
||||
const tbody_child = tbody.children()
|
||||
const hideTheadDom = thead.find('[data-name=process_capability]')
|
||||
hideTheadDom.hide().next().hide()
|
||||
hideTheadDom.before('<th customTh>精加工</th><th customTh>粗加工</th>')
|
||||
tbody_child.each(function () {
|
||||
const dom = $(this).children('[name=process_capability]')
|
||||
if(!dom.length) return
|
||||
dom.css('cssText', 'display: none!important').next().css('cssText', 'display: none!important')
|
||||
const isCu = dom.text() == '粗加工' // 是否粗加工
|
||||
const v = dom.next().text() // 切削速度
|
||||
dom.after(`<td customSpeed="1" name="process_capability" is="精加工" val="${ v }">${!isCu ? v : ''}</td><td customSpeed="1" name="process_capability" is="粗加工" val="${ v }">${isCu ? v : ''}</td>`)
|
||||
setListenClick()
|
||||
})
|
||||
return;
|
||||
handleTbody(tbody, newTableData, ΦList, table)
|
||||
}
|
||||
|
||||
// 监听点击
|
||||
function setListenClick() {
|
||||
$(document).click(function (e) {
|
||||
if ($(e.target).attr('customSpeed')) {
|
||||
const orginV = $('[customInput=1]').children('input').val()
|
||||
$('[customInput=1]').parent().html(orginV)
|
||||
const v = $(e.target).attr('val')
|
||||
const is = $(e.target).attr('is')
|
||||
$(e.target).html('')
|
||||
const input = $('<div customInput="1" is="' + is + '" class="o_field_widget o_field_char"><input class="o_input" type="text" autocomplete="off" maxlength="20"></div>')
|
||||
input.children('input').val(v)
|
||||
$(e.target).append(input)
|
||||
input.children('input').focus()
|
||||
input.children('input').select()
|
||||
} else if ($(e.target).attr('customInput')) {
|
||||
|
||||
} else {
|
||||
const orginV = $('[customInput=1]').children('input').val()
|
||||
$('[customInput=1]').parent().html(orginV)
|
||||
const v = $(e.target).attr('val')
|
||||
}
|
||||
})
|
||||
$(document).off('change') // 防止重复绑定
|
||||
$(document).on('change', '[customInput] input', async function () {
|
||||
$(this).parents('td').attr('val', $(this).val())
|
||||
$(this).parents('td').siblings('[customspeed]').attr('val', $(this).val())
|
||||
var eve1 = new Event('change')
|
||||
var eve2 = new Event('input')
|
||||
var eve3 = new Event('click')
|
||||
let patchSpeedDom = $(this).parents('td').siblings('[name=cutting_speed]')
|
||||
let patchProcessDom = $(this).parents('td').siblings('[name=process_capability]')
|
||||
$(this).parents('td').siblings('[customspeed]').text('') // 清空其他加工类型的数据
|
||||
await timeOut(500)
|
||||
patchProcessDom[0].dispatchEvent(eve3)
|
||||
await timeOut(200)
|
||||
const processVal = $(this).parent().attr('is')
|
||||
patchProcessDom.find('select').val(`"${processVal}"`) // 设置源select的val为“加工类型 is”、
|
||||
patchProcessDom.attr("data-tooltip", `${processVal}`)
|
||||
patchProcessDom.find('select')[0].dispatchEvent(eve1)
|
||||
|
||||
patchSpeedDom[0].dispatchEvent(eve3)
|
||||
await timeOut(200)
|
||||
patchSpeedDom.find('input').val($(this).val())
|
||||
await timeOut(50)
|
||||
patchSpeedDom.find('input')[0].dispatchEvent(eve2)
|
||||
patchSpeedDom.find('input')[0].dispatchEvent(eve1)
|
||||
})
|
||||
$(document).off('blur') // 防止重复绑定
|
||||
$(document).on('blur', '[customInput] input', async function () {
|
||||
if(!$(this).length) return
|
||||
|
||||
$(this).parents('td').siblings('[customspeed]').text('') // 清空其他加工类型的数据
|
||||
let patchProcessDom = $(this).parents('td').siblings('[name=process_capability]')
|
||||
try {
|
||||
patchProcessDom[0].dispatchEvent(new Event('click'))
|
||||
const processVal = $(this).parent().attr('is')
|
||||
patchProcessDom.find('select').val(`"${processVal}"`) // 设置源select的val为“加工类型 is”、
|
||||
patchProcessDom.attr("data-tooltip", `${processVal}`)
|
||||
patchProcessDom.find('select')[0].dispatchEvent(new Event('change'))
|
||||
} catch {
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
function timeOut(time) {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
resolve()
|
||||
}, time)
|
||||
})
|
||||
}
|
||||
|
||||
function listenAdd() {
|
||||
$('td.o_field_x2many_list_row_add a').click(async function () {
|
||||
await timeOut(500)
|
||||
const tr = $('.o_list_table').children('tbody').children('tr').eq(-2)
|
||||
if(tr.children('td').eq(2).text() == '') {
|
||||
const dom = tr.children('[name=process_capability]')
|
||||
if(!dom.length) return
|
||||
dom.css('cssText', 'display: none!important').next().css('cssText', 'display: none!important')
|
||||
const isCu = dom.text() == '粗加工' // 是否粗加工
|
||||
const v = dom.next().text() // 切削速度
|
||||
dom.after(`<td customSpeed="1" name="process_capability" is="精加工" val="${ v }">${!isCu ? v : ''}</td><td customSpeed="1" name="process_capability" is="粗加工" val="${ v }">${isCu ? v : ''}</td>`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function listenSave() {
|
||||
$('.o_form_button_save').click( async function () {
|
||||
await timeOut(1000)
|
||||
if($(this).parent().next().length) return
|
||||
$('th[customTh],td[cusomSpeed]').remove()
|
||||
getDomData()
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
listenAdd()
|
||||
listenSave()
|
||||
getDomData()
|
||||
@@ -1,47 +0,0 @@
|
||||
// 因为表格可以拖动设置宽度,所以需要用js设置初始宽度
|
||||
function setBasicParamTableWidth() {
|
||||
// const _100px = 'th[data-name="cutting_blade_length"],th[data-name="cutting_blade_length"],th[data-name="name"],th[data-name="tip_handling_size"],th[data-name="cutting_depth_max"],th[data-name="diameter_inner_circle"],th[data-name="diameter_mounting_hole" ],th[data-name="radius_tip_re" ],th[data-name="is_chip_breaker"],th[data-name="chip_breaker_type_code"],th[data-name="blade_profile"]'
|
||||
// const _65px = 'th[data-name="edge_angle"],th[data-name="relief_angle"],[data-name="total_length"],th[data-name="length"],th[data-name="thickness"],th[data-name="blade_number"]'
|
||||
// const _80px = 'th[data-name="arbor_diameter"],th[data-name="head_height"],th[data-name="head_width"],th[data-name="head_length"],th[data-name="blade_diameter"],th[data-name="blade_length"] ,th[data-name="neck_length"] ,th[data-name="neck_diameter"] ,th[data-name="shank_diameter"],th[data-name="shank_length"],th[data-name="tip_diameter"],th[data-name="knife_tip_taper"],th[data-name="blade_helix_angle"] ,th[data-name="blade_width"],th[data-name="blade_depth"]'
|
||||
// const _50px = 'th[data-name="pitch"],th[data-name="width"],th[data-name="height"]'
|
||||
|
||||
const basicParamDom = $('.fixTableCss')
|
||||
// const basicParamDom_100px = basicParamDom.find(_100px) // 四字以上
|
||||
// const basicParamDom_65px = basicParamDom.find(_65px) // 大概三个字加单位
|
||||
// const basicParamDom_80px = basicParamDom.find(_80px) // 大概四个字加单位
|
||||
// const basicParamDom_50px= basicParamDom.find(_50px) // 大概两个字加单位
|
||||
//
|
||||
// basicParamDom_100px.css({'width': '100px', 'max-width': 'auto', ',min-width': 'auto'})
|
||||
// basicParamDom_65px.css({'width': '65px', 'max-width': 'auto', ',min-width': 'auto'})
|
||||
// basicParamDom_80px.css({'width': '80px', 'max-width': 'auto', ',min-width': 'auto'})
|
||||
// basicParamDom_50px.css({'width': '50px', 'max-width': 'auto', ',min-width': 'auto'})
|
||||
let dom = []
|
||||
try {
|
||||
dom = basicParamDom.find('table').find('thead').children().children()
|
||||
|
||||
} catch {
|
||||
dom = []
|
||||
}
|
||||
if (!dom) return
|
||||
dom.each(function () {
|
||||
if ($(this).hasClass('row_no') >= 0) { // 序号列
|
||||
// 不设置 通过css设置
|
||||
}
|
||||
const text = $(this).text().split('(')
|
||||
if ($(this).attr('data-name') == 'name' || text[0].length > 4) {
|
||||
$(this).width('100px')
|
||||
} else if(text[0].length == 4){
|
||||
$(this).width('80px')
|
||||
} else if(text[0].length == 3){
|
||||
$(this).width('65px')
|
||||
} else if(text[0].length == 2){
|
||||
$(this).width('50px')
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
setBasicParamTableWidth()
|
||||
$('.o_field_many2one_selection').on('click', $('#cutting_tool_material_id + ul'), function () {
|
||||
setTimeout(setBasicParamTableWidth, 500)
|
||||
})
|
||||
@@ -1,159 +0,0 @@
|
||||
// 获取表格数据
|
||||
function getDomData() {
|
||||
const dom = $('#updateTable').prev()
|
||||
if (!dom.length) return
|
||||
const table = $('#updateTable').prev().find('.o_list_table')
|
||||
const customTable = table.clone()
|
||||
customTable.addClass('customTable')
|
||||
table.parent().append(customTable)
|
||||
table.hide()
|
||||
const thead = customTable.children('thead')
|
||||
const tbody = customTable.children('tbody')
|
||||
const tableData = []
|
||||
const tbody_child = tbody.children()
|
||||
|
||||
const tbody_child_len = tbody_child.length
|
||||
|
||||
for (let v = 0; v < tbody_child_len; v++) { // 将数据取出来到tableData里面
|
||||
const data = tbody_child[v].innerText.split('\t')
|
||||
// console.log('dom data',data)
|
||||
const [index, deep, name, Φ, value] = data
|
||||
tableData.push({index, deep, name, Φ, value})
|
||||
}
|
||||
const ΦList = [...new Set(tableData.map(_ => _.name))] // ΦList去重
|
||||
const newTableData = {}
|
||||
tableData.forEach(_ => {
|
||||
const key = _.deep + '|' + _.Φ
|
||||
!newTableData[key] ? newTableData[key] = {i: _.index} : '';
|
||||
if (_.Φ) { // 去除没有Φ的脏数据
|
||||
newTableData[key]['Φ' + _.Φ] = _.value
|
||||
newTableData[key]['Φ' + _.Φ + 'i'] = _.index
|
||||
}
|
||||
})
|
||||
// console.log('qwdh',tableData, ΦList, newTableData);
|
||||
|
||||
if (ΦList.filter(_ => _).length == 0) return;
|
||||
handleThead(thead, ΦList)
|
||||
|
||||
handleTbody(tbody, newTableData, ΦList, table)
|
||||
}
|
||||
|
||||
// 重新设置表头、
|
||||
function handleThead(thead, ΦList) {
|
||||
const dom = thead.children().eq(0).children()
|
||||
const len = dom.length
|
||||
dom.eq(0).attr('rowspan', 2)
|
||||
dom.eq(1).attr('rowspan', 2)
|
||||
len == 5 ? dom.eq(2).attr('rowspan', 2) : ''
|
||||
dom.eq(-2).attr('colspan', ΦList.length)
|
||||
dom.eq(-1).remove()
|
||||
|
||||
const tr = document.createElement('tr')
|
||||
for (let v = 0; v < ΦList.length; v++) {
|
||||
const th = document.createElement('th')
|
||||
th.innerText = 'Φ' + ΦList[v]
|
||||
tr.append(th)
|
||||
}
|
||||
thead.append(tr)
|
||||
}
|
||||
|
||||
// 重新设置表格
|
||||
function handleTbody(tbody, newTableData, ΦList, table) {
|
||||
console.log(newTableData)
|
||||
tbody.html('')
|
||||
let i = 0
|
||||
const data = Object.keys(newTableData)
|
||||
// data.sort((a, b) => {
|
||||
// a = a.split('=')[1].split('%')[0]
|
||||
// b = b.split('=')[1].split('%')[0]
|
||||
// return a - b
|
||||
// })
|
||||
// console.log('wqoqw ',ΦList)
|
||||
data.forEach(_ => {
|
||||
i++
|
||||
const tr = $('<tr class="o_data_row"></tr>')
|
||||
const td0 = $('<td></td>')
|
||||
td0.text(i)
|
||||
tr.append(td0)
|
||||
const lit = _.split('|')
|
||||
//
|
||||
const td1 = $('<td></td>')
|
||||
const td2 = $('<td></td>')
|
||||
td1.text(lit[0])
|
||||
td2.text(lit[1] || '')
|
||||
tr.append(td1)
|
||||
tr.append(td2)
|
||||
ΦList.forEach(Φ => {
|
||||
const td = $('<td class="o_data_cell cursor-pointer o_field_cell o_list_char"></td>')
|
||||
td.text(newTableData[_]['Φ' + Φ])
|
||||
td.attr('col', newTableData[_]['Φ' + Φ + 'i'])
|
||||
td.attr('val', newTableData[_]['Φ' + Φ])
|
||||
td.attr('coustomTd', 1)
|
||||
tr.append(td)
|
||||
})
|
||||
// // for (let j = 0; j < ΦList.length; j++) {
|
||||
// // const td = document.createElement('td')
|
||||
// // td.innerText = newTableData[data[v]][_]
|
||||
// // th.append(td)
|
||||
// // }
|
||||
tbody.append(tr)
|
||||
})
|
||||
// $(document).click(function (e) {
|
||||
// if ($(e.target).attr('coustomTd')) {
|
||||
// const orginV = $('[coustomInput=1]').children('input').val()
|
||||
// $('[coustomInput=1]').parent().html(orginV)
|
||||
// const v = $(e.target).attr('val')
|
||||
// console.log($(e.target));
|
||||
// $(e.target).html('')
|
||||
// const input = $('<div coustomInput="1" name="feed_per_tooth" class="o_field_widget o_field_char"><input class="o_input" type="text" autocomplete="off" maxlength="20"></div>')
|
||||
// input.children('input').val(v)
|
||||
// $(e.target).append(input)
|
||||
// input.children('input').focus()
|
||||
// input.children('input').select()
|
||||
// } else if ($(e.target).attr('coustomInput')) {
|
||||
//
|
||||
// } else {
|
||||
// const orginV = $('[coustomInput=1]').children('input').val()
|
||||
// $('[coustomInput=1]').parent().html(orginV)
|
||||
// const v = $(e.target).attr('val')
|
||||
// }
|
||||
// })
|
||||
// $(document).off('change') // 防止重复绑定
|
||||
// $(document).on('change', '[coustomInput] input', function () {
|
||||
// $(this).parents('td').attr('val', $(this).val());
|
||||
// var eve1 = new Event('change');
|
||||
// var eve2 = new Event('input');
|
||||
// var eve3 = new Event('click');
|
||||
// const i = $(this).parents('td').attr('col');
|
||||
// let patchDom = table.find('tbody').children('tr').eq(i - 1);
|
||||
//
|
||||
// if (patchDom.length === 0) {
|
||||
// console.error('No such row found');
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// patchDom = patchDom.children().eq(-1);
|
||||
//
|
||||
// setTimeout(() => {
|
||||
// if (patchDom.length === 0) {
|
||||
// console.error('No such cell found');
|
||||
// return;
|
||||
// }
|
||||
// patchDom[0].dispatchEvent(eve3); // Simulate click event
|
||||
//
|
||||
// setTimeout(() => {
|
||||
// patchDom = patchDom.find('input');
|
||||
// if (patchDom.length === 0) {
|
||||
// console.error('No input found in the target cell');
|
||||
// return;
|
||||
// }
|
||||
// patchDom.val($(this).val());
|
||||
// patchDom[0].dispatchEvent(eve2);
|
||||
// patchDom[0].dispatchEvent(eve1);
|
||||
// }, 200);
|
||||
// }, 500);
|
||||
// });
|
||||
|
||||
}
|
||||
|
||||
getDomData()
|
||||
@@ -1,62 +0,0 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registry } from "@web/core/registry";
|
||||
import { barcodeGenericHandlers } from '@barcodes/barcode_handlers';
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
|
||||
// 定义新的 clickOnButton 函数
|
||||
function customClickOnButton(selector) {
|
||||
console.log("This is the custom clickOnButton function!");
|
||||
|
||||
const buttons = document.body.querySelectorAll(selector);
|
||||
|
||||
let length = buttons.length;
|
||||
if (length > 0) {
|
||||
buttons[length - 1].click();
|
||||
} else {
|
||||
console.warn(`Button with selector ${selector} not found`);
|
||||
}
|
||||
}
|
||||
|
||||
patch(barcodeGenericHandlers, "start", {
|
||||
start(env, { ui, barcode, notification }) {
|
||||
// 使用新定义的 clickOnButton 函数
|
||||
const COMMANDS = {
|
||||
"O-CMD.EDIT": () => customClickOnButton(".o_form_button_edit"),
|
||||
"O-CMD.DISCARD": () => customClickOnButton(".o_form_button_cancel"),
|
||||
"O-CMD.SAVE": () => customClickOnButton(".o_form_button_save"),
|
||||
"O-CMD.PREV": () => customClickOnButton(".o_pager_previous"),
|
||||
"O-CMD.NEXT": () => customClickOnButton(".o_pager_next"),
|
||||
"O-CMD.PAGER-FIRST": () => updatePager("first"),
|
||||
"O-CMD.PAGER-LAST": () => updatePager("last"),
|
||||
"O-CMD.CONFIRM": () => customClickOnButton(".jikimo_button_confirm"),
|
||||
"O-CMD.FLUSHED": () => customClickOnButton(".jikimo_button_flushed"),
|
||||
};
|
||||
|
||||
barcode.bus.addEventListener("barcode_scanned", (ev) => {
|
||||
const barcode = ev.detail.barcode;
|
||||
if (barcode.startsWith("O-BTN.")) {
|
||||
let targets = [];
|
||||
try {
|
||||
targets = getVisibleElements(ui.activeElement, `[barcode_trigger=${barcode.slice(6)}]`);
|
||||
} catch (_e) {
|
||||
console.warn(`Barcode '${barcode}' is not valid`);
|
||||
}
|
||||
for (let elem of targets) {
|
||||
elem.click();
|
||||
}
|
||||
}
|
||||
if (barcode.startsWith("O-CMD.")) {
|
||||
const fn = COMMANDS[barcode];
|
||||
if (fn) {
|
||||
fn();
|
||||
} else {
|
||||
notification.add(env._t("Barcode: ") + `'${barcode}'`, {
|
||||
title: env._t("Unknown barcode command"),
|
||||
type: "danger"
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
@@ -1,42 +0,0 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registry } from '@web/core/registry';
|
||||
|
||||
import { formView } from '@web/views/form/form_view';
|
||||
import { FormController } from '@web/views/form/form_controller';
|
||||
|
||||
import { listView } from '@web/views/list/list_view';
|
||||
import { ListController } from '@web/views/list/list_controller'
|
||||
|
||||
import { onRendered, onMounted } from "@odoo/owl";
|
||||
|
||||
export class RemoveFocusFormController extends FormController {
|
||||
setup() {
|
||||
super.setup();
|
||||
|
||||
onMounted(() => {
|
||||
this.__owl__.bdom.el.querySelectorAll(':focus').forEach(element => element.blur());
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
registry.category('views').add('remove_focus_form_view', {
|
||||
...formView,
|
||||
Controller: RemoveFocusFormController,
|
||||
});
|
||||
|
||||
|
||||
export class RemoveFocusListController extends ListController {
|
||||
setup() {
|
||||
super.setup();
|
||||
|
||||
onMounted(() => {
|
||||
this.__owl__.bdom.el.querySelectorAll(':focus').forEach(element => element.blur());
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
registry.category('views').add('remove_focus_list_view', {
|
||||
...listView,
|
||||
Controller: RemoveFocusListController,
|
||||
});
|
||||
@@ -1,52 +0,0 @@
|
||||
.o_list_renderer .o_list_table tbody > tr > td:not(.o_list_record_selector):not(.o_handle_cell):not(.o_list_button):not(.o_list_record_remove) {
|
||||
white-space: nowrap !important;
|
||||
}
|
||||
|
||||
.text-truncate {
|
||||
overflow: unset !important;
|
||||
text-overflow: unset !important;
|
||||
white-space: unset !important;
|
||||
}
|
||||
|
||||
|
||||
// 设置表格不超出页面宽度
|
||||
.o_form_view .o_field_widget .o_list_renderer {
|
||||
width: calc(100% - 64px) !important;
|
||||
margin:0 auto;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
// 表格针对处理
|
||||
.fixTableCss {
|
||||
text-align: center;
|
||||
.o_list_number_th,.o_list_number {
|
||||
text-align: center!important;
|
||||
}
|
||||
.ui-sortable {
|
||||
tr > td:first-child {
|
||||
padding: 0!important;
|
||||
}
|
||||
}
|
||||
.row_no {
|
||||
padding: 0!important;;
|
||||
width: 35px!important;
|
||||
}
|
||||
|
||||
th[data-name="total_length"],th[data-name="length"],th[data-name="thickness"] {
|
||||
.flex-row-reverse {
|
||||
span {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 其他不能用js处理的表格
|
||||
.otherTableFix {
|
||||
th[data-name="cutting_tool_material_id"] {
|
||||
width: 100px!important;
|
||||
}
|
||||
th[data-name="ramping_angle_max"],th[data-name="ramping_angle_min"] {
|
||||
width: 200px!important;
|
||||
}
|
||||
}
|
||||
@@ -159,6 +159,9 @@ td.o_required_modifier {
|
||||
display:inline;
|
||||
}
|
||||
.diameter{
|
||||
display: flex !important;
|
||||
justify-content: flex-start !important;
|
||||
align-items: center !important;
|
||||
}
|
||||
.o_address_format {
|
||||
display: flex !important;
|
||||
|
||||
@@ -132,9 +132,11 @@
|
||||
<group string="加工能力">
|
||||
<div>
|
||||
<field name='jg_image_id' widget="custom_many2many_checkboxes">
|
||||
|
||||
<tree>
|
||||
<field name="name"/>
|
||||
<field name="image" widget="image"/>
|
||||
<field name="image" widget="image"
|
||||
options="{'size': [100, 100], 'click enlarge': True}"/>
|
||||
|
||||
</tree>
|
||||
</field>
|
||||
@@ -147,7 +149,8 @@
|
||||
|
||||
<tree>
|
||||
<field name="name"/>
|
||||
<field name="image" widget="image"/>
|
||||
<field name="image" widget="image"
|
||||
options="{'size': [100, 100], 'click enlarge': True}"/>
|
||||
|
||||
</tree>
|
||||
</field>
|
||||
@@ -614,23 +617,4 @@
|
||||
<field name="res_model">sf.machine.control_system</field>
|
||||
<field name="view_mode">tree</field>
|
||||
</record>
|
||||
|
||||
#------------------加工精度------------------
|
||||
<record model="ir.ui.view" id="tree_sf_machining_accuracy_view">
|
||||
<field name="name">tree.sf.machining.accuracy</field>
|
||||
<field name="model">sf.machining.accuracy</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="加工精度" create="0" edit="0" delete="0">
|
||||
<field name="name"/>
|
||||
<field name="standard_tolerance"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_sf_machining_accuracy" model="ir.actions.act_window">
|
||||
<field name="name">加工精度</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">sf.machining.accuracy</field>
|
||||
<field name="view_mode">tree</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -12,6 +12,7 @@
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="mrs_production_process_parameter_form">
|
||||
<field name="model">sf.production.process.parameter</field>
|
||||
<field name="arch" type="xml">
|
||||
@@ -25,19 +26,14 @@
|
||||
<group>
|
||||
<group>
|
||||
<field name="code" readonly="1"/>
|
||||
<field name="process_id" attrs="{'readonly': [('code', '!=', False)]}"/>
|
||||
<field name="process_description" attrs="{'readonly': [('code', '!=', False)]}"/>
|
||||
<field name="process_id" readonly="1"/>
|
||||
<field name="gain_way"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="processing_day" attrs="{'readonly': [('code', '!=', False)]}"/>
|
||||
<field name="travel_day" attrs="{'readonly': [('code', '!=', False)]}"/>
|
||||
<field name="processing_mm" attrs="{'readonly': [('code', '!=', False)]}"/>
|
||||
</group>
|
||||
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="适用材料">
|
||||
<field name="materials_model_ids" attrs="{'readonly': [('code', '!=', False)]}"></field>
|
||||
<field name="materials_model_ids"></field>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
@@ -52,7 +48,7 @@
|
||||
<search>
|
||||
<filter name="filter_active" string="已归档" domain="[('active','=',False)]"/>
|
||||
<field name="name" string="名称" filter_domain="[('name','ilike',self)]"/>
|
||||
<field name="code" string="编码" filter_domain="[('code','ilike',self)]"/>
|
||||
<field name="code" string="编码" filter_domain="[('codeNum','ilike',self)]"/>
|
||||
<searchpanel class="account_root">
|
||||
<field name="process_id" icon="fa-filter"/>
|
||||
</searchpanel>
|
||||
@@ -140,7 +136,7 @@
|
||||
<field name="model">sf.production.process.category</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="表面工艺类别" default_order="sequence, id" create="0" edit="0" delete="1">
|
||||
<field name="sequence" widget="handle" string="序号" readonly="1"/>
|
||||
<field name="sequence" widget="handle" string="序号"/>
|
||||
<field name="code"/>
|
||||
<field name="name" string="名称"/>
|
||||
</tree>
|
||||
@@ -163,8 +159,7 @@
|
||||
<record model="ir.ui.view" id="sf_production_process_tree">
|
||||
<field name="model">sf.production.process</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="表面工艺" create="0" edit="0" delete="0">
|
||||
<field name="sequence" string="加工顺序" readonly="1"/>
|
||||
<tree string="表面工艺" create="0" edit="0" delete="1">
|
||||
<field name="code"/>
|
||||
<field name="name" string="名称"/>
|
||||
<field name="remark"/>
|
||||
@@ -175,7 +170,7 @@
|
||||
<record model="ir.ui.view" id="sf_production_process_form">
|
||||
<field name="model">sf.production.process</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="表面工艺" create="0" delete="0">
|
||||
<form string="表面工艺" create="0" edit="1" delete="1">
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
@@ -184,20 +179,14 @@
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="code" readonly="1"/>
|
||||
<field name="category_id" readonly="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="processing_day" readonly="1"/>
|
||||
<field name="travel_day" readonly="1"/>
|
||||
</group>
|
||||
<field name="code"/>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="可选参数">
|
||||
<field name="parameter_ids">
|
||||
<tree force_save="1" create="0">
|
||||
<tree force_save="1">
|
||||
<field name="code" readonly="1" force_save="1"/>
|
||||
<field name="name" readonly="1"/>
|
||||
<field name="name"/>
|
||||
<field name="gain_way"/>
|
||||
<field name='process_id' default="default"/>
|
||||
</tree>
|
||||
@@ -224,6 +213,7 @@
|
||||
</page>
|
||||
|
||||
</notebook>
|
||||
</group>
|
||||
<group>
|
||||
<group>
|
||||
<field name="remark"/>
|
||||
@@ -261,7 +251,7 @@
|
||||
<group>
|
||||
<group>
|
||||
<field name="materials_no" readonly="1" force_save="1"/>
|
||||
<field name="gain_way" required="0"/>
|
||||
<field name="gain_way" required="1"/>
|
||||
<field name="tensile_strength" required="1"/>
|
||||
<field name="hardness" required="1"/>
|
||||
<field name="density" readonly="1"/>
|
||||
@@ -280,9 +270,9 @@
|
||||
<notebook>
|
||||
<page string="供应商">
|
||||
<field name='supplier_ids' class="supplier_ids_set_css">
|
||||
<tree editable='bottom' delete="1">
|
||||
<tree editable='bottom'>
|
||||
<field name="sequence" widget="handle" string="序号"/>
|
||||
<field name="partner_id" string="名称" options="{'no_create': True}"/>
|
||||
<field name="partner_id" string="名称"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
|
||||
@@ -171,7 +171,7 @@
|
||||
<field name="width"/>
|
||||
<field name="height"/>
|
||||
<field name="diameter"/>
|
||||
<field name="weight" string="重量(kg)"/>
|
||||
<field name="weight"/>
|
||||
<field name="orientation_dish_diameter"/>
|
||||
<field name="clamping_diameter"/>
|
||||
<field name="clamping_num"/>
|
||||
@@ -197,7 +197,7 @@
|
||||
<field name="width"/>
|
||||
<field name="height"/>
|
||||
<field name="diameter"/>
|
||||
<field name="weight" string="重量(kg)"/>
|
||||
<field name="weight"/>
|
||||
<field name="clamping_diameter"/>
|
||||
<field name="connector_diameter"/>
|
||||
<field name="chucking_power_max"/>
|
||||
@@ -220,7 +220,7 @@
|
||||
<field name="length"/>
|
||||
<field name="width"/>
|
||||
<field name="height"/>
|
||||
<field name="weight" string="重量(kg)"/>
|
||||
<field name="weight"/>
|
||||
<field name="gripper_length_min"/>
|
||||
<field name="gripper_width_min"/>
|
||||
<field name="gripper_height_min"/>
|
||||
@@ -248,7 +248,7 @@
|
||||
<field name="length"/>
|
||||
<field name="width"/>
|
||||
<field name="height"/>
|
||||
<field name="weight" string="重量(kg)"/>
|
||||
<field name="weight"/>
|
||||
<field name="gripper_length_min"/>
|
||||
<field name="gripper_width_min"/>
|
||||
<field name="gripper_height_min"/>
|
||||
@@ -278,7 +278,7 @@
|
||||
<field name="width"/>
|
||||
<field name="height"/>
|
||||
<field name="height_tolerance_value"/>
|
||||
<field name="weight" string="重量(kg)"/>
|
||||
<field name="weight"/>
|
||||
<field name="gripper_length_min"/>
|
||||
<field name="gripper_width_min"/>
|
||||
<field name="gripper_height_min"/>
|
||||
@@ -307,7 +307,7 @@
|
||||
<field name="length"/>
|
||||
<field name="width"/>
|
||||
<field name="height"/>
|
||||
<field name="weight" string="重量(kg)"/>
|
||||
<field name="weight"/>
|
||||
<field name="gripper_length_min"/>
|
||||
<field name="gripper_width_min"/>
|
||||
<field name="gripper_height_min"/>
|
||||
@@ -335,7 +335,7 @@
|
||||
<field name="width"/>
|
||||
<field name="height"/>
|
||||
<field name="diameter"/>
|
||||
<field name="weight" string="重量(kg)"/>
|
||||
<field name="weight"/>
|
||||
<field name="gripper_length_min"/>
|
||||
<field name="gripper_width_min"/>
|
||||
<field name="gripper_height_min"/>
|
||||
|
||||
@@ -141,18 +141,12 @@
|
||||
sequence="1"
|
||||
action="action_sf_machine_brand"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_sf_machining_accuracy"
|
||||
parent="menu_sf_base"
|
||||
name="加工精度"
|
||||
sequence="1"
|
||||
action="action_sf_machining_accuracy"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_sf_machine_control_system"
|
||||
parent="menu_sf_base"
|
||||
name="数控系统"
|
||||
sequence="2"
|
||||
sequence="1"
|
||||
action="action_sf_machine_control_system"/>
|
||||
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<field name="handle_length"/>
|
||||
<field name="blade_tip_diameter"/>
|
||||
<field name="blade_tip_working_size"/>
|
||||
<field name="tip_r_size"/>
|
||||
<field name="blade_tip_taper"/>
|
||||
<field name="blade_diameter"/>
|
||||
<field name="blade_length"/>
|
||||
@@ -96,7 +95,6 @@
|
||||
<field name="handle_length"/>
|
||||
<field name="blade_tip_diameter"/>
|
||||
<field name="blade_tip_working_size"/>
|
||||
<field name="tip_r_size"/>
|
||||
<field name="blade_tip_taper"/>
|
||||
<field name="blade_diameter"/>
|
||||
<field name="blade_length"/>
|
||||
@@ -141,7 +139,6 @@
|
||||
</group>
|
||||
<group attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')]}">
|
||||
<field name="blade_tip_working_size"/>
|
||||
<field name="tip_r_size"/>
|
||||
<field name="blade_tip_diameter" class="diameter"/>
|
||||
<field name="blade_tip_taper"/>
|
||||
<field name="blade_helix_angle"/>
|
||||
|
||||
@@ -80,10 +80,10 @@
|
||||
<field name="name">sf.cutter.function.tree</field>
|
||||
<field name="model">sf.functional.cutting.tool.model</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="功能刀具类型" create="0" delete="0" edit="1" editable="bottom">
|
||||
<field name="name" string="名称" readonly="1"/>
|
||||
<field name="code" readonly="1"/>
|
||||
<field name="remark" readonly="1"/>
|
||||
<tree string="功能刀具类型" create="0" delete="0" edit="1">
|
||||
<field name="name" string="名称"/>
|
||||
<field name="code"/>
|
||||
<field name="remark"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
@@ -222,7 +222,6 @@
|
||||
<field name="handle_diameter" class="diameter"/>
|
||||
<field name="handle_length"/>
|
||||
<field name="blade_tip_working_size" class="du"/>
|
||||
<field name="tip_r_size"/>
|
||||
<field name="blade_tip_diameter" class="diameter"/>
|
||||
<field name="blade_tip_taper" class="du"/>
|
||||
<field name="blade_helix_angle" class="du"/>
|
||||
@@ -360,7 +359,6 @@
|
||||
<field name="cooling_jacket"/>
|
||||
</tree>
|
||||
</field>
|
||||
<script src="/sf_base/static/js/setTableWidth.js?time=3"></script>
|
||||
</page>
|
||||
<page string="切削速度Vc"
|
||||
attrs="{'invisible': [('cutting_tool_type', 'not in', ('整体式刀具','刀片'))]}">
|
||||
@@ -381,9 +379,6 @@
|
||||
<field name="cutting_speed"/>
|
||||
</tree>
|
||||
</field>
|
||||
<script src="/sf_base/static/js/customTable.js?time=3"></script>
|
||||
<script src="/sf_base/static/js/setTableWidth.js?time=3"></script>
|
||||
|
||||
</page>
|
||||
<page string="每齿走刀量fz"
|
||||
attrs="{'invisible': [('cutting_tool_type', 'not in', ('整体式刀具','刀片'))]}">
|
||||
@@ -396,8 +391,6 @@
|
||||
<field name="feed_per_tooth"/>
|
||||
</tree>
|
||||
</field>
|
||||
<div id="updateTable"></div>
|
||||
<script src="/sf_base/static/js/updateTable.js?time=3"></script>
|
||||
<field name="feed_per_tooth_ids_3"
|
||||
attrs="{'invisible': [('cutting_tool_type', 'not in', ('刀片'))]}">
|
||||
<tree editable="bottom" class="center" create="0" delete="0">
|
||||
@@ -562,9 +555,9 @@
|
||||
<field name="model">sf.tool.inventory</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="功能刀具清单" create="1" edit="1" delete="0" editable="bottom">
|
||||
<field name="name" attrs="{'readonly': [('id', '!=', False)]}"/>
|
||||
<field name="name"/>
|
||||
<field name="functional_cutting_tool_model_id"/>
|
||||
<field name="tool_groups_id" required="1" attrs="{'readonly': [('id', '!=', False)]}"/>
|
||||
<field name="tool_groups_id"/>
|
||||
<field name="work_material"/>
|
||||
<field name="life_span"/>
|
||||
<field name="prefix" optional="hide"/>
|
||||
@@ -584,7 +577,7 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_cutting_tool_inventory_search">
|
||||
<record model="ir.ui.view" id="view_cutting_tool_material_search">
|
||||
<field name="name">sf.tool.inventory.search</field>
|
||||
<field name="model">sf.tool.inventory</field>
|
||||
<field name="arch" type="xml">
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user