Compare commits
1 Commits
feature/pl
...
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", {
|
patch(WebClient.prototype, "kolpolok_custom_title_and_favicon.WebClient", {
|
||||||
setup() {
|
setup() {
|
||||||
this._super();
|
this._super();
|
||||||
// this.title.setParts({ zopenerp: "JIKIMO" });
|
this.title.setParts({ zopenerp: "JIKIMO" });
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -1,99 +1,41 @@
|
|||||||
|
.zoomed {
|
||||||
.processing-capabilities-grid {
|
position: fixed !important;
|
||||||
display: grid;
|
top: 50%;
|
||||||
grid-template-columns: repeat(6, 1fr);
|
left: 50%;
|
||||||
gap: 10px;
|
transform: translate(-50%, -50%) scale(10);
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid-item {
|
.many2many_flex {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-content {
|
.many2many_flex>div {
|
||||||
display: flex;
|
margin-right: 15px;
|
||||||
flex-direction: column;
|
display: flex;
|
||||||
align-items: center;
|
flex-direction: column;
|
||||||
text-align: center;
|
align-items: center;
|
||||||
}
|
|
||||||
/*控制图片大小*/
|
|
||||||
.item-icon {
|
|
||||||
width: 50px;
|
|
||||||
height: 50px;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-label {
|
.many2many_flex>div>:nth-child(2) {
|
||||||
font-size: 12px;
|
position: relative;
|
||||||
word-break: break-word;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1200px) {
|
.close {
|
||||||
.processing-capabilities-grid {
|
width: 20px;
|
||||||
grid-template-columns: repeat(4, 1fr);
|
height: 20px;
|
||||||
}
|
position: absolute;
|
||||||
|
top: -8.8px;
|
||||||
|
right: -8.8px;
|
||||||
|
color: #fff;
|
||||||
|
background-color: #000;
|
||||||
|
opacity: 0;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 20px;
|
||||||
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
.img_close {
|
||||||
.processing-capabilities-grid {
|
opacity: 1;
|
||||||
grid-template-columns: repeat(3, 1fr);
|
transform: scale(0.1);
|
||||||
}
|
cursor: pointer;
|
||||||
}
|
|
||||||
|
|
||||||
@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 {
|
|
||||||
position: absolute;
|
|
||||||
top: 20px;
|
|
||||||
right: 30px;
|
|
||||||
color: #fff;
|
|
||||||
font-size: 40px;
|
|
||||||
font-weight: bold;
|
|
||||||
transition: 0.3s;
|
|
||||||
cursor: pointer;
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-preview-close:hover,
|
|
||||||
.image-preview-close:focus {
|
|
||||||
opacity: 1;
|
|
||||||
text-decoration: none;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
@@ -4,57 +4,35 @@ import {Many2ManyCheckboxesField} from "@web/views/fields/many2many_checkboxes/m
|
|||||||
import {registry} from "@web/core/registry";
|
import {registry} from "@web/core/registry";
|
||||||
|
|
||||||
export class MyCustomWidget extends Many2ManyCheckboxesField {
|
export class MyCustomWidget extends Many2ManyCheckboxesField {
|
||||||
|
// 你可以重写或者添加一些方法和属性
|
||||||
|
// 例如,你可以重写setup方法来添加一些事件监听器或者初始化一些变量
|
||||||
setup() {
|
setup() {
|
||||||
super.setup();
|
super.setup(); // 调用父类的setup方法
|
||||||
|
// 你自己的代码
|
||||||
}
|
}
|
||||||
|
|
||||||
onImageClick(event, src) {
|
onImageClick(event) {
|
||||||
event.preventDefault();
|
// 放大图片逻辑
|
||||||
event.stopPropagation();
|
// 获取图片元素
|
||||||
|
const img = event.target;
|
||||||
|
const close = img.nextSibling;
|
||||||
|
|
||||||
// 创建预览框
|
// 实现放大图片逻辑
|
||||||
const previewContainer = document.createElement('div');
|
// 比如使用 CSS 放大
|
||||||
previewContainer.className = 'image-preview-container';
|
img.parentElement.classList.add('zoomed');
|
||||||
|
close.classList.add('img_close');
|
||||||
|
}
|
||||||
|
|
||||||
const previewImg = document.createElement('img');
|
onCloseClick(event) {
|
||||||
previewImg.src = src;
|
const close = event.target;
|
||||||
previewImg.className = 'image-preview';
|
const img = close.previousSibling;
|
||||||
// 设置放大的预览图片大小
|
img.parentElement.classList.remove('zoomed');
|
||||||
previewImg.style.width = '600px';
|
close.classList.remove('img_close');
|
||||||
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();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 使用 setTimeout 来触发过渡效果
|
|
||||||
setTimeout(() => {
|
|
||||||
previewContainer.classList.add('show');
|
|
||||||
}, 10);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MyCustomWidget.template = "jikimo_frontend.MyCustomWidget";
|
MyCustomWidget.template = "jikimo_frontend.MyCustomWidget";
|
||||||
|
// MyCustomWidget.supportedTypes = ['many2many'];
|
||||||
|
|
||||||
|
registry.category("fields").add("custom_many2many_checkboxes", MyCustomWidget);
|
||||||
|
|
||||||
registry.category("fields").add("custom_many2many_checkboxes", MyCustomWidget);
|
|
||||||
@@ -2,22 +2,27 @@
|
|||||||
<templates xml:space="preserve">
|
<templates xml:space="preserve">
|
||||||
|
|
||||||
<t t-name="jikimo_frontend.MyCustomWidget" owl="1">
|
<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]">
|
<t t-foreach="items" t-as="item" t-key="item[0]">
|
||||||
<div class="grid-item">
|
<div>
|
||||||
<CheckBox
|
<CheckBox
|
||||||
value="isSelected(item)"
|
value="isSelected(item)"
|
||||||
disabled="props.readonly"
|
disabled="props.readonly"
|
||||||
onChange="(ev) => this.onChange(item[0], ev)"
|
onChange="(ev) => this.onChange(item[0], ev)"
|
||||||
>
|
>
|
||||||
<div class="item-content">
|
<t t-esc="item[1]"/>
|
||||||
<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>
|
|
||||||
</CheckBox>
|
</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>
|
||||||
|
</div>
|
||||||
|
|
||||||
</t>
|
</t>
|
||||||
</div>
|
</div>
|
||||||
</t>
|
</t>
|
||||||
|
|
||||||
</templates>
|
</templates>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {patch} from '@web/core/utils/patch';
|
|||||||
import {_t} from "@web/core/l10n/translation";
|
import {_t} from "@web/core/l10n/translation";
|
||||||
import {FormStatusIndicator} from "@web/views/form/form_status_indicator/form_status_indicator";
|
import {FormStatusIndicator} from "@web/views/form/form_status_indicator/form_status_indicator";
|
||||||
import {ListRenderer} from "@web/views/list/list_renderer";
|
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";
|
import {Field} from "@web/views/fields/field";
|
||||||
|
|
||||||
@@ -53,23 +53,6 @@ const tableRequiredList = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
patch(FormStatusIndicator.prototype, 'jikimo_frontend.FormStatusIndicator', {
|
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() {
|
async _onDiscardChanges() {
|
||||||
// var self = this;
|
// var self = this;
|
||||||
@@ -170,36 +153,47 @@ patch(ListRenderer.prototype, 'jikimo_frontend.ListRenderer', {
|
|||||||
|
|
||||||
|
|
||||||
// 根据进度条设置水印
|
// 根据进度条设置水印
|
||||||
// const statusbar_params = {
|
const statusbar_params = {
|
||||||
// '已完工': 'bg-primary',
|
'已完工': 'bg-primary',
|
||||||
// '完成': 'bg-primary',
|
'完成': 'bg-primary',
|
||||||
// '采购订单': 'bg-primary',
|
'采购订单': 'bg-primary',
|
||||||
// '作废': 'bg-danger',
|
'作废': 'bg-danger',
|
||||||
// '封存(报废)': 'bg-danger',
|
'封存(报废)': 'bg-danger',
|
||||||
// }
|
}
|
||||||
// patch(StatusBarField.prototype, 'jikimo_frontend.StatusBarField', {
|
patch(StatusBarField.prototype, 'jikimo_frontend.StatusBarField', {
|
||||||
// setup() {
|
setup() {
|
||||||
// owl.onMounted(this.ribbons);
|
owl.onMounted(this.ribbons);
|
||||||
// return this._super(...arguments);
|
return this._super(...arguments);
|
||||||
// },
|
},
|
||||||
// ribbons() {
|
ribbons() {
|
||||||
// try {
|
try {
|
||||||
// const dom = $('.o_form_sheet.position-relative')
|
const dom = $('.o_form_sheet.position-relative')
|
||||||
// const status = statusbar_params[this.currentName]
|
const status = statusbar_params[this.currentName]
|
||||||
// if(status && dom.length) {
|
if(status && dom.length) {
|
||||||
// dom.prepend(`<div class="o_widget o_widget_web_ribbon">
|
dom.prepend(`<div class="o_widget o_widget_web_ribbon">
|
||||||
// <div class="ribbon ribbon-top-right">
|
<div class="ribbon ribbon-top-right">
|
||||||
// <span class="bg-opacity-75 ${status}" title="">${this.currentName}</span>
|
<span class="bg-opacity-75 ${status}" title="">${this.currentName}</span>
|
||||||
// </div>
|
</div>
|
||||||
// </div>`)
|
</div>`)
|
||||||
// }
|
}
|
||||||
// } catch (e) {
|
} catch (e) {
|
||||||
// console.log(e)
|
console.log(e)
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// })
|
})
|
||||||
|
|
||||||
$(function () {
|
$(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() {
|
function customRequired() {
|
||||||
let timer = null
|
let timer = null
|
||||||
|
|||||||
@@ -108,10 +108,6 @@ td.o_required_modifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.color_3 {
|
.color_3 {
|
||||||
background-color: #808080;
|
|
||||||
}
|
|
||||||
|
|
||||||
.color_4 {
|
|
||||||
background-color: rgb(255, 150, 0);
|
background-color: rgb(255, 150, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -525,14 +521,4 @@ div:has(.o_required_modifier) > label::before {
|
|||||||
.o_list_renderer.o_renderer {
|
.o_list_renderer.o_renderer {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
overflow-x: auto;
|
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">
|
<template id="favicon_icon" inherit_id="web.layout" name="Web layout">
|
||||||
<!-- change the title with reliance partner -->
|
<!-- change the title with reliance partner -->
|
||||||
<!-- <xpath expr="//head//title" position="before">
|
<xpath expr="//head//title" position="before">
|
||||||
<title t-esc="'JIKIMO'"/>
|
<title t-esc="'JIKIMO'"/>
|
||||||
</xpath> -->
|
</xpath>
|
||||||
<!-- change the default favicon icon with -->
|
<!-- change the default favicon icon with -->
|
||||||
<xpath expr="//head//link[@rel='shortcut icon']" position="replace">
|
<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"/>
|
<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 及管理数据库 -->
|
<!-- hide 登录页面 powerd by odoo 及管理数据库 -->
|
||||||
<template id="login_page_layout" inherit_id="web.login_layout" name="Login Page Layout">
|
<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>
|
</template>
|
||||||
|
|
||||||
<!-- 隐藏odoo版本信息 -->
|
<!-- 隐藏odoo版本信息 -->
|
||||||
|
|||||||
@@ -301,27 +301,53 @@ def unlink(self):
|
|||||||
# This is used to restrict the access right to unlink a record
|
# This is used to restrict the access right to unlink a record
|
||||||
current_model_id = self.env['ir.model'].sudo().search(
|
current_model_id = self.env['ir.model'].sudo().search(
|
||||||
[('model', '=', self._name)]).id
|
[('model', '=', self._name)]).id
|
||||||
access_right_rec = self.env['access.right'].sudo().search_read(
|
# access_right_rec = self.env['access.right'].sudo().search_read(
|
||||||
[('model_id', '=', current_model_id)], ['model_id', 'is_delete',
|
# [('model_id', '=', current_model_id)], ['model_id', 'is_delete',
|
||||||
'groups_id'])
|
# 'groups_id'])
|
||||||
if access_right_rec and not self.env.is_admin():
|
# if access_right_rec and not self.env.is_admin():
|
||||||
for rec in access_right_rec:
|
# for rec in access_right_rec:
|
||||||
group_name = self.env['ir.model.data'].sudo().search([
|
# group_name = self.env['ir.model.data'].sudo().search([
|
||||||
('model', '=', 'res.groups'),
|
# ('model', '=', 'res.groups'),
|
||||||
('res_id', '=', rec['groups_id'][0])
|
# ('res_id', '=', rec['groups_id'][0])
|
||||||
]).name
|
# ]).name
|
||||||
module_name = self.env['ir.model.data'].sudo().search([
|
# module_name = self.env['ir.model.data'].sudo().search([
|
||||||
('model', '=', 'res.groups'),
|
# ('model', '=', 'res.groups'),
|
||||||
('res_id', '=', rec['groups_id'][0])
|
# ('res_id', '=', rec['groups_id'][0])
|
||||||
]).module
|
# ]).module
|
||||||
group = module_name + "." + group_name
|
# group = module_name + "." + group_name
|
||||||
if self.env.user.has_group(group):
|
# if self.env.user.has_group(group):
|
||||||
if rec['is_delete']:
|
# if rec['is_delete']:
|
||||||
raise UserError(_('You are restricted from performing this'
|
# raise UserError(_('You are restricted from performing this'
|
||||||
' operation. Please contact the'
|
# ' operation. Please contact the'
|
||||||
' administrator.'))
|
# ' 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']
|
||||||
|
)
|
||||||
|
|
||||||
|
if access_right_rec and not self.env.is_admin():
|
||||||
|
for rec in access_right_rec:
|
||||||
|
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
|
return True
|
||||||
|
|
||||||
|
|
||||||
BaseModel._create = _create
|
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': str(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,2 +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
|
|
||||||
|
@@ -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)
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
# 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):
|
class MrpProduction(models.Model):
|
||||||
@@ -12,8 +12,7 @@ class MrpProduction(models.Model):
|
|||||||
check_ids = fields.One2many('quality.check', 'production_id', string="Checks")
|
check_ids = fields.One2many('quality.check', 'production_id', string="Checks")
|
||||||
|
|
||||||
def _split_productions(self, amounts=False, cancel_remaining_qty=False, set_consumed_qty=False):
|
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,
|
productions = super()._split_productions(amounts=amounts, cancel_remaining_qty=cancel_remaining_qty, set_consumed_qty=set_consumed_qty)
|
||||||
set_consumed_qty=set_consumed_qty)
|
|
||||||
backorders = productions[1:]
|
backorders = productions[1:]
|
||||||
if not backorders:
|
if not backorders:
|
||||||
return productions
|
return productions
|
||||||
@@ -21,4 +20,3 @@ class MrpProduction(models.Model):
|
|||||||
if wo.current_quality_check_id.component_id:
|
if wo.current_quality_check_id.component_id:
|
||||||
wo.current_quality_check_id._update_component_quantity()
|
wo.current_quality_check_id._update_component_quantity()
|
||||||
return productions
|
return productions
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class MrpWorkcenter(models.Model):
|
|||||||
|
|
||||||
class MrpProductionWorkcenterLine(models.Model):
|
class MrpProductionWorkcenterLine(models.Model):
|
||||||
_name = 'mrp.workorder'
|
_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_ids = fields.Many2many('quality.point', compute='_compute_quality_point_ids', store=True)
|
||||||
quality_point_count = fields.Integer('Steps', compute='_compute_quality_point_count')
|
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_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_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',
|
is_last_unfinished_wo = fields.Boolean('Is Last Work Order To Process', compute='_compute_is_last_unfinished_wo', store=False)
|
||||||
store=False)
|
|
||||||
lot_id = fields.Many2one(related='current_quality_check_id.lot_id', readonly=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_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_id = fields.Many2one(related='current_quality_check_id.move_line_id', readonly=False)
|
||||||
move_line_ids = fields.One2many(related='move_id.move_line_ids')
|
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",
|
quality_state = fields.Selection(related='current_quality_check_id.quality_state', string="Quality State", readonly=False)
|
||||||
readonly=False)
|
|
||||||
qty_done = fields.Float(related='current_quality_check_id.qty_done', 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',
|
test_type_id = fields.Many2one('quality.point.test_type', 'Test Type', related='current_quality_check_id.test_type_id')
|
||||||
related='current_quality_check_id.test_type_id')
|
|
||||||
test_type = fields.Char(related='test_type_id.technical_name')
|
test_type = fields.Char(related='test_type_id.technical_name')
|
||||||
user_id = fields.Many2one(related='current_quality_check_id.user_id', readonly=False)
|
user_id = fields.Many2one(related='current_quality_check_id.user_id', readonly=False)
|
||||||
worksheet_page = fields.Integer('Worksheet page')
|
worksheet_page = fields.Integer('Worksheet page')
|
||||||
@@ -68,8 +65,7 @@ class MrpProductionWorkcenterLine(models.Model):
|
|||||||
def _compute_quality_point_ids(self):
|
def _compute_quality_point_ids(self):
|
||||||
for workorder in self:
|
for workorder in self:
|
||||||
quality_points = workorder.operation_id.quality_point_ids
|
quality_points = workorder.operation_id.quality_point_ids
|
||||||
quality_points = quality_points.filtered(
|
quality_points = quality_points.filtered(lambda qp: not qp.product_ids or workorder.production_id.product_id in qp.product_ids)
|
||||||
lambda qp: not qp.product_ids or workorder.production_id.product_id in qp.product_ids)
|
|
||||||
workorder.quality_point_ids = quality_points
|
workorder.quality_point_ids = quality_points
|
||||||
|
|
||||||
@api.depends('operation_id')
|
@api.depends('operation_id')
|
||||||
@@ -95,8 +91,7 @@ class MrpProductionWorkcenterLine(models.Model):
|
|||||||
@api.depends('check_ids')
|
@api.depends('check_ids')
|
||||||
def _compute_finished_product_check_ids(self):
|
def _compute_finished_product_check_ids(self):
|
||||||
for wo in self:
|
for wo in self:
|
||||||
wo.finished_product_check_ids = wo.check_ids.filtered(
|
wo.finished_product_check_ids = wo.check_ids.filtered(lambda c: c.finished_product_sequence == wo.qty_produced)
|
||||||
lambda c: c.finished_product_sequence == wo.qty_produced)
|
|
||||||
|
|
||||||
def write(self, values):
|
def write(self, values):
|
||||||
res = super().write(values)
|
res = super().write(values)
|
||||||
@@ -143,8 +138,7 @@ class MrpProductionWorkcenterLine(models.Model):
|
|||||||
self.finished_lot_id = self.env['stock.lot'].create({
|
self.finished_lot_id = self.env['stock.lot'].create({
|
||||||
'product_id': self.product_id.id,
|
'product_id': self.product_id.id,
|
||||||
'company_id': self.company_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[
|
'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'),
|
||||||
'ir.sequence'].next_by_code('stock.lot.serial'),
|
|
||||||
})
|
})
|
||||||
|
|
||||||
def _create_subsequent_checks(self):
|
def _create_subsequent_checks(self):
|
||||||
@@ -158,7 +152,7 @@ class MrpProductionWorkcenterLine(models.Model):
|
|||||||
"""
|
"""
|
||||||
# Create another quality check if necessary
|
# Create another quality check if necessary
|
||||||
next_check = self.current_quality_check_id.next_check_id
|
next_check = self.current_quality_check_id.next_check_id
|
||||||
if next_check.component_id != self.current_quality_check_id.product_id or \
|
if next_check.component_id != self.current_quality_check_id.product_id or\
|
||||||
next_check.point_id != self.current_quality_check_id.point_id:
|
next_check.point_id != self.current_quality_check_id.point_id:
|
||||||
# TODO: manage reservation here
|
# TODO: manage reservation here
|
||||||
|
|
||||||
@@ -285,8 +279,7 @@ class MrpProductionWorkcenterLine(models.Model):
|
|||||||
if self.current_quality_check_id:
|
if self.current_quality_check_id:
|
||||||
team = self.current_quality_check_id.team_id
|
team = self.current_quality_check_id.team_id
|
||||||
else:
|
else:
|
||||||
team = self.env['quality.alert.team'].search(
|
team = self.env['quality.alert.team'].search(['|', ('company_id', '=', self.company_id.id), ('company_id', '=', False)], limit=1)
|
||||||
['|', ('company_id', '=', self.company_id.id), ('company_id', '=', False)], limit=1)
|
|
||||||
return {
|
return {
|
||||||
'type': 'ir.actions.act_window',
|
'type': 'ir.actions.act_window',
|
||||||
'res_model': 'quality.check',
|
'res_model': 'quality.check',
|
||||||
@@ -327,8 +320,7 @@ class MrpProductionWorkcenterLine(models.Model):
|
|||||||
production = wo.production_id
|
production = wo.production_id
|
||||||
|
|
||||||
move_raw_ids = wo.move_raw_ids.filtered(lambda m: m.state not in ('done', 'cancel'))
|
move_raw_ids = wo.move_raw_ids.filtered(lambda m: m.state not in ('done', 'cancel'))
|
||||||
move_finished_ids = wo.move_finished_ids.filtered(
|
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)
|
||||||
lambda m: m.state not in ('done', 'cancel') and m.product_id != wo.production_id.product_id)
|
|
||||||
previous_check = self.env['quality.check']
|
previous_check = self.env['quality.check']
|
||||||
for point in wo.quality_point_ids:
|
for point in wo.quality_point_ids:
|
||||||
# Check if we need a quality control for this point
|
# Check if we need a quality control for this point
|
||||||
@@ -350,13 +342,11 @@ class MrpProductionWorkcenterLine(models.Model):
|
|||||||
if point.test_type == 'register_byproducts':
|
if point.test_type == 'register_byproducts':
|
||||||
moves = move_finished_ids.filtered(lambda m: m.product_id == point.component_id)
|
moves = move_finished_ids.filtered(lambda m: m.product_id == point.component_id)
|
||||||
if not moves:
|
if not moves:
|
||||||
moves = production.move_finished_ids.filtered(
|
moves = production.move_finished_ids.filtered(lambda m: not m.operation_id and m.product_id == point.component_id)
|
||||||
lambda m: not m.operation_id and m.product_id == point.component_id)
|
|
||||||
elif point.test_type == 'register_consumed_materials':
|
elif point.test_type == 'register_consumed_materials':
|
||||||
moves = move_raw_ids.filtered(lambda m: m.product_id == point.component_id)
|
moves = move_raw_ids.filtered(lambda m: m.product_id == point.component_id)
|
||||||
if not moves:
|
if not moves:
|
||||||
moves = production.move_raw_ids.filtered(
|
moves = production.move_raw_ids.filtered(lambda m: not m.operation_id and m.product_id == point.component_id)
|
||||||
lambda m: not m.operation_id and m.product_id == point.component_id)
|
|
||||||
else:
|
else:
|
||||||
check = self.env['quality.check'].create(values)
|
check = self.env['quality.check'].create(values)
|
||||||
previous_check.next_check_id = check
|
previous_check.next_check_id = check
|
||||||
@@ -373,10 +363,8 @@ class MrpProductionWorkcenterLine(models.Model):
|
|||||||
processed_move |= moves
|
processed_move |= moves
|
||||||
|
|
||||||
# Generate quality checks associated with unreferenced components
|
# Generate quality checks associated with unreferenced components
|
||||||
moves_without_check = ((move_raw_ids | move_finished_ids) - processed_move).filtered(lambda move: (
|
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)
|
||||||
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
|
||||||
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:
|
for move in moves_without_check:
|
||||||
values = {
|
values = {
|
||||||
'production_id': production.id,
|
'production_id': production.id,
|
||||||
@@ -424,8 +412,7 @@ class MrpProductionWorkcenterLine(models.Model):
|
|||||||
|
|
||||||
backorder = False
|
backorder = False
|
||||||
# Trigger the backorder process if we produce less than expected
|
# Trigger the backorder process if we produce less than expected
|
||||||
if float_compare(self.qty_producing, self.qty_remaining,
|
if float_compare(self.qty_producing, self.qty_remaining, precision_rounding=self.product_uom_id.rounding) == -1 and self.is_first_started_wo:
|
||||||
precision_rounding=self.product_uom_id.rounding) == -1 and self.is_first_started_wo:
|
|
||||||
backorder = self.production_id._split_productions()[1:]
|
backorder = self.production_id._split_productions()[1:]
|
||||||
for workorder in backorder.workorder_ids:
|
for workorder in backorder.workorder_ids:
|
||||||
if workorder.product_tracking == 'serial':
|
if workorder.product_tracking == 'serial':
|
||||||
@@ -436,8 +423,7 @@ class MrpProductionWorkcenterLine(models.Model):
|
|||||||
else:
|
else:
|
||||||
if self.operation_id:
|
if self.operation_id:
|
||||||
backorder = (self.production_id.procurement_group_id.mrp_production_ids - self.production_id).filtered(
|
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 (
|
lambda p: p.workorder_ids.filtered(lambda wo: wo.operation_id == self.operation_id).state not in ('cancel', 'done')
|
||||||
'cancel', 'done')
|
|
||||||
)[:1]
|
)[:1]
|
||||||
else:
|
else:
|
||||||
index = list(self.production_id.workorder_ids).index(self)
|
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()
|
wo.current_quality_check_id._update_component_quantity()
|
||||||
if not self.env.context.get('no_start_next'):
|
if not self.env.context.get('no_start_next'):
|
||||||
if self.operation_id:
|
if self.operation_id:
|
||||||
return backorder.workorder_ids.filtered(
|
return backorder.workorder_ids.filtered(lambda wo: wo.operation_id == self.operation_id).open_tablet_view()
|
||||||
lambda wo: wo.operation_id == self.operation_id).open_tablet_view()
|
|
||||||
else:
|
else:
|
||||||
index = list(self.production_id.workorder_ids).index(self)
|
index = list(self.production_id.workorder_ids).index(self)
|
||||||
return backorder.workorder_ids[index].open_tablet_view()
|
return backorder.workorder_ids[index].open_tablet_view()
|
||||||
@@ -481,8 +466,7 @@ class MrpProductionWorkcenterLine(models.Model):
|
|||||||
|
|
||||||
def open_tablet_view(self):
|
def open_tablet_view(self):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
if not self.is_user_working and self.working_state != 'blocked' and self.state in (
|
if not self.is_user_working and self.working_state != 'blocked' and self.state in ('ready', 'waiting', 'progress', 'pending'):
|
||||||
'ready', 'waiting', 'progress', 'pending'):
|
|
||||||
self.button_start()
|
self.button_start()
|
||||||
action = self.env["ir.actions.actions"]._for_xml_id("mrp_workorder.tablet_client_action")
|
action = self.env["ir.actions.actions"]._for_xml_id("mrp_workorder.tablet_client_action")
|
||||||
action['target'] = 'fullscreen'
|
action['target'] = 'fullscreen'
|
||||||
@@ -537,8 +521,7 @@ class MrpProductionWorkcenterLine(models.Model):
|
|||||||
data = {
|
data = {
|
||||||
'mrp.workorder': self.read(self._get_fields_for_tablet(), load=False)[0],
|
'mrp.workorder': self.read(self._get_fields_for_tablet(), load=False)[0],
|
||||||
'quality.check': self.check_ids._get_fields_for_tablet(sorted_check_list),
|
'quality.check': self.check_ids._get_fields_for_tablet(sorted_check_list),
|
||||||
'operation': self.operation_id.read(self.operation_id._get_fields_for_tablet())[
|
'operation': self.operation_id.read(self.operation_id._get_fields_for_tablet())[0] if self.operation_id else {},
|
||||||
0] if self.operation_id else {},
|
|
||||||
'working_state': self.workcenter_id.working_state,
|
'working_state': self.workcenter_id.working_state,
|
||||||
'views': {
|
'views': {
|
||||||
'workorder': self.env.ref('mrp_workorder.mrp_workorder_view_form_tablet').id,
|
'workorder': self.env.ref('mrp_workorder.mrp_workorder_view_form_tablet').id,
|
||||||
@@ -570,8 +553,7 @@ class MrpProductionWorkcenterLine(models.Model):
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
'duration': self.duration,
|
'duration': self.duration,
|
||||||
'position': bisect_left(last30op, self.duration),
|
'position': bisect_left(last30op, self.duration), # which position regarded other workorders ranked by duration
|
||||||
# which position regarded other workorders ranked by duration
|
|
||||||
'quality_score': score,
|
'quality_score': score,
|
||||||
'show_rainbow': show_rainbow,
|
'show_rainbow': show_rainbow,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,44 +1,41 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<odoo>
|
<odoo>
|
||||||
<!-- Manufacturing Order for Planing view -->
|
<!-- Manufacturing Order for Planing view -->
|
||||||
<record id="mrp_production_tree_view_planning" model="ir.ui.view">
|
<record id="mrp_production_tree_view_planning" model="ir.ui.view">
|
||||||
<field name="name">mrp.production.tree.inherit.planning</field>
|
<field name="name">mrp.production.tree.inherit.planning</field>
|
||||||
<field name="model">mrp.production</field>
|
<field name="model">mrp.production</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<tree default_order="date_planned_start asc" decoration-info="state=='confirmed'"
|
<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">
|
||||||
decoration-danger="date_planned_start<current_date and state not in ('done','cancel')"
|
<field name="message_needaction" invisible="1"/>
|
||||||
decoration-muted="state in ('done','cancel')" string="Manufacturing Orders" name="Production">
|
<field name="name"/>
|
||||||
<field name="message_needaction" invisible="1"/>
|
<field name="date_planned_start"/>
|
||||||
<field name="name"/>
|
<field name="product_id"/>
|
||||||
<field name="date_planned_start"/>
|
<field name="product_qty" sum="Total Qty" string="Quantity"/>
|
||||||
<field name="product_id"/>
|
<field name="product_uom_id" string="Unit of Measure" options="{'no_open':True,'no_create':True}" groups="uom.group_uom"/>
|
||||||
<field name="product_qty" sum="Total Qty" string="Quantity"/>
|
<field name="reservation_state" string="Availability"/>
|
||||||
<field name="product_uom_id" string="Unit of Measure" options="{'no_open':True,'no_create':True}"
|
<field name="origin"/>
|
||||||
groups="uom.group_uom"/>
|
<field name="state"/>
|
||||||
<field name="reservation_state" string="Availability"/>
|
</tree>
|
||||||
<field name="origin"/>
|
</field>
|
||||||
<field name="state"/>
|
</record>
|
||||||
</tree>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- <record id="mrp_production_form_inherit_planning" model="ir.ui.view">-->
|
<!-- <record id="mrp_production_form_inherit_planning" model="ir.ui.view">-->
|
||||||
<!-- <field name="name">mrp.production.form_inherit_planning</field>-->
|
<!-- <field name="name">mrp.production.form_inherit_planning</field>-->
|
||||||
<!-- <field name="model">mrp.production</field>-->
|
<!-- <field name="model">mrp.production</field>-->
|
||||||
<!-- <field name="inherit_id" ref="mrp.mrp_production_form_view"/>-->
|
<!-- <field name="inherit_id" ref="mrp.mrp_production_form_view"/>-->
|
||||||
<!-- <field name="arch" type="xml">-->
|
<!-- <field name="arch" type="xml">-->
|
||||||
<!-- <xpath expr="div[hasclass('oe_chatter')]" position="replace">-->
|
<!-- <xpath expr="div[hasclass('oe_chatter')]" position="replace">-->
|
||||||
<!-- <!– 这里放置替换后的内容 –>-->
|
<!-- <!– 这里放置替换后的内容 –>-->
|
||||||
<!-- </xpath>-->
|
<!-- </xpath>-->
|
||||||
<!-- <xpath expr="//notebook" position="after">-->
|
<!-- <xpath expr="//notebook" position="after">-->
|
||||||
<!-- <div class="oe_chatter">-->
|
<!-- <div class="oe_chatter">-->
|
||||||
<!-- <field name="message_follower_ids"/>-->
|
<!-- <field name="message_follower_ids"/>-->
|
||||||
<!-- <field name="activity_ids"/>-->
|
<!-- <field name="activity_ids"/>-->
|
||||||
<!-- <field name="message_ids"/>-->
|
<!-- <field name="message_ids"/>-->
|
||||||
<!-- </div>-->
|
<!-- </div>-->
|
||||||
<!-- </xpath>-->
|
<!-- </xpath>-->
|
||||||
<!-- </field>-->
|
<!-- </field>-->
|
||||||
<!-- </record>-->
|
<!-- </record>-->
|
||||||
|
|
||||||
<record id="mrp_production_view_search_inherit_planning" model="ir.ui.view">
|
<record id="mrp_production_view_search_inherit_planning" model="ir.ui.view">
|
||||||
<field name="name">mrp.production.search.view.inherit.planning</field>
|
<field name="name">mrp.production.search.view.inherit.planning</field>
|
||||||
@@ -46,9 +43,7 @@
|
|||||||
<field name="inherit_id" ref="mrp.view_mrp_production_filter"/>
|
<field name="inherit_id" ref="mrp.view_mrp_production_filter"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<filter name="filter_planned" position="attributes">
|
<filter name="filter_planned" position="attributes">
|
||||||
<attribute name="domain">[('is_planned', '=', True), ('date_planned_start', '!=', False),
|
<attribute name="domain">[('is_planned', '=', True), ('date_planned_start', '!=', False), ('date_planned_finished', '!=', False)]</attribute>
|
||||||
('date_planned_finished', '!=', False)]
|
|
||||||
</attribute>
|
|
||||||
</filter>
|
</filter>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
@@ -56,33 +51,30 @@
|
|||||||
<record id="production_order_unplan_server_action" model="ir.actions.server">
|
<record id="production_order_unplan_server_action" model="ir.actions.server">
|
||||||
<field name="name">Unplan orders</field>
|
<field name="name">Unplan orders</field>
|
||||||
<field name="model_id" ref="mrp.model_mrp_production"/>
|
<field name="model_id" ref="mrp.model_mrp_production"/>
|
||||||
<field name="binding_model_id" ref="mrp.model_mrp_production"/>
|
<field name="binding_model_id" ref="mrp.model_mrp_production" />
|
||||||
<field name="binding_view_types">list</field>
|
<field name="binding_view_types">list</field>
|
||||||
<field name="state">code</field>
|
<field name="state">code</field>
|
||||||
<field name="code">records.button_unplan()</field>
|
<field name="code">records.button_unplan()</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="mrp.act_product_mrp_production_workcenter" model="ir.actions.act_window">
|
<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),
|
<field name="domain">[('bom_id', '!=', False), ('bom_id.operation_ids.workcenter_id', '=', active_id), ('date_planned_start', '!=', False), ('date_planned_finished', '!=', False)]</field>
|
||||||
('date_planned_start', '!=', False), ('date_planned_finished', '!=', False)]
|
|
||||||
</field>
|
|
||||||
<field name="view_id" ref="mrp_production_tree_view_planning"/>
|
<field name="view_id" ref="mrp_production_tree_view_planning"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|
||||||
<menuitem id="mrp_workorder_menu_planning"
|
<menuitem id="mrp_workorder_menu_planning"
|
||||||
name="Work Orders"
|
name="Work Orders"
|
||||||
sequence="2"
|
sequence="2"
|
||||||
parent="mrp.mrp_planning_menu_root"
|
parent="mrp.mrp_planning_menu_root"
|
||||||
groups="mrp.group_mrp_routings"/>
|
groups="mrp.group_mrp_routings"/>
|
||||||
<menuitem id="menu_mrp_workorder_production"
|
<menuitem id="menu_mrp_workorder_production"
|
||||||
name="Planning by Production"
|
name="Planning by Production"
|
||||||
sequence="1"
|
sequence="1"
|
||||||
action="mrp.action_mrp_workorder_production"
|
action="mrp.action_mrp_workorder_production"
|
||||||
parent="mrp_workorder_menu_planning"/>
|
parent="mrp_workorder_menu_planning"/>
|
||||||
<menuitem id="menu_mrp_workorder_workcenter"
|
<menuitem id="menu_mrp_workorder_workcenter"
|
||||||
name="Planning by Workcenter"
|
name="Planning by Workcenter"
|
||||||
sequence="2"
|
sequence="2"
|
||||||
action="mrp_workorder.action_mrp_workorder_dependencies_workcenter"
|
action="mrp_workorder.action_mrp_workorder_dependencies_workcenter"
|
||||||
parent="mrp_workorder_menu_planning"/>
|
parent="mrp_workorder_menu_planning"/>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
@@ -27,13 +27,6 @@
|
|||||||
</field>
|
</field>
|
||||||
</page>
|
</page>
|
||||||
</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>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 702 B |
@@ -1024,7 +1024,7 @@
|
|||||||
<menuitem
|
<menuitem
|
||||||
id="menu_quality_root"
|
id="menu_quality_root"
|
||||||
name="Quality"
|
name="Quality"
|
||||||
web_icon="quality_control,static/description/质量.png"
|
web_icon="quality_control,static/description/icon.svg"
|
||||||
sequence="150"
|
sequence="150"
|
||||||
groups="quality.group_quality_user"/>
|
groups="quality.group_quality_user"/>
|
||||||
|
|
||||||
@@ -1033,7 +1033,7 @@
|
|||||||
name="Overview"
|
name="Overview"
|
||||||
action="quality_alert_team_action"
|
action="quality_alert_team_action"
|
||||||
parent="menu_quality_root"
|
parent="menu_quality_root"
|
||||||
sequence="5" active="False"/>
|
sequence="5"/>
|
||||||
|
|
||||||
<menuitem
|
<menuitem
|
||||||
id="menu_quality_control"
|
id="menu_quality_control"
|
||||||
|
|||||||
@@ -1,3 +1,2 @@
|
|||||||
pystrich
|
pystrich
|
||||||
cpca
|
cpca
|
||||||
pycryptodome==3.20
|
|
||||||
|
|||||||
@@ -35,7 +35,6 @@
|
|||||||
],
|
],
|
||||||
'web.assets_backend': [
|
'web.assets_backend': [
|
||||||
'sf_base/static/src/scss/*.scss',
|
'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}
|
res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
|
||||||
logging.info('get_maintenance_tool_groups_Info error:%s' % e)
|
logging.info('get_maintenance_tool_groups_Info error:%s' % e)
|
||||||
return json.JSONEncoder().encode(res)
|
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 functional_fixture
|
||||||
from . import tool_other_features
|
from . import tool_other_features
|
||||||
from . import basic_parameters_fixture
|
from . import basic_parameters_fixture
|
||||||
from . import ir_sequence
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class BasicParametersFixture(models.Model):
|
|||||||
diameter = fields.Float('直径(mm)', digits=(16, 2))
|
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))
|
orientation_dish_diameter = fields.Float('定位盘直径(mm)', digits=(16, 2))
|
||||||
clamping_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='装夹单元数')
|
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='供应商')
|
supplier_ids = fields.One2many('sf.supplier.sort', 'materials_model_id', string='供应商')
|
||||||
active = fields.Boolean('有效', default=True)
|
active = fields.Boolean('有效', default=True)
|
||||||
|
|
||||||
@api.constrains("gain_way")
|
@api.onchange('gain_way')
|
||||||
def _check_supplier_ids(self):
|
def _check_gain_way(self):
|
||||||
for item in self:
|
if not self.gain_way:
|
||||||
if item.gain_way in ('外协', '采购') and not item.supplier_ids:
|
raise UserError("请选择获取方式")
|
||||||
|
if self.gain_way in ['外协', '采购']:
|
||||||
|
if not self.supplier_ids:
|
||||||
raise UserError("请添加供应商")
|
raise UserError("请添加供应商")
|
||||||
|
|
||||||
|
|
||||||
@@ -84,21 +86,17 @@ class MrsProductionProcessCategory(models.Model):
|
|||||||
class MrsProductionProcess(models.Model):
|
class MrsProductionProcess(models.Model):
|
||||||
_name = 'sf.production.process'
|
_name = 'sf.production.process'
|
||||||
_description = '表面工艺'
|
_description = '表面工艺'
|
||||||
order = 'sequence asc'
|
|
||||||
|
|
||||||
code = fields.Char("编码")
|
code = fields.Char("编码")
|
||||||
name = fields.Char('名称')
|
name = fields.Char('名称')
|
||||||
remark = fields.Text("备注")
|
remark = fields.Text("备注")
|
||||||
sequence = fields.Integer('排序')
|
|
||||||
# processing_order_ids = fields.One2many('sf.processing.order', 'production_process_id', string='工序')
|
# processing_order_ids = fields.One2many('sf.processing.order', 'production_process_id', string='工序')
|
||||||
partner_process_ids = fields.Many2many('res.partner', 'process_ids', '加工工厂')
|
partner_process_ids = fields.Many2many('res.partner', 'process_ids', '加工工厂')
|
||||||
active = fields.Boolean('有效', default=True)
|
active = fields.Boolean('有效', default=True)
|
||||||
parameter_ids = fields.One2many('sf.production.process.parameter', 'process_id', string='可选参数')
|
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)
|
# 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):
|
# class MrsProcessingTechnology(models.Model):
|
||||||
# _name = 'sf.processing.technology'
|
# _name = 'sf.processing.technology'
|
||||||
@@ -145,12 +143,8 @@ class MrsProductionProcessParameter(models.Model):
|
|||||||
is_check = fields.Boolean(default=False)
|
is_check = fields.Boolean(default=False)
|
||||||
# price = fields.Float('单价')
|
# price = fields.Float('单价')
|
||||||
process_id = fields.Many2one('sf.production.process', string='表面工艺')
|
process_id = fields.Many2one('sf.production.process', string='表面工艺')
|
||||||
process_description = fields.Char(string='工艺描述')
|
|
||||||
materials_model_ids = fields.Many2many('sf.materials.model', 'applicable_material', 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)
|
active = fields.Boolean('有效', default=True)
|
||||||
processing_mm = fields.Char('加工厚度/mm')
|
|
||||||
|
|
||||||
def name_get(self):
|
def name_get(self):
|
||||||
result = []
|
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('前缀')
|
prefix = fields.Char('前缀')
|
||||||
postfix = fields.Char('后缀')
|
postfix = fields.Char('后缀')
|
||||||
diameter = fields.Float('直径(mm)')
|
diameter = fields.Float('直径(mm)')
|
||||||
angle = fields.Float('R角(mm)',default=0)
|
angle = fields.Float('R角(mm)')
|
||||||
tool_length = fields.Float('刀具总长(mm)')
|
tool_length = fields.Float('刀具总长(mm)')
|
||||||
blade_length = fields.Float('避空长/刃长(mm)')
|
blade_length = fields.Float('避空长/刃长(mm)')
|
||||||
knife_head_name = fields.Char('刀头名称')
|
knife_head_name = fields.Char('刀头名称')
|
||||||
@@ -331,7 +331,7 @@ class ToolInventory(models.Model):
|
|||||||
work_material = fields.Selection([('钢', '钢'), ('铝', '铝')], string='加工材料')
|
work_material = fields.Selection([('钢', '钢'), ('铝', '铝')], string='加工材料')
|
||||||
life_span = fields.Float('寿命(min)')
|
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)
|
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)')
|
neck_length = fields.Float('颈部长度(mm)')
|
||||||
handle_diameter = fields.Float('柄部直径(mm)')
|
handle_diameter = fields.Float('柄部直径(mm)')
|
||||||
handle_length = fields.Float('柄部长度(mm)')
|
handle_length = fields.Float('柄部长度(mm)')
|
||||||
blade_tip_diameter = fields.Float('刀尖直径(mm)')
|
blade_tip_diameter = fields.Integer('刀尖直径(mm)')
|
||||||
blade_tip_working_size = fields.Char('刀尖倒角度(°)', size=20)
|
blade_tip_working_size = fields.Char('刀尖处理尺寸(R半径mm/倒角度)', size=20)
|
||||||
tip_r_size = fields.Float('刀尖R角(mm)',default=0)
|
|
||||||
blade_tip_taper = fields.Integer('刀尖锥度(°)')
|
blade_tip_taper = fields.Integer('刀尖锥度(°)')
|
||||||
blade_diameter = fields.Float('刃部直径(mm)')
|
blade_diameter = fields.Float('刃部直径(mm)')
|
||||||
blade_length = fields.Float('刃部长度(mm)')
|
blade_length = fields.Float('刃部长度(mm)')
|
||||||
@@ -38,7 +37,7 @@ class ToolMaterialsBasicParameters(models.Model):
|
|||||||
width = fields.Float('宽度(mm)')
|
width = fields.Float('宽度(mm)')
|
||||||
cutting_blade_length = fields.Float('切削刃长(mm)')
|
cutting_blade_length = fields.Float('切削刃长(mm)')
|
||||||
relief_angle = fields.Integer('后角(°)')
|
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)')
|
inscribed_circle_diameter = fields.Float('内接圆直径IC/D(mm)')
|
||||||
install_aperture_diameter = fields.Float('安装孔直径(mm)')
|
install_aperture_diameter = fields.Float('安装孔直径(mm)')
|
||||||
chip_breaker_groove = fields.Selection([('无', '无'), ('单面', '单面'), ('双面', '双面')],
|
chip_breaker_groove = fields.Selection([('无', '无'), ('单面', '单面'), ('双面', '双面')],
|
||||||
|
|||||||
@@ -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_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_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_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_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,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,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,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_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
|
access_sf_production_materials,sf_production_materials,model_sf_production_materials,base.group_user,1,1,1,0
|
||||||
@@ -242,8 +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_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_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_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
|
|
||||||
|
|||||||
|
@@ -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,
|
|
||||||
});
|
|
||||||
@@ -159,6 +159,9 @@ td.o_required_modifier {
|
|||||||
display:inline;
|
display:inline;
|
||||||
}
|
}
|
||||||
.diameter{
|
.diameter{
|
||||||
|
display: flex !important;
|
||||||
|
justify-content: flex-start !important;
|
||||||
|
align-items: center !important;
|
||||||
}
|
}
|
||||||
.o_address_format {
|
.o_address_format {
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
|
|||||||
@@ -109,7 +109,7 @@
|
|||||||
<field name="name">form.sf.machine_tool.type</field>
|
<field name="name">form.sf.machine_tool.type</field>
|
||||||
<field name="model">sf.machine_tool.type</field>
|
<field name="model">sf.machine_tool.type</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form string="机床型号" delete="0">
|
<form string="机床型号" delete="0">
|
||||||
<sheet>
|
<sheet>
|
||||||
<div class="oe_title">
|
<div class="oe_title">
|
||||||
<h1>
|
<h1>
|
||||||
@@ -129,28 +129,31 @@
|
|||||||
<field name="machine_tool_picture" widget="image" nolabel="1"/>
|
<field name="machine_tool_picture" widget="image" nolabel="1"/>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
<group string="加工能力">
|
<group string="加工能力">
|
||||||
<div>
|
<div>
|
||||||
<field name='jg_image_id' widget="custom_many2many_checkboxes">
|
<field name='jg_image_id' widget="custom_many2many_checkboxes">
|
||||||
<tree>
|
|
||||||
<field name="name"/>
|
|
||||||
<field name="image" widget="image"/>
|
|
||||||
|
|
||||||
</tree>
|
<tree>
|
||||||
</field>
|
<field name="name"/>
|
||||||
|
<field name="image" widget="image"
|
||||||
|
options="{'size': [100, 100], 'click enlarge': True}"/>
|
||||||
|
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</group>
|
</group>
|
||||||
<group string="冷却方式">
|
<group string="冷却方式">
|
||||||
<div>
|
<div>
|
||||||
<field name='lq_image_id' widget="custom_many2many_checkboxes">
|
<field name='lq_image_id' widget="custom_many2many_checkboxes">
|
||||||
|
|
||||||
<tree>
|
<tree>
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
<field name="image" widget="image"/>
|
<field name="image" widget="image"
|
||||||
|
options="{'size': [100, 100], 'click enlarge': True}"/>
|
||||||
|
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</group>
|
</group>
|
||||||
@@ -175,7 +178,7 @@
|
|||||||
<field name="workbench_H" class="o_address_zip" required="1"
|
<field name="workbench_H" class="o_address_zip" required="1"
|
||||||
options="{'format': false}"/>
|
options="{'format': false}"/>
|
||||||
</div>
|
</div>
|
||||||
<field name="workpiece_load"/>
|
<field name="workpiece_load"/>
|
||||||
<label for="machine_tool_L" string="机床尺寸(mm)"/>
|
<label for="machine_tool_L" string="机床尺寸(mm)"/>
|
||||||
<div class="test_model">
|
<div class="test_model">
|
||||||
<label for="machine_tool_L" string="长"/>
|
<label for="machine_tool_L" string="长"/>
|
||||||
@@ -189,7 +192,7 @@
|
|||||||
<field name="machine_tool_H" class="o_address_zip"
|
<field name="machine_tool_H" class="o_address_zip"
|
||||||
options="{'format': false}"/>
|
options="{'format': false}"/>
|
||||||
</div>
|
</div>
|
||||||
<label for="T_trough_num" string="T型槽尺寸:"/>
|
<label for="T_trough_num" string="T型槽尺寸:"/>
|
||||||
<div class="test_model">
|
<div class="test_model">
|
||||||
<label for="T_trough_num" string="槽数"/>
|
<label for="T_trough_num" string="槽数"/>
|
||||||
<field name="T_trough_num" class="o_address_zip"
|
<field name="T_trough_num" class="o_address_zip"
|
||||||
@@ -202,20 +205,20 @@
|
|||||||
<field name="T_trough_distance" class="o_address_zip"
|
<field name="T_trough_distance" class="o_address_zip"
|
||||||
options="{'format': false}"/>
|
options="{'format': false}"/>
|
||||||
</div>
|
</div>
|
||||||
<!-- <field name="feed_speed" required="1"/>-->
|
<!-- <field name="feed_speed" required="1"/>-->
|
||||||
<!-- <label for="precision_min" string="X轴定位精度(mm)"/>-->
|
<!-- <label for="precision_min" string="X轴定位精度(mm)"/>-->
|
||||||
<!-- <div class="test_model">-->
|
<!-- <div class="test_model">-->
|
||||||
<!-- <label for="precision_min" string="最小(min)"/>-->
|
<!-- <label for="precision_min" string="最小(min)"/>-->
|
||||||
<!-- <field name="precision_min" class="o_address_zip" required="1"-->
|
<!-- <field name="precision_min" class="o_address_zip" required="1"-->
|
||||||
<!-- options="{'format': false}"/>-->
|
<!-- options="{'format': false}"/>-->
|
||||||
<!-- <span>&nbsp;</span>-->
|
<!-- <span>&nbsp;</span>-->
|
||||||
<!-- <label for="precision_max" string="最大(max)"/>-->
|
<!-- <label for="precision_max" string="最大(max)"/>-->
|
||||||
<!-- <field name="precision_max" class="o_address_zip" required="1"-->
|
<!-- <field name="precision_max" class="o_address_zip" required="1"-->
|
||||||
<!-- options="{'format': false}"/>-->
|
<!-- options="{'format': false}"/>-->
|
||||||
<!-- </div>-->
|
<!-- </div>-->
|
||||||
|
|
||||||
<!-- <field name="lead_screw" required="1"/>-->
|
<!-- <field name="lead_screw" required="1"/>-->
|
||||||
<!-- <field name="guide_rail" required="1"/>-->
|
<!-- <field name="guide_rail" required="1"/>-->
|
||||||
<field name="number_of_axles" required="1" widget="radio"
|
<field name="number_of_axles" required="1" widget="radio"
|
||||||
options="{'horizontal': true}"/>
|
options="{'horizontal': true}"/>
|
||||||
<label for="x_axis" string="加工行程(mm)"
|
<label for="x_axis" string="加工行程(mm)"
|
||||||
@@ -255,7 +258,7 @@
|
|||||||
</group>
|
</group>
|
||||||
<group string="主轴">
|
<group string="主轴">
|
||||||
<field name="taper_type_id" required="1"/>
|
<field name="taper_type_id" required="1"/>
|
||||||
<label for="distance_min" string="主轴端面-工作台距离(mm)"/>
|
<label for="distance_min" string="主轴端面-工作台距离(mm)"/>
|
||||||
<div class="test_model">
|
<div class="test_model">
|
||||||
<label for="distance_min" string="最小(min)"/>
|
<label for="distance_min" string="最小(min)"/>
|
||||||
<field name="distance_min" class="o_address_zip"
|
<field name="distance_min" class="o_address_zip"
|
||||||
@@ -265,7 +268,7 @@
|
|||||||
<field name="distance_max" class="o_address_zip"
|
<field name="distance_max" class="o_address_zip"
|
||||||
options="{'format': false}"/>
|
options="{'format': false}"/>
|
||||||
</div>
|
</div>
|
||||||
<field name="rotate_speed" string="主轴最高转速(r/min)"
|
<field name="rotate_speed" string="主轴最高转速(r/min)"
|
||||||
options="{'format': false}"/>
|
options="{'format': false}"/>
|
||||||
<field name="spindle_center_distance"/>
|
<field name="spindle_center_distance"/>
|
||||||
<field name="spindle_continuous_power"/>
|
<field name="spindle_continuous_power"/>
|
||||||
@@ -283,50 +286,50 @@
|
|||||||
<page string="进给/精度参数">
|
<page string="进给/精度参数">
|
||||||
<group>
|
<group>
|
||||||
<group string="进给参数">
|
<group string="进给参数">
|
||||||
<field name="X_axis_rapid_traverse_speed"/>
|
<field name="X_axis_rapid_traverse_speed"/>
|
||||||
<field name="Y_axis_rapid_traverse_speed"/>
|
<field name="Y_axis_rapid_traverse_speed"/>
|
||||||
<field name="Z_axis_rapid_traverse_speed"/>
|
<field name="Z_axis_rapid_traverse_speed"/>
|
||||||
<field name="a_axis_rapid_traverse_speed"/>
|
<field name="a_axis_rapid_traverse_speed"/>
|
||||||
<field name="b_axis_rapid_traverse_speed"/>
|
<field name="b_axis_rapid_traverse_speed"/>
|
||||||
<field name="c_axis_rapid_traverse_speed"/>
|
<field name="c_axis_rapid_traverse_speed"/>
|
||||||
<field name="straight_cutting_feed_rate"/>
|
<field name="straight_cutting_feed_rate"/>
|
||||||
<field name="rotary_cutting_feed_rate"/>
|
<field name="rotary_cutting_feed_rate"/>
|
||||||
</group>
|
</group>
|
||||||
<group string="精度参数">
|
<group string="精度参数">
|
||||||
<field name="X_precision"/>
|
<field name="X_precision"/>
|
||||||
<field name="X_precision_repeat"/>
|
<field name="X_precision_repeat"/>
|
||||||
<field name="Y_precision"/>
|
<field name="Y_precision"/>
|
||||||
<field name="Y_precision_repeat"/>
|
<field name="Y_precision_repeat"/>
|
||||||
<field name="Z_precision"/>
|
<field name="Z_precision"/>
|
||||||
<field name="Z_precision_repeat"/>
|
<field name="Z_precision_repeat"/>
|
||||||
<field name="a_precision"/>
|
<field name="a_precision"/>
|
||||||
<field name="a_precision_repeat"/>
|
<field name="a_precision_repeat"/>
|
||||||
<field name="b_precision"/>
|
<field name="b_precision"/>
|
||||||
<field name="b_precision_repeat"/>
|
<field name="b_precision_repeat"/>
|
||||||
<field name="c_precision"/>
|
<field name="c_precision"/>
|
||||||
<field name="c_precision_repeat"/>
|
<field name="c_precision_repeat"/>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
</page>
|
</page>
|
||||||
<page string="刀库参数">
|
<page string="刀库参数">
|
||||||
<group>
|
<group>
|
||||||
<group string="刀具">
|
<group string="刀具">
|
||||||
<!-- <field name="knife_type" required="1"/>-->
|
<!-- <field name="knife_type" required="1"/>-->
|
||||||
<field name="number_of_knife_library" required="1" options="{'format': false}"/>
|
<field name="number_of_knife_library" required="1" options="{'format': false}"/>
|
||||||
<!-- <field name="tool_speed" required="1"/>-->
|
<!-- <field name="tool_speed" required="1"/>-->
|
||||||
<field name="tool_full_diameter_max"/>
|
<field name="tool_full_diameter_max"/>
|
||||||
<field name="tool_perimeter_diameter_max"/>
|
<field name="tool_perimeter_diameter_max"/>
|
||||||
<field name="tool_long_max"/>
|
<field name="tool_long_max"/>
|
||||||
<!-- <label for="tool_diameter_min" string="刀具刀径(mm)"/>-->
|
<!-- <label for="tool_diameter_min" string="刀具刀径(mm)"/>-->
|
||||||
<!-- <div class="test_model">-->
|
<!-- <div class="test_model">-->
|
||||||
<!-- <label for="tool_diameter_min" string="最小(min)"/>-->
|
<!-- <label for="tool_diameter_min" string="最小(min)"/>-->
|
||||||
<!-- <field name="tool_diameter_min" class="o_address_zip" required="1"-->
|
<!-- <field name="tool_diameter_min" class="o_address_zip" required="1"-->
|
||||||
<!-- options="{'format': false}"/>-->
|
<!-- options="{'format': false}"/>-->
|
||||||
<!-- <span>&nbsp;</span>-->
|
<!-- <span>&nbsp;</span>-->
|
||||||
<!-- <label for="tool_diameter_max" string="最大(max)"/>-->
|
<!-- <label for="tool_diameter_max" string="最大(max)"/>-->
|
||||||
<!-- <field name="tool_diameter_max" class="o_address_zip" required="1"-->
|
<!-- <field name="tool_diameter_max" class="o_address_zip" required="1"-->
|
||||||
<!-- options="{'format': false}"/>-->
|
<!-- options="{'format': false}"/>-->
|
||||||
<!-- </div>-->
|
<!-- </div>-->
|
||||||
<field name="tool_quality_max"/>
|
<field name="tool_quality_max"/>
|
||||||
<field name="T_tool_time"/>
|
<field name="T_tool_time"/>
|
||||||
<field name="C_tool_time"/>
|
<field name="C_tool_time"/>
|
||||||
|
|||||||
@@ -12,10 +12,11 @@
|
|||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="ir.ui.view" id="mrs_production_process_parameter_form">
|
<record model="ir.ui.view" id="mrs_production_process_parameter_form">
|
||||||
<field name="model">sf.production.process.parameter</field>
|
<field name="model">sf.production.process.parameter</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form string="表面工艺可选参数" create="0" delete="0" >
|
<form string="表面工艺可选参数" create="0" delete="0">
|
||||||
<sheet>
|
<sheet>
|
||||||
<div class="oe_title">
|
<div class="oe_title">
|
||||||
<h1>
|
<h1>
|
||||||
@@ -25,19 +26,14 @@
|
|||||||
<group>
|
<group>
|
||||||
<group>
|
<group>
|
||||||
<field name="code" readonly="1"/>
|
<field name="code" readonly="1"/>
|
||||||
<field name="process_id" attrs="{'readonly': [('code', '!=', False)]}"/>
|
<field name="process_id" readonly="1"/>
|
||||||
<field name="process_description" attrs="{'readonly': [('code', '!=', False)]}"/>
|
|
||||||
<field name="gain_way"/>
|
<field name="gain_way"/>
|
||||||
</group>
|
</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>
|
</group>
|
||||||
<notebook>
|
<notebook>
|
||||||
<page string="适用材料">
|
<page string="适用材料">
|
||||||
<field name="materials_model_ids" attrs="{'readonly': [('code', '!=', False)]}"></field>
|
<field name="materials_model_ids"></field>
|
||||||
</page>
|
</page>
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
@@ -52,7 +48,7 @@
|
|||||||
<search>
|
<search>
|
||||||
<filter name="filter_active" string="已归档" domain="[('active','=',False)]"/>
|
<filter name="filter_active" string="已归档" domain="[('active','=',False)]"/>
|
||||||
<field name="name" string="名称" filter_domain="[('name','ilike',self)]"/>
|
<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">
|
<searchpanel class="account_root">
|
||||||
<field name="process_id" icon="fa-filter"/>
|
<field name="process_id" icon="fa-filter"/>
|
||||||
</searchpanel>
|
</searchpanel>
|
||||||
@@ -140,7 +136,7 @@
|
|||||||
<field name="model">sf.production.process.category</field>
|
<field name="model">sf.production.process.category</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<tree string="表面工艺类别" default_order="sequence, id" create="0" edit="0" delete="1">
|
<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="code"/>
|
||||||
<field name="name" string="名称"/>
|
<field name="name" string="名称"/>
|
||||||
</tree>
|
</tree>
|
||||||
@@ -163,8 +159,7 @@
|
|||||||
<record model="ir.ui.view" id="sf_production_process_tree">
|
<record model="ir.ui.view" id="sf_production_process_tree">
|
||||||
<field name="model">sf.production.process</field>
|
<field name="model">sf.production.process</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<tree string="表面工艺" create="0" edit="0" delete="0">
|
<tree string="表面工艺" create="0" edit="0" delete="1">
|
||||||
<field name="sequence" string="加工顺序" readonly="1"/>
|
|
||||||
<field name="code"/>
|
<field name="code"/>
|
||||||
<field name="name" string="名称"/>
|
<field name="name" string="名称"/>
|
||||||
<field name="remark"/>
|
<field name="remark"/>
|
||||||
@@ -175,7 +170,7 @@
|
|||||||
<record model="ir.ui.view" id="sf_production_process_form">
|
<record model="ir.ui.view" id="sf_production_process_form">
|
||||||
<field name="model">sf.production.process</field>
|
<field name="model">sf.production.process</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form string="表面工艺" create="0" delete="0">
|
<form string="表面工艺" create="0" edit="1" delete="1">
|
||||||
<sheet>
|
<sheet>
|
||||||
<div class="oe_title">
|
<div class="oe_title">
|
||||||
<h1>
|
<h1>
|
||||||
@@ -184,46 +179,41 @@
|
|||||||
</div>
|
</div>
|
||||||
<group>
|
<group>
|
||||||
<group>
|
<group>
|
||||||
<field name="code" readonly="1"/>
|
<field name="code"/>
|
||||||
<field name="category_id" readonly="1"/>
|
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<notebook>
|
||||||
<field name="processing_day" readonly="1"/>
|
<page string="可选参数">
|
||||||
<field name="travel_day" readonly="1"/>
|
<field name="parameter_ids">
|
||||||
</group>
|
<tree force_save="1">
|
||||||
</group>
|
<field name="code" readonly="1" force_save="1"/>
|
||||||
<notebook>
|
<field name="name"/>
|
||||||
<page string="可选参数" >
|
<field name="gain_way"/>
|
||||||
<field name="parameter_ids" >
|
<field name='process_id' default="default"/>
|
||||||
<tree force_save="1" create="0">
|
</tree>
|
||||||
<field name="code" readonly="1" force_save="1"/>
|
<form>
|
||||||
<field name="name" readonly="1"/>
|
<sheet>
|
||||||
<field name="gain_way"/>
|
|
||||||
<field name='process_id' default="default"/>
|
|
||||||
</tree>
|
|
||||||
<form>
|
|
||||||
<sheet>
|
|
||||||
<group>
|
|
||||||
<group>
|
<group>
|
||||||
<field name="code"/>
|
<group>
|
||||||
<field name="name" string="参数名"/>
|
<field name="code"/>
|
||||||
|
<field name="name" string="参数名"/>
|
||||||
|
</group>
|
||||||
|
<group>
|
||||||
|
<field name='process_id'/>
|
||||||
|
<field name="gain_way"/>
|
||||||
|
</group>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<notebook>
|
||||||
<field name='process_id'/>
|
<page string="适用材料">
|
||||||
<field name="gain_way"/>
|
<field name="materials_model_ids"/>
|
||||||
</group>
|
</page>
|
||||||
</group>
|
</notebook>
|
||||||
<notebook>
|
</sheet>
|
||||||
<page string="适用材料">
|
</form>
|
||||||
<field name="materials_model_ids"/>
|
</field>
|
||||||
</page>
|
</page>
|
||||||
</notebook>
|
|
||||||
</sheet>
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</page>
|
|
||||||
|
|
||||||
</notebook>
|
</notebook>
|
||||||
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<group>
|
<group>
|
||||||
<field name="remark"/>
|
<field name="remark"/>
|
||||||
@@ -261,7 +251,7 @@
|
|||||||
<group>
|
<group>
|
||||||
<group>
|
<group>
|
||||||
<field name="materials_no" readonly="1" force_save="1"/>
|
<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="tensile_strength" required="1"/>
|
||||||
<field name="hardness" required="1"/>
|
<field name="hardness" required="1"/>
|
||||||
<field name="density" readonly="1"/>
|
<field name="density" readonly="1"/>
|
||||||
@@ -280,9 +270,9 @@
|
|||||||
<notebook>
|
<notebook>
|
||||||
<page string="供应商">
|
<page string="供应商">
|
||||||
<field name='supplier_ids' class="supplier_ids_set_css">
|
<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="sequence" widget="handle" string="序号"/>
|
||||||
<field name="partner_id" string="名称" options="{'no_create': True}"/>
|
<field name="partner_id" string="名称"/>
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
</page>
|
</page>
|
||||||
|
|||||||
@@ -171,7 +171,7 @@
|
|||||||
<field name="width"/>
|
<field name="width"/>
|
||||||
<field name="height"/>
|
<field name="height"/>
|
||||||
<field name="diameter"/>
|
<field name="diameter"/>
|
||||||
<field name="weight" string="重量(kg)"/>
|
<field name="weight"/>
|
||||||
<field name="orientation_dish_diameter"/>
|
<field name="orientation_dish_diameter"/>
|
||||||
<field name="clamping_diameter"/>
|
<field name="clamping_diameter"/>
|
||||||
<field name="clamping_num"/>
|
<field name="clamping_num"/>
|
||||||
@@ -197,7 +197,7 @@
|
|||||||
<field name="width"/>
|
<field name="width"/>
|
||||||
<field name="height"/>
|
<field name="height"/>
|
||||||
<field name="diameter"/>
|
<field name="diameter"/>
|
||||||
<field name="weight" string="重量(kg)"/>
|
<field name="weight"/>
|
||||||
<field name="clamping_diameter"/>
|
<field name="clamping_diameter"/>
|
||||||
<field name="connector_diameter"/>
|
<field name="connector_diameter"/>
|
||||||
<field name="chucking_power_max"/>
|
<field name="chucking_power_max"/>
|
||||||
@@ -220,7 +220,7 @@
|
|||||||
<field name="length"/>
|
<field name="length"/>
|
||||||
<field name="width"/>
|
<field name="width"/>
|
||||||
<field name="height"/>
|
<field name="height"/>
|
||||||
<field name="weight" string="重量(kg)"/>
|
<field name="weight"/>
|
||||||
<field name="gripper_length_min"/>
|
<field name="gripper_length_min"/>
|
||||||
<field name="gripper_width_min"/>
|
<field name="gripper_width_min"/>
|
||||||
<field name="gripper_height_min"/>
|
<field name="gripper_height_min"/>
|
||||||
@@ -248,7 +248,7 @@
|
|||||||
<field name="length"/>
|
<field name="length"/>
|
||||||
<field name="width"/>
|
<field name="width"/>
|
||||||
<field name="height"/>
|
<field name="height"/>
|
||||||
<field name="weight" string="重量(kg)"/>
|
<field name="weight"/>
|
||||||
<field name="gripper_length_min"/>
|
<field name="gripper_length_min"/>
|
||||||
<field name="gripper_width_min"/>
|
<field name="gripper_width_min"/>
|
||||||
<field name="gripper_height_min"/>
|
<field name="gripper_height_min"/>
|
||||||
@@ -278,7 +278,7 @@
|
|||||||
<field name="width"/>
|
<field name="width"/>
|
||||||
<field name="height"/>
|
<field name="height"/>
|
||||||
<field name="height_tolerance_value"/>
|
<field name="height_tolerance_value"/>
|
||||||
<field name="weight" string="重量(kg)"/>
|
<field name="weight"/>
|
||||||
<field name="gripper_length_min"/>
|
<field name="gripper_length_min"/>
|
||||||
<field name="gripper_width_min"/>
|
<field name="gripper_width_min"/>
|
||||||
<field name="gripper_height_min"/>
|
<field name="gripper_height_min"/>
|
||||||
@@ -307,7 +307,7 @@
|
|||||||
<field name="length"/>
|
<field name="length"/>
|
||||||
<field name="width"/>
|
<field name="width"/>
|
||||||
<field name="height"/>
|
<field name="height"/>
|
||||||
<field name="weight" string="重量(kg)"/>
|
<field name="weight"/>
|
||||||
<field name="gripper_length_min"/>
|
<field name="gripper_length_min"/>
|
||||||
<field name="gripper_width_min"/>
|
<field name="gripper_width_min"/>
|
||||||
<field name="gripper_height_min"/>
|
<field name="gripper_height_min"/>
|
||||||
@@ -335,7 +335,7 @@
|
|||||||
<field name="width"/>
|
<field name="width"/>
|
||||||
<field name="height"/>
|
<field name="height"/>
|
||||||
<field name="diameter"/>
|
<field name="diameter"/>
|
||||||
<field name="weight" string="重量(kg)"/>
|
<field name="weight"/>
|
||||||
<field name="gripper_length_min"/>
|
<field name="gripper_length_min"/>
|
||||||
<field name="gripper_width_min"/>
|
<field name="gripper_width_min"/>
|
||||||
<field name="gripper_height_min"/>
|
<field name="gripper_height_min"/>
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
<field name="handle_length"/>
|
<field name="handle_length"/>
|
||||||
<field name="blade_tip_diameter"/>
|
<field name="blade_tip_diameter"/>
|
||||||
<field name="blade_tip_working_size"/>
|
<field name="blade_tip_working_size"/>
|
||||||
<field name="tip_r_size"/>
|
|
||||||
<field name="blade_tip_taper"/>
|
<field name="blade_tip_taper"/>
|
||||||
<field name="blade_diameter"/>
|
<field name="blade_diameter"/>
|
||||||
<field name="blade_length"/>
|
<field name="blade_length"/>
|
||||||
@@ -96,7 +95,6 @@
|
|||||||
<field name="handle_length"/>
|
<field name="handle_length"/>
|
||||||
<field name="blade_tip_diameter"/>
|
<field name="blade_tip_diameter"/>
|
||||||
<field name="blade_tip_working_size"/>
|
<field name="blade_tip_working_size"/>
|
||||||
<field name="tip_r_size"/>
|
|
||||||
<field name="blade_tip_taper"/>
|
<field name="blade_tip_taper"/>
|
||||||
<field name="blade_diameter"/>
|
<field name="blade_diameter"/>
|
||||||
<field name="blade_length"/>
|
<field name="blade_length"/>
|
||||||
@@ -141,7 +139,6 @@
|
|||||||
</group>
|
</group>
|
||||||
<group attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')]}">
|
<group attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')]}">
|
||||||
<field name="blade_tip_working_size"/>
|
<field name="blade_tip_working_size"/>
|
||||||
<field name="tip_r_size"/>
|
|
||||||
<field name="blade_tip_diameter" class="diameter"/>
|
<field name="blade_tip_diameter" class="diameter"/>
|
||||||
<field name="blade_tip_taper"/>
|
<field name="blade_tip_taper"/>
|
||||||
<field name="blade_helix_angle"/>
|
<field name="blade_helix_angle"/>
|
||||||
|
|||||||
@@ -80,10 +80,10 @@
|
|||||||
<field name="name">sf.cutter.function.tree</field>
|
<field name="name">sf.cutter.function.tree</field>
|
||||||
<field name="model">sf.functional.cutting.tool.model</field>
|
<field name="model">sf.functional.cutting.tool.model</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<tree string="功能刀具类型" create="0" delete="0" edit="1" editable="bottom">
|
<tree string="功能刀具类型" create="0" delete="0" edit="1">
|
||||||
<field name="name" string="名称" readonly="1"/>
|
<field name="name" string="名称"/>
|
||||||
<field name="code" readonly="1"/>
|
<field name="code"/>
|
||||||
<field name="remark" readonly="1"/>
|
<field name="remark"/>
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
@@ -222,7 +222,6 @@
|
|||||||
<field name="handle_diameter" class="diameter"/>
|
<field name="handle_diameter" class="diameter"/>
|
||||||
<field name="handle_length"/>
|
<field name="handle_length"/>
|
||||||
<field name="blade_tip_working_size" class="du"/>
|
<field name="blade_tip_working_size" class="du"/>
|
||||||
<field name="tip_r_size"/>
|
|
||||||
<field name="blade_tip_diameter" class="diameter"/>
|
<field name="blade_tip_diameter" class="diameter"/>
|
||||||
<field name="blade_tip_taper" class="du"/>
|
<field name="blade_tip_taper" class="du"/>
|
||||||
<field name="blade_helix_angle" class="du"/>
|
<field name="blade_helix_angle" class="du"/>
|
||||||
@@ -556,9 +555,9 @@
|
|||||||
<field name="model">sf.tool.inventory</field>
|
<field name="model">sf.tool.inventory</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<tree string="功能刀具清单" create="1" edit="1" delete="0" editable="bottom">
|
<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="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="work_material"/>
|
||||||
<field name="life_span"/>
|
<field name="life_span"/>
|
||||||
<field name="prefix" optional="hide"/>
|
<field name="prefix" optional="hide"/>
|
||||||
@@ -578,7 +577,7 @@
|
|||||||
</field>
|
</field>
|
||||||
</record>
|
</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="name">sf.tool.inventory.search</field>
|
||||||
<field name="model">sf.tool.inventory</field>
|
<field name="model">sf.tool.inventory</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ class Http(models.AbstractModel):
|
|||||||
def _auth_method_sf_token(cls):
|
def _auth_method_sf_token(cls):
|
||||||
# 从headers.environ中获取对方传过来的token,timestamp,加密的校验字符串
|
# 从headers.environ中获取对方传过来的token,timestamp,加密的校验字符串
|
||||||
datas = request.httprequest.headers.environ
|
datas = request.httprequest.headers.environ
|
||||||
_logger.info('datas:%s' % datas)
|
|
||||||
if 'HTTP_TOKEN' in datas:
|
if 'HTTP_TOKEN' in datas:
|
||||||
_logger.info('token:%s' % datas['HTTP_TOKEN'])
|
_logger.info('token:%s' % datas['HTTP_TOKEN'])
|
||||||
# 查询密钥
|
# 查询密钥
|
||||||
@@ -36,7 +35,7 @@ class Http(models.AbstractModel):
|
|||||||
post_time = int(datas['HTTP_TIMESTAMP'])
|
post_time = int(datas['HTTP_TIMESTAMP'])
|
||||||
datetime_post = datetime.fromtimestamp(post_time)
|
datetime_post = datetime.fromtimestamp(post_time)
|
||||||
datetime_now = datetime.now().replace(microsecond=0)
|
datetime_now = datetime.now().replace(microsecond=0)
|
||||||
datetime_del = datetime_now + timedelta(seconds=30)
|
datetime_del = datetime_now + timedelta(seconds=5)
|
||||||
if datetime_post > datetime_del:
|
if datetime_post > datetime_del:
|
||||||
raise AuthenticationError('请求已过期')
|
raise AuthenticationError('请求已过期')
|
||||||
check_str = '%s%s%s' % (datas['HTTP_TOKEN'], post_time, factory_secret.sf_secret_key)
|
check_str = '%s%s%s' % (datas['HTTP_TOKEN'], post_time, factory_secret.sf_secret_key)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import requests
|
|||||||
import cpca
|
import cpca
|
||||||
# from odoo.exceptions import UserError
|
# from odoo.exceptions import UserError
|
||||||
# from odoo.exceptions import ValidationError
|
# from odoo.exceptions import ValidationError
|
||||||
from odoo import api, fields, models, _
|
from odoo import api, fields, models
|
||||||
from odoo.exceptions import ValidationError
|
from odoo.exceptions import ValidationError
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
@@ -14,7 +14,7 @@ _logger = logging.getLogger(__name__)
|
|||||||
class JdEclp(models.Model):
|
class JdEclp(models.Model):
|
||||||
_inherit = 'stock.picking'
|
_inherit = 'stock.picking'
|
||||||
|
|
||||||
senderNickName = fields.Char(string='寄件工厂简称', required=True, default='XT')
|
senderNickName = fields.Char(string='寄件工厂简称', required=True, default='MW')
|
||||||
|
|
||||||
# receiverName = fields.Char(string='收件人姓名')
|
# receiverName = fields.Char(string='收件人姓名')
|
||||||
# receiverMobile = fields.Char(string='收件人电话')
|
# receiverMobile = fields.Char(string='收件人电话')
|
||||||
@@ -67,10 +67,9 @@ class JdEclp(models.Model):
|
|||||||
"""
|
"""
|
||||||
判断是否为出库单
|
判断是否为出库单
|
||||||
"""
|
"""
|
||||||
for record in self:
|
if self.name:
|
||||||
if record.name:
|
is_check_out = self.name.split('/')
|
||||||
is_check_out = record.name.split('/')
|
self.check_out = is_check_out[1]
|
||||||
record.check_out = is_check_out[1]
|
|
||||||
|
|
||||||
@api.depends('carrier_tracking_ref')
|
@api.depends('carrier_tracking_ref')
|
||||||
def query_bill_pdf(self):
|
def query_bill_pdf(self):
|
||||||
@@ -149,7 +148,7 @@ class JdEclp(models.Model):
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
_logger.info('准备调接口1')
|
_logger.info('准备调接口1')
|
||||||
url1 = config['bfm_url_new'] + '/api/create/jd/order'
|
url1 = config['bfm_url'] + '/api/create/jd/order'
|
||||||
requests.post(url1, json=json1, data=None)
|
requests.post(url1, json=json1, data=None)
|
||||||
_logger.info('调用成功1')
|
_logger.info('调用成功1')
|
||||||
_logger.info('准备调接口2')
|
_logger.info('准备调接口2')
|
||||||
@@ -158,31 +157,18 @@ class JdEclp(models.Model):
|
|||||||
'orderNo': self.origin,
|
'orderNo': self.origin,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
url2 = config['bfm_url_new'] + '/api/get/jd/no'
|
url2 = config['bfm_url'] + '/api/get/jd/no'
|
||||||
response = requests.post(url2, json=json2, data=None)
|
response = requests.post(url2, json=json2, data=None)
|
||||||
# _logger.info('调用成功2', response.json()['result']['wbNo'])
|
# _logger.info('调用成功2', response.json()['result']['wbNo'])
|
||||||
tem_ret = response.json().get('result')
|
self.carrier_tracking_ref = response.json()['result']['wbNo']
|
||||||
if not tem_ret:
|
|
||||||
raise ValidationError('京东物流返回异常,请联系管理员')
|
|
||||||
self.carrier_tracking_ref = response.json()['result'].get('wbNo')
|
|
||||||
if not self.carrier_tracking_ref:
|
|
||||||
raise ValidationError('物流下单未成功,请联系管理员')
|
|
||||||
self.is_bill = True
|
self.is_bill = True
|
||||||
self.logistics_status = '1'
|
self.logistics_status = '1'
|
||||||
|
|
||||||
notification = {
|
# # 京东物流下单后,销售订单状态改为待收货
|
||||||
'type': 'ir.actions.client',
|
# self.env['sale.order'].search([('name', '=', self.origin)]).write({'scheduled_status': 'to receive'})
|
||||||
'tag': 'display_notification',
|
|
||||||
'params': {
|
|
||||||
'title': _('成功'),
|
|
||||||
'type': 'success',
|
|
||||||
'message': '物流下单成功',
|
|
||||||
'sticky': False,
|
|
||||||
'next': {'type': 'ir.actions.client', 'tag': 'reload'}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return notification
|
# else:
|
||||||
|
# raise UserError("选择京东物流才能下单呦")
|
||||||
|
|
||||||
def get_bill(self):
|
def get_bill(self):
|
||||||
"""
|
"""
|
||||||
@@ -196,7 +182,7 @@ class JdEclp(models.Model):
|
|||||||
'no': self.origin,
|
'no': self.origin,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
url1 = config['bfm_url_new'] + '/api/create/jd/bill'
|
url1 = config['bfm_url'] + '/api/create/jd/bill'
|
||||||
response = requests.post(url1, json=json1, data=None)
|
response = requests.post(url1, json=json1, data=None)
|
||||||
# _logger.info('调用成功2', response.json())
|
# _logger.info('调用成功2', response.json())
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import traceback
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import logging
|
import logging
|
||||||
import requests
|
import requests
|
||||||
from odoo.exceptions import UserError
|
from odoo import fields, models
|
||||||
from odoo import fields, models, _
|
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -16,53 +14,26 @@ class StatusChange(models.Model):
|
|||||||
def action_confirm(self):
|
def action_confirm(self):
|
||||||
# 在原有方法执行前记录日志和执行其他操作
|
# 在原有方法执行前记录日志和执行其他操作
|
||||||
logging.info('函数已经执行=============')
|
logging.info('函数已经执行=============')
|
||||||
server_product_none = []
|
|
||||||
for order in self.order_line:
|
|
||||||
gain_way_no = order.product_template_id.model_process_parameters_ids.filtered(lambda a: not a.gain_way)
|
|
||||||
if gain_way_no:
|
|
||||||
process_parameters = [item.name for item in gain_way_no]
|
|
||||||
raise UserError(
|
|
||||||
_("请先至【制造】-【配置】中【表面工艺可选参数】为【%s】填写获取方式", ", ".join(process_parameters)))
|
|
||||||
for item in order.product_template_id.model_process_parameters_ids:
|
|
||||||
if item.gain_way == '外协':
|
|
||||||
server_product = self.env['product.template'].search(
|
|
||||||
[('server_product_process_parameters_id', '=', item.id),
|
|
||||||
('detailed_type', '=', 'service')])
|
|
||||||
if not server_product:
|
|
||||||
server_product_none.append(item.name)
|
|
||||||
if server_product_none:
|
|
||||||
raise UserError(_("请先至【产品】中创建【表面工艺参数】为【%s】的服务产品", ", ".join(server_product_none)))
|
|
||||||
|
|
||||||
# 使用super()来调用原始方法(在本例中为'sale.order'模型的'action_confirm'方法)
|
# 使用super()来调用原始方法(在本例中为'sale.order'模型的'action_confirm'方法)
|
||||||
try:
|
res = super(StatusChange, self).action_confirm()
|
||||||
res = super(StatusChange, self).action_confirm()
|
|
||||||
logging.info('原生方法返回结果:%s' % res)
|
# 原有方法执行后,进行额外的操作(如调用外部API)
|
||||||
# 原有方法执行后,进行额外的操作(如调用外部API)
|
process_start_time = str(datetime.now())
|
||||||
process_start_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
config = self.env['res.config.settings'].get_values()
|
||||||
config = self.env['res.config.settings'].get_values()
|
json1 = {
|
||||||
json1 = {
|
'params': {
|
||||||
'params': {
|
'model_name': 'jikimo.process.order',
|
||||||
'model_name': 'jikimo.process.order',
|
'field_name': 'name',
|
||||||
'field_name': 'name',
|
'default_code': self.default_code,
|
||||||
'default_code': self.default_code,
|
'state': '加工中',
|
||||||
'state': '加工中',
|
'process_start_time': process_start_time,
|
||||||
'process_start_time': process_start_time,
|
},
|
||||||
},
|
}
|
||||||
}
|
url1 = config['bfm_url'] + '/api/get/state/get_order'
|
||||||
url1 = config['bfm_url_new'] + '/api/get/state/get_order'
|
requests.post(url1, json=json1, data=None)
|
||||||
ret = requests.post(url1, json=json1, data=None)
|
logging.info('接口已经执行=============')
|
||||||
ret = ret.json()
|
|
||||||
if not ret.get('error'):
|
|
||||||
logging.info('接口已经执行=============')
|
|
||||||
else:
|
|
||||||
traceback_error = traceback.format_exc()
|
|
||||||
logging.error("bfm订单状态同步失败:%s" % traceback_error)
|
|
||||||
raise UserError('工厂加工同步订单状态到bfm失败')
|
|
||||||
except UserError as e:
|
|
||||||
traceback_error = traceback.format_exc()
|
|
||||||
logging.error("工厂加工同步订单状态失败:%s " % traceback_error)
|
|
||||||
raise UserError(e)
|
|
||||||
logging.info('最终返回值:%s' % res)
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def action_cancel(self):
|
def action_cancel(self):
|
||||||
@@ -83,7 +54,7 @@ class StatusChange(models.Model):
|
|||||||
'state': '待派单',
|
'state': '待派单',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
url1 = config['bfm_url_new'] + '/api/get/state/cancel_order'
|
url1 = config['bfm_url'] + '/api/get/state/cancel_order'
|
||||||
requests.post(url1, json=json1, data=None)
|
requests.post(url1, json=json1, data=None)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
@@ -231,12 +202,12 @@ class FinishStatusChange(models.Model):
|
|||||||
[('id', 'child_of', self.picking_type_id.warehouse_id.view_location_id.id),
|
[('id', 'child_of', self.picking_type_id.warehouse_id.view_location_id.id),
|
||||||
('usage', '!=', 'supplier')])
|
('usage', '!=', 'supplier')])
|
||||||
if self.env['stock.move'].search([
|
if self.env['stock.move'].search([
|
||||||
('state', 'in', ['confirmed', 'partially_available', 'waiting', 'assigned']),
|
('state', 'in', ['confirmed', 'partially_available', 'waiting', 'assigned']),
|
||||||
('product_qty', '>', 0),
|
('product_qty', '>', 0),
|
||||||
('location_id', 'in', wh_location_ids),
|
('location_id', 'in', wh_location_ids),
|
||||||
('move_orig_ids', '=', False),
|
('move_orig_ids', '=', False),
|
||||||
('picking_id', 'not in', self.ids),
|
('picking_id', 'not in', self.ids),
|
||||||
('product_id', 'in', lines.product_id.ids)], limit=1):
|
('product_id', 'in', lines.product_id.ids)], limit=1):
|
||||||
action = self.action_view_reception_report()
|
action = self.action_view_reception_report()
|
||||||
action['context'] = {'default_picking_ids': self.ids}
|
action['context'] = {'default_picking_ids': self.ids}
|
||||||
return action
|
return action
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
<field name="is_bill" invisible="True"/>
|
<field name="is_bill" invisible="True"/>
|
||||||
<field name="logistics_status" invisible="True"/>
|
<field name="logistics_status" invisible="True"/>
|
||||||
<field name="logistics_way" invisible="True"/>
|
<field name="logistics_way" invisible="True"/>
|
||||||
<button string="物流下单" name="create_order" type="object" confirm="是否确认物流下单" class="btn-primary"
|
<button string="京东物流下单" name="create_order" type="object" confirm="是否确认物流下单" class="btn-primary"
|
||||||
attrs="{'invisible': ['|', '|', '|', ('check_out', '!=', 'OUT'), ('state', '!=', 'assigned'), ('is_bill', '=', True), ('logistics_way', '=', '自提')]}"/>
|
attrs="{'invisible': ['|', '|', '|', ('check_out', '!=', 'OUT'), ('state', '!=', 'assigned'), ('is_bill', '=', True), ('logistics_way', '=', '自提')]}"/>
|
||||||
<button string="获取物流面单" name="get_bill" type="object" confirm="是否获取物流面单" class="btn-primary"
|
<button string="获取物流面单" name="get_bill" type="object" confirm="是否获取物流面单" class="btn-primary"
|
||||||
attrs="{'invisible': ['|', '|', '|', '|', ('check_out', '!=', 'OUT'), ('state', '!=', 'assigned'), ('logistics_status', '=', '2'), ('is_bill', '=', False), ('logistics_way', '=', '自提')]}"/>
|
attrs="{'invisible': ['|', '|', '|', '|', ('check_out', '!=', 'OUT'), ('state', '!=', 'assigned'), ('logistics_status', '=', '2'), ('is_bill', '=', False), ('logistics_way', '=', '自提')]}"/>
|
||||||
@@ -45,50 +45,42 @@
|
|||||||
<field name="model">stock.picking</field>
|
<field name="model">stock.picking</field>
|
||||||
<field name="inherit_id" ref="delivery.view_picking_withcarrier_out_form"/>
|
<field name="inherit_id" ref="delivery.view_picking_withcarrier_out_form"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
|
|
||||||
<field name="location_id" position="after">
|
<field name="location_id" position="after">
|
||||||
<field name="logistics_status" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
<field name="logistics_status" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||||
<field name="logistics_way" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
<field name="logistics_way" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||||
</field>
|
</field>
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="tracking_only_view" model="ir.ui.view">
|
<xpath expr="//group//field[@name='carrier_id']" position="after">
|
||||||
<field name="name">tracking only</field>
|
<!-- <field name="senderNickName" domain="[('self.name', 'like', '%OUT%')]"/> -->
|
||||||
<field name="model">stock.picking</field>
|
<field name="senderNickName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||||
<field name="inherit_id" ref="stock.view_picking_form"/>
|
<field name="expressItemName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||||
<field name="arch" type="xml">
|
<field name="deliveryType" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||||
<xpath expr="//form//sheet//notebook//page[@name='operations']" position="after">
|
<field name="receiverName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||||
<page string="发货信息" name="tracking">
|
<field name="receiverMobile" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||||
<group>
|
<field name="receiverProvinceName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||||
<group>
|
<field name="receiverCityName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||||
<field name="senderNickName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
<field name="receiverCountyName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||||
<field name="expressItemName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
<field name="receiverTownName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||||
<field name="grossWeight" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
<field name="receiverCompany" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||||
<field name="grossVolume" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
<field name="remark" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||||
<field name="deliveryType" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
<field name="grossWeight" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||||
<field name="receiverName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
<field name="grossVolume" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||||
<field name="receiverMobile" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
<field name="pickupBeginTime" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||||
<field name="receiverProvinceName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
<field name="bill_show" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||||
<field name="receiverCityName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
<field name="logistics_status"/>
|
||||||
<field name="receiverCountyName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
|
||||||
<field name="receiverTownName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
|
||||||
<field name="receiverCompany" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
|
||||||
<field name="remark" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
|
||||||
|
|
||||||
<field name="pickupBeginTime" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
|
||||||
</group>
|
|
||||||
<group>
|
|
||||||
<field name="logistics_status"/>
|
|
||||||
<field name="carrier_id"/>
|
|
||||||
<field name="carrier_tracking_ref"/>
|
|
||||||
|
|
||||||
<field name="bill_show" attrs="{'invisible': [('check_out', '!=', 'OUT')]}" string='面单下载'/>
|
|
||||||
<field name="bill_show" widget="pdf_viewer" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
|
||||||
|
|
||||||
</group>
|
|
||||||
</group>
|
|
||||||
</page>
|
|
||||||
</xpath>
|
</xpath>
|
||||||
|
<xpath expr="//group//field[@name='group_id']" position="after">
|
||||||
|
<field name="bill_show" widget="pdf_viewer" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
|
||||||
|
</xpath>
|
||||||
|
<!-- <xpath expr="//group[@name='other_infos']" position="after"> -->
|
||||||
|
<!-- <div> -->
|
||||||
|
<!-- <button string="京东物流下单" name="create_order" type="object" confirm="是否确认物流下单" class="btn-primary"/> -->
|
||||||
|
<!-- </div> -->
|
||||||
|
<!-- <div> -->
|
||||||
|
<!-- <button string="获取物流面单" name="get_bill" type="object" confirm="是否获取物流面单" class="btn-primary"/> -->
|
||||||
|
<!-- </div> -->
|
||||||
|
<!-- </xpath> -->
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
</odoo>
|
</odoo>
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
""",
|
""",
|
||||||
'category': 'sf',
|
'category': 'sf',
|
||||||
'website': 'https://www.sf.jikimo.com',
|
'website': 'https://www.sf.jikimo.com',
|
||||||
'depends': ['sf_base', 'mrp_subcontracting', 'purchase_stock', 'uom'],
|
'depends': ['sf_base', 'web_widget_model_viewer', 'mrp_subcontracting', 'purchase_stock', 'uom', ],
|
||||||
'data': [
|
'data': [
|
||||||
'data/product_data.xml',
|
'data/product_data.xml',
|
||||||
'data/uom_data.xml',
|
'data/uom_data.xml',
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ class ResMrpBomMo(models.Model):
|
|||||||
# 查bom的原材料
|
# 查bom的原材料
|
||||||
def get_raw_bom(self, product):
|
def get_raw_bom(self, product):
|
||||||
raw_bom = self.env['product.product'].search(
|
raw_bom = self.env['product.product'].search(
|
||||||
[('categ_id.type', '=', '原材料'), ('materials_type_id', '=', product.materials_type_id.id)],limit=1)
|
[('categ_id.type', '=', '原材料'), ('materials_type_id', '=', product.materials_type_id.id)])
|
||||||
return raw_bom
|
return raw_bom
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,16 +22,6 @@
|
|||||||
<field name="company_id" ref="base.main_company"/>
|
<field name="company_id" ref="base.main_company"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="stock_location_tool_dismantle" model="stock.location">
|
|
||||||
<field name="name">拆解</field>
|
|
||||||
<field name="location_id" ref="stock.stock_location_locations_virtual"/>
|
|
||||||
<field name="usage">internal</field>
|
|
||||||
<field name="barcode">DJCJ</field>
|
|
||||||
<field name="scrap_location">true</field>
|
|
||||||
<field name="active">true</field>
|
|
||||||
<field name="company_id" ref="base.main_company"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
|
|
||||||
<record id="after_assembly_picking_in" model="stock.picking.type">
|
<record id="after_assembly_picking_in" model="stock.picking.type">
|
||||||
<field name="name">刀具组装入库</field>
|
<field name="name">刀具组装入库</field>
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<odoo>
|
<odoo>
|
||||||
<data>
|
<data>
|
||||||
<record id="mrp.product_template_action" model="ir.actions.act_window">
|
|
||||||
<field name="context">
|
|
||||||
{"search_default_categ_id":1,"search_default_consumable": 1, 'default_detailed_type': 'product'}
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
<record model="ir.ui.view" id="view_sale_product_template_form_inherit_sf">
|
<record model="ir.ui.view" id="view_sale_product_template_form_inherit_sf">
|
||||||
<field name="name">product.template.form.inherit.sf</field>
|
<field name="name">product.template.form.inherit.sf</field>
|
||||||
<field name="model">product.template</field>
|
<field name="model">product.template</field>
|
||||||
@@ -15,9 +10,6 @@
|
|||||||
<field name='categ_id' class="custom_required" attrs="{'readonly': [('id', '!=', False)]}"/>
|
<field name='categ_id' class="custom_required" attrs="{'readonly': [('id', '!=', False)]}"/>
|
||||||
<field name='is_bfm' invisible="1"/>
|
<field name='is_bfm' invisible="1"/>
|
||||||
<field name='categ_type' invisible="1"/>
|
<field name='categ_type' invisible="1"/>
|
||||||
<field name='part_number' attrs="{'invisible': [('categ_type', '!=', '成品')]}"/>
|
|
||||||
<field name='machining_drawings' attrs="{'invisible': [('categ_type', '!=', '成品')]}" widget="adaptive_viewer"/>
|
|
||||||
<field name='quality_standard' attrs="{'invisible': [('categ_type', '!=', '成品')]}" widget="adaptive_viewer"/>
|
|
||||||
<field name='manual_quotation' attrs="{'invisible':[('upload_model_file', '=', [])]}"/>
|
<field name='manual_quotation' attrs="{'invisible':[('upload_model_file', '=', [])]}"/>
|
||||||
<field name="upload_model_file"
|
<field name="upload_model_file"
|
||||||
widget="many2many_binary"
|
widget="many2many_binary"
|
||||||
@@ -39,11 +31,9 @@
|
|||||||
options="{'no_create': True}"
|
options="{'no_create': True}"
|
||||||
attrs="{'invisible': [('categ_type', '!=', '刀具')],'required': [('categ_type', '=', '刀具')],'readonly': [('id', '!=', False)]}"
|
attrs="{'invisible': [('categ_type', '!=', '刀具')],'required': [('categ_type', '=', '刀具')],'readonly': [('id', '!=', False)]}"
|
||||||
placeholder="请选择"/>
|
placeholder="请选择"/>
|
||||||
<field name="brand_id" options="{'no_create': True}" placeholder="请选择"
|
|
||||||
attrs="{'invisible': [('categ_type', '!=', '刀具')],'required': [('categ_type', '=', '刀具')],'readonly': [('id', '!=', False)]}"/>
|
|
||||||
<field name="cutting_tool_model_id" placeholder="请选择" class="custom_required"
|
<field name="cutting_tool_model_id" placeholder="请选择" class="custom_required"
|
||||||
options="{'no_create': True}"
|
options="{'no_create': True}"
|
||||||
domain="[('cutting_tool_material_id','=',cutting_tool_material_id),('brand_id', '=', brand_id)]"
|
domain="[('cutting_tool_material_id','=',cutting_tool_material_id)]"
|
||||||
context="{'default_cutting_tool_material_id': cutting_tool_material_id}"
|
context="{'default_cutting_tool_material_id': cutting_tool_material_id}"
|
||||||
attrs="{'invisible': [('categ_type', '!=', '刀具')],'required': [('categ_type', '=', '刀具')],'readonly': [('id', '!=', False)]}">
|
attrs="{'invisible': [('categ_type', '!=', '刀具')],'required': [('categ_type', '=', '刀具')],'readonly': [('id', '!=', False)]}">
|
||||||
</field>
|
</field>
|
||||||
@@ -57,10 +47,10 @@
|
|||||||
<field name="fixture_material_id"
|
<field name="fixture_material_id"
|
||||||
attrs="{'invisible': [('categ_type', '!=', '夹具')],'required': [('categ_type', '=', '夹具')]}"
|
attrs="{'invisible': [('categ_type', '!=', '夹具')],'required': [('categ_type', '=', '夹具')]}"
|
||||||
placeholder="请选择" options="{'no_create': True}"/>
|
placeholder="请选择" options="{'no_create': True}"/>
|
||||||
<field name="fixture_model_id" string="型号名称" placeholder="请选择" options="{'no_create': True}"
|
<field name="fixture_model_id" string="型号" placeholder="请选择" options="{'no_create': True}"
|
||||||
attrs="{'invisible': [('categ_type', '!=', '夹具')],'required': [('categ_type', '=', '夹具')]}"
|
attrs="{'invisible': [('categ_type', '!=', '夹具')],'required': [('categ_type', '=', '夹具')]}"
|
||||||
domain="[('fixture_material_id','=',fixture_material_id)]"/>
|
domain="[('fixture_material_id','=',fixture_material_id)]"/>
|
||||||
<field name="specification_fixture_id" string="物料号" placeholder="请选择"
|
<field name="specification_fixture_id" string="规格" placeholder="请选择"
|
||||||
options="{'no_create': True}"
|
options="{'no_create': True}"
|
||||||
attrs="{'invisible': [('categ_type', '!=', '夹具')],'required': [('categ_type', '=', '夹具')]}"
|
attrs="{'invisible': [('categ_type', '!=', '夹具')],'required': [('categ_type', '=', '夹具')]}"
|
||||||
domain="[('fixture_model_id','=',fixture_model_id)]"/>
|
domain="[('fixture_model_id','=',fixture_model_id)]"/>
|
||||||
@@ -95,8 +85,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<field name="model_volume" string="体积[mm³]"/>
|
<field name="model_volume" string="体积[mm³]"/>
|
||||||
<field name="product_model_type_id" string="模型类型"/>
|
<field name="product_model_type_id" string="模型类型"/>
|
||||||
<field name="model_processing_panel" placeholder="例如R,U" string="加工面板"
|
<field name="model_processing_panel" placeholder="例如R,U" string="加工面板"/>
|
||||||
readonly="1"/>
|
|
||||||
<field name="model_machining_precision"/>
|
<field name="model_machining_precision"/>
|
||||||
<field name="model_process_parameters_ids" string="表面工艺参数"
|
<field name="model_process_parameters_ids" string="表面工艺参数"
|
||||||
widget="many2many_tags"
|
widget="many2many_tags"
|
||||||
@@ -106,16 +95,6 @@
|
|||||||
</group>
|
</group>
|
||||||
</page>
|
</page>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='name']" position="attributes">
|
|
||||||
<attribute name="attrs">{'readonly': ['|',('id','!=',False),('categ_type', '=',
|
|
||||||
'刀具')], 'required': True}
|
|
||||||
</attribute>
|
|
||||||
</xpath>
|
|
||||||
<!-- <xpath expr="//field[@name='default_code']" position="attributes">-->
|
|
||||||
<!-- <attribute name="attrs">{'readonly': [('categ_type', '=', '刀具')], 'invisible':-->
|
|
||||||
<!-- [('product_variant_count', '>' , 1)]}-->
|
|
||||||
<!-- </attribute>-->
|
|
||||||
<!-- </xpath>-->
|
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
@@ -193,8 +172,6 @@
|
|||||||
attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')],'readonly': [('id', '!=', False)]}"/>
|
attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')],'readonly': [('id', '!=', False)]}"/>
|
||||||
<field name="cutting_tool_blade_tip_working_size"
|
<field name="cutting_tool_blade_tip_working_size"
|
||||||
attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')],'readonly': [('id', '!=', False)]}"/>
|
attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')],'readonly': [('id', '!=', False)]}"/>
|
||||||
<field name="cutting_tool_blade_tip_r_size"
|
|
||||||
attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')],'readonly': [('id', '!=', False)]}"/>
|
|
||||||
<field name="cutting_tool_blade_tip_diameter" string="刀尖直径(mm)" class="diameter"
|
<field name="cutting_tool_blade_tip_diameter" string="刀尖直径(mm)" class="diameter"
|
||||||
attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')],'readonly': [('id', '!=', False)]}"/>
|
attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')],'readonly': [('id', '!=', False)]}"/>
|
||||||
<field name="cutting_tool_blade_tip_taper" string="刀尖锥度(°)"
|
<field name="cutting_tool_blade_tip_taper" string="刀尖锥度(°)"
|
||||||
@@ -315,7 +292,7 @@
|
|||||||
<field name="cutting_tool_blade_type"
|
<field name="cutting_tool_blade_type"
|
||||||
attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')],'readonly': [('id', '!=', False)]}"/>
|
attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')],'readonly': [('id', '!=', False)]}"/>
|
||||||
<field name="cutting_tool_coarse_medium_fine" string="粗/中/精" placeholder="请选择"
|
<field name="cutting_tool_coarse_medium_fine" string="粗/中/精" placeholder="请选择"
|
||||||
attrs="{'invisible': [('cutting_tool_type', 'not in', ('整体式刀具','刀片'))],'readonly': [('id', '!=', False)]}"/>
|
attrs="{'required': [('cutting_tool_type','=','整体式刀具')],'invisible': [('cutting_tool_type', 'not in', ('整体式刀具','刀片'))],'readonly': [('id', '!=', False)]}"/>
|
||||||
<!--整体式刀具-->
|
<!--整体式刀具-->
|
||||||
<field name="cutting_tool_shank_diameter" string="柄部直径(mm)" class="diameter"
|
<field name="cutting_tool_shank_diameter" string="柄部直径(mm)" class="diameter"
|
||||||
attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')],'readonly': [('id', '!=', False)]}"/>
|
attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')],'readonly': [('id', '!=', False)]}"/>
|
||||||
@@ -478,8 +455,7 @@
|
|||||||
<tree editable="bottom">
|
<tree editable="bottom">
|
||||||
<!-- <field name="cutting_speed"-->
|
<!-- <field name="cutting_speed"-->
|
||||||
<!-- attrs="{'readonly': [('materials_type_id','!=',False)]}"/>-->
|
<!-- attrs="{'readonly': [('materials_type_id','!=',False)]}"/>-->
|
||||||
<field name="materials_type_id" options="{'no_create': True}"
|
<field name="materials_type_id" options="{'no_create': True}" placeholder="请选择"/>
|
||||||
placeholder="请选择"/>
|
|
||||||
<field name="blade_diameter"/>
|
<field name="blade_diameter"/>
|
||||||
<field name="feed_per_tooth"/>
|
<field name="feed_per_tooth"/>
|
||||||
</tree>
|
</tree>
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from . import models
|
|
||||||
@@ -1,24 +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': ['base', 'hr'],
|
|
||||||
'data': [
|
|
||||||
'views/hr_employee.xml',
|
|
||||||
'views/res_config_settings_views.xml',
|
|
||||||
'data/cron_data.xml',
|
|
||||||
],
|
|
||||||
'demo': [
|
|
||||||
],
|
|
||||||
'qweb': [
|
|
||||||
],
|
|
||||||
'license': 'LGPL-3',
|
|
||||||
'installable': True,
|
|
||||||
'application': False,
|
|
||||||
'auto_install': False,
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
<odoo>
|
|
||||||
<data noupdate="1">
|
|
||||||
<record model="ir.cron" id="ir_cron_employee_info_sync">
|
|
||||||
<field name="name">员工企微id同步</field>
|
|
||||||
<field name="model_id" ref="hr.model_hr_employee"/>
|
|
||||||
<field name="state">code</field>
|
|
||||||
<field name="code">model._employee_info_sync()</field>
|
|
||||||
<field name="interval_number">1</field>
|
|
||||||
<field name="interval_type">days</field>
|
|
||||||
<field name="numbercall">-1</field>
|
|
||||||
<field name="doall" eval="False"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
</data>
|
|
||||||
</odoo>
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from . import hr_employee
|
|
||||||
from . import res_config_setting
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
import logging
|
|
||||||
import requests
|
|
||||||
from odoo import models, fields, api, _
|
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class JkmPracticeEmployee(models.Model):
|
|
||||||
_inherit = 'hr.employee'
|
|
||||||
_description = '员工信息'
|
|
||||||
|
|
||||||
we_id = fields.Char(string='企微ID', index=True)
|
|
||||||
|
|
||||||
def _employee_info_sync(self):
|
|
||||||
url = '/api/get/organization'
|
|
||||||
config = self.env['res.config.settings'].get_values()
|
|
||||||
ret = requests.post((config['ims_url'] + url), json={}, data={})
|
|
||||||
result = ret.json()['result']
|
|
||||||
if result['code'] == 200:
|
|
||||||
if result['employee_list']:
|
|
||||||
for employee_info in result['employee_list']:
|
|
||||||
if employee_info['work_email']:
|
|
||||||
hr_employee = self.sudo().search([('work_email', '=', employee_info['work_email'])])
|
|
||||||
hr_employee.write({'we_id': employee_info['we_id']})
|
|
||||||
if hr_employee.user_id:
|
|
||||||
hr_employee.user_id.write({'we_employee_id': employee_info['we_id']})
|
|
||||||
else:
|
|
||||||
logging.info('_employee_info_sync error:%s' % result['message'])
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user