Compare commits
1 Commits
feature/ne
...
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 {
|
||||||
|
margin-right: 15px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
text-align: 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;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.processing-capabilities-grid {
|
|
||||||
grid-template-columns: repeat(3, 1fr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 480px) {
|
|
||||||
.processing-capabilities-grid {
|
|
||||||
grid-template-columns: repeat(2, 1fr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.image-preview-container {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: rgba(0, 0, 0, 0.9);
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
z-index: 1000;
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-preview-container.show {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-preview {
|
|
||||||
max-width: 90%;
|
|
||||||
max-height: 90%;
|
|
||||||
object-fit: contain;
|
|
||||||
box-shadow: 0 0 20px rgba(255, 255, 255, 0.2);
|
|
||||||
border-radius: 5px;
|
|
||||||
transform: scale(0.9);
|
|
||||||
transition: transform 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-preview-container.show .image-preview {
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-preview-close {
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 20px;
|
top: -8.8px;
|
||||||
right: 30px;
|
right: -8.8px;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 40px;
|
background-color: #000;
|
||||||
font-weight: bold;
|
opacity: 0;
|
||||||
transition: 0.3s;
|
text-align: center;
|
||||||
cursor: pointer;
|
line-height: 20px;
|
||||||
opacity: 0.7;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-preview-close:hover,
|
.img_close {
|
||||||
.image-preview-close:focus {
|
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
text-decoration: none;
|
transform: scale(0.1);
|
||||||
cursor: pointer;
|
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');
|
|
||||||
previewImg.src = src;
|
|
||||||
previewImg.className = 'image-preview';
|
|
||||||
// 设置放大的预览图片大小
|
|
||||||
previewImg.style.width = '600px';
|
|
||||||
previewImg.style.height = 'auto'; // 保持宽高比
|
|
||||||
|
|
||||||
const closeButton = document.createElement('span');
|
|
||||||
closeButton.innerHTML = '×';
|
|
||||||
closeButton.className = 'image-preview-close';
|
|
||||||
|
|
||||||
previewContainer.appendChild(previewImg);
|
|
||||||
previewContainer.appendChild(closeButton);
|
|
||||||
document.body.appendChild(previewContainer);
|
|
||||||
|
|
||||||
// 添加关闭预览的事件监听器
|
|
||||||
const closePreview = () => {
|
|
||||||
previewContainer.classList.remove('show');
|
|
||||||
setTimeout(() => {
|
|
||||||
document.body.removeChild(previewContainer);
|
|
||||||
}, 300);
|
|
||||||
};
|
|
||||||
|
|
||||||
closeButton.addEventListener('click', closePreview);
|
|
||||||
|
|
||||||
// 点击预览框外部也可以关闭
|
|
||||||
previewContainer.addEventListener('click', (e) => {
|
|
||||||
if (e.target === previewContainer) {
|
|
||||||
closePreview();
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
// 使用 setTimeout 来触发过渡效果
|
onCloseClick(event) {
|
||||||
setTimeout(() => {
|
const close = event.target;
|
||||||
previewContainer.classList.add('show');
|
const img = close.previousSibling;
|
||||||
}, 10);
|
img.parentElement.classList.remove('zoomed');
|
||||||
|
close.classList.remove('img_close');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,20 +2,25 @@
|
|||||||
<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>
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -526,13 +522,3 @@ div:has(.o_required_modifier) > label::before {
|
|||||||
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(
|
||||||
|
# [('model_id', '=', current_model_id)], ['model_id', 'is_delete',
|
||||||
|
# 'groups_id'])
|
||||||
|
# if access_right_rec and not self.env.is_admin():
|
||||||
|
# for rec in access_right_rec:
|
||||||
|
# group_name = self.env['ir.model.data'].sudo().search([
|
||||||
|
# ('model', '=', 'res.groups'),
|
||||||
|
# ('res_id', '=', rec['groups_id'][0])
|
||||||
|
# ]).name
|
||||||
|
# module_name = self.env['ir.model.data'].sudo().search([
|
||||||
|
# ('model', '=', 'res.groups'),
|
||||||
|
# ('res_id', '=', rec['groups_id'][0])
|
||||||
|
# ]).module
|
||||||
|
# group = module_name + "." + group_name
|
||||||
|
# if self.env.user.has_group(group):
|
||||||
|
# if rec['is_delete']:
|
||||||
|
# raise UserError(_('You are restricted from performing this'
|
||||||
|
# ' operation. Please contact the'
|
||||||
|
# ' administrator.'))
|
||||||
|
# 检查 'access.right' 模型是否存在于环境中
|
||||||
|
if 'access.right' in self.env:
|
||||||
|
# current_model_id = self.env['ir.model'].sudo().search([('model', '=', self._name)]).id
|
||||||
access_right_rec = self.env['access.right'].sudo().search_read(
|
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_data = self.env['ir.model.data'].sudo().search_read(
|
||||||
('model', '=', 'res.groups'),
|
[('model', '=', 'res.groups'), ('res_id', '=', rec['groups_id'][0])],
|
||||||
('res_id', '=', rec['groups_id'][0])
|
['name', 'module']
|
||||||
]).name
|
)
|
||||||
module_name = self.env['ir.model.data'].sudo().search([
|
|
||||||
('model', '=', 'res.groups'),
|
if group_data:
|
||||||
('res_id', '=', rec['groups_id'][0])
|
group_name = group_data[0]['name']
|
||||||
]).module
|
module_name = group_data[0]['module']
|
||||||
group = module_name + "." + group_name
|
group_xml_id = f"{module_name}.{group_name}"
|
||||||
if self.env.user.has_group(group):
|
|
||||||
if rec['is_delete']:
|
if self.env.user.has_group(group_xml_id) and rec['is_delete']:
|
||||||
raise UserError(_('You are restricted from performing this'
|
raise UserError(
|
||||||
' operation. Please contact the'
|
_('You are restricted from performing this operation. Please contact the administrator.'))
|
||||||
' administrator.'))
|
else:
|
||||||
|
# 如果 'access.right' 模型不存在,可以在这里定义备选逻辑
|
||||||
|
pass
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
BaseModel._create = _create
|
BaseModel._create = _create
|
||||||
# BaseModel.unlink = unlink
|
BaseModel.unlink = unlink
|
||||||
|
|||||||
@@ -1,143 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from . import models
|
|
||||||
from . import controllers
|
|
||||||
|
|
||||||
from odoo import api, SUPERUSER_ID
|
|
||||||
|
|
||||||
def _data_install(cr, registry):
|
|
||||||
env = api.Environment(cr, SUPERUSER_ID, {})
|
|
||||||
# 获取所有需要设置的产品模板
|
|
||||||
env.ref('jikimo_sale_multiple_supply_methods.product_template_purchase').product_variant_id.write({'active': False, 'is_bfm': True})
|
|
||||||
env.ref('jikimo_sale_multiple_supply_methods.product_template_manual_processing').product_variant_id.write({'active': False, 'single_manufacturing': True, 'is_bfm': True})
|
|
||||||
env.ref('jikimo_sale_multiple_supply_methods.product_template_default').product_variant_id.write({'active': False, 'is_bfm': True})
|
|
||||||
env.ref('jikimo_sale_multiple_supply_methods.product_template_embryo_customer_provided').product_variant_id.write({'active': False})
|
|
||||||
env.ref('jikimo_sale_multiple_supply_methods.product_template_outsourcing').product_variant_id.write({'active': False, 'is_bfm': True})
|
|
||||||
env.ref('sf_dlm.product_embryo_sf_self_machining').product_tmpl_id.write({'categ_type': '坯料'})
|
|
||||||
env.ref('sf_dlm.product_template_sf').product_tmpl_id.write({'categ_type': '成品'})
|
|
||||||
env.ref('sf_dlm.product_embryo_sf_outsource').product_tmpl_id.write({'categ_type': '坯料'})
|
|
||||||
env.ref('sf_dlm.product_embryo_sf_purchase').product_tmpl_id.write({'categ_type': '坯料'})
|
|
||||||
|
|
||||||
# 为三步制造增加规则
|
|
||||||
warehouse = env['stock.warehouse'].search([('company_id', '=', env.company.id)], limit=1)
|
|
||||||
product_route_id = warehouse.pbm_route_id
|
|
||||||
# 创建规则:原料存货区 -> 制造前, 坯料存货区 -> 制造前, 制造后 -> 坯料存货区, 制造后 -> 成品存货区
|
|
||||||
raw_material_location_id = env['stock.location'].search([('name', '=', '坯料存货区')], limit=1)
|
|
||||||
picking_type_production = warehouse.pbm_type_id
|
|
||||||
picking_type_stock = warehouse.sam_type_id
|
|
||||||
material_location_id = env['stock.location'].search([('name', '=', '原料存货区')], limit=1)
|
|
||||||
# 为mto增加规则
|
|
||||||
mto_route_id = env.ref('stock.route_warehouse0_mto')
|
|
||||||
# 创建规则:原料存货区 -> 外包位置, 坯料存货区 -> 外包位置
|
|
||||||
subcontracting_location_id = env.company.subcontracting_location_id
|
|
||||||
picking_type_subcontracting = warehouse.subcontracting_resupply_type_id
|
|
||||||
# 为补给外包商增加规则
|
|
||||||
resupply_route_id = warehouse.subcontracting_route_id
|
|
||||||
|
|
||||||
rules_data = [
|
|
||||||
{
|
|
||||||
'name': 'WH: 原料存货区 → 制造前',
|
|
||||||
'location_src_id': material_location_id.id,
|
|
||||||
'location_dest_id': warehouse.pbm_loc_id.id,
|
|
||||||
'route_id': product_route_id.id,
|
|
||||||
'picking_type_id': picking_type_production.id,
|
|
||||||
'action': 'pull',
|
|
||||||
'sequence': 20,
|
|
||||||
'warehouse_id': warehouse.id,
|
|
||||||
'procure_method': 'mts_else_mto',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'WH: 坯料存货区 → 制造前',
|
|
||||||
'location_src_id': raw_material_location_id.id,
|
|
||||||
'location_dest_id': warehouse.pbm_loc_id.id,
|
|
||||||
'route_id': product_route_id.id,
|
|
||||||
'picking_type_id': picking_type_production.id,
|
|
||||||
'action': 'pull',
|
|
||||||
'sequence': 21,
|
|
||||||
'warehouse_id': warehouse.id,
|
|
||||||
'procure_method': 'mts_else_mto',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'WH: 制造后 → 坯料存货区',
|
|
||||||
'location_src_id': warehouse.sam_loc_id.id,
|
|
||||||
'location_dest_id': raw_material_location_id.id,
|
|
||||||
'route_id': product_route_id.id,
|
|
||||||
'picking_type_id': picking_type_stock.id,
|
|
||||||
'action': 'push',
|
|
||||||
'sequence': 23,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'WH: 制造后 → 成品存货区',
|
|
||||||
'location_src_id': warehouse.sam_loc_id.id,
|
|
||||||
'location_dest_id': env['stock.location'].search([('name', '=', '成品存货区')], limit=1).id,
|
|
||||||
'route_id': product_route_id.id,
|
|
||||||
'picking_type_id': picking_type_stock.id,
|
|
||||||
'action': 'push',
|
|
||||||
'sequence': 24,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'WH: 原料存货区 → 外包位置 (MTO)',
|
|
||||||
'location_src_id': material_location_id.id,
|
|
||||||
'location_dest_id': subcontracting_location_id.id,
|
|
||||||
'route_id': mto_route_id.id,
|
|
||||||
'picking_type_id': picking_type_subcontracting.id,
|
|
||||||
'action': 'pull',
|
|
||||||
'sequence': 24,
|
|
||||||
'warehouse_id': warehouse.id,
|
|
||||||
'procure_method': 'mts_else_mto',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'WH: 坯料存货区 → 外包位置 (MTO)',
|
|
||||||
'location_src_id': raw_material_location_id.id,
|
|
||||||
'location_dest_id': subcontracting_location_id.id,
|
|
||||||
'route_id': mto_route_id.id,
|
|
||||||
'picking_type_id': picking_type_subcontracting.id,
|
|
||||||
'action': 'pull',
|
|
||||||
'sequence': 25,
|
|
||||||
'warehouse_id': warehouse.id,
|
|
||||||
'procure_method': 'mts_else_mto',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'name': 'WH: 坯料存货区 → 外包位置',
|
|
||||||
'location_src_id': raw_material_location_id.id,
|
|
||||||
'location_dest_id': subcontracting_location_id.id,
|
|
||||||
'route_id': resupply_route_id.id,
|
|
||||||
'picking_type_id': picking_type_subcontracting.id,
|
|
||||||
'action': 'pull',
|
|
||||||
'sequence': 26,
|
|
||||||
'warehouse_id': warehouse.id,
|
|
||||||
'procure_method': 'make_to_stock',
|
|
||||||
}
|
|
||||||
]
|
|
||||||
# 遍历每个规则数据,执行创建或更新操作
|
|
||||||
for rule_data in rules_data:
|
|
||||||
_create_or_update_stock_rule(env, rule_data)
|
|
||||||
|
|
||||||
def _create_or_update_stock_rule(env, rule_data):
|
|
||||||
# 尝试查找现有的 stock.rule
|
|
||||||
existing_rule = env['stock.rule'].search([
|
|
||||||
('name', '=', rule_data['name']),
|
|
||||||
('route_id', '=', rule_data.get('route_id'))
|
|
||||||
], limit=1)
|
|
||||||
|
|
||||||
if existing_rule:
|
|
||||||
# 如果存在,更新现有记录
|
|
||||||
existing_rule.write(rule_data)
|
|
||||||
else:
|
|
||||||
# 如果不存在,创建新记录
|
|
||||||
env['stock.rule'].create(rule_data)
|
|
||||||
|
|
||||||
def _data_uninstall(cr, registry):
|
|
||||||
env = api.Environment(cr, SUPERUSER_ID, {})
|
|
||||||
warehouse = env['stock.warehouse'].search([('company_id', '=', env.company.id)], limit=1)
|
|
||||||
product_route_id = warehouse.pbm_route_id
|
|
||||||
resupply_route_id = warehouse.subcontracting_route_id
|
|
||||||
mto_route_id = env.ref('stock.route_warehouse0_mto')
|
|
||||||
# Fail unlink means that the route is used somewhere (e.g. route_id on stock.rule). In this case
|
|
||||||
# we don't try to do anything.
|
|
||||||
try:
|
|
||||||
with env.cr.savepoint():
|
|
||||||
env['stock.rule'].search([('name', 'in', ('WH: 原料存货区 → 制造前', 'WH: 坯料存货区 → 制造前', 'WH: 制造后 → 坯料存货区', 'WH: 制造后 → 成品存货区')), ('route_id', '=', product_route_id.id)]).unlink()
|
|
||||||
env['stock.rule'].search([('name', 'in', ('WH: 原料存货区 → 外包位置 (MTO)', 'WH: 坯料存货区 → 外包位置 (MTO)')), ('route_id', '=', mto_route_id.id)]).unlink()
|
|
||||||
env['stock.rule'].search([('name', '=', 'WH: 坯料存货区 → 外包位置'), ('route_id', '=', resupply_route_id.id)]).unlink()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
{
|
|
||||||
'name': '机企猫 多供货方式',
|
|
||||||
'version': '16.0.1.0.0',
|
|
||||||
'summary': """ 报价单提供(自动化产线加工/人工线下加工/外购/委外加工)多种供货方式选择 """,
|
|
||||||
'author': 'fox',
|
|
||||||
'website': '',
|
|
||||||
'category': '',
|
|
||||||
'depends': ['sf_dlm', 'sale_stock', 'sf_sale'],
|
|
||||||
"data": [
|
|
||||||
'security/ir.model.access.csv',
|
|
||||||
'data/stock_routes.xml',
|
|
||||||
'data/product_data.xml',
|
|
||||||
'views/sale_order_views.xml',
|
|
||||||
# 'views/product_product_views.xml',
|
|
||||||
],'assets': {
|
|
||||||
# 'web.assets_backend': [
|
|
||||||
# 'jikimo_sale_multiple_supply_methods/static/src/**/*'
|
|
||||||
# ],
|
|
||||||
},
|
|
||||||
'post_init_hook': '_data_install',
|
|
||||||
'uninstall_hook': '_data_uninstall',
|
|
||||||
'application': True,
|
|
||||||
'installable': True,
|
|
||||||
'auto_install': False,
|
|
||||||
'license': 'LGPL-3',
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from . import main
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
import logging
|
|
||||||
import json
|
|
||||||
from odoo import http
|
|
||||||
from odoo.http import request
|
|
||||||
from odoo.addons.sf_bf_connect.controllers.controllers import Sf_Bf_Connect
|
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
class JikimoSaleRoutePicking(Sf_Bf_Connect):
|
|
||||||
|
|
||||||
@http.route('/api/bfm_process_order/list', type='http', auth='sf_token', methods=['GET', 'POST'], csrf=False,
|
|
||||||
cors="*")
|
|
||||||
def get_bfm_process_order_list(self, **kw):
|
|
||||||
"""
|
|
||||||
接收业务平台加工订单分配工厂时传送来的订单数据并生成销售订单和产品及坯料
|
|
||||||
:param kw:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
res = {'status': 1, 'factory_order_no': ''}
|
|
||||||
# _logger.info('get_bfm_process_order_list:%s' % kw['order_number'])
|
|
||||||
try:
|
|
||||||
product_id = request.env.ref('jikimo_sale_multiple_supply_methods.product_template_default').with_context(active_test=False).sudo().product_variant_id
|
|
||||||
_logger.info('product_id:%s' % product_id)
|
|
||||||
company_id = request.env.ref('base.main_company').sudo()
|
|
||||||
bfm_process_order_list = json.loads(kw['bfm_process_order_list'])
|
|
||||||
order_id = request.env['sale.order'].with_user(request.env.ref("base.user_admin")).sale_order_create(
|
|
||||||
company_id, kw['delivery_name'], kw['delivery_telephone'], kw['delivery_address'],
|
|
||||||
kw['delivery_end_date'], kw['payments_way'], kw['pay_way'], state='draft')
|
|
||||||
i = 1
|
|
||||||
# 给sale_order的default_code字段赋值
|
|
||||||
# aa = request.env['sale.order'].sudo().search([('name', '=', order_id.name)])
|
|
||||||
# _logger.info('get_bfm_process_or===================================:%s' % order_id.name)
|
|
||||||
order_id.default_code = kw['order_number']
|
|
||||||
if kw.get('logistics_way'):
|
|
||||||
order_id.logistics_way = kw['logistics_way']
|
|
||||||
for item in bfm_process_order_list:
|
|
||||||
if item.get('embryo_redundancy_id'):
|
|
||||||
item['embryo_redundancy'] = request.env['sf.embryo.redundancy'].sudo().search([('code', '=', item['embryo_redundancy_id'])], limit=1)
|
|
||||||
item['embryo_redundancy_id'] = item['embryo_redundancy'].id
|
|
||||||
product = request.env['product.template'].sudo().product_create(product_id, item, order_id,
|
|
||||||
kw['order_number'], i)
|
|
||||||
product.product_tmpl_id.is_customer_provided = True if item['embryo_redundancy_id'] else False
|
|
||||||
order_id.with_user(request.env.ref("base.user_admin")).sale_order_create_line(product, item)
|
|
||||||
i += 1
|
|
||||||
res['factory_order_no'] = order_id.name
|
|
||||||
except Exception as e:
|
|
||||||
_logger.info('get_bfm_process_order_list error:%s' % e)
|
|
||||||
res['status'] = -1
|
|
||||||
res['message'] = '工厂创建销售订单和产品失败,请联系管理员'
|
|
||||||
request.cr.rollback()
|
|
||||||
return json.JSONEncoder().encode(res)
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<odoo>
|
|
||||||
<data noupdate="1">
|
|
||||||
<record id="product_template_manual_processing" model="product.template">
|
|
||||||
<field name="name">人工线下加工模板</field>
|
|
||||||
<field name="active" eval="False"/>
|
|
||||||
<field name="categ_id" ref="sf_dlm.product_category_finished_sf"/>
|
|
||||||
<field name="route_ids"
|
|
||||||
eval="[ref('stock.route_warehouse0_mto'), ref('mrp.route_warehouse0_manufacture')]"/>
|
|
||||||
<field name="invoice_policy">delivery</field>
|
|
||||||
<field name="detailed_type">product</field>
|
|
||||||
<field name="purchase_ok">false</field>
|
|
||||||
<field name="uom_id" ref="uom.product_uom_unit"/>
|
|
||||||
<field name="uom_po_id" ref="uom.product_uom_unit"/>
|
|
||||||
<field name="company_id" ref="base.main_company"/>
|
|
||||||
<field name="single_manufacturing">true</field>
|
|
||||||
<field name="tracking">serial</field>
|
|
||||||
<!-- <field name="categ_type">成品</field> -->
|
|
||||||
<field name="is_manual_processing">true</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="product_template_purchase" model="product.template">
|
|
||||||
<field name="name">成品外购模板</field>
|
|
||||||
<field name="active" eval="False"/>
|
|
||||||
<field name="categ_id" ref="sf_dlm.product_category_finished_sf"/>
|
|
||||||
<field name="route_ids"
|
|
||||||
eval="[ref('stock.route_warehouse0_mto'), ref('purchase_stock.route_warehouse0_buy')]"/>
|
|
||||||
<field name="tracking">serial</field>
|
|
||||||
<field name="detailed_type">product</field>
|
|
||||||
<field name="uom_id" ref="uom.product_uom_unit"/>
|
|
||||||
<field name="uom_po_id" ref="uom.product_uom_unit"/>
|
|
||||||
<field name="company_id" ref="base.main_company"/>
|
|
||||||
<!-- <field name="categ_type">成品</field> -->
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="product_template_outsourcing" model="product.template">
|
|
||||||
<field name="name">成品委外加工模板</field>
|
|
||||||
<field name="active" eval="False"/>
|
|
||||||
<field name="categ_id" ref="sf_dlm.product_category_finished_sf"/>
|
|
||||||
<field name="route_ids"
|
|
||||||
eval="[ref('stock.route_warehouse0_mto'), ref('purchase_stock.route_warehouse0_buy'), ref('mrp_subcontracting.route_resupply_subcontractor_mto')]"/>
|
|
||||||
<field name="tracking">serial</field>
|
|
||||||
<field name="detailed_type">product</field>
|
|
||||||
<field name="uom_id" ref="uom.product_uom_unit"/>
|
|
||||||
<field name="uom_po_id" ref="uom.product_uom_unit"/>
|
|
||||||
<field name="company_id" ref="base.main_company"/>
|
|
||||||
<!-- <field name="categ_type">成品</field> -->
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="product_template_default" model="product.template">
|
|
||||||
<field name="name">成品初始化模板</field>
|
|
||||||
<field name="active" eval="False"/>
|
|
||||||
<field name="categ_id" ref="sf_dlm.product_category_finished_sf"/>
|
|
||||||
<field name="route_ids" eval="[]"/>
|
|
||||||
<field name="tracking">serial</field>
|
|
||||||
<field name="detailed_type">product</field>
|
|
||||||
<field name="uom_id" ref="uom.product_uom_unit"/>
|
|
||||||
<field name="uom_po_id" ref="uom.product_uom_unit"/>
|
|
||||||
<field name="company_id" ref="base.main_company"/>
|
|
||||||
<!-- <field name="categ_type">成品</field> -->
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- 供应商信息(业务平台),由于数据是python创建,只能指定ID -->
|
|
||||||
<record id="product_supplierinfo_bfm" model="product.supplierinfo">
|
|
||||||
<field name="partner_id" eval="91"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="product_template_embryo_customer_provided" model="product.template">
|
|
||||||
<field name="name">坯料客供料模板</field>
|
|
||||||
<field name="active" eval="False"/>
|
|
||||||
<field name="categ_id" ref="sf_dlm.product_category_embryo_sf"/>
|
|
||||||
<field name="route_ids" eval="[
|
|
||||||
ref('stock.route_warehouse0_mto'),
|
|
||||||
ref('mrp_subcontracting.route_resupply_subcontractor_mto'),
|
|
||||||
ref('jikimo_sale_multiple_supply_methods.route_material_processing')]"/>
|
|
||||||
<field name="sale_ok">false</field>
|
|
||||||
<field name="tracking">serial</field>
|
|
||||||
<field name="detailed_type">product</field>
|
|
||||||
<field name="uom_id" ref="uom.product_uom_unit"/>
|
|
||||||
<field name="uom_po_id" ref="uom.product_uom_unit"/>
|
|
||||||
<field name="company_id" ref="base.main_company"/>
|
|
||||||
<!-- <field name="categ_type">坯料</field> -->
|
|
||||||
<field name="seller_ids" eval="[ref('jikimo_sale_multiple_supply_methods.product_supplierinfo_bfm')]"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="sf_dlm.product_embryo_sf_self_machining" model="product.product">
|
|
||||||
<field name="is_manual_processing">true</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="sf_dlm.product_embryo_sf_self_machining" model="product.product">
|
|
||||||
<field name="route_ids" eval="[(4, ref('mrp_subcontracting.route_resupply_subcontractor_mto'))]"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="sf_dlm.product_embryo_sf_purchase" model="product.product">
|
|
||||||
<field name="route_ids" eval="[(4, ref('mrp_subcontracting.route_resupply_subcontractor_mto'))]"/>
|
|
||||||
</record>
|
|
||||||
</data>
|
|
||||||
</odoo>
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<odoo>
|
|
||||||
<data noupdate="1">
|
|
||||||
<record id="route_material_processing" model="stock.route">
|
|
||||||
<field name="name">带料加工</field>
|
|
||||||
<field name="product_selectable">true</field>
|
|
||||||
<field name="warehouse_selectable">true</field>
|
|
||||||
<field name="warehouse_ids" eval="[ref('stock.warehouse0')]"/>
|
|
||||||
<field name="sequence">16</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="material_picking_in" model="stock.picking.type">
|
|
||||||
<field name="name">客供料入库</field>
|
|
||||||
<field name="code">incoming</field>
|
|
||||||
<field name="active">true</field>
|
|
||||||
<field name="company_id" ref="base.main_company"/>
|
|
||||||
<field name="sequence_code">DL</field>
|
|
||||||
<field name="warehouse_id" ref="stock.warehouse0"/>
|
|
||||||
<field name="default_location_src_id" ref="stock.stock_location_customers"/>
|
|
||||||
<field name="default_location_dest_id" eval="25"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="rule_material_receiving" model="stock.rule">
|
|
||||||
<field name="name">带料收货</field>
|
|
||||||
<field name="route_id" ref="route_material_processing"/>
|
|
||||||
<field name="location_dest_id" ref="stock.stock_location_company"/>
|
|
||||||
<field name="location_src_id" ref="stock.stock_location_customers"/>
|
|
||||||
<field name="picking_type_id" ref="material_picking_in"/>
|
|
||||||
<field name="action">pull</field>
|
|
||||||
</record>
|
|
||||||
</data>
|
|
||||||
</odoo>
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from . import product_template
|
|
||||||
from . import sale_order
|
|
||||||
from . import mrp_bom
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
from odoo import models, fields
|
|
||||||
|
|
||||||
class MrpBom(models.Model):
|
|
||||||
_inherit = 'mrp.bom'
|
|
||||||
|
|
||||||
# 业务平台分配工厂后在智能工厂先创建销售订单再创建该产品后再次进行创建bom
|
|
||||||
def bom_create(self, product, bom_type, product_type):
|
|
||||||
bom_id = super(MrpBom, self).bom_create(product, bom_type, product_type)
|
|
||||||
|
|
||||||
# 成品的供应商从模板中获取
|
|
||||||
if product_type == 'product':
|
|
||||||
bom_id.subcontractor_id = product.product_tmpl_id.seller_ids.partner_id.id
|
|
||||||
return bom_id
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
from odoo import models, fields, api
|
|
||||||
|
|
||||||
class ProductTemplate(models.Model):
|
|
||||||
_inherit = 'product.template'
|
|
||||||
|
|
||||||
is_manual_processing = fields.Boolean(string='人工线下加工')
|
|
||||||
is_customer_provided = fields.Boolean(string='客供料')
|
|
||||||
|
|
||||||
def copy_template(self, product_template_id):
|
|
||||||
if not isinstance(product_template_id, ProductTemplate):
|
|
||||||
raise ValueError('%s必须是ProductTemplate类型' % product_template_id)
|
|
||||||
|
|
||||||
self.route_ids = product_template_id.route_ids
|
|
||||||
self.categ_id = product_template_id.categ_id
|
|
||||||
self.invoice_policy = product_template_id.invoice_policy
|
|
||||||
self.detailed_type = product_template_id.detailed_type
|
|
||||||
self.purchase_ok = product_template_id.purchase_ok
|
|
||||||
self.uom_id = product_template_id.uom_id
|
|
||||||
self.uom_po_id = product_template_id.uom_po_id
|
|
||||||
self.company_id = product_template_id.company_id
|
|
||||||
self.single_manufacturing = product_template_id.single_manufacturing
|
|
||||||
self.tracking = product_template_id.tracking
|
|
||||||
self.is_bfm = product_template_id.is_bfm
|
|
||||||
self.is_manual_processing = product_template_id.is_manual_processing
|
|
||||||
# 复制 seller_ids
|
|
||||||
self.seller_ids = [(0, 0, {'partner_id': seller.partner_id.id, 'delay': 1.0}) for seller in product_template_id.seller_ids]
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
from datetime import datetime
|
|
||||||
from odoo import models
|
|
||||||
|
|
||||||
import logging
|
|
||||||
import base64
|
|
||||||
import hashlib
|
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class QuickEasyOrder(models.Model):
|
|
||||||
_inherit = 'quick.easy.order'
|
|
||||||
|
|
||||||
def distribute_to_factory(self, obj):
|
|
||||||
"""
|
|
||||||
多供货方式,重写派单到工厂
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
_logger.info('---------派单到工厂-------')
|
|
||||||
res = {'bfm_process_order_list': []}
|
|
||||||
for item in obj:
|
|
||||||
attachment = item.upload_model_file[0]
|
|
||||||
base64_data = base64.b64encode(attachment.datas)
|
|
||||||
base64_datas = base64_data.decode('utf-8')
|
|
||||||
barcode = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
|
|
||||||
# logging.info('model_file-size: %s' % len(item.model_file))
|
|
||||||
res['bfm_process_order_list'].append({
|
|
||||||
'model_long': item.model_length,
|
|
||||||
'model_width': item.model_width,
|
|
||||||
'model_height': item.model_height,
|
|
||||||
'model_volume': item.model_volume,
|
|
||||||
'model_machining_precision': item.machining_precision,
|
|
||||||
'model_name': attachment.name,
|
|
||||||
'model_data': base64_datas,
|
|
||||||
'model_file': base64.b64encode(item.model_file).decode('utf-8'),
|
|
||||||
'texture_code': item.material_id.materials_no,
|
|
||||||
'texture_type_code': item.material_model_id.materials_no,
|
|
||||||
# 'surface_process_code': self.env['jikimo.surface.process']._json_surface_process_code(item),
|
|
||||||
'process_parameters_code': self.env[
|
|
||||||
'sf.production.process.parameter']._json_production_process_item_code(
|
|
||||||
item),
|
|
||||||
'price': item.price,
|
|
||||||
'number': item.quantity,
|
|
||||||
'total_amount': item.price,
|
|
||||||
'remark': '',
|
|
||||||
'manual_quotation': True,
|
|
||||||
'barcode': barcode,
|
|
||||||
'part_number': item.part_drawing_number,
|
|
||||||
'machining_drawings_name': '',
|
|
||||||
'quality_standard_name': '',
|
|
||||||
'machining_drawings_mimetype': '',
|
|
||||||
'quality_standard_mimetype': '',
|
|
||||||
'machining_drawings': item.machining_drawings,
|
|
||||||
'quality_standard': '',
|
|
||||||
'part_name': '',
|
|
||||||
})
|
|
||||||
company_id = self.env.ref('base.main_company').sudo()
|
|
||||||
product_id = self.env.ref('jikimo_sale_multiple_supply_methods.product_template_default').sudo().with_context(active_test=False).product_variant_id
|
|
||||||
# user_id = request.env.ref('base.user_admin').sudo()
|
|
||||||
order_id = self.env['sale.order'].sale_order_create(company_id, 'XXXXX', 'XXXXX', 'XXXXX',
|
|
||||||
str(datetime.now()), '现结', '支付宝', state='draft')
|
|
||||||
order_id.default_code = obj.name
|
|
||||||
i = 1
|
|
||||||
for item in res['bfm_process_order_list']:
|
|
||||||
product = self.env['product.template'].sudo().product_create(product_id, item, order_id,
|
|
||||||
obj.name, i)
|
|
||||||
order_id.with_user(self.env.ref("base.user_admin")).sale_order_create_line(product, item)
|
|
||||||
return order_id
|
|
||||||
except Exception as e:
|
|
||||||
return UserError('工厂创建销售订单和产品失败,请联系管理员')
|
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
import logging
|
|
||||||
import json
|
|
||||||
from odoo import models, fields, api
|
|
||||||
from odoo.exceptions import UserError
|
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
class SaleOrder(models.Model):
|
|
||||||
_inherit = 'sale.order'
|
|
||||||
|
|
||||||
state = fields.Selection([
|
|
||||||
('draft', "报价"),
|
|
||||||
('sent', "报价已发送"),
|
|
||||||
('supply method', "供货方式待确认"),
|
|
||||||
('sale', "销售订单"),
|
|
||||||
('done', "已锁定"),
|
|
||||||
('cancel', "已取消"),
|
|
||||||
])
|
|
||||||
|
|
||||||
def confirm_to_supply_method(self):
|
|
||||||
self.state = 'supply method'
|
|
||||||
|
|
||||||
def action_confirm(self):
|
|
||||||
# 判断是否所有产品都选择了供货方式
|
|
||||||
filter_line = self.order_line.filtered(lambda line: not line.supply_method)
|
|
||||||
if filter_line:
|
|
||||||
raise UserError('当前订单内(%s)产品未选择路线,请选择后重试' % ','.join(filter_line.mapped('product_id.name')))
|
|
||||||
|
|
||||||
for line in self.order_line:
|
|
||||||
bom_type = ''
|
|
||||||
# 根据供货方式修改成品模板
|
|
||||||
if line.supply_method == 'automation':
|
|
||||||
bom_type = 'normal'
|
|
||||||
product_template_id = self.env.ref('sf_dlm.product_template_sf').sudo().product_tmpl_id
|
|
||||||
elif line.supply_method == 'outsourcing':
|
|
||||||
bom_type = 'subcontract'
|
|
||||||
product_template_id = self.env.ref('jikimo_sale_multiple_supply_methods.product_template_outsourcing').sudo()
|
|
||||||
elif line.supply_method == 'purchase':
|
|
||||||
product_template_id = self.env.ref('jikimo_sale_multiple_supply_methods.product_template_purchase').sudo()
|
|
||||||
elif line.supply_method == 'manual':
|
|
||||||
bom_type = 'normal'
|
|
||||||
product_template_id = self.env.ref('jikimo_sale_multiple_supply_methods.product_template_manual_processing').sudo()
|
|
||||||
|
|
||||||
# 复制成品模板上的属性
|
|
||||||
line.product_id.product_tmpl_id.copy_template(product_template_id)
|
|
||||||
|
|
||||||
order_id = self
|
|
||||||
product = line.product_id
|
|
||||||
# 拼接方法需要的item结构
|
|
||||||
item = {
|
|
||||||
'texture_code': product.materials_id.materials_no,
|
|
||||||
'texture_type_code': product.materials_type_id.materials_no,
|
|
||||||
'model_long': product.length,
|
|
||||||
'model_width': product.width,
|
|
||||||
'model_height': product.height,
|
|
||||||
'price': product.list_price,
|
|
||||||
'embryo_redundancy_id': line.embryo_redundancy_id,
|
|
||||||
}
|
|
||||||
# 获取成品名结尾-n的n
|
|
||||||
product_seria = int(product.name.split('-')[-1])
|
|
||||||
# 成品供货方式为采购则不生成bom
|
|
||||||
if line.supply_method != 'purchase':
|
|
||||||
bom_data = self.env['mrp.bom'].with_user(self.env.ref("base.user_admin")).get_bom(product)
|
|
||||||
_logger.info('bom_data:%s' % bom_data)
|
|
||||||
if bom_data:
|
|
||||||
bom = self.env['mrp.bom'].with_user(self.env.ref("base.user_admin")).bom_create(product, 'normal', False)
|
|
||||||
bom.with_user(self.env.ref("base.user_admin")).bom_create_line_has(bom_data)
|
|
||||||
else:
|
|
||||||
# 当成品上带有客供料选项时,生成坯料时选择“客供料”路线
|
|
||||||
if line.embryo_redundancy_id:
|
|
||||||
# 将成品模板的内容复制到成品上
|
|
||||||
customer_provided_embryo = self.env.ref('jikimo_sale_multiple_supply_methods.product_template_embryo_customer_provided').sudo()
|
|
||||||
# 创建坯料,客供料的批量不需要创建bom
|
|
||||||
material_customer_provided_embryo = self.env['product.template'].sudo().no_bom_product_create(
|
|
||||||
customer_provided_embryo.with_context(active_test=False).product_variant_id,
|
|
||||||
item,
|
|
||||||
order_id, 'material_customer_provided', product_seria, product)
|
|
||||||
# 成品配置bom
|
|
||||||
product_bom_material_customer_provided = self.env['mrp.bom'].with_user(
|
|
||||||
self.env.ref("base.user_admin")).bom_create(
|
|
||||||
product, bom_type, 'product')
|
|
||||||
product_bom_material_customer_provided.with_user(self.env.ref("base.user_admin")).bom_create_line_has(
|
|
||||||
material_customer_provided_embryo)
|
|
||||||
elif line.product_id.materials_type_id.gain_way == '自加工':
|
|
||||||
self_machining_id = self.env.ref('sf_dlm.product_embryo_sf_self_machining').sudo()
|
|
||||||
# 创建坯料
|
|
||||||
self_machining_embryo = self.env['product.template'].sudo().no_bom_product_create(
|
|
||||||
self_machining_id,
|
|
||||||
item,
|
|
||||||
order_id, 'self_machining', product_seria, product)
|
|
||||||
# 创建坯料的bom
|
|
||||||
self_machining_bom = self.env['mrp.bom'].with_user(
|
|
||||||
self.env.ref("base.user_admin")).bom_create(
|
|
||||||
self_machining_embryo, 'normal', False)
|
|
||||||
# 创建坯料里bom的组件
|
|
||||||
self_machining_bom_line = self_machining_bom.with_user(
|
|
||||||
self.env.ref("base.user_admin")).bom_create_line(
|
|
||||||
self_machining_embryo)
|
|
||||||
if not self_machining_bom_line:
|
|
||||||
raise UserError('该订单模型的材料型号暂未有原材料,请先配置再进行分配')
|
|
||||||
# 产品配置bom
|
|
||||||
product_bom_self_machining = self.env['mrp.bom'].with_user(
|
|
||||||
self.env.ref("base.user_admin")).bom_create(
|
|
||||||
product, bom_type, 'product')
|
|
||||||
product_bom_self_machining.with_user(self.env.ref("base.user_admin")).bom_create_line_has(
|
|
||||||
self_machining_embryo)
|
|
||||||
elif line.product_id.materials_type_id.gain_way == '外协':
|
|
||||||
outsource_id = self.env.ref('sf_dlm.product_embryo_sf_outsource').sudo()
|
|
||||||
# 创建坯料
|
|
||||||
outsource_embryo = self.env['product.template'].sudo().no_bom_product_create(outsource_id,
|
|
||||||
item,
|
|
||||||
order_id,
|
|
||||||
'subcontract',
|
|
||||||
product_seria, product)
|
|
||||||
if outsource_embryo == -3:
|
|
||||||
raise UserError('该订单模型的材料型号暂未设置获取方式和供应商,请先配置再进行分配')
|
|
||||||
# 创建坯料的bom
|
|
||||||
outsource_bom = self.env['mrp.bom'].with_user(self.env.ref("base.user_admin")).bom_create(
|
|
||||||
outsource_embryo,
|
|
||||||
'subcontract', True)
|
|
||||||
# 创建坯料的bom的组件
|
|
||||||
outsource_bom_line = outsource_bom.with_user(
|
|
||||||
self.env.ref("base.user_admin")).bom_create_line(outsource_embryo)
|
|
||||||
if not outsource_bom_line:
|
|
||||||
raise UserError('该订单模型的材料型号暂未有原材料,请先配置再进行分配')
|
|
||||||
# 产品配置bom
|
|
||||||
product_bom_outsource = self.env['mrp.bom'].with_user(
|
|
||||||
self.env.ref("base.user_admin")).bom_create(product, bom_type, 'product')
|
|
||||||
product_bom_outsource.with_user(self.env.ref("base.user_admin")).bom_create_line_has(
|
|
||||||
outsource_embryo)
|
|
||||||
elif line.product_id.materials_type_id.gain_way == '采购':
|
|
||||||
purchase_id = self.env.ref('sf_dlm.product_embryo_sf_purchase').sudo()
|
|
||||||
purchase_embryo = self.env['product.template'].sudo().no_bom_product_create(purchase_id,
|
|
||||||
item,
|
|
||||||
order_id,
|
|
||||||
'purchase', product_seria,
|
|
||||||
product)
|
|
||||||
if purchase_embryo == -3:
|
|
||||||
raise UserError('该订单模型的材料型号暂未设置获取方式和供应商,请先配置再进行分配')
|
|
||||||
else:
|
|
||||||
# 产品配置bom
|
|
||||||
product_bom_purchase = self.env['mrp.bom'].with_user(
|
|
||||||
self.env.ref("base.user_admin")).bom_create(product, bom_type, 'product')
|
|
||||||
product_bom_purchase.with_user(self.env.ref("base.user_admin")).bom_create_line_has(
|
|
||||||
purchase_embryo)
|
|
||||||
return super(SaleOrder, self).action_confirm()
|
|
||||||
|
|
||||||
class SaleOrderLine(models.Model):
|
|
||||||
_inherit = 'sale.order.line'
|
|
||||||
|
|
||||||
# 供货方式
|
|
||||||
supply_method = fields.Selection([
|
|
||||||
('automation', "自动化产线加工"),
|
|
||||||
('manual', "人工线下加工"),
|
|
||||||
('purchase', "外购"),
|
|
||||||
('outsourcing', "委外加工"),
|
|
||||||
], string='供货方式')
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
|
||||||
access_sale_order_group_production_engineer,sale.order_group_production_engineer,sale.model_sale_order,sf_base.group_production_engineer,1,1,0,0
|
|
||||||
access_sale_order_line_group_production_engineer,sale_order_line_group_production_engineer,sale.model_sale_order_line,sf_base.group_production_engineer,1,1,0,0
|
|
||||||
access_product_product_group_production_engineer,product_product_group_production_engineer,product.model_product_product,sf_base.group_production_engineer,1,0,0,0
|
|
||||||
access_product_template_group_production_engineer,product_template_group_production_engineer,product.model_product_template,sf_base.group_production_engineer,1,0,0,0
|
|
||||||
access_stock_picking_group_production_engineer,stock_picking_group_production_engineer,stock.model_stock_picking,sf_base.group_production_engineer,1,0,0,0
|
|
||||||
access_stock_move_group_production_engineer,stock_move_group_production_engineer,stock.model_stock_move,sf_base.group_production_engineer,1,0,0,0
|
|
||||||
access_mrp_bom_group_production_engineer,mrp_bom_group_production_engineer,mrp.model_mrp_bom,sf_base.group_production_engineer,1,0,0,0
|
|
||||||
|
@@ -1,16 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
|
||||||
<odoo>
|
|
||||||
<!-- 由于该模块不能依赖sf_dlm_management, 该功能只能在sf_dlm_management中实现,并且依赖该模块-->
|
|
||||||
<record id="view_product_product_form_inherit_sf" model="ir.ui.view">
|
|
||||||
<field name="name">view.product.template.form.inherit.sf</field>
|
|
||||||
<field name="model">product.template</field>
|
|
||||||
<field name="inherit_id" ref="sf_dlm_management.view_sale_product_template_form_inherit_sf"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<xpath expr="//field[@name='manual_quotation']" position="after">
|
|
||||||
<field name="is_customer_provided" attrs="{'invisible': [('categ_type', 'not in', ['成品', '坯料'])], 'readonly': True}" />
|
|
||||||
</xpath>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
</odoo>
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
|
||||||
<odoo>
|
|
||||||
<record id="view_order_form_inherit_sf" model="ir.ui.view">
|
|
||||||
<field name="name">view.sale.order.form.inherit.sf</field>
|
|
||||||
<field name="inherit_id" ref="sale_stock.view_order_form_inherit_sale_stock_qty"/>
|
|
||||||
<field name="model">sale.order</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<xpath expr="//page/field[@name='order_line']/form/group/group/div[@name='ordered_qty']/widget[@name='qty_at_date_widget']" position="replace">
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//page/field[@name='order_line']/tree/widget[@name='qty_at_date_widget']" position="replace">
|
|
||||||
</xpath>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="view_order_form_inherit_supply_method" model="ir.ui.view">
|
|
||||||
<field name="name">view.sale.order.form.inherit.supply.method</field>
|
|
||||||
<field name="inherit_id" ref="sf_sale.view_sale_order_form_inherit_sf"/>
|
|
||||||
<field name="model">sale.order</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<xpath expr="//header/button[@name='action_confirm'][last()]" position="attributes">
|
|
||||||
<attribute name="attrs">{'invisible': [('state', '!=', 'draft')]}</attribute>
|
|
||||||
<attribute name="name">confirm_to_supply_method</attribute>
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//header/button[@name='confirm_to_supply_method']" position="before">
|
|
||||||
<button name="action_confirm" string="供货方式确认" type="object" attrs="{'invisible': [('state', '!=', 'supply method')]}" confirm="确认供货方式"/>
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//header/field[@name='state']" position="attributes">
|
|
||||||
<attribute name="statusbar_visible">draft,sent,supply method,sale</attribute>
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//page/field[@name='order_line']/tree/field[@name='remark']" position="before">
|
|
||||||
<field name="supply_method" attrs="{'invisible': [('state', '=', 'draft')], 'required': [('state', '=', 'supply method')]}" />
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//header/button[@name='action_cancel']" position="attributes">
|
|
||||||
<attribute name="attrs">{'invisible': [('state', '!=', 'draft')]}</attribute>
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//header/button[@name='action_cancel']" position="attributes">
|
|
||||||
<attribute name="attrs">{'invisible': [('state', '!=', 'draft')]}</attribute>
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//header/button[@name='action_quotation_send'][5]" position="attributes">
|
|
||||||
<attribute name="attrs">{'invisible': ['|','&',('check_status', '!=', 'approved'),('state', 'in', ['draft','cancel','supply method']),'&',('check_status', '=', 'approved'),('state', 'in', ['sale','cancel','supply method'])]}</attribute>
|
|
||||||
</xpath>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="jikimo_sale_order_view_search_inherit_quotation_supply_method" model="ir.ui.view">
|
|
||||||
<field name="name">jikimo.sale.order.search.inherit.quotation.supply.method</field>
|
|
||||||
<field name="model">sale.order</field>
|
|
||||||
<field name="mode">primary</field>
|
|
||||||
<field name="inherit_id" ref="sale.sale_order_view_search_inherit_quotation"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<xpath expr="//filter[@name='my_quotation']" position="attributes">
|
|
||||||
<attribute name="domain">[('state', 'in', ('draft', 'sent')), ('user_id', '=', uid)]</attribute>
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//filter[@name='draft']" position="after">
|
|
||||||
<filter string="供货方式待确认" name="supply_method" domain="[('state', '=', 'supply method')]"/>
|
|
||||||
</xpath>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="sale.action_quotations_with_onboarding" model="ir.actions.act_window">
|
|
||||||
<field name="search_view_id" ref="jikimo_sale_order_view_search_inherit_quotation_supply_method"/>
|
|
||||||
<field name="context">{'search_default_draft': 1}</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="action_quotations_supply_method" model="ir.actions.act_window">
|
|
||||||
<field name="name">报价单</field>
|
|
||||||
<field name="type">ir.actions.act_window</field>
|
|
||||||
<field name="res_model">sale.order</field>
|
|
||||||
<field name="view_mode">tree,kanban,form,calendar,pivot,graph,activity</field>
|
|
||||||
<field name="view_id" ref="sale.view_quotation_tree_with_onboarding"/>
|
|
||||||
<field name="search_view_id" ref="jikimo_sale_order_view_search_inherit_quotation_supply_method"/>
|
|
||||||
<field name="context">{'search_default_supply_method': 1}</field>
|
|
||||||
<field name="help" type="html">
|
|
||||||
<p class="o_view_nocontent_smiling_face">
|
|
||||||
Create a new quotation, the first step of a new sale!
|
|
||||||
</p><p>
|
|
||||||
Once the quotation is confirmed by the customer, it becomes a sales order.<br/> You will be able to create an invoice and collect the payment.
|
|
||||||
</p>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
<menuitem
|
|
||||||
id="sale.sale_menu_root"
|
|
||||||
groups="sf_base.group_production_engineer,sf_base.group_sale_director,sf_base.group_sale_salemanager"
|
|
||||||
/>
|
|
||||||
<!--供货路线专员菜单-->
|
|
||||||
<menuitem
|
|
||||||
id="sale_order_menu_quotations_supply_method"
|
|
||||||
name="报价"
|
|
||||||
action="action_quotations_supply_method"
|
|
||||||
parent="sale.sale_order_menu"
|
|
||||||
groups="sf_base.group_production_engineer"
|
|
||||||
sequence="2"/>
|
|
||||||
|
|
||||||
<record id="sale.menu_sale_order" model="ir.ui.menu">
|
|
||||||
<field name="groups_id" eval="[(4, ref('sf_base.group_production_engineer'))]"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="sale.report_sales_team" model="ir.ui.menu">
|
|
||||||
<field name="groups_id" eval="[(4, ref('sf_base.group_production_engineer'))]"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="sale.res_partner_menu" model="ir.ui.menu">
|
|
||||||
<field name="groups_id" eval="[(4, ref('sf_base.group_production_engineer'))]"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</odoo>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from . import controllers
|
|
||||||
from . import models
|
|
||||||
from . import wizard
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
{
|
|
||||||
'name': "jikimo_system_order",
|
|
||||||
|
|
||||||
'summary': """
|
|
||||||
系统工单""",
|
|
||||||
|
|
||||||
'description': """
|
|
||||||
用于处理针对系统的工作任务;
|
|
||||||
员工可以通过系统工单发起申请,由维护人员处理以后,填写处理结果。
|
|
||||||
""",
|
|
||||||
|
|
||||||
'author': "机企猫",
|
|
||||||
'website': "http://www.jikimo.com",
|
|
||||||
|
|
||||||
# Categories can be used to filter modules in modules listing
|
|
||||||
# Check https://github.com/odoo/odoo/blob/master/odoo/addons/base/module/module_data.xml
|
|
||||||
# for the full list
|
|
||||||
'category': 'Uncategorized',
|
|
||||||
'version': '0.1',
|
|
||||||
|
|
||||||
# any module necessary for this one to work correctly
|
|
||||||
'depends': ['base','mail'],
|
|
||||||
|
|
||||||
# always loaded
|
|
||||||
'data': [
|
|
||||||
'security/account_security.xml',
|
|
||||||
'security/ir.model.access.csv',
|
|
||||||
'wizard/order_wizard.xml',
|
|
||||||
'views/notice_user_config.xml',
|
|
||||||
'views/yizuo_system_order_view.xml',
|
|
||||||
'views/work_order_number.xml',
|
|
||||||
'views/res_config_settings_views.xml',
|
|
||||||
],
|
|
||||||
# only loaded in demonstration mode
|
|
||||||
'demo': [
|
|
||||||
'demo/demo.xml',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from . import controllers
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from odoo import http
|
|
||||||
|
|
||||||
# class TopSystemOrder(http.Controller):
|
|
||||||
# @http.route('/jikimo_system_order/jikimo_system_order/', auth='public')
|
|
||||||
# def index(self, **kw):
|
|
||||||
# return "Hello, world"
|
|
||||||
|
|
||||||
# @http.route('/jikimo_system_order/jikimo_system_order/objects/', auth='public')
|
|
||||||
# def list(self, **kw):
|
|
||||||
# return http.request.render('jikimo_system_order.listing', {
|
|
||||||
# 'root': '/jikimo_system_order/jikimo_system_order',
|
|
||||||
# 'objects': http.request.env['jikimo_system_order.jikimo_system_order'].search([]),
|
|
||||||
# })
|
|
||||||
|
|
||||||
# @http.route('/jikimo_system_order/jikimo_system_order/objects/<model("jikimo_system_order.jikimo_system_order"):obj>/', auth='public')
|
|
||||||
# def object(self, obj, **kw):
|
|
||||||
# return http.request.render('jikimo_system_order.object', {
|
|
||||||
# 'object': obj
|
|
||||||
# })
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
<odoo>
|
|
||||||
<data>
|
|
||||||
<!-- -->
|
|
||||||
<!-- <record id="object0" model="jikimo_system_order.jikimo_system_order"> -->
|
|
||||||
<!-- <field name="name">Object 0</field> -->
|
|
||||||
<!-- <field name="value">0</field> -->
|
|
||||||
<!-- </record> -->
|
|
||||||
<!-- -->
|
|
||||||
<!-- <record id="object1" model="jikimo_system_order.jikimo_system_order"> -->
|
|
||||||
<!-- <field name="name">Object 1</field> -->
|
|
||||||
<!-- <field name="value">10</field> -->
|
|
||||||
<!-- </record> -->
|
|
||||||
<!-- -->
|
|
||||||
<!-- <record id="object2" model="jikimo_system_order.jikimo_system_order"> -->
|
|
||||||
<!-- <field name="name">Object 2</field> -->
|
|
||||||
<!-- <field name="value">20</field> -->
|
|
||||||
<!-- </record> -->
|
|
||||||
<!-- -->
|
|
||||||
<!-- <record id="object3" model="jikimo_system_order.jikimo_system_order"> -->
|
|
||||||
<!-- <field name="name">Object 3</field> -->
|
|
||||||
<!-- <field name="value">30</field> -->
|
|
||||||
<!-- </record> -->
|
|
||||||
<!-- -->
|
|
||||||
<!-- <record id="object4" model="jikimo_system_order.jikimo_system_order"> -->
|
|
||||||
<!-- <field name="name">Object 4</field> -->
|
|
||||||
<!-- <field name="value">40</field> -->
|
|
||||||
<!-- </record> -->
|
|
||||||
<!-- -->
|
|
||||||
</data>
|
|
||||||
</odoo>
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from . import constant
|
|
||||||
from . import order_classify
|
|
||||||
from . import system_work_order
|
|
||||||
from . import work_order_template
|
|
||||||
from . import res_config_setting
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# 工单状态
|
|
||||||
STATE_SELECTION = [('draft', u'草稿'), ('unconfirmed', u'待确认'), ('pending', u'待处理'),
|
|
||||||
('processed', u'已处理待评分'), ('completed', u'已完成'), ('closed', u'已关闭')]
|
|
||||||
|
|
||||||
GRADE = [('1', '1非常不满意'), ('2', '2不满意'), ('3', '3一般'), ('4', '4满意'), ('5', '5非常满意')]
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from odoo import models, fields, api
|
|
||||||
from odoo.exceptions import ValidationError
|
|
||||||
|
|
||||||
|
|
||||||
class OrderClassify(models.Model):
|
|
||||||
_name = 'order.classify'
|
|
||||||
_order = 'sequence, name'
|
|
||||||
|
|
||||||
|
|
||||||
@api.constrains('name')
|
|
||||||
def check_base_name(self):
|
|
||||||
"""类型名称唯一"""
|
|
||||||
name_obj = self.env['order.classify'].search([('name', '=', self.name)])
|
|
||||||
if len(name_obj) >= 2:
|
|
||||||
raise ValidationError(u'该类型已存在')
|
|
||||||
|
|
||||||
# 名称
|
|
||||||
name = fields.Char(string=u'名称', size=20)
|
|
||||||
# 排序
|
|
||||||
sequence = fields.Integer(default=10)
|
|
||||||
# 是否有效
|
|
||||||
state = fields.Boolean(default=True, string='是否有效')
|
|
||||||
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import logging
|
|
||||||
from odoo import api, fields, models, _
|
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class ResModelWeConfigSettings(models.TransientModel):
|
|
||||||
_inherit = 'res.config.settings'
|
|
||||||
|
|
||||||
lost_agent_id = fields.Char('企微通知应用ID')
|
|
||||||
|
|
||||||
@api.model
|
|
||||||
def get_values(self):
|
|
||||||
"""
|
|
||||||
重载获取参数的方法,参数都存在系统参数中
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
values = super(ResModelWeConfigSettings, self).get_values()
|
|
||||||
config = self.env['ir.config_parameter'].sudo()
|
|
||||||
lost_agent_id = config.get_param('lost_agent_id', default='')
|
|
||||||
values.update(
|
|
||||||
lost_agent_id=lost_agent_id,
|
|
||||||
)
|
|
||||||
return values
|
|
||||||
|
|
||||||
def set_values(self):
|
|
||||||
super(ResModelWeConfigSettings, self).set_values()
|
|
||||||
ir_config = self.env['ir.config_parameter'].sudo()
|
|
||||||
ir_config.set_param("lost_agent_id", self.lost_agent_id or "")
|
|
||||||
|
|
||||||
@@ -1,183 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from odoo import models, fields, api
|
|
||||||
from odoo.exceptions import ValidationError
|
|
||||||
from odoo import exceptions
|
|
||||||
from .constant import STATE_SELECTION, GRADE
|
|
||||||
import datetime
|
|
||||||
import logging
|
|
||||||
|
|
||||||
|
|
||||||
class SystemWorkOrder(models.Model):
|
|
||||||
_name = 'system.work.order'
|
|
||||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
|
||||||
_order = 'date desc'
|
|
||||||
_description = u'系统工单'
|
|
||||||
_rec_name = 'order_number'
|
|
||||||
|
|
||||||
def get_is_technicist(self):
|
|
||||||
self._cr.execute(
|
|
||||||
"select u.id from res_users u left join res_groups_users_rel r on r.uid = u.id where r.gid in (select g.id from res_groups g where g.name = '技术员权限') and u.id ='%s'",
|
|
||||||
(self.env.user.id,))
|
|
||||||
hr = self._cr.dictfetchall()
|
|
||||||
if len(hr) > 0:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
# def get_user_department_id(self):
|
|
||||||
# """根据用户id系统员工id"""
|
|
||||||
# employee = self.env['hr.employee'].sudo().search([('user_id', '=', self.env.uid)], limit=1)
|
|
||||||
# if employee:
|
|
||||||
# if len(employee) > 0:
|
|
||||||
# if not employee.department_id:
|
|
||||||
# raise exceptions.Warning(u'您当前使用的用户没有所属部门')
|
|
||||||
# return employee.department_id
|
|
||||||
# else:
|
|
||||||
# return False
|
|
||||||
# else:
|
|
||||||
# raise exceptions.Warning(u'您当前使用的用户没有关联员工')
|
|
||||||
|
|
||||||
@api.onchange('order_template_id')
|
|
||||||
def get_title(self):
|
|
||||||
"""选择模板自动填充"""
|
|
||||||
if self.order_template_id:
|
|
||||||
self.title = self.order_template_id.title_template
|
|
||||||
self.text = self.order_template_id.text_template
|
|
||||||
|
|
||||||
# 工单编号
|
|
||||||
order_number = fields.Char(string=u'工单编号', default='/')
|
|
||||||
# 紧急程度
|
|
||||||
urgency_degree = fields.Selection([('0', u'0星'), ('1', u'一星'), ('2', u'二星'), ('3', u'三星'), ('4', u'四星'),
|
|
||||||
('5', u'五星')], string=u'紧急程度', help='五星为最紧急!', default='5')
|
|
||||||
# 工单分类(可以配置,并调整优先级)
|
|
||||||
order_type = fields.Many2one('order.classify', string=u'工单分类', domain=[('state', '=', True)])
|
|
||||||
# 发起人所属公司(res.company)
|
|
||||||
initiator_company_id = fields.Many2one('res.company', string=u'发起人所属公司', default=lambda self: self.env.user.company_id)
|
|
||||||
# 发起人部门(hr.department)
|
|
||||||
# initiator_department_id = fields.Many2one('hr.department', string=u'发起人部门', default=get_user_department_id)
|
|
||||||
# 发起人(hr.employee)
|
|
||||||
initiator_id = fields.Many2one('res.users', string=u'发起人', default=lambda self: self.env.user)
|
|
||||||
# 发起时间
|
|
||||||
date = fields.Datetime(string=u'发起时间', default=lambda self: fields.datetime.now())
|
|
||||||
# 确认人
|
|
||||||
confirm_id = fields.Many2one('res.users', string=u'确认人')
|
|
||||||
# 确认日期
|
|
||||||
confirmation_date = fields.Datetime(string=u'确认时间')
|
|
||||||
# 模板
|
|
||||||
order_template_id = fields.Many2one('work.order.template', string=u'模板', domain=[('state', '=', True)])
|
|
||||||
# 标题
|
|
||||||
title = fields.Char(string=u'标题')
|
|
||||||
# 正文
|
|
||||||
text = fields.Html(string=u'正文')
|
|
||||||
# 状态[草稿\待确认\待处理\已处理\已关闭]
|
|
||||||
state = fields.Selection(STATE_SELECTION, default='draft', string=u'状态')
|
|
||||||
# 关闭原因
|
|
||||||
close_cause = fields.Text(string=u'关闭问题原因')
|
|
||||||
# 关闭时间
|
|
||||||
close_time = fields.Datetime(string=u'关闭问题时间')
|
|
||||||
# 关闭人
|
|
||||||
close_user_id = fields.Many2one('res.users', string=u'关闭人')
|
|
||||||
# 解决人
|
|
||||||
solve_people_id = fields.Many2one('res.users', string=u'解决人')
|
|
||||||
# 用户实际问题
|
|
||||||
users_problem = fields.Text(string=u'用户实际问题')
|
|
||||||
# 最终解决方案
|
|
||||||
solution = fields.Text(string=u'最终解决方案')
|
|
||||||
# 判断是否为技术人员
|
|
||||||
# is_technicist = fields.Boolean(string=u'是否为技术人员', default=get_is_technicist)
|
|
||||||
# 打分
|
|
||||||
grade = fields.Selection(GRADE, string=u'评分')
|
|
||||||
# 评价按钮的显示
|
|
||||||
is_display = fields.Boolean('控制显示评价按钮', compute='compute_is_display')
|
|
||||||
|
|
||||||
def compute_is_display(self):
|
|
||||||
for item in self:
|
|
||||||
if item.state == 'processed' and self.env.user.id == item.initiator_id.id:
|
|
||||||
item.is_display = True
|
|
||||||
else:
|
|
||||||
item.is_display = False
|
|
||||||
|
|
||||||
@api.onchange('order_type')
|
|
||||||
def _onchange_order_type(self):
|
|
||||||
self.order_template_id = None
|
|
||||||
self.title = None
|
|
||||||
self.text = None
|
|
||||||
|
|
||||||
@api.model
|
|
||||||
def create(self, vals):
|
|
||||||
# 创建编号
|
|
||||||
if vals.get('order_number', '/') == '/':
|
|
||||||
vals['order_number'] = self.env['ir.sequence'].get('system.work.order') or '/'
|
|
||||||
return super(SystemWorkOrder, self).create(vals)
|
|
||||||
|
|
||||||
def do_draft(self, order=None):
|
|
||||||
"""状态草稿"""
|
|
||||||
bill = self
|
|
||||||
if order:
|
|
||||||
bill = order
|
|
||||||
if bill.state == 'unconfirmed':
|
|
||||||
state_remark = u'待确认 --> 草稿'
|
|
||||||
# bill.message_post(u'操作人:%s,操作时间:%s,状态变更过程:%s' % (self.env.user.name,
|
|
||||||
# (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), state_remark))
|
|
||||||
bill.state = 'draft'
|
|
||||||
|
|
||||||
def do_unconfirmed(self):
|
|
||||||
"""状态待确认"""
|
|
||||||
if self.state == 'draft':
|
|
||||||
state_remark = u'草稿 --> 待确认'
|
|
||||||
# self.message_post(u'操作人:%s,操作时间:%s,状态变更过程:%s' % (
|
|
||||||
# self.env.user.name,
|
|
||||||
# (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), state_remark))
|
|
||||||
self.state = 'unconfirmed'
|
|
||||||
# 获取通知人
|
|
||||||
objs = self.env['system.order.notice'].search([])
|
|
||||||
user_ids = objs.notice_user_ids.filtered(lambda item: item.we_employee_id not in ['', False])
|
|
||||||
we_employee_ids = user_ids.mapped('we_employee_id')
|
|
||||||
lost_agent_id = self.env['ir.config_parameter'].sudo().get_param('lost_agent_id')
|
|
||||||
wechat = self.env['we.config'].sudo().get_wechat(agent_id=lost_agent_id)
|
|
||||||
# agent_id, user_ids, content
|
|
||||||
content = """您有一张工单<font color=\"warning\">待处理</font>:**工单标题:{2}**
|
|
||||||
>创建人:{1}
|
|
||||||
>提交时间:{3}
|
|
||||||
>紧急程度:{0}星
|
|
||||||
请查看工单消息,并及时处理!
|
|
||||||
""".format(self.urgency_degree,
|
|
||||||
self.initiator_id.name, self.title, (self.date + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M'))
|
|
||||||
for we_employee_id in we_employee_ids:
|
|
||||||
try:
|
|
||||||
wechat.message.send_markdown(agent_id=lost_agent_id, user_ids=we_employee_id, content=content)
|
|
||||||
except Exception as e:
|
|
||||||
logging.error('工单处理发送消息异常%s' % str(e))
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def do_pending(self):
|
|
||||||
"""状态待处理"""
|
|
||||||
if self.state == 'unconfirmed':
|
|
||||||
state_remark = u'待确认 --> 待处理'
|
|
||||||
# self.message_post(u'操作人:%s,操作时间:%s,状态变更过程:%s' % (
|
|
||||||
# self.env.user.name,
|
|
||||||
# (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), state_remark))
|
|
||||||
self.state = 'pending'
|
|
||||||
self.confirm_id = self.env.user
|
|
||||||
self.confirmation_date = fields.datetime.now()
|
|
||||||
return True
|
|
||||||
|
|
||||||
def urned_off(self):
|
|
||||||
"""状态关闭"""
|
|
||||||
if self.close_cause:
|
|
||||||
self.state = 'closed'
|
|
||||||
self.close_time = fields.datetime.now()
|
|
||||||
else:
|
|
||||||
raise ValidationError(u'请注明关闭原因')
|
|
||||||
return True
|
|
||||||
|
|
||||||
def unlink(self):
|
|
||||||
for item in self:
|
|
||||||
if item.state != "draft":
|
|
||||||
raise ValidationError(u'只能删除状态为【草稿】的工单。')
|
|
||||||
elif item.env.uid != item.initiator_id.id:
|
|
||||||
raise ValidationError(u'非本人不能删除')
|
|
||||||
else:
|
|
||||||
super(SystemWorkOrder, item).unlink()
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from odoo import models, fields, api
|
|
||||||
|
|
||||||
|
|
||||||
class WorkOrderTemplate(models.Model):
|
|
||||||
_name = 'work.order.template'
|
|
||||||
_order = 'num'
|
|
||||||
|
|
||||||
# 编号
|
|
||||||
num = fields.Char(string=u'编号', default='/')
|
|
||||||
# 名称
|
|
||||||
name = fields.Char(string=u'模板名称', required="1")
|
|
||||||
# 分类
|
|
||||||
work_order_type = fields.Many2one('order.classify', string=u'系统工单分类', domain=[('state', '=', True)])
|
|
||||||
# 模板标题
|
|
||||||
title_template = fields.Char(string=u'模板标题')
|
|
||||||
# 模板正文
|
|
||||||
text_template = fields.Html(string=u'模板正文')
|
|
||||||
# 模板说明
|
|
||||||
template_explain = fields.Text(string=u'模板说明')
|
|
||||||
# 是否有效
|
|
||||||
state = fields.Boolean(default=True, string=u'是否有效')
|
|
||||||
|
|
||||||
@api.model
|
|
||||||
def create(self, vals):
|
|
||||||
# 创建编号
|
|
||||||
if vals.get('num', '/') == '/':
|
|
||||||
vals['num'] = self.env['ir.sequence'].get('work.order.template') or '/'
|
|
||||||
return super(WorkOrderTemplate, self).create(vals)
|
|
||||||
|
|
||||||
|
|
||||||
class SystemOrderNotice(models.Model):
|
|
||||||
_name = 'system.order.notice'
|
|
||||||
_description = '工单处理人设置'
|
|
||||||
|
|
||||||
notice_user_ids = fields.Many2many('res.users', string='工单处理人')
|
|
||||||
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<odoo>
|
|
||||||
<data noupdate="0"> <!-- noupdate表示,当模块升级时是否更新本条数据-->
|
|
||||||
<!--运维权限组-->
|
|
||||||
<record id="group_operations_permissions_rwc" model="res.groups">
|
|
||||||
<field name="name">运维权限</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="system_order_user_rule" model="ir.rule">
|
|
||||||
<field name="name">用户访问工单信息</field>
|
|
||||||
<field name="model_id" ref="model_system_work_order"/>
|
|
||||||
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
|
|
||||||
<field name="domain_force">[('initiator_id', '=', user.id)]</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="system_order_group_operations_rule" model="ir.rule">
|
|
||||||
<field name="name">运维访问工单信息</field>
|
|
||||||
<field name="model_id" ref="model_system_work_order"/>
|
|
||||||
<field name="groups" eval="[(4, ref('jikimo_system_order.group_operations_permissions_rwc'))]"/>
|
|
||||||
<field name="domain_force">[(1, '=', 1)]</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
</data>
|
|
||||||
</odoo>
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
|
||||||
|
|
||||||
inside_system_order_classify_r,jikimo_system_order.order_classify,model_order_classify,,1,1,1,1
|
|
||||||
inside_system_work_order_rc,jikimo_system_order.system_work_order,model_system_work_order,,1,1,1,1
|
|
||||||
inside_work_order_template_r,jikimo_system_order.work_order_template,model_work_order_template,,1,1,1,1
|
|
||||||
|
|
||||||
inside_system_order_classify_rwc,jikimo_system_order.order_classify,model_order_classify,group_operations_permissions_rwc,1,1,1,0
|
|
||||||
inside_system_work_order_rwc,jikimo_system_order.system_work_order,model_system_work_order,group_operations_permissions_rwc,1,1,1,0
|
|
||||||
inside_work_order_template_rwc,jikimo_system_order.work_order_template,model_work_order_template,group_operations_permissions_rwc,1,1,1,0
|
|
||||||
|
|
||||||
order_close_wizard_group_user,jikimo_system_order.order_close_wizard,model_order_close_wizard,base.group_user,1,1,1,1
|
|
||||||
order_other_wizard_group_user,jikimo_system_order.order_other_wizard,model_order_other_wizard,base.group_user,1,1,1,1
|
|
||||||
order_technician_wizard_group_user,jikimo_system_order.order_technician_wizard,model_order_technician_wizard,base.group_user,1,1,1,1
|
|
||||||
system_work_order_wizard_group_user,jikimo_system_order.system_work_order_wizard,model_system_work_order_wizard,base.group_user,1,1,1,1
|
|
||||||
|
|
||||||
system_order_notice_group_user,jikimo_system_order.system_order_notice,model_system_order_notice,base.group_user,1,1,1,1
|
|
||||||
|
Binary file not shown.
|
Before Width: | Height: | Size: 2.7 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 533 B |
@@ -1,58 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
|
||||||
<odoo>
|
|
||||||
<data>
|
|
||||||
# ---------- 工单通知处理人设置 ------------
|
|
||||||
|
|
||||||
<record model="ir.ui.view" id="tree_system_order_notice_view">
|
|
||||||
<field name="name">tree.system.order.notice</field>
|
|
||||||
<field name="model">system.order.notice</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<tree string="工单处理人设置" editable="top">
|
|
||||||
<field name="notice_user_ids" widget="many2many_tags" required="1" options="{'no_create': True, 'no_edit': True}"/>
|
|
||||||
</tree>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
|
|
||||||
<record model="ir.ui.view" id="search_system_order_notice_view">
|
|
||||||
<field name="name">search.system.order.notice</field>
|
|
||||||
<field name="model">system.order.notice</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<search string="工单处理人设置">
|
|
||||||
<field name="notice_user_ids" string="模糊搜索"
|
|
||||||
filter_domain="[('notice_user_ids', 'ilike', self)]"/>
|
|
||||||
<separator></separator>
|
|
||||||
|
|
||||||
<field name="notice_user_ids" string="处理人"/>
|
|
||||||
|
|
||||||
</search>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
|
|
||||||
<record model="ir.actions.act_window" id="action_system_order_notice_view">
|
|
||||||
<field name="name">工单处理人</field>
|
|
||||||
<field name="res_model">system.order.notice</field>
|
|
||||||
<field name="view_mode">tree</field>
|
|
||||||
<field name="domain">[]</field>
|
|
||||||
<field name="context">{}</field>
|
|
||||||
<field name="help" type="html">
|
|
||||||
<p class="o_view_nocontent_smiling_face">
|
|
||||||
[工单处理人] 还没有哦!点左上角的[创建]按钮,沙发归你了!
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
</p>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</data>
|
|
||||||
</odoo>
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<odoo>
|
|
||||||
<data>
|
|
||||||
<record id="res_config_settings_we_view_form_inherit" model="ir.ui.view">
|
|
||||||
<field name="name">res.config.settings.we.view.form.inherit.bpm</field>
|
|
||||||
<field name="model">res.config.settings</field>
|
|
||||||
<field name="inherit_id" ref="base.res_config_settings_view_form"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<xpath expr="//div[hasclass('app_settings_block')]/div[6]" position="after">
|
|
||||||
<div>
|
|
||||||
<h2>企微通知应用ID</h2>
|
|
||||||
<div class="row mt16 o_settings_container" id="jd_api">
|
|
||||||
<div class="col-12 col-lg-6 o_setting_box">
|
|
||||||
<div class="o_setting_left_pane"/>
|
|
||||||
<div class="o_setting_right_pane">
|
|
||||||
<div class="text-muted">
|
|
||||||
<label for="lost_agent_id"/>
|
|
||||||
<field name="lost_agent_id"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</xpath>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
</data>
|
|
||||||
</odoo>
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<odoo>
|
|
||||||
<data noupdate="True">
|
|
||||||
<!-- 工单流水号 -->
|
|
||||||
<record id="seq_work_order" model="ir.sequence">
|
|
||||||
<field name="name">seq_work_order</field>
|
|
||||||
<field name="company_id"/>
|
|
||||||
<field name="code">system.work.order</field>
|
|
||||||
<field name="prefix">SO%(year)s%(month)s%(day)s</field>
|
|
||||||
<field name="padding">1</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- 模板编号 -->
|
|
||||||
<record id="seq_order_template" model="ir.sequence">
|
|
||||||
<field name="name">seq_order_template</field>
|
|
||||||
<field name="company_id"/>
|
|
||||||
<field name="code">work.order.template</field>
|
|
||||||
<field name="prefix">TL</field>
|
|
||||||
<field name="padding">1</field>
|
|
||||||
</record>
|
|
||||||
</data>
|
|
||||||
</odoo>
|
|
||||||
@@ -1,243 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<odoo>
|
|
||||||
<data>
|
|
||||||
<!--工单信息-->
|
|
||||||
<record model="ir.ui.view" id="work_order_tree">
|
|
||||||
<field name="name">工单信息</field>
|
|
||||||
<field name="model">system.work.order</field><!--对应表单名称-->
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<tree>
|
|
||||||
<field name="state" widget="badge" decoration-primary="state == 'draft'"
|
|
||||||
decoration-success="state in ('processed', 'completed')"
|
|
||||||
decoration-danger="state == 'pending'" decoration-warning="state in ('unconfirmed')"/>
|
|
||||||
<field name="order_number"/>
|
|
||||||
<field name="title"/>
|
|
||||||
<field name="initiator_id"/>
|
|
||||||
<field name="date"/>
|
|
||||||
</tree>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!--新建系统工单-->
|
|
||||||
<record model="ir.ui.view" id="ork_order_form">
|
|
||||||
<field name="name">新建系统工单</field>
|
|
||||||
<field name="model">system.work.order</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<form>
|
|
||||||
<header>
|
|
||||||
<field name="is_display" invisible="1"/>
|
|
||||||
<button string='提交' class="oe_highlight" states="draft"
|
|
||||||
type="object" name="do_unconfirmed"
|
|
||||||
attrs="{'invisible': [('state', '!=', 'draft')]}"/>
|
|
||||||
<button string='追回编辑' states="unconfirmed"
|
|
||||||
type="action" name="%(system_work_order_wizard_view_act_window)d"
|
|
||||||
context="{'explain':'确认要执行此操作吗?','object_name':'system.work.order','function_name':'do_draft','object_id':id}"/>
|
|
||||||
|
|
||||||
<button name="do_pending" states="unconfirmed"
|
|
||||||
string="确认可处理" type="object" class="oe_highlight"
|
|
||||||
groups="jikimo_system_order.group_operations_permissions_rwc"/>
|
|
||||||
|
|
||||||
<button string='处理工单' class="oe_highlight" states="pending"
|
|
||||||
type="action" name="%(launch_order_technician_wizard)d"
|
|
||||||
groups="jikimo_system_order.group_operations_permissions_rwc"/>
|
|
||||||
<button string='评价' class="oe_highlight" attrs="{'invisible': [('is_display', '=', False)]}"
|
|
||||||
type="action" name="%(launch_order_other_wizard)d" context="{'active_id':id}"/>
|
|
||||||
<button name="%(launch_order_close_wizard)d" string="关闭该工单"
|
|
||||||
attrs="{'invisible': ['|',('state', '=', 'draft'),'|',('state','=','completed'),('state','=','closed')]}"
|
|
||||||
type="action" context="{'active_id':id}"/>
|
|
||||||
|
|
||||||
<field name="state" widget="statusbar"/>
|
|
||||||
</header>
|
|
||||||
<sheet>
|
|
||||||
<group>
|
|
||||||
<!-- <label for="order_number" class="oe_edit_only"/>-->
|
|
||||||
<group>
|
|
||||||
<field name="order_number" required="True" readonly="1"/>
|
|
||||||
<field name="order_type" required="True" attrs="{'readonly': [('state', '!=', 'draft')]}" options="{'no_create': True}"/>
|
|
||||||
<field name="date" required="True" readonly="True"/>
|
|
||||||
<field name="order_template_id" attrs="{'readonly': [('state', '!=', 'draft')]}"
|
|
||||||
domain="[('work_order_type','=',order_type),('state','=',True)]" options="{'no_create': True}"/>
|
|
||||||
<field name="confirmation_date" readonly="True"/>
|
|
||||||
<field name="urgency_degree" required="True" attrs="{'readonly': [('state','!=','draft')]}" widget="priority"/>
|
|
||||||
</group>
|
|
||||||
<group>
|
|
||||||
<field name="initiator_company_id" required="True" readonly="True"/>
|
|
||||||
<!-- <field name="initiator_department_id" required="True" readonly="True"/>-->
|
|
||||||
<field name="initiator_id" required="True" readonly="True"/>
|
|
||||||
<field name="confirm_id" readonly="True"/>
|
|
||||||
<field name="solve_people_id" readonly="True"/>
|
|
||||||
<field name="close_user_id" readonly="True"/>
|
|
||||||
</group>
|
|
||||||
<group>
|
|
||||||
<field name="title" attrs="{'readonly': [('state', '!=', 'draft')]}" required="True"/>
|
|
||||||
</group>
|
|
||||||
</group>
|
|
||||||
<notebook>
|
|
||||||
<page string="工单内容">
|
|
||||||
<field name="text" attrs="{'readonly': [('state','!=','draft')]}" required="True"/>
|
|
||||||
</page>
|
|
||||||
<page string="解决方案">
|
|
||||||
<group>
|
|
||||||
<field name="users_problem" readonly="True"/>
|
|
||||||
<field name="solution" readonly="True"/>
|
|
||||||
</group>
|
|
||||||
</page>
|
|
||||||
<page string="其他">
|
|
||||||
<group>
|
|
||||||
<field name="close_cause" readonly="True"/>
|
|
||||||
<field name="close_time" readonly="True"/>
|
|
||||||
<field name="grade" readonly="True"/>
|
|
||||||
</group>
|
|
||||||
</page>
|
|
||||||
</notebook>
|
|
||||||
</sheet>
|
|
||||||
<!-- <div class="oe_chatter">-->
|
|
||||||
<!-- <field name="message_follower_ids" widget="mail_followers"/>-->
|
|
||||||
<!-- <field name="message_ids" widget="mail_thread"/>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- 搜索工单 -->
|
|
||||||
<record model="ir.ui.view" id="restaurant_search">
|
|
||||||
<field name="name">搜索工单</field>
|
|
||||||
<field name="model">system.work.order</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<search>
|
|
||||||
<field string='发起人' name="initiator_id" widget="char" required="True"/>
|
|
||||||
<field string='标题' name="title" widget="char"/>
|
|
||||||
<field string='正文' name="text" widget="html"/>
|
|
||||||
<field string='实际问题' name="users_problem" widget="text"/>
|
|
||||||
<field string='解决方案' name="solution" widget="text"/>
|
|
||||||
<filter name="today" string="今日工单" domain="[('date','=',time.strftime('%%Y-%%m-%%d'))]"/>
|
|
||||||
<filter name="yesterday" string="昨日工单"
|
|
||||||
domain="[('date', '=', (context_today() - relativedelta(days=1)).strftime('%Y-%m-%d'))]"/>
|
|
||||||
<filter name="month" string="本月工单"
|
|
||||||
domain="[('date','>=', time.strftime('%Y-%m-01')),('date','<', (context_today() + relativedelta(months=1)).strftime('%Y-%m-01'))]"/>
|
|
||||||
<filter name="last_month" string="上月工单"
|
|
||||||
domain="[('date','<', time.strftime('%Y-%m-01')),('date','>=', (context_today() - relativedelta(months=1)).strftime('%Y-%m-01'))]"/>
|
|
||||||
<filter name="unconfirmed" string="待确认" domain="[('state','=','unconfirmed')]"/>
|
|
||||||
<filter name="pending" string="待处理" domain="[('state','=','pending')]"/>
|
|
||||||
<filter name="processed" string="已处理"
|
|
||||||
domain="['|', ('state','=','processed'), ('state','=','closed')]"/>
|
|
||||||
<group>
|
|
||||||
<filter string='发起人' name="initiator_id" context='{"group_by":"initiator_id"}'/>
|
|
||||||
<filter string='工单分类' name="order_type" context='{"group_by":"order_type"}'/>
|
|
||||||
<filter string='模板' name="order_template_id" context='{"group_by":"order_template_id"}'/>
|
|
||||||
<filter string='状态' name="state" context='{"group_by":"state"}'/>
|
|
||||||
<filter string='紧急情况' name="state" context='{"group_by":"urgency_degree"}'/>
|
|
||||||
</group>
|
|
||||||
</search>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record model="ir.ui.view" id="graph_tree">
|
|
||||||
<field name="name">工单图表</field>
|
|
||||||
<field name="model">system.work.order</field><!--对应表单名称-->
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<pivot>
|
|
||||||
<field name="date" type="row" interval="day"/>
|
|
||||||
<field name="order_type" type="col"/>
|
|
||||||
<field name="state" type="row"/>
|
|
||||||
</pivot>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- 工单 -->
|
|
||||||
<record model="ir.actions.act_window" id="system_order">
|
|
||||||
<field name="name">工单</field>
|
|
||||||
<field name="res_model">system.work.order</field>
|
|
||||||
<field name="view_mode">tree,form,search,graph,pivot</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!--工单模板信息-->
|
|
||||||
<record model="ir.ui.view" id="order_template_tree">
|
|
||||||
<field name="name">工单模板信息</field>
|
|
||||||
<field name="model">work.order.template</field><!--对应表单名称-->
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<tree>
|
|
||||||
<field name="num"/>
|
|
||||||
<field name="name"/>
|
|
||||||
<field name="work_order_type"/>
|
|
||||||
<field name="title_template"/>
|
|
||||||
<field name="template_explain"/>
|
|
||||||
<field name="state"/>
|
|
||||||
</tree>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!--新建系统工单模板-->
|
|
||||||
<record model="ir.ui.view" id="order_template_form">
|
|
||||||
<field name="name">新建系统工单模板</field>
|
|
||||||
<field name="model">work.order.template</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<form>
|
|
||||||
<sheet>
|
|
||||||
<group>
|
|
||||||
<field name="num" required="True" readonly="True"/>
|
|
||||||
<field name="name" required="True"/>
|
|
||||||
<field name="work_order_type" required="True"/>
|
|
||||||
<field name="template_explain" required="True" style="height: 50px;"/>
|
|
||||||
<field name="title_template" required="True"/>
|
|
||||||
<field name="state"/>
|
|
||||||
<field name="text_template" required="True"/>
|
|
||||||
</group>
|
|
||||||
</sheet>
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- 工单模板 -->
|
|
||||||
<record model="ir.actions.act_window" id="work_template">
|
|
||||||
<field name="name">工单模板</field>
|
|
||||||
<field name="res_model">work.order.template</field>
|
|
||||||
<field name="view_mode">tree,form</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!--工单分类信息-->
|
|
||||||
<record model="ir.ui.view" id="order_type_tree">
|
|
||||||
<field name="name">工单分类信息</field>
|
|
||||||
<field name="model">order.classify</field><!--对应表单名称-->
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<tree>
|
|
||||||
<field name="sequence" widget="handle"/>
|
|
||||||
<field name="name"/>
|
|
||||||
<field name="state"/>
|
|
||||||
</tree>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!--新建系统分类信息-->
|
|
||||||
<record model="ir.ui.view" id="order_type_form">
|
|
||||||
<field name="name">新建系统分类信息</field>
|
|
||||||
<field name="model">order.classify</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<form>
|
|
||||||
<sheet>
|
|
||||||
<group>
|
|
||||||
<field name="name" required="True"/>
|
|
||||||
<field name="sequence" invisible="True"/>
|
|
||||||
<field name="state"/>
|
|
||||||
</group>
|
|
||||||
</sheet>
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- 工单分类 -->
|
|
||||||
<record model="ir.actions.act_window" id="classify">
|
|
||||||
<field name="name">工单分类</field>
|
|
||||||
<field name="res_model">order.classify</field>
|
|
||||||
<field name="view_mode">tree,form</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
|
|
||||||
<menuitem name="系统工单" id="work_order_1_list" web_icon="jikimo_system_order,static/description/系统工单.png"/>
|
|
||||||
<menuitem name="工单" id="work_order" parent="work_order_1_list" action="system_order"/>
|
|
||||||
<menuitem name="工单模板" id="work_order_template" parent="work_order_1_list" action="work_template" groups="jikimo_system_order.group_operations_permissions_rwc"/>
|
|
||||||
<menuitem name="工单分类" id="work_order_type" parent="work_order_1_list" action="classify" groups="jikimo_system_order.group_operations_permissions_rwc"/>
|
|
||||||
<menuitem name="工单设置" id="system_order_notice_user_config" parent="work_order_1_list" action="action_system_order_notice_view" groups="jikimo_system_order.group_operations_permissions_rwc"/>
|
|
||||||
</data>
|
|
||||||
</odoo>
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from . import order_other_wizard
|
|
||||||
from . import order_technician_wizard
|
|
||||||
from . import order_close_wizard
|
|
||||||
from . import system_work_order_wizard
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from odoo import models, fields, api
|
|
||||||
from odoo.addons.jikimo_system_order.models.constant import STATE_SELECTION
|
|
||||||
from odoo.exceptions import ValidationError
|
|
||||||
import datetime, logging
|
|
||||||
|
|
||||||
|
|
||||||
class OrderCloseWizard(models.TransientModel):
|
|
||||||
_name = 'order.close.wizard'
|
|
||||||
|
|
||||||
|
|
||||||
def get_context(self):
|
|
||||||
if self._context.get('active_id'):
|
|
||||||
obj = self.env['system.work.order'].browse(self._context.get('active_id'))
|
|
||||||
if obj.initiator_id.id != self.env.user.id:
|
|
||||||
raise ValidationError(u'非本人无法操作')
|
|
||||||
return obj
|
|
||||||
|
|
||||||
order_id = fields.Many2one('system.work.order', string=u'工单ID',
|
|
||||||
default=lambda self: self.get_context().id)
|
|
||||||
# 关闭原因
|
|
||||||
close_cause = fields.Text(string=u'关闭问题原因', default=lambda self: self.get_context().close_cause)
|
|
||||||
# 关闭时间
|
|
||||||
close_time = fields.Datetime(string=u'关闭问题时间', default=fields.datetime.now())
|
|
||||||
# 状态
|
|
||||||
state = fields.Selection(STATE_SELECTION, default='closed', string=u'状态')
|
|
||||||
# 关闭人
|
|
||||||
close_user_id = fields.Many2one('res.users', string=u'关闭人', default=lambda self: self.env.user)
|
|
||||||
|
|
||||||
|
|
||||||
def sure(self):
|
|
||||||
self.order_id.close_cause = self.close_cause
|
|
||||||
self.order_id.close_time = self.close_time
|
|
||||||
if self.order_id.state == 'unconfirmed':
|
|
||||||
state_remark = u'待确认 --> 已关闭'
|
|
||||||
if self.order_id.state == 'pending':
|
|
||||||
state_remark = u'待处理 --> 已关闭'
|
|
||||||
if self.order_id.state == 'processed':
|
|
||||||
state_remark = u'已处理待评分 --> 已关闭'
|
|
||||||
# self.order_id.message_post(u'操作人:%s,操作时间:%s,状态变更过程:%s' % (
|
|
||||||
# self.env.user.name,
|
|
||||||
# (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), state_remark))
|
|
||||||
self.order_id.state = self.state
|
|
||||||
self.order_id.close_user_id = self.close_user_id
|
|
||||||
we_employee_ids = []
|
|
||||||
if self.order_id.initiator_id.we_employee_id:
|
|
||||||
we_employee_ids.append(self.order_id.initiator_id.we_employee_id)
|
|
||||||
lost_agent_id = self.env['ir.config_parameter'].sudo().get_param('lost_agent_id')
|
|
||||||
wechat = self.env['we.config'].sudo().get_wechat(agent_id=lost_agent_id)
|
|
||||||
# agent_id, user_ids, content
|
|
||||||
content = """您提交的工单-**工单标题:{0}**-<font color=\"#FF0000\">**已关闭**</font>
|
|
||||||
>提交时间:{1}
|
|
||||||
>处理时间:{2}
|
|
||||||
>处理人:{3}
|
|
||||||
如有问题,请联系系统管理员!
|
|
||||||
""".format(self.order_id.title,
|
|
||||||
(self.order_id.date + datetime.timedelta(hours=8)).strftime(
|
|
||||||
'%Y-%m-%d %H:%M'), (datetime.datetime.now() + datetime.timedelta(
|
|
||||||
hours=8)).strftime('%Y-%m-%d %H:%M'), self.env.user.name or '')
|
|
||||||
# wechat.message.send_markdown(agent_id=lost_agent_id, user_ids=we_employee_ids, content=content)
|
|
||||||
for we_employee_id in we_employee_ids:
|
|
||||||
try:
|
|
||||||
wechat.message.send_markdown(agent_id=lost_agent_id, user_ids=we_employee_id, content=content)
|
|
||||||
except Exception as e:
|
|
||||||
logging.error('工单关闭发送消息异常%s' % str(e))
|
|
||||||
return {}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from odoo import models, fields, api
|
|
||||||
from odoo.exceptions import ValidationError
|
|
||||||
from odoo.addons.jikimo_system_order.models.constant import STATE_SELECTION, GRADE
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
|
|
||||||
class OrderOtherWizard(models.TransientModel):
|
|
||||||
_name = 'order.other.wizard'
|
|
||||||
|
|
||||||
|
|
||||||
def get_context(self):
|
|
||||||
if self._context.get('active_id'):
|
|
||||||
obj = self.env['system.work.order'].browse(self._context.get('active_id'))
|
|
||||||
if obj.initiator_id.id != self.env.user.id:
|
|
||||||
raise ValidationError(u'非本人无法操作')
|
|
||||||
return obj
|
|
||||||
|
|
||||||
order_id = fields.Many2one('system.work.order', string=u'工单ID',
|
|
||||||
default=lambda self: self.get_context().id)
|
|
||||||
# 关闭时间
|
|
||||||
close_time = fields.Datetime(string=u'关闭时间', default=fields.datetime.now())
|
|
||||||
# 状态
|
|
||||||
state = fields.Selection(STATE_SELECTION, default='completed', string=u'状态')
|
|
||||||
# 打分
|
|
||||||
grade = fields.Selection(GRADE, string=u'评分')
|
|
||||||
# 关闭人
|
|
||||||
close_user_id = fields.Many2one('res.users', string=u'关闭人', default=lambda self: self.env.user)
|
|
||||||
|
|
||||||
|
|
||||||
def sure(self):
|
|
||||||
self.order_id.close_time = self.close_time
|
|
||||||
self.order_id.grade = self.grade
|
|
||||||
if self.order_id.state == 'processed':
|
|
||||||
state_remark = u'已处理待评分 --> 已完成'
|
|
||||||
# self.order_id.message_post(u'操作人:%s,操作时间:%s,状态变更过程:%s' % (
|
|
||||||
# self.env.user.name,
|
|
||||||
# (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), state_remark))
|
|
||||||
self.order_id.state = self.state
|
|
||||||
self.order_id.close_user_id = self.close_user_id
|
|
||||||
return {}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from odoo import models, fields, api
|
|
||||||
from odoo.addons.jikimo_system_order.models.constant import STATE_SELECTION
|
|
||||||
import datetime
|
|
||||||
import logging
|
|
||||||
|
|
||||||
|
|
||||||
class OrderTechnicianWizard(models.TransientModel):
|
|
||||||
_name = 'order.technician.wizard'
|
|
||||||
|
|
||||||
order_id = fields.Many2one('system.work.order', string=u'工单ID',
|
|
||||||
default=lambda self: self.env.context.get('active_id'))
|
|
||||||
# 解决人
|
|
||||||
solve_people_id = fields.Many2one('res.users', string=u'解决人', default=lambda self: self.env.user)
|
|
||||||
# 用户实际问题
|
|
||||||
users_problem = fields.Text(string=u'用户实际问题')
|
|
||||||
# 最终解决方案
|
|
||||||
solution = fields.Text(string=u'最终解决方案')
|
|
||||||
# 状态
|
|
||||||
state = fields.Selection(STATE_SELECTION, default='processed', string=u'状态')
|
|
||||||
|
|
||||||
def sure(self):
|
|
||||||
self.order_id.solve_people_id = self.solve_people_id
|
|
||||||
self.order_id.users_problem = self.users_problem
|
|
||||||
self.order_id.solution = self.solution
|
|
||||||
if self.order_id.state == 'pending':
|
|
||||||
state_remark = u'待处理 --> 已处理待评分'
|
|
||||||
# self.order_id.message_post(u'操作人:%s,操作时间:%s,状态变更过程:%s' % (
|
|
||||||
# self.env.user.name,
|
|
||||||
# (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S'), state_remark))
|
|
||||||
self.order_id.state = self.state
|
|
||||||
# 获取通知人
|
|
||||||
# objs = self.env['system.order.notice'].search([])
|
|
||||||
# user_ids = objs.notice_user_ids.filtered(lambda item: item.we_employee_id not in ['', False])
|
|
||||||
# we_employee_ids = user_ids.mapped('we_employee_id')
|
|
||||||
we_employee_ids = []
|
|
||||||
if self.order_id.initiator_id.we_employee_id:
|
|
||||||
we_employee_ids.append(self.order_id.initiator_id.we_employee_id)
|
|
||||||
print(we_employee_ids)
|
|
||||||
lost_agent_id = self.env['ir.config_parameter'].sudo().get_param('lost_agent_id')
|
|
||||||
wechat = self.env['we.config'].sudo().get_wechat(agent_id=lost_agent_id)
|
|
||||||
# agent_id, user_ids, content
|
|
||||||
content = """您提交的工单-**工单标题:{0}**-<font color=\"info\">**已处理**</font>
|
|
||||||
>提交时间:{1}
|
|
||||||
>处理反馈:{4}
|
|
||||||
>处理时间:{2}
|
|
||||||
>处理人:{3}
|
|
||||||
如有问题,请联系系统管理员!
|
|
||||||
""".format(self.order_id.title,
|
|
||||||
(self.order_id.date + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M'), (datetime.datetime.now() + datetime.timedelta(hours=8)).strftime('%Y-%m-%d %H:%M'), self.env.user.name or '', self.solution or '')
|
|
||||||
# wechat.message.send_markdown(agent_id=lost_agent_id, user_ids=we_employee_ids, content=content)
|
|
||||||
for we_employee_id in we_employee_ids:
|
|
||||||
try:
|
|
||||||
wechat.message.send_markdown(agent_id=lost_agent_id, user_ids=we_employee_id, content=content)
|
|
||||||
except Exception as e:
|
|
||||||
logging.error('工单处理发送消息异常%s' % str(e))
|
|
||||||
|
|
||||||
return {}
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<odoo>
|
|
||||||
<data>
|
|
||||||
<!-- 技术员向导form-->
|
|
||||||
<record model="ir.ui.view" id="wizard_technician_form_view">
|
|
||||||
<field name="name">技术员向导</field>
|
|
||||||
<field name="model">order.technician.wizard</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<form string="技术员编辑">
|
|
||||||
<group>
|
|
||||||
<field name="order_id" required="1" readonly="1"/>
|
|
||||||
<field name="solve_people_id" required="1"/>
|
|
||||||
<field name="users_problem" required="1" style="height: 50px;"/>
|
|
||||||
<field name="solution" required="1" style="height: 50px;"/>
|
|
||||||
</group>
|
|
||||||
<footer>
|
|
||||||
<button name="sure" string="确定" type="object" class="oe_highlight"/>
|
|
||||||
or
|
|
||||||
<button string="取消" class="oe_link" special="cancel"/>
|
|
||||||
</footer>
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record model="ir.actions.act_window" id="launch_order_technician_wizard">
|
|
||||||
<field name="name">技术员编辑</field>
|
|
||||||
<field name="type">ir.actions.act_window</field>
|
|
||||||
<field name="res_model">order.technician.wizard</field>
|
|
||||||
<field name="view_mode">form</field>
|
|
||||||
<field name="view_id" ref="wizard_technician_form_view"/>
|
|
||||||
<field name="context">{'display_default_code':False}</field>
|
|
||||||
<field name="target">new</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- 其它向导form-->
|
|
||||||
<record model="ir.ui.view" id="wizard_other_form_view">
|
|
||||||
<field name="name">其它向导</field>
|
|
||||||
<field name="model">order.other.wizard</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<form string="其它编辑">
|
|
||||||
<group>
|
|
||||||
<field name="order_id" required="1" readonly="1"/>
|
|
||||||
<field name="close_time" required="1" readonly="1"/>
|
|
||||||
<field name="grade" required="1"/>
|
|
||||||
<field name="close_user_id" required="1" readonly="1"/>
|
|
||||||
</group>
|
|
||||||
<footer>
|
|
||||||
<button name="sure" string="确定" type="object" class="oe_highlight"/>
|
|
||||||
or
|
|
||||||
<button string="取消" class="oe_link" special="cancel"/>
|
|
||||||
</footer>
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record model="ir.actions.act_window" id="launch_order_other_wizard">
|
|
||||||
<field name="name">其它编辑</field>
|
|
||||||
<field name="type">ir.actions.act_window</field>
|
|
||||||
<field name="res_model">order.other.wizard</field>
|
|
||||||
<field name="view_mode">form</field>
|
|
||||||
<field name="view_id" ref="wizard_other_form_view"/>
|
|
||||||
<field name="context">{'display_default_code':False}</field>
|
|
||||||
<field name="target">new</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!--关闭向导form-->
|
|
||||||
<record model="ir.ui.view" id="wizard_close_form_view">
|
|
||||||
<field name="name">关闭向导</field>
|
|
||||||
<field name="model">order.close.wizard</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<form string="关闭工单">
|
|
||||||
<group>
|
|
||||||
<field name="order_id" required="1" readonly="1"/>
|
|
||||||
<field name="close_cause" required="1" style="height: 50px;"/>
|
|
||||||
<field name="close_time" required="1" readonly="1"/>
|
|
||||||
<field name="close_user_id" required="1" readonly="1"/>
|
|
||||||
</group>
|
|
||||||
<footer>
|
|
||||||
<button name="sure" string="确定" type="object" class="oe_highlight"/>
|
|
||||||
or
|
|
||||||
<button string="取消" class="oe_link" special="cancel"/>
|
|
||||||
</footer>
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record model="ir.actions.act_window" id="launch_order_close_wizard">
|
|
||||||
<field name="name">关闭工单</field>
|
|
||||||
<field name="type">ir.actions.act_window</field>
|
|
||||||
<field name="res_model">order.close.wizard</field>
|
|
||||||
<field name="view_mode">form</field>
|
|
||||||
<field name="view_id" ref="wizard_close_form_view"/>
|
|
||||||
<field name="context">{'display_default_code':False}</field>
|
|
||||||
<field name="target">new</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="system_work_order_wizard_view" model="ir.ui.view">
|
|
||||||
<field name="name">system_work_order_wizard_view</field>
|
|
||||||
<field name="model">system.work.order.wizard</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<form string="二次确认">
|
|
||||||
<field name="explain" readonly="1"/>
|
|
||||||
<footer>
|
|
||||||
<button name="sure" string="确定" type="object" class="oe_highlight"/>
|
|
||||||
or
|
|
||||||
<button string="取消" class="oe_link" special="cancel"/>
|
|
||||||
</footer>
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record model="ir.actions.act_window" id="system_work_order_wizard_view_act_window">
|
|
||||||
<field name="name">二次确认</field>
|
|
||||||
<field name="type">ir.actions.act_window</field>
|
|
||||||
<field name="res_model">system.work.order.wizard</field>
|
|
||||||
<field name="view_mode">form</field>
|
|
||||||
<field name="target">new</field>
|
|
||||||
</record>
|
|
||||||
</data>
|
|
||||||
</odoo>
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# @Time : 2017/12/12 9:46
|
|
||||||
# @Author : GuoXiang
|
|
||||||
# @Site :
|
|
||||||
# @File : system_work_order_wizard.py
|
|
||||||
# @Software: PyCharm
|
|
||||||
# @Desc :
|
|
||||||
# @license : Copyright©2018 www.dasmaster.com All Rights Reserved.
|
|
||||||
# @Contact : xg1230205321@163.com
|
|
||||||
from odoo import models, api, fields
|
|
||||||
from odoo.exceptions import ValidationError
|
|
||||||
|
|
||||||
|
|
||||||
class SystemWorkOrderWizard(models.TransientModel):
|
|
||||||
_name = "system.work.order.wizard"
|
|
||||||
_description = u"追回确认"
|
|
||||||
|
|
||||||
|
|
||||||
def _get_explain(self):
|
|
||||||
if self._context.get('object_id'):
|
|
||||||
obj = self.env['system.work.order'].browse(self._context.get('object_id'))
|
|
||||||
if obj.initiator_id.id != self.env.user.id:
|
|
||||||
raise ValidationError(u'非本人无法操作')
|
|
||||||
if self._context.get('explain'):
|
|
||||||
return self._context["explain"]
|
|
||||||
|
|
||||||
explain = fields.Char(default=_get_explain)
|
|
||||||
|
|
||||||
|
|
||||||
def sure(self):
|
|
||||||
"""
|
|
||||||
确认
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if self._context.get('object_id') and self._context.get('object_name') and self._context.get(
|
|
||||||
'explain') and self._context.get('function_name'):
|
|
||||||
work_sheet_obj = self.env[self._context["object_name"]].search([('id', '=', int(self._context["object_id"]))])
|
|
||||||
class_name = self._context.get('object_name') # 获得对象类名
|
|
||||||
method_name = self._context.get('function_name') # 获得对象的方法
|
|
||||||
obj_function = getattr(self.env[class_name], method_name)
|
|
||||||
obj_function(work_sheet_obj)
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from . import models
|
|
||||||
from . import controllers
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
||||||
{
|
|
||||||
'name': '机企猫 工单异常记录',
|
|
||||||
'version': '1.0',
|
|
||||||
'summary': '记录工单的异常日志',
|
|
||||||
'sequence': 1,
|
|
||||||
'category': 'sf',
|
|
||||||
'website': 'https://www.sf.jikimo.com',
|
|
||||||
'depends': ['sf_manufacturing', 'sf_mrs_connect'],
|
|
||||||
'data': [
|
|
||||||
'views/mrp_workorder_views.xml',
|
|
||||||
'security/ir.model.access.csv',
|
|
||||||
],
|
|
||||||
'demo': [
|
|
||||||
],
|
|
||||||
'license': 'LGPL-3',
|
|
||||||
'installable': True,
|
|
||||||
'application': False,
|
|
||||||
'auto_install': False,
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
from . import main
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
from odoo import http, fields
|
|
||||||
from odoo.http import request
|
|
||||||
import json
|
|
||||||
import logging
|
|
||||||
from odoo.addons.sf_mrs_connect.controllers.controllers import Sf_Mrs_Connect
|
|
||||||
from odoo.addons.sf_manufacturing.controllers.controllers import Manufacturing_Connect
|
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
class WorkorderExceptionConroller(http.Controller):
|
|
||||||
|
|
||||||
@http.route('/AutoDeviceApi/BillError', type='json', auth='public', methods=['GET', 'POST'], csrf=False,
|
|
||||||
cors="*")
|
|
||||||
def workder_exception(self, **kw):
|
|
||||||
"""
|
|
||||||
记录工单异常
|
|
||||||
:param kw:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
_logger.info('workder_exception:%s' % kw)
|
|
||||||
try:
|
|
||||||
res = {'Succeed': True, 'ErrorCode': 0, 'Error': ''}
|
|
||||||
datas = request.httprequest.data
|
|
||||||
ret = json.loads(datas)
|
|
||||||
if not ret.get('RfidCode') or not ret.get('coding'):
|
|
||||||
res = {'Succeed': False, 'ErrorCode': 400, 'Error': '参数错误'}
|
|
||||||
return json.JSONEncoder().encode(res)
|
|
||||||
|
|
||||||
# 通过RfidCode获取就绪的CNC工单
|
|
||||||
workorder = request.env['mrp.workorder'].sudo().search([
|
|
||||||
('rfid_code', '=', ret['RfidCode']),
|
|
||||||
('routing_type', '=', 'CNC加工'),
|
|
||||||
])
|
|
||||||
if not workorder:
|
|
||||||
res = {'Succeed': False, 'ErrorCode': 401, 'Error': '无效的工单'}
|
|
||||||
return json.JSONEncoder().encode(res)
|
|
||||||
|
|
||||||
# 创建工单异常记录,关联工单
|
|
||||||
request.env['jikimo.workorder.exception'].sudo().create({
|
|
||||||
'workorder_id': workorder.id,
|
|
||||||
'exception_code': ret.get('coding'),
|
|
||||||
'exception_content': ret.get('Error', '')
|
|
||||||
})
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
|
|
||||||
_logger.info('workder_exception error:%s' % e)
|
|
||||||
return json.JSONEncoder().encode(res)
|
|
||||||
|
|
||||||
|
|
||||||
class SfMrsConnectController(Sf_Mrs_Connect):
|
|
||||||
|
|
||||||
@http.route('/api/cnc_processing/create', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
|
|
||||||
cors="*")
|
|
||||||
def get_cnc_processing_create(self, **kw):
|
|
||||||
"""
|
|
||||||
更新工单异常记录【'YC001', 'YC004'】
|
|
||||||
"""
|
|
||||||
res = super(SfMrsConnectController, self).get_cnc_processing_create(**kw)
|
|
||||||
# 如果有未完成的YC0001、YC0004异常记录,则标记为完成
|
|
||||||
res = json.loads(res)
|
|
||||||
_logger.info('已进入工单异常:%s' % res)
|
|
||||||
if res.get('production_ids'):
|
|
||||||
try:
|
|
||||||
productions = request.env['mrp.production'].sudo().search([('id', 'in', res.get('production_ids'))])
|
|
||||||
if productions.workorder_ids:
|
|
||||||
productions.workorder_ids.handle_exception(['YC0001', 'YC0004'])
|
|
||||||
except Exception as e:
|
|
||||||
_logger.info('更新工单异常记录失败:%s' % e)
|
|
||||||
return json.JSONEncoder().encode(res)
|
|
||||||
|
|
||||||
class ManufactruingController(Manufacturing_Connect):
|
|
||||||
|
|
||||||
@http.route('/AutoDeviceApi/FeedBackStart', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
|
|
||||||
cors="*")
|
|
||||||
def button_Work_START(self, **kw):
|
|
||||||
"""
|
|
||||||
更新工单异常记录【'YC0002', 'YC0003'】
|
|
||||||
"""
|
|
||||||
res = super(ManufactruingController, self).button_Work_START(**kw)
|
|
||||||
res = json.loads(res)
|
|
||||||
_logger.info('已进入工单异常:%s' % res)
|
|
||||||
if res.get('workorder_id'):
|
|
||||||
try:
|
|
||||||
workorder = request.env['mrp.workorder'].sudo().browse(int(res.get('workorder_id')))
|
|
||||||
workorder.handle_exception(['YC0002', 'YC0003'])
|
|
||||||
except Exception as e:
|
|
||||||
_logger.info('更新工单异常记录失败:%s' % e)
|
|
||||||
return json.JSONEncoder().encode(res)
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from . import jikimo_workorder_exception
|
|
||||||
from . import mrp_workorder
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
from odoo import models, fields
|
|
||||||
|
|
||||||
|
|
||||||
class JikimoWorkorderException(models.Model):
|
|
||||||
_name = 'jikimo.workorder.exception'
|
|
||||||
_description = '工单异常记录'
|
|
||||||
_order = 'id desc'
|
|
||||||
|
|
||||||
workorder_id = fields.Many2one('mrp.workorder', string='工单')
|
|
||||||
exception_code = fields.Char('异常编码')
|
|
||||||
exception_content = fields.Char('反馈的异常/问题信息')
|
|
||||||
completion_time = fields.Datetime('处理完成时间')
|
|
||||||
state = fields.Selection([('pending', '进行中'), ('done', '已处理')], string='状态', default='pending')
|
|
||||||
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
from odoo import models, fields
|
|
||||||
import logging
|
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
class MrpWorkorder(models.Model):
|
|
||||||
_inherit = 'mrp.workorder'
|
|
||||||
|
|
||||||
exception_ids = fields.One2many('jikimo.workorder.exception', 'workorder_id', string='工单异常记录')
|
|
||||||
|
|
||||||
def write(self, values):
|
|
||||||
if values.get('test_results') and self.exception_ids:
|
|
||||||
pending_exception = self.exception_ids.filtered(
|
|
||||||
lambda exc: exc.state == 'pending' and exc.exception_code == 'YC0005'
|
|
||||||
)
|
|
||||||
if pending_exception:
|
|
||||||
pending_exception.write({
|
|
||||||
'completion_time': fields.Datetime.now(),
|
|
||||||
'state': 'done'
|
|
||||||
})
|
|
||||||
return super(MrpWorkorder, self).write(values)
|
|
||||||
|
|
||||||
def handle_exception(self, exception_codes):
|
|
||||||
"""
|
|
||||||
处理异常
|
|
||||||
:param exception_codes: 需要处理的异常编码列表
|
|
||||||
"""
|
|
||||||
if not isinstance(exception_codes, list):
|
|
||||||
exception_codes = [exception_codes]
|
|
||||||
if self.exception_ids:
|
|
||||||
_logger.info('workorder.exception_ids:%s' % self.exception_ids)
|
|
||||||
pending_exception = self.exception_ids.filtered(
|
|
||||||
lambda exc: exc.state == 'pending' and exc.exception_code in exception_codes
|
|
||||||
)
|
|
||||||
_logger.info('pending_exception:%s' % pending_exception)
|
|
||||||
if pending_exception:
|
|
||||||
pending_exception.write({
|
|
||||||
'completion_time': fields.Datetime.now(),
|
|
||||||
'state': 'done'
|
|
||||||
})
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
|
||||||
"access_jikimo_workorder_exception","access.jikimo.workorder.exception","model_jikimo_workorder_exception","mrp.group_mrp_user",1,1,1,0
|
|
||||||
"access_jikimo_workorder_exception_group_quality","access.jikimo.workorder.exception.group_quality","model_jikimo_workorder_exception","sf_base.group_quality",1,1,1,0
|
|
||||||
"access_jikimo_workorder_exception_group_quality_director","access.jikimo.workorder.exception.group_quality_director","model_jikimo_workorder_exception","sf_base.group_quality_director",1,1,1,0
|
|
||||||
|
|
||||||
|
@@ -1,2 +0,0 @@
|
|||||||
from . import common
|
|
||||||
from . import test_jikimo_workorder_exception
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
||||||
from odoo import fields, Command
|
|
||||||
from odoo.tests.common import TransactionCase, HttpCase, tagged, Form
|
|
||||||
|
|
||||||
import json
|
|
||||||
import time
|
|
||||||
import base64
|
|
||||||
from lxml import etree
|
|
||||||
|
|
||||||
@tagged('post_install', '-at_install')
|
|
||||||
class TestJikimoWorkorderExceptionCommon(TransactionCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(TestJikimoWorkorderExceptionCommon, self).setUp()
|
|
||||||
# 获取名字为“1#自动生产线”的制造中心
|
|
||||||
workcenter = self.env['mrp.workcenter'].search([('name', '=', '1#自动生产线')], limit=1)
|
|
||||||
# 创建一个产品
|
|
||||||
product_product = self.env['product.product'].create({
|
|
||||||
'name': '测试产品',
|
|
||||||
'type': 'product',
|
|
||||||
})
|
|
||||||
uom_unit = self.env.ref('uom.product_uom_unit')
|
|
||||||
# 创建一个bom
|
|
||||||
self.bom = self.env['mrp.bom'].create({
|
|
||||||
'product_id': product_product.id,
|
|
||||||
'product_tmpl_id': product_product.product_tmpl_id.id,
|
|
||||||
'product_uom_id': uom_unit.id,
|
|
||||||
'product_qty': 1.0,
|
|
||||||
'type': 'normal',
|
|
||||||
})
|
|
||||||
# 创建一个制造订单
|
|
||||||
self.production = self.env['mrp.production'].create({
|
|
||||||
'name': 'Test Production',
|
|
||||||
'product_id': product_product.id,
|
|
||||||
'bom_id': self.bom.id,
|
|
||||||
'company_id': self.env.ref('base.main_company').id,
|
|
||||||
})
|
|
||||||
# 创建一个测试工单
|
|
||||||
self.workorder = self.env['mrp.workorder'].create({
|
|
||||||
'name': 'Test order',
|
|
||||||
'workcenter_id': workcenter.id,
|
|
||||||
'product_uom_id': self.bom.product_uom_id.id,
|
|
||||||
'production_id': self.production.id,
|
|
||||||
'duration_expected': 1.0,
|
|
||||||
'rfid_code': 'test-123456',
|
|
||||||
'routing_type': 'CNC加工'
|
|
||||||
})
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
import json
|
|
||||||
from datetime import datetime
|
|
||||||
from odoo.addons.jikimo_workorder_exception.tests.common import TestJikimoWorkorderExceptionCommon
|
|
||||||
|
|
||||||
class TestJikimoWorkorderException(TestJikimoWorkorderExceptionCommon):
|
|
||||||
|
|
||||||
def test_create_exception_record(self):
|
|
||||||
exception_record = self.env['jikimo.workorder.exception'].create({
|
|
||||||
'workorder_id': self.workorder.id,
|
|
||||||
'exception_code': 'YC0001',
|
|
||||||
'exception_content': '无CNC编程'
|
|
||||||
})
|
|
||||||
|
|
||||||
self.assertTrue(exception_record)
|
|
||||||
self.assertEqual(exception_record.exception_content, '无CNC编程')
|
|
||||||
self.assertEqual(exception_record.workorder_id.id, self.workorder.id)
|
|
||||||
self.assertEqual(exception_record.exception_code, 'YC0001')
|
|
||||||
|
|
||||||
def test_handle_exception(self):
|
|
||||||
exception_record = self.env['jikimo.workorder.exception'].create({
|
|
||||||
'workorder_id': self.workorder.id,
|
|
||||||
'exception_code': 'YC0001',
|
|
||||||
'exception_content': '无CNC编程'
|
|
||||||
})
|
|
||||||
self.workorder.handle_exception('YC0001')
|
|
||||||
self.assertEqual(exception_record.state, 'done')
|
|
||||||
# 判断完成时间是否为当前分钟
|
|
||||||
self.assertEqual(exception_record.completion_time.minute, datetime.now().minute)
|
|
||||||
|
|
||||||
def test_handle_exception_with_invalid_code(self):
|
|
||||||
exception_record = self.env['jikimo.workorder.exception'].create({
|
|
||||||
'workorder_id': self.workorder.id,
|
|
||||||
'exception_code': 'YC0001',
|
|
||||||
'exception_content': '无CNC编程'
|
|
||||||
})
|
|
||||||
self.workorder.handle_exception(['YC0002', 'YC0004'])
|
|
||||||
self.assertEqual(exception_record.state, 'pending')
|
|
||||||
self.assertEqual(exception_record.completion_time, False)
|
|
||||||
|
|
||||||
|
|
||||||
def test_handle_exception_with_test_results(self):
|
|
||||||
exception_record = self.env['jikimo.workorder.exception'].create({
|
|
||||||
'workorder_id': self.workorder.id,
|
|
||||||
'exception_code': 'YC0005',
|
|
||||||
'exception_content': '工单加工失败'
|
|
||||||
})
|
|
||||||
self.workorder.write({
|
|
||||||
'test_results': '返工',
|
|
||||||
'reason': 'cutter',
|
|
||||||
'detailed_reason': '刀坏了',
|
|
||||||
})
|
|
||||||
self.assertEqual(exception_record.state, 'done')
|
|
||||||
self.assertEqual(exception_record.completion_time.minute, datetime.now().minute)
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<odoo>
|
|
||||||
<data>
|
|
||||||
<record id="jikimo_workorder_exception_form_view_inherit" model="ir.ui.view">
|
|
||||||
<field name="name">mrp.workorder.form</field>
|
|
||||||
<field name="model">mrp.workorder</field>
|
|
||||||
<field name="inherit_id" ref="mrp.mrp_production_workorder_form_view_inherit"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<xpath expr="//notebook/page[last()]" position="after">
|
|
||||||
<page string="异常记录" name="workorder_exception" attrs="{'invisible': [('routing_type', '!=', 'CNC加工')]}">
|
|
||||||
<field name="exception_ids" nolabel="1" readonly="1">
|
|
||||||
<tree create="false" delete="false" edit="false">
|
|
||||||
<field name="exception_content" string="反馈的异常/问题信息"/>
|
|
||||||
<field name="create_date" string="时间"/>
|
|
||||||
<field name="completion_time"/>
|
|
||||||
</tree>
|
|
||||||
</field>
|
|
||||||
</page>
|
|
||||||
</xpath>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
</data>
|
|
||||||
</odoo>
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from . import models
|
|
||||||
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
||||||
{
|
|
||||||
'name': '机企猫 工单异常消息通知',
|
|
||||||
'version': '1.0',
|
|
||||||
'summary': '当产生工单异常时,发送消息通知',
|
|
||||||
'sequence': 1,
|
|
||||||
'category': 'sf',
|
|
||||||
'website': 'https://www.sf.jikimo.com',
|
|
||||||
'depends': ['jikimo_workorder_exception', 'jikimo_message_notify'],
|
|
||||||
'data': [
|
|
||||||
'data/bussiness_node.xml',
|
|
||||||
'data/template_data.xml',
|
|
||||||
# 'security/ir.model.access.csv',
|
|
||||||
],
|
|
||||||
'demo': [
|
|
||||||
],
|
|
||||||
'license': 'LGPL-3',
|
|
||||||
'installable': True,
|
|
||||||
'application': False,
|
|
||||||
'auto_install': False,
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
<?xml version="1.0" ?>
|
|
||||||
<odoo>
|
|
||||||
<data noupdate="1">
|
|
||||||
<record id="bussiness_no_functional_tool" model="jikimo.message.bussiness.node">
|
|
||||||
<field name="name">无功能刀具</field>
|
|
||||||
<field name="model">jikimo.workorder.exception</field>
|
|
||||||
</record>
|
|
||||||
<record id="bussiness_no_position_data" model="jikimo.message.bussiness.node">
|
|
||||||
<field name="name">无定位数据</field>
|
|
||||||
<field name="model">jikimo.workorder.exception</field>
|
|
||||||
</record>
|
|
||||||
<record id="bussiness_processing_failure" model="jikimo.message.bussiness.node">
|
|
||||||
<field name="name">加工失败</field>
|
|
||||||
<field name="model">jikimo.workorder.exception</field>
|
|
||||||
</record>
|
|
||||||
</data>
|
|
||||||
</odoo>
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
<?xml version="1.0" ?>
|
|
||||||
<odoo>
|
|
||||||
<data noupdate="1">
|
|
||||||
<record id="template_no_function_tool" model="jikimo.message.template">
|
|
||||||
<field name="name">生产线无功能刀具提醒</field>
|
|
||||||
<field name="model_id" ref="jikimo_workorder_exception_notify.model_jikimo_workorder_exception"/>
|
|
||||||
<field name="model">jikimo.workorder.exception</field>
|
|
||||||
<field name="bussiness_node_id" ref="bussiness_no_functional_tool"/>
|
|
||||||
<field name="msgtype">markdown</field>
|
|
||||||
<field name="urgency">urgent</field>
|
|
||||||
<field name="content">### 生产线无功能刀具提醒
|
|
||||||
单号:工单[{{workorder_id.production_id.name}}]({{url}})
|
|
||||||
原因:生产线无加工程序要用的功能刀具</field>
|
|
||||||
</record>
|
|
||||||
<record id="template_no_position_data" model="jikimo.message.template">
|
|
||||||
<field name="name">工单无定位数据提醒</field>
|
|
||||||
<field name="model_id" ref="jikimo_workorder_exception_notify.model_jikimo_workorder_exception"/>
|
|
||||||
<field name="model">jikimo.workorder.exception</field>
|
|
||||||
<field name="bussiness_node_id" ref="bussiness_no_position_data"/>
|
|
||||||
<field name="msgtype">markdown</field>
|
|
||||||
<field name="urgency">urgent</field>
|
|
||||||
<field name="content">### 工单无定位数据提醒
|
|
||||||
单号:工单[{{workorder_id.production_id.name}}]({{url}})
|
|
||||||
原因:无装夹定位测量数据</field>
|
|
||||||
</record>
|
|
||||||
<record id="template_processing_failure" model="jikimo.message.template">
|
|
||||||
<field name="name">工单加工失败提醒</field>
|
|
||||||
<field name="model_id" ref="jikimo_workorder_exception_notify.model_jikimo_workorder_exception"/>
|
|
||||||
<field name="model">jikimo.workorder.exception</field>
|
|
||||||
<field name="bussiness_node_id" ref="bussiness_processing_failure"/>
|
|
||||||
<field name="msgtype">markdown</field>
|
|
||||||
<field name="urgency">urgent</field>
|
|
||||||
<field name="content">### 工单加工失败提醒
|
|
||||||
单号:工单[{{workorder_id.production_id.name}}]({{url}})
|
|
||||||
原因:加工失败,工件下产线处理</field>
|
|
||||||
</record>
|
|
||||||
</data>
|
|
||||||
</odoo>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from . import jikimo_message_template
|
|
||||||
from . import jikimo_workorder_exception
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
from odoo import models
|
|
||||||
|
|
||||||
|
|
||||||
class JikimoMessageTemplate(models.Model):
|
|
||||||
_inherit = "jikimo.message.template"
|
|
||||||
|
|
||||||
def _get_message_model(self):
|
|
||||||
res = super(JikimoMessageTemplate, self)._get_message_model()
|
|
||||||
res.append('jikimo.workorder.exception')
|
|
||||||
return res
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
from odoo import models, api
|
|
||||||
from odoo.addons.sf_base.commons.common import Common
|
|
||||||
import requests, logging
|
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class JikimoWorkorderException(models.Model):
|
|
||||||
_name = 'jikimo.workorder.exception'
|
|
||||||
_inherit = ['jikimo.workorder.exception', 'jikimo.message.dispatch']
|
|
||||||
|
|
||||||
@api.model_create_multi
|
|
||||||
def create(self, vals_list):
|
|
||||||
res = super(JikimoWorkorderException, self).create(vals_list)
|
|
||||||
# 根据异常编码发送消息提醒
|
|
||||||
try:
|
|
||||||
for rec in res:
|
|
||||||
if rec.exception_code == 'YC0001':
|
|
||||||
# 无CNC程序,调用cloud接口
|
|
||||||
data = {'name': rec.workorder_id.production_id.programming_no, 'exception_code': 'YC0001'}
|
|
||||||
configsettings = self.env['res.config.settings'].sudo().get_values()
|
|
||||||
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
|
|
||||||
url = '/api/message/workorder_exception'
|
|
||||||
config_url = configsettings['sf_url'] + url
|
|
||||||
data['token'] = configsettings['token']
|
|
||||||
ret = requests.post(config_url, json=data, headers=config_header)
|
|
||||||
ret = ret.json()
|
|
||||||
_logger.info('无CNC程序异常消息推送接口:%s' % ret)
|
|
||||||
elif rec.exception_code == 'YC0002':
|
|
||||||
# 无功能刀具
|
|
||||||
rec.add_queue('无功能刀具')
|
|
||||||
elif rec.exception_code == 'YC0003':
|
|
||||||
# 无定位数据
|
|
||||||
rec.add_queue('无定位数据')
|
|
||||||
elif rec.exception_code == 'YC0004':
|
|
||||||
# 无FTP文件,调用cloud接口
|
|
||||||
data = {'name': rec.workorder_id.production_id.programming_no, 'exception_code': 'YC0004'}
|
|
||||||
configsettings = self.env['res.config.settings'].sudo().get_values()
|
|
||||||
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
|
|
||||||
url = '/api/message/workorder_exception'
|
|
||||||
config_url = configsettings['sf_url'] + url
|
|
||||||
data['token'] = configsettings['token']
|
|
||||||
ret = requests.post(config_url, json=data, headers=config_header)
|
|
||||||
ret = ret.json()
|
|
||||||
_logger.info('无FTP文件异常消息推送接口:%s' % ret)
|
|
||||||
elif rec.exception_code == 'YC0005':
|
|
||||||
# 加工失败
|
|
||||||
rec.add_queue('加工失败')
|
|
||||||
except Exception as e:
|
|
||||||
_logger.error('异常编码发送消息提醒失败:%s' % e)
|
|
||||||
return res
|
|
||||||
|
|
||||||
def _get_message(self, message_queue_ids):
|
|
||||||
contents = super(JikimoWorkorderException, self)._get_message(message_queue_ids)
|
|
||||||
url = self.env['ir.config_parameter'].get_param('web.base.url')
|
|
||||||
action_id = self.env.ref('mrp.mrp_production_action').id
|
|
||||||
for index, content in enumerate(contents):
|
|
||||||
exception_id = self.env['jikimo.workorder.exception'].browse(message_queue_ids[index].res_id)
|
|
||||||
url = url + '/web#id=%s&view_type=form&action=%s' % (exception_id.workorder_id.production_id.id, action_id)
|
|
||||||
contents[index] = content.replace('{{url}}', url)
|
|
||||||
return contents
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
from . import common
|
|
||||||
from . import test_jikimo_workorder_exception_notify
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
||||||
from odoo import fields, Command
|
|
||||||
from odoo.tests.common import TransactionCase, HttpCase, tagged, Form
|
|
||||||
|
|
||||||
import json
|
|
||||||
import time
|
|
||||||
import base64
|
|
||||||
from lxml import etree
|
|
||||||
|
|
||||||
@tagged('post_install', '-at_install')
|
|
||||||
class TestJikimoWorkorderExceptionNotifyCommonNotify(TransactionCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(TestJikimoWorkorderExceptionNotifyCommonNotify, self).setUp()
|
|
||||||
# 获取最后一个工单
|
|
||||||
self.workorder = self.env['mrp.workorder'].search([], order='id desc', limit=1)
|
|
||||||
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
import json
|
|
||||||
from datetime import datetime
|
|
||||||
from odoo.addons.jikimo_workorder_exception_notify.tests.common import TestJikimoWorkorderExceptionNotifyCommonNotify
|
|
||||||
|
|
||||||
class TestJikimoWorkorderExceptionNotify(TestJikimoWorkorderExceptionNotifyCommonNotify):
|
|
||||||
|
|
||||||
def test_create_message_template(self):
|
|
||||||
self.assertTrue(self.env['jikimo.message.template'].search([
|
|
||||||
('name', '=', '生产线无功能刀具提醒'),
|
|
||||||
('model', '=', 'jikimo.workorder.exception')
|
|
||||||
]))
|
|
||||||
self.assertTrue(self.env['jikimo.message.template'].search([
|
|
||||||
('name', '=', '工单无定位数据提醒'),
|
|
||||||
('model', '=', 'jikimo.workorder.exception')
|
|
||||||
]))
|
|
||||||
self.assertTrue(self.env['jikimo.message.template'].search([
|
|
||||||
('name', '=', '工单加工失败提醒'),
|
|
||||||
('model', '=', 'jikimo.workorder.exception')
|
|
||||||
]))
|
|
||||||
|
|
||||||
def test_create_message_queue_yc0001(self):
|
|
||||||
exception_record = self.env['jikimo.workorder.exception'].create({
|
|
||||||
'workorder_id': self.workorder.id,
|
|
||||||
'exception_code': 'YC0001',
|
|
||||||
'exception_content': '无CNC程序'
|
|
||||||
})
|
|
||||||
|
|
||||||
message_record = self.env['jikimo.message.queue'].search([
|
|
||||||
('res_id', '=', exception_record.id),
|
|
||||||
('model', '=', 'jikimo.workorder.exception'),
|
|
||||||
('message_status', '=', 'pending')
|
|
||||||
])
|
|
||||||
self.assertFalse(message_record)
|
|
||||||
|
|
||||||
def test_create_message_queue_yc0002(self):
|
|
||||||
exception_record = self.env['jikimo.workorder.exception'].create({
|
|
||||||
'workorder_id': self.workorder.id,
|
|
||||||
'exception_code': 'YC0002',
|
|
||||||
'exception_content': '无功能刀具'
|
|
||||||
})
|
|
||||||
|
|
||||||
bussiness_node = self.env['jikimo.message.bussiness.node'].search([
|
|
||||||
('name', '=', '无功能刀具'),
|
|
||||||
('model', '=', 'jikimo.workorder.exception')
|
|
||||||
])
|
|
||||||
|
|
||||||
message_template = self.env['jikimo.message.template'].search([
|
|
||||||
('bussiness_node_id', '=', bussiness_node.id),
|
|
||||||
('model', '=', 'jikimo.workorder.exception')
|
|
||||||
])
|
|
||||||
|
|
||||||
message_record = self.env['jikimo.message.queue'].search([
|
|
||||||
('res_id', '=', exception_record.id),
|
|
||||||
('model', '=', 'jikimo.workorder.exception'),
|
|
||||||
('message_status', '=', 'pending'),
|
|
||||||
('message_template_id', '=', message_template.id)
|
|
||||||
])
|
|
||||||
self.assertTrue(message_record)
|
|
||||||
|
|
||||||
def test_create_message_queue_yc0003(self):
|
|
||||||
exception_record = self.env['jikimo.workorder.exception'].create({
|
|
||||||
'workorder_id': self.workorder.id,
|
|
||||||
'exception_code': 'YC0003',
|
|
||||||
'exception_content': '无定位数据'
|
|
||||||
})
|
|
||||||
|
|
||||||
bussiness_node = self.env['jikimo.message.bussiness.node'].search([
|
|
||||||
('name', '=', '无定位数据'),
|
|
||||||
('model', '=', 'jikimo.workorder.exception')
|
|
||||||
])
|
|
||||||
|
|
||||||
message_template = self.env['jikimo.message.template'].search([
|
|
||||||
('bussiness_node_id', '=', bussiness_node.id),
|
|
||||||
('model', '=', 'jikimo.workorder.exception')
|
|
||||||
])
|
|
||||||
|
|
||||||
message_record = self.env['jikimo.message.queue'].search([
|
|
||||||
('res_id', '=', exception_record.id),
|
|
||||||
('model', '=', 'jikimo.workorder.exception'),
|
|
||||||
('message_status', '=', 'pending'),
|
|
||||||
('message_template_id', '=', message_template.id)
|
|
||||||
])
|
|
||||||
self.assertTrue(message_record)
|
|
||||||
|
|
||||||
def test_create_message_queue_yc0004(self):
|
|
||||||
exception_record = self.env['jikimo.workorder.exception'].create({
|
|
||||||
'workorder_id': self.workorder.id,
|
|
||||||
'exception_code': 'YC0004',
|
|
||||||
'exception_content': '无CNC程序'
|
|
||||||
})
|
|
||||||
|
|
||||||
message_record = self.env['jikimo.message.queue'].search([
|
|
||||||
('res_id', '=', exception_record.id),
|
|
||||||
('model', '=', 'jikimo.workorder.exception'),
|
|
||||||
('message_status', '=', 'pending')
|
|
||||||
])
|
|
||||||
self.assertFalse(message_record)
|
|
||||||
|
|
||||||
def test_get_message(self):
|
|
||||||
exception_record = self.env['jikimo.workorder.exception'].create({
|
|
||||||
'workorder_id': self.workorder.id,
|
|
||||||
'exception_code': 'YC0002',
|
|
||||||
'exception_content': '无功能刀具'
|
|
||||||
})
|
|
||||||
message_queue_ids = self.env['jikimo.message.queue'].search([
|
|
||||||
('res_id', '=', exception_record.id),
|
|
||||||
('model', '=', 'jikimo.workorder.exception'),
|
|
||||||
('message_status', '=', 'pending')
|
|
||||||
])
|
|
||||||
message = self.env['jikimo.workorder.exception']._get_message(message_queue_ids)
|
|
||||||
self.assertTrue(message)
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1273,18 +1273,3 @@ msgstr ""
|
|||||||
#: model:product.template,description_sale:mrp_workorder.product_template_stool_top
|
#: model:product.template,description_sale:mrp_workorder.product_template_stool_top
|
||||||
msgid "wooden stool top"
|
msgid "wooden stool top"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: mrp_workorder
|
|
||||||
#: model:quality.point.test_type,name:mrp_workorder.test_type_register_consumed_materials
|
|
||||||
msgid "Register Consumed Materials"
|
|
||||||
msgstr "登记消耗材料"
|
|
||||||
|
|
||||||
#. module: mrp_workorder
|
|
||||||
#: model:quality.point.test_type,name:mrp_workorder.test_type_register_byproducts
|
|
||||||
msgid "Register By-products"
|
|
||||||
msgstr "按产品注册"
|
|
||||||
|
|
||||||
#. module: mrp_workorder
|
|
||||||
#: model:quality.point.test_type,name:mrp_workorder.test_type_print_label
|
|
||||||
msgid "Print label"
|
|
||||||
msgstr "打印标签"
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- 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,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,16 +5,13 @@
|
|||||||
<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')"
|
|
||||||
decoration-muted="state in ('done','cancel')" string="Manufacturing Orders" name="Production">
|
|
||||||
<field name="message_needaction" invisible="1"/>
|
<field name="message_needaction" invisible="1"/>
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
<field name="date_planned_start"/>
|
<field name="date_planned_start"/>
|
||||||
<field name="product_id"/>
|
<field name="product_id"/>
|
||||||
<field name="product_qty" sum="Total Qty" string="Quantity"/>
|
<field name="product_qty" sum="Total Qty" string="Quantity"/>
|
||||||
<field name="product_uom_id" string="Unit of Measure" options="{'no_open':True,'no_create':True}"
|
<field name="product_uom_id" string="Unit of Measure" options="{'no_open':True,'no_create':True}" groups="uom.group_uom"/>
|
||||||
groups="uom.group_uom"/>
|
|
||||||
<field name="reservation_state" string="Availability"/>
|
<field name="reservation_state" string="Availability"/>
|
||||||
<field name="origin"/>
|
<field name="origin"/>
|
||||||
<field name="state"/>
|
<field name="state"/>
|
||||||
@@ -22,23 +19,23 @@
|
|||||||
</field>
|
</field>
|
||||||
</record>
|
</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,20 +51,17 @@
|
|||||||
<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"
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -1050,13 +1050,3 @@ msgstr "工作中心故障"
|
|||||||
#: model:ir.model.fields,field_description:quality.field_quality_point_test_type__active
|
#: model:ir.model.fields,field_description:quality.field_quality_point_test_type__active
|
||||||
msgid "active"
|
msgid "active"
|
||||||
msgstr "有效"
|
msgstr "有效"
|
||||||
|
|
||||||
#. module: quality
|
|
||||||
#: model:quality.point.test_type,name:quality.test_type_instructions
|
|
||||||
msgid "Instructions"
|
|
||||||
msgstr "使用说明"
|
|
||||||
|
|
||||||
#. module: quality
|
|
||||||
#: model:quality.point.test_type,name:quality.test_type_picture
|
|
||||||
msgid "Take a Picture"
|
|
||||||
msgstr "照片"
|
|
||||||
@@ -15,7 +15,7 @@ class TestType(models.Model):
|
|||||||
_description = "Quality Control Test Type"
|
_description = "Quality Control Test Type"
|
||||||
|
|
||||||
# Used instead of selection field in order to hide a choice depending on the view.
|
# Used instead of selection field in order to hide a choice depending on the view.
|
||||||
name = fields.Char('Name', required=True,translate=True)
|
name = fields.Char('Name', required=True)
|
||||||
technical_name = fields.Char('Technical name', required=True)
|
technical_name = fields.Char('Technical name', required=True)
|
||||||
active = fields.Boolean('active', default=True)
|
active = fields.Boolean('active', default=True)
|
||||||
|
|
||||||
|
|||||||
@@ -1185,14 +1185,3 @@ msgstr "请先进行质量检查!"
|
|||||||
#: model_terms:ir.ui.view,arch_db:quality_control.quality_alert_team_view_form
|
#: model_terms:ir.ui.view,arch_db:quality_control.quality_alert_team_view_form
|
||||||
msgid "e.g. The QA Masters"
|
msgid "e.g. The QA Masters"
|
||||||
msgstr "例如:QA大师"
|
msgstr "例如:QA大师"
|
||||||
|
|
||||||
|
|
||||||
#. module: quality_control
|
|
||||||
#: model:quality.point.test_type,name:quality_control.test_type_passfail
|
|
||||||
msgid "Pass - Fail"
|
|
||||||
msgstr "通过-失败"
|
|
||||||
|
|
||||||
#. module: quality_control
|
|
||||||
#: model:quality.point.test_type,name:quality_control.test_type_measure
|
|
||||||
msgid "Measure"
|
|
||||||
msgstr "测量"
|
|
||||||
@@ -6,4 +6,3 @@ from . import stock_move
|
|||||||
from . import stock_move_line
|
from . import stock_move_line
|
||||||
from . import stock_picking
|
from . import stock_picking
|
||||||
from . import stock_lot
|
from . import stock_lot
|
||||||
from . import product_category
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
||||||
from math import sqrt
|
|
||||||
from dateutil.relativedelta import relativedelta
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
import random
|
|
||||||
|
|
||||||
from odoo import api, models, fields, _
|
|
||||||
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, float_round
|
|
||||||
from odoo.osv.expression import OR
|
|
||||||
|
|
||||||
|
|
||||||
class ProductCategory(models.Model):
|
|
||||||
_inherit = 'product.category'
|
|
||||||
@api.model
|
|
||||||
def name_search(self, name='', args=None, operator='ilike', limit=100):
|
|
||||||
if args is None:
|
|
||||||
args = []
|
|
||||||
# 添加过滤条件,确保只返回名称为 'abc' 的记录
|
|
||||||
args += [('name', 'not in', ['Saleable', 'Expenses', 'Deliveries'])]
|
|
||||||
|
|
||||||
# 调用父类的 name_search 方法
|
|
||||||
return super(ProductCategory, self).name_search(name, args=args, operator=operator, limit=limit)
|
|
||||||
|
|
||||||
@api.model
|
|
||||||
def search(self, args, limit=100, offset=0, order=None, count=False):
|
|
||||||
# 添加过滤条件,确保只返回名称不在指定列表中的记录
|
|
||||||
args += [('name', 'not in', ['Saleable', 'Expenses', 'Deliveries'])]
|
|
||||||
|
|
||||||
# 调用父类的 search 方法
|
|
||||||
return super(ProductCategory, self).search(args, limit=limit, offset=offset, order=order, count=count)
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 702 B |
@@ -203,7 +203,7 @@
|
|||||||
<record id="quality_alert_action_check" model="ir.actions.act_window">
|
<record id="quality_alert_action_check" model="ir.actions.act_window">
|
||||||
<field name="name">Quality Alerts</field>
|
<field name="name">Quality Alerts</field>
|
||||||
<field name="res_model">quality.alert</field>
|
<field name="res_model">quality.alert</field>
|
||||||
<field name="view_mode">tree,kanban,form,pivot,graph,calendar</field>
|
<field name="view_mode">kanban,tree,form,pivot,graph,calendar</field>
|
||||||
<field name="help" type="html">
|
<field name="help" type="html">
|
||||||
<p class="o_view_nocontent_smiling_face">
|
<p class="o_view_nocontent_smiling_face">
|
||||||
Create a new quality alert
|
Create a new quality alert
|
||||||
@@ -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
|
|
||||||
|
|||||||
@@ -394,30 +394,3 @@ class MachineToolCategory(models.Model):
|
|||||||
active = fields.Boolean('有效', default=True)
|
active = fields.Boolean('有效', default=True)
|
||||||
category = fields.Selection([('shukong', u'数控'), ('putong', u'普通')], string=u'机床类别',
|
category = fields.Selection([('shukong', u'数控'), ('putong', u'普通')], string=u'机床类别',
|
||||||
default='shukong')
|
default='shukong')
|
||||||
|
|
||||||
|
|
||||||
class MachiningAccuracy(models.Model):
|
|
||||||
_name = 'sf.machining.accuracy'
|
|
||||||
_description = '加工精度'
|
|
||||||
name = fields.Char('一般公差', index=True)
|
|
||||||
standard_tolerance = fields.Char(string="标准公差")
|
|
||||||
sync_id = fields.Char('同步ID')
|
|
||||||
|
|
||||||
|
|
||||||
class ReSaleOrder(models.Model):
|
|
||||||
_inherit = 'sale.order'
|
|
||||||
|
|
||||||
person_of_delivery = fields.Char('收货人')
|
|
||||||
telephone_of_delivery = fields.Char('电话号码')
|
|
||||||
address_of_delivery = fields.Char('联系地址')
|
|
||||||
|
|
||||||
|
|
||||||
class EmbryoRedundancy(models.Model):
|
|
||||||
_name = "sf.embryo.redundancy"
|
|
||||||
|
|
||||||
code = fields.Char('编码', required=True)
|
|
||||||
name = fields.Char('名称', required=True)
|
|
||||||
long = fields.Float('长度(mm)', required=True)
|
|
||||||
width = fields.Float('宽度(mm)', required=True)
|
|
||||||
height = fields.Float('高度(mm)', required=True)
|
|
||||||
active = fields.Boolean('有效', default=True)
|
|
||||||
|
|||||||
@@ -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='装夹单元数')
|
||||||
|
|||||||
@@ -56,15 +56,17 @@ class MrsMaterialModel(models.Model):
|
|||||||
finish_machining = fields.Float("精加工Vc(m/min)")
|
finish_machining = fields.Float("精加工Vc(m/min)")
|
||||||
remark = fields.Text("备注")
|
remark = fields.Text("备注")
|
||||||
gain_way = fields.Selection(
|
gain_way = fields.Selection(
|
||||||
[("自加工", "自加工"), ("外协", "委外加工"), ("采购", "采购")],
|
[("自加工", "自加工"), ("外协", "外协"), ("采购", "采购")],
|
||||||
default="", string="获取方式")
|
default="", string="获取方式")
|
||||||
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,16 @@ 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):
|
||||||
@@ -146,20 +143,14 @@ 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 = []
|
||||||
for parameter in self:
|
for parameter in self:
|
||||||
if parameter.process_id:
|
if parameter.process_id:
|
||||||
name = parameter.process_id.name + '-' + parameter.name
|
name = parameter.process_id.name + '-' + parameter.name
|
||||||
else:
|
|
||||||
name = parameter.name
|
|
||||||
result.append((parameter.id, name))
|
result.append((parameter.id, name))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|||||||
@@ -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([('无', '无'), ('单面', '单面'), ('双面', '双面')],
|
||||||
|
|||||||
@@ -46,11 +46,6 @@
|
|||||||
<field name="category_id" ref="base.module_category_manufacturing_manufacturing"/>
|
<field name="category_id" ref="base.module_category_manufacturing_manufacturing"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="group_production_engineer" model="res.groups">
|
|
||||||
<field name="name">工艺工程师</field>
|
|
||||||
<field name="implied_ids" eval="[(4, ref('group_sf_mrp_user'))]"/>
|
|
||||||
<field name="category_id" ref="base.module_category_manufacturing_manufacturing"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record model="ir.module.category" id="module_category_plan">
|
<record model="ir.module.category" id="module_category_plan">
|
||||||
<field name="name">计划</field>
|
<field name="name">计划</field>
|
||||||
@@ -70,7 +65,7 @@
|
|||||||
<record id="group_plan_dispatch" model="res.groups">
|
<record id="group_plan_dispatch" model="res.groups">
|
||||||
<field name="name">计划调度岗</field>
|
<field name="name">计划调度岗</field>
|
||||||
<field name="category_id" ref="module_category_plan"/>
|
<field name="category_id" ref="module_category_plan"/>
|
||||||
<!-- <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/> -->
|
<!-- <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/> -->
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="group_plan_director" model="res.groups">
|
<record id="group_plan_director" model="res.groups">
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user