Compare commits

..

1 Commits

Author SHA1 Message Date
jinling.yang
609e65e36f Merge branch 'hotfix/修复工件上下产线' 2024-06-05 10:16:16 +08:00
443 changed files with 92863 additions and 29321 deletions

View File

@@ -1,4 +0,0 @@
# -*- coding: utf-8 -*-
from . import controllers
from . import models

View File

@@ -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',
],
}

View File

@@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
from . import controllers

View File

@@ -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
# })

View File

@@ -1,4 +0,0 @@
# -*- coding: utf-8 -*-
from . import models
from . import account_move

View File

@@ -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)

View File

@@ -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

View File

@@ -6,6 +6,6 @@ import { patch } from "web.utils";
patch(WebClient.prototype, "kolpolok_custom_title_and_favicon.WebClient", {
setup() {
this._super();
// this.title.setParts({ zopenerp: "JIKIMO" });
this.title.setParts({ zopenerp: "JIKIMO" });
},
});

View File

@@ -1,99 +1,41 @@
.processing-capabilities-grid {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 10px;
width: 100%;
.zoomed {
position: fixed !important;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(10);
}
.grid-item {
display: flex;
align-items: center;
.many2many_flex {
display: flex;
}
.item-content {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}
/*控制图片大小*/
.item-icon {
width: 50px;
height: 50px;
margin-bottom: 5px;
.many2many_flex>div {
margin-right: 15px;
display: flex;
flex-direction: column;
align-items: center;
}
.item-label {
font-size: 12px;
word-break: break-word;
.many2many_flex>div>:nth-child(2) {
position: relative;
}
@media (max-width: 1200px) {
.processing-capabilities-grid {
grid-template-columns: repeat(4, 1fr);
}
.close {
width: 20px;
height: 20px;
position: absolute;
top: -8.8px;
right: -8.8px;
color: #fff;
background-color: #000;
opacity: 0;
text-align: center;
line-height: 20px;
font-size: 18px;
}
@media (max-width: 768px) {
.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;
top: 20px;
right: 30px;
color: #fff;
font-size: 40px;
font-weight: bold;
transition: 0.3s;
cursor: pointer;
opacity: 0.7;
}
.image-preview-close:hover,
.image-preview-close:focus {
opacity: 1;
text-decoration: none;
cursor: pointer;
.img_close {
opacity: 1;
transform: scale(0.1);
cursor: pointer;
}

View File

@@ -4,57 +4,35 @@ import {Many2ManyCheckboxesField} from "@web/views/fields/many2many_checkboxes/m
import {registry} from "@web/core/registry";
export class MyCustomWidget extends Many2ManyCheckboxesField {
// 你可以重写或者添加一些方法和属性
// 例如你可以重写setup方法来添加一些事件监听器或者初始化一些变量
setup() {
super.setup();
super.setup(); // 调用父类的setup方法
// 你自己的代码
}
onImageClick(event, src) {
event.preventDefault();
event.stopPropagation();
onImageClick(event) {
// 放大图片逻辑
// 获取图片元素
const img = event.target;
const close = img.nextSibling;
// 创建预览框
const previewContainer = document.createElement('div');
previewContainer.className = 'image-preview-container';
// 实现放大图片逻辑
// 比如使用 CSS 放大
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 = '&times;';
closeButton.className = 'image-preview-close';
previewContainer.appendChild(previewImg);
previewContainer.appendChild(closeButton);
document.body.appendChild(previewContainer);
// 添加关闭预览的事件监听器
const closePreview = () => {
previewContainer.classList.remove('show');
setTimeout(() => {
document.body.removeChild(previewContainer);
}, 300);
};
closeButton.addEventListener('click', closePreview);
// 点击预览框外部也可以关闭
previewContainer.addEventListener('click', (e) => {
if (e.target === previewContainer) {
closePreview();
}
});
// 使用 setTimeout 来触发过渡效果
setTimeout(() => {
previewContainer.classList.add('show');
}, 10);
onCloseClick(event) {
const close = event.target;
const img = close.previousSibling;
img.parentElement.classList.remove('zoomed');
close.classList.remove('img_close');
}
}
MyCustomWidget.template = "jikimo_frontend.MyCustomWidget";
// MyCustomWidget.supportedTypes = ['many2many'];
registry.category("fields").add("custom_many2many_checkboxes", MyCustomWidget);
registry.category("fields").add("custom_many2many_checkboxes", MyCustomWidget);

View File

@@ -2,22 +2,27 @@
<templates xml:space="preserve">
<t t-name="jikimo_frontend.MyCustomWidget" owl="1">
<div aria-atomic="true" class="many2many_flex processing-capabilities-grid">
<div aria-atomic="true" class="many2many_flex">
<t t-foreach="items" t-as="item" t-key="item[0]">
<div class="grid-item">
<div>
<CheckBox
value="isSelected(item)"
disabled="props.readonly"
onChange="(ev) => this.onChange(item[0], ev)"
>
<div class="item-content">
<img t-att-src="item[2]" class="item-icon" t-on-click="(ev) => this.onImageClick(ev, item[2])"/>
<span class="item-label"><t t-esc="item[1]"/></span>
</div>
<t t-esc="item[1]"/>
</CheckBox>
<div t-on-dblclick="onImageClick">
<t>
<img t-att-src="item[2]" width="50" height="50"/>
<div class="close" t-on-click="onCloseClick">×</div>
</t>
</div>
</div>
</t>
</div>
</t>
</templates>
</templates>

View File

@@ -5,7 +5,7 @@ import {patch} from '@web/core/utils/patch';
import {_t} from "@web/core/l10n/translation";
import {FormStatusIndicator} from "@web/views/form/form_status_indicator/form_status_indicator";
import {ListRenderer} from "@web/views/list/list_renderer";
// import {StatusBarField} from "@web/views/fields/statusbar/statusbar_field";
import {StatusBarField} from "@web/views/fields/statusbar/statusbar_field";
import {Field} from "@web/views/fields/field";
@@ -53,23 +53,6 @@ const tableRequiredList = [
]
patch(FormStatusIndicator.prototype, 'jikimo_frontend.FormStatusIndicator', {
setup() {
owl.onMounted(() => {
try {
const dom = this.__owl__.bdom.el
const buttonsDom = $(dom).find('.o_form_status_indicator_buttons ')
if (buttonsDom) {
const dom1 = buttonsDom.children('.o_form_button_save')
const dom2 = buttonsDom.children('.o_form_button_cancel')
dom1.append('保存')
dom2.append('取消')
}
} catch (e) {
console.log(e)
}
});
},
// 你可以重写或者添加一些方法和属性
async _onDiscardChanges() {
// var self = this;
@@ -170,36 +153,47 @@ patch(ListRenderer.prototype, 'jikimo_frontend.ListRenderer', {
// 根据进度条设置水印
// const statusbar_params = {
// '已完工': 'bg-primary',
// '完成': 'bg-primary',
// '采购订单': 'bg-primary',
// '作废': 'bg-danger',
// '封存(报废)': 'bg-danger',
// }
// patch(StatusBarField.prototype, 'jikimo_frontend.StatusBarField', {
// setup() {
// owl.onMounted(this.ribbons);
// return this._super(...arguments);
// },
// ribbons() {
// try {
// const dom = $('.o_form_sheet.position-relative')
// const status = statusbar_params[this.currentName]
// if(status && dom.length) {
// dom.prepend(`<div class="o_widget o_widget_web_ribbon">
// <div class="ribbon ribbon-top-right">
// <span class="bg-opacity-75 ${status}" title="">${this.currentName}</span>
// </div>
// </div>`)
// }
// } catch (e) {
// console.log(e)
// }
// }
// })
const statusbar_params = {
'已完工': 'bg-primary',
'完成': 'bg-primary',
'采购订单': 'bg-primary',
'作废': 'bg-danger',
'封存(报废)': 'bg-danger',
}
patch(StatusBarField.prototype, 'jikimo_frontend.StatusBarField', {
setup() {
owl.onMounted(this.ribbons);
return this._super(...arguments);
},
ribbons() {
try {
const dom = $('.o_form_sheet.position-relative')
const status = statusbar_params[this.currentName]
if(status && dom.length) {
dom.prepend(`<div class="o_widget o_widget_web_ribbon">
<div class="ribbon ribbon-top-right">
<span class="bg-opacity-75 ${status}" title="">${this.currentName}</span>
</div>
</div>`)
}
} catch (e) {
console.log(e)
}
}
})
$(function () {
document.addEventListener('click', function () {
const dom = $('.o_form_status_indicator_buttons ')
if (dom) {
const dom1 = dom.children().eq(0)
const dom2 = dom.children().eq(1)
if (!dom1.text()) {
dom1.append('保存')
dom2.append('取消')
}
}
})
function customRequired() {
let timer = null

View File

@@ -108,10 +108,6 @@ td.o_required_modifier {
}
.color_3 {
background-color: #808080;
}
.color_4 {
background-color: rgb(255, 150, 0);
}
@@ -525,14 +521,4 @@ div:has(.o_required_modifier) > label::before {
.o_list_renderer.o_renderer {
max-width: 100%;
overflow-x: auto;
}
// 设置表单页面label文本不换行
.o_form_view .o_group .o_wrap_label .o_form_label {
white-space: nowrap;
}
// 修复表格内容覆盖表头bug
.o_list_renderer .o_list_table tbody th {
position: unset;
}
}

View File

@@ -5,9 +5,9 @@
<!-- 修改页面头部图标及文字 -->
<template id="favicon_icon" inherit_id="web.layout" name="Web layout">
<!-- change the title with reliance partner -->
<!-- <xpath expr="//head//title" position="before">
<xpath expr="//head//title" position="before">
<title t-esc="'JIKIMO'"/>
</xpath> -->
</xpath>
<!-- change the default favicon icon with -->
<xpath expr="//head//link[@rel='shortcut icon']" position="replace">
<link type="image/x-icon" rel="shortcut icon" href="/jikimo_frontend/static/src/img/jikimo-logo.ico"/>
@@ -16,7 +16,7 @@
<!-- hide 登录页面 powerd by odoo 及管理数据库 -->
<template id="login_page_layout" inherit_id="web.login_layout" name="Login Page Layout">
<!-- <xpath expr="//div[@class='card-body']/div[last()]" position="replace"></xpath> -->
<xpath expr="//div[@class='card-body']//div[last()]" position="replace"></xpath>
</template>
<!-- 隐藏odoo版本信息 -->

View File

@@ -301,27 +301,53 @@ def unlink(self):
# This is used to restrict the access right to unlink a record
current_model_id = self.env['ir.model'].sudo().search(
[('model', '=', self._name)]).id
access_right_rec = self.env['access.right'].sudo().search_read(
[('model_id', '=', current_model_id)], ['model_id', 'is_delete',
'groups_id'])
if access_right_rec and not self.env.is_admin():
for rec in access_right_rec:
group_name = self.env['ir.model.data'].sudo().search([
('model', '=', 'res.groups'),
('res_id', '=', rec['groups_id'][0])
]).name
module_name = self.env['ir.model.data'].sudo().search([
('model', '=', 'res.groups'),
('res_id', '=', rec['groups_id'][0])
]).module
group = module_name + "." + group_name
if self.env.user.has_group(group):
if rec['is_delete']:
raise UserError(_('You are restricted from performing this'
' operation. Please contact the'
' administrator.'))
# access_right_rec = self.env['access.right'].sudo().search_read(
# [('model_id', '=', current_model_id)], ['model_id', 'is_delete',
# 'groups_id'])
# if access_right_rec and not self.env.is_admin():
# for rec in access_right_rec:
# group_name = self.env['ir.model.data'].sudo().search([
# ('model', '=', 'res.groups'),
# ('res_id', '=', rec['groups_id'][0])
# ]).name
# module_name = self.env['ir.model.data'].sudo().search([
# ('model', '=', 'res.groups'),
# ('res_id', '=', rec['groups_id'][0])
# ]).module
# group = module_name + "." + group_name
# if self.env.user.has_group(group):
# if rec['is_delete']:
# raise UserError(_('You are restricted from performing this'
# ' operation. Please contact the'
# ' administrator.'))
# 检查 'access.right' 模型是否存在于环境中
if 'access.right' in self.env:
# current_model_id = self.env['ir.model'].sudo().search([('model', '=', self._name)]).id
access_right_rec = self.env['access.right'].sudo().search_read(
[('model_id', '=', current_model_id)], ['model_id', 'is_delete', 'groups_id']
)
if access_right_rec and not self.env.is_admin():
for rec in access_right_rec:
group_data = self.env['ir.model.data'].sudo().search_read(
[('model', '=', 'res.groups'), ('res_id', '=', rec['groups_id'][0])],
['name', 'module']
)
if group_data:
group_name = group_data[0]['name']
module_name = group_data[0]['module']
group_xml_id = f"{module_name}.{group_name}"
if self.env.user.has_group(group_xml_id) and rec['is_delete']:
raise UserError(
_('You are restricted from performing this operation. Please contact the administrator.'))
else:
# 如果 'access.right' 模型不存在,可以在这里定义备选逻辑
pass
return True
BaseModel._create = _create
# BaseModel.unlink = unlink
BaseModel.unlink = unlink

View File

@@ -1,5 +0,0 @@
# -*- coding: utf-8 -*-
from . import controllers
from . import models
from . import wizard

View File

@@ -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',
],
}

View File

@@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
from . import controllers

View File

@@ -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
# })

View File

@@ -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>

View File

@@ -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

View File

@@ -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非常满意')]

View File

@@ -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='是否有效')

View File

@@ -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 "")

View File

@@ -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()

View File

@@ -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='工单处理人')

View File

@@ -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>

View File

@@ -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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 inside_system_order_classify_r jikimo_system_order.order_classify model_order_classify 1 1 1 1
3 inside_system_work_order_rc jikimo_system_order.system_work_order model_system_work_order 1 1 1 1
4 inside_work_order_template_r jikimo_system_order.work_order_template model_work_order_template 1 1 1 1
5 inside_system_order_classify_rwc jikimo_system_order.order_classify model_order_classify group_operations_permissions_rwc 1 1 1 0
6 inside_system_work_order_rwc jikimo_system_order.system_work_order model_system_work_order group_operations_permissions_rwc 1 1 1 0
7 inside_work_order_template_rwc jikimo_system_order.work_order_template model_work_order_template group_operations_permissions_rwc 1 1 1 0
8 order_close_wizard_group_user jikimo_system_order.order_close_wizard model_order_close_wizard base.group_user 1 1 1 1
9 order_other_wizard_group_user jikimo_system_order.order_other_wizard model_order_other_wizard base.group_user 1 1 1 1
10 order_technician_wizard_group_user jikimo_system_order.order_technician_wizard model_order_technician_wizard base.group_user 1 1 1 1
11 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
12 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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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','&gt;=', time.strftime('%Y-%m-01')),('date','&lt;', (context_today() + relativedelta(months=1)).strftime('%Y-%m-01'))]"/>
<filter name="last_month" string="上月工单"
domain="[('date','&lt;', time.strftime('%Y-%m-01')),('date','&gt;=', (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>

View File

@@ -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

View File

@@ -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 {}

View File

@@ -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 {}

View File

@@ -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 {}

View File

@@ -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>

View File

@@ -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)

View File

@@ -1,4 +0,0 @@
# -*- coding: utf-8 -*-
from . import models
from . import controllers

View File

@@ -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,
}

View File

@@ -1 +0,0 @@
from . import main

View File

@@ -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)

View File

@@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
from . import jikimo_workorder_exception
from . import mrp_workorder

View File

@@ -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')

View File

@@ -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'
})

View File

@@ -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 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_jikimo_workorder_exception access.jikimo.workorder.exception model_jikimo_workorder_exception mrp.group_mrp_user 1 1 1 0
3 access_jikimo_workorder_exception_group_quality access.jikimo.workorder.exception.group_quality model_jikimo_workorder_exception sf_base.group_quality 1 1 1 0
4 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

View File

@@ -1,2 +0,0 @@
from . import common
from . import test_jikimo_workorder_exception

View File

@@ -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加工'
})

View File

@@ -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)

View File

@@ -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>

View File

@@ -1,4 +0,0 @@
# -*- coding: utf-8 -*-
from . import models

View File

@@ -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,
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
from . import jikimo_message_template
from . import jikimo_workorder_exception

View File

@@ -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

View File

@@ -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

View File

@@ -1,2 +0,0 @@
from . import common
from . import test_jikimo_workorder_exception_notify

View File

@@ -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)

View File

@@ -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)

View File

@@ -1273,18 +1273,3 @@ msgstr ""
#: model:product.template,description_sale:mrp_workorder.product_template_stool_top
msgid "wooden stool top"
msgstr ""
#. module: mrp_workorder
#: model:quality.point.test_type,name:mrp_workorder.test_type_register_consumed_materials
msgid "Register Consumed Materials"
msgstr "登记消耗材料"
#. module: mrp_workorder
#: model:quality.point.test_type,name:mrp_workorder.test_type_register_byproducts
msgid "Register By-products"
msgstr "按产品注册"
#. module: mrp_workorder
#: model:quality.point.test_type,name:mrp_workorder.test_type_print_label
msgid "Print label"
msgstr "打印标签"

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models, api
from odoo import fields, models
class MrpProduction(models.Model):
@@ -12,8 +12,7 @@ class MrpProduction(models.Model):
check_ids = fields.One2many('quality.check', 'production_id', string="Checks")
def _split_productions(self, amounts=False, cancel_remaining_qty=False, set_consumed_qty=False):
productions = super()._split_productions(amounts=amounts, cancel_remaining_qty=cancel_remaining_qty,
set_consumed_qty=set_consumed_qty)
productions = super()._split_productions(amounts=amounts, cancel_remaining_qty=cancel_remaining_qty, set_consumed_qty=set_consumed_qty)
backorders = productions[1:]
if not backorders:
return productions
@@ -21,4 +20,3 @@ class MrpProduction(models.Model):
if wo.current_quality_check_id.component_id:
wo.current_quality_check_id._update_component_quantity()
return productions

View File

@@ -27,7 +27,7 @@ class MrpWorkcenter(models.Model):
class MrpProductionWorkcenterLine(models.Model):
_name = 'mrp.workorder'
_inherit = ['mrp.workorder', 'barcodes.barcode_events_mixin', 'mail.thread', 'mail.activity.mixin']
_inherit = ['mrp.workorder', 'barcodes.barcode_events_mixin']
quality_point_ids = fields.Many2many('quality.point', compute='_compute_quality_point_ids', store=True)
quality_point_count = fields.Integer('Steps', compute='_compute_quality_point_count')
@@ -47,17 +47,14 @@ class MrpProductionWorkcenterLine(models.Model):
is_last_lot = fields.Boolean('Is Last lot', compute='_compute_is_last_lot')
is_first_started_wo = fields.Boolean('Is The first Work Order', compute='_compute_is_last_unfinished_wo')
is_last_unfinished_wo = fields.Boolean('Is Last Work Order To Process', compute='_compute_is_last_unfinished_wo',
store=False)
is_last_unfinished_wo = fields.Boolean('Is Last Work Order To Process', compute='_compute_is_last_unfinished_wo', store=False)
lot_id = fields.Many2one(related='current_quality_check_id.lot_id', readonly=False)
move_id = fields.Many2one(related='current_quality_check_id.move_id', readonly=False)
move_line_id = fields.Many2one(related='current_quality_check_id.move_line_id', readonly=False)
move_line_ids = fields.One2many(related='move_id.move_line_ids')
quality_state = fields.Selection(related='current_quality_check_id.quality_state', string="Quality State",
readonly=False)
quality_state = fields.Selection(related='current_quality_check_id.quality_state', string="Quality State", readonly=False)
qty_done = fields.Float(related='current_quality_check_id.qty_done', readonly=False)
test_type_id = fields.Many2one('quality.point.test_type', 'Test Type',
related='current_quality_check_id.test_type_id')
test_type_id = fields.Many2one('quality.point.test_type', 'Test Type', related='current_quality_check_id.test_type_id')
test_type = fields.Char(related='test_type_id.technical_name')
user_id = fields.Many2one(related='current_quality_check_id.user_id', readonly=False)
worksheet_page = fields.Integer('Worksheet page')
@@ -68,8 +65,7 @@ class MrpProductionWorkcenterLine(models.Model):
def _compute_quality_point_ids(self):
for workorder in self:
quality_points = workorder.operation_id.quality_point_ids
quality_points = quality_points.filtered(
lambda qp: not qp.product_ids or workorder.production_id.product_id in qp.product_ids)
quality_points = quality_points.filtered(lambda qp: not qp.product_ids or workorder.production_id.product_id in qp.product_ids)
workorder.quality_point_ids = quality_points
@api.depends('operation_id')
@@ -95,8 +91,7 @@ class MrpProductionWorkcenterLine(models.Model):
@api.depends('check_ids')
def _compute_finished_product_check_ids(self):
for wo in self:
wo.finished_product_check_ids = wo.check_ids.filtered(
lambda c: c.finished_product_sequence == wo.qty_produced)
wo.finished_product_check_ids = wo.check_ids.filtered(lambda c: c.finished_product_sequence == wo.qty_produced)
def write(self, values):
res = super().write(values)
@@ -143,8 +138,7 @@ class MrpProductionWorkcenterLine(models.Model):
self.finished_lot_id = self.env['stock.lot'].create({
'product_id': self.product_id.id,
'company_id': self.company_id.id,
'name': self.env['stock.lot']._get_next_serial(self.company_id, self.product_id) or self.env[
'ir.sequence'].next_by_code('stock.lot.serial'),
'name': self.env['stock.lot']._get_next_serial(self.company_id, self.product_id) or self.env['ir.sequence'].next_by_code('stock.lot.serial'),
})
def _create_subsequent_checks(self):
@@ -158,7 +152,7 @@ class MrpProductionWorkcenterLine(models.Model):
"""
# Create another quality check if necessary
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:
# TODO: manage reservation here
@@ -285,8 +279,7 @@ class MrpProductionWorkcenterLine(models.Model):
if self.current_quality_check_id:
team = self.current_quality_check_id.team_id
else:
team = self.env['quality.alert.team'].search(
['|', ('company_id', '=', self.company_id.id), ('company_id', '=', False)], limit=1)
team = self.env['quality.alert.team'].search(['|', ('company_id', '=', self.company_id.id), ('company_id', '=', False)], limit=1)
return {
'type': 'ir.actions.act_window',
'res_model': 'quality.check',
@@ -327,8 +320,7 @@ class MrpProductionWorkcenterLine(models.Model):
production = wo.production_id
move_raw_ids = wo.move_raw_ids.filtered(lambda m: m.state not in ('done', 'cancel'))
move_finished_ids = wo.move_finished_ids.filtered(
lambda m: m.state not in ('done', 'cancel') and m.product_id != wo.production_id.product_id)
move_finished_ids = wo.move_finished_ids.filtered(lambda m: m.state not in ('done', 'cancel') and m.product_id != wo.production_id.product_id)
previous_check = self.env['quality.check']
for point in wo.quality_point_ids:
# Check if we need a quality control for this point
@@ -350,13 +342,11 @@ class MrpProductionWorkcenterLine(models.Model):
if point.test_type == 'register_byproducts':
moves = move_finished_ids.filtered(lambda m: m.product_id == point.component_id)
if not moves:
moves = production.move_finished_ids.filtered(
lambda m: not m.operation_id and m.product_id == point.component_id)
moves = production.move_finished_ids.filtered(lambda m: not m.operation_id and m.product_id == point.component_id)
elif point.test_type == 'register_consumed_materials':
moves = move_raw_ids.filtered(lambda m: m.product_id == point.component_id)
if not moves:
moves = production.move_raw_ids.filtered(
lambda m: not m.operation_id and m.product_id == point.component_id)
moves = production.move_raw_ids.filtered(lambda m: not m.operation_id and m.product_id == point.component_id)
else:
check = self.env['quality.check'].create(values)
previous_check.next_check_id = check
@@ -373,10 +363,8 @@ class MrpProductionWorkcenterLine(models.Model):
processed_move |= moves
# Generate quality checks associated with unreferenced components
moves_without_check = ((move_raw_ids | move_finished_ids) - processed_move).filtered(lambda move: (
move.has_tracking != 'none' and not move.raw_material_production_id.use_auto_consume_components_lots) or move.operation_id)
quality_team_id = self.env['quality.alert.team'].search(
['|', ('company_id', '=', wo.company_id.id), ('company_id', '=', False)], limit=1).id
moves_without_check = ((move_raw_ids | move_finished_ids) - processed_move).filtered(lambda move: (move.has_tracking != 'none' and not move.raw_material_production_id.use_auto_consume_components_lots) or move.operation_id)
quality_team_id = self.env['quality.alert.team'].search(['|', ('company_id', '=', wo.company_id.id), ('company_id', '=', False)], limit=1).id
for move in moves_without_check:
values = {
'production_id': production.id,
@@ -424,8 +412,7 @@ class MrpProductionWorkcenterLine(models.Model):
backorder = False
# Trigger the backorder process if we produce less than expected
if float_compare(self.qty_producing, self.qty_remaining,
precision_rounding=self.product_uom_id.rounding) == -1 and self.is_first_started_wo:
if float_compare(self.qty_producing, self.qty_remaining, precision_rounding=self.product_uom_id.rounding) == -1 and self.is_first_started_wo:
backorder = self.production_id._split_productions()[1:]
for workorder in backorder.workorder_ids:
if workorder.product_tracking == 'serial':
@@ -436,8 +423,7 @@ class MrpProductionWorkcenterLine(models.Model):
else:
if self.operation_id:
backorder = (self.production_id.procurement_group_id.mrp_production_ids - self.production_id).filtered(
lambda p: p.workorder_ids.filtered(lambda wo: wo.operation_id == self.operation_id).state not in (
'cancel', 'done')
lambda p: p.workorder_ids.filtered(lambda wo: wo.operation_id == self.operation_id).state not in ('cancel', 'done')
)[:1]
else:
index = list(self.production_id.workorder_ids).index(self)
@@ -456,8 +442,7 @@ class MrpProductionWorkcenterLine(models.Model):
wo.current_quality_check_id._update_component_quantity()
if not self.env.context.get('no_start_next'):
if self.operation_id:
return backorder.workorder_ids.filtered(
lambda wo: wo.operation_id == self.operation_id).open_tablet_view()
return backorder.workorder_ids.filtered(lambda wo: wo.operation_id == self.operation_id).open_tablet_view()
else:
index = list(self.production_id.workorder_ids).index(self)
return backorder.workorder_ids[index].open_tablet_view()
@@ -481,8 +466,7 @@ class MrpProductionWorkcenterLine(models.Model):
def open_tablet_view(self):
self.ensure_one()
if not self.is_user_working and self.working_state != 'blocked' and self.state in (
'ready', 'waiting', 'progress', 'pending'):
if not self.is_user_working and self.working_state != 'blocked' and self.state in ('ready', 'waiting', 'progress', 'pending'):
self.button_start()
action = self.env["ir.actions.actions"]._for_xml_id("mrp_workorder.tablet_client_action")
action['target'] = 'fullscreen'
@@ -537,8 +521,7 @@ class MrpProductionWorkcenterLine(models.Model):
data = {
'mrp.workorder': self.read(self._get_fields_for_tablet(), load=False)[0],
'quality.check': self.check_ids._get_fields_for_tablet(sorted_check_list),
'operation': self.operation_id.read(self.operation_id._get_fields_for_tablet())[
0] if self.operation_id else {},
'operation': self.operation_id.read(self.operation_id._get_fields_for_tablet())[0] if self.operation_id else {},
'working_state': self.workcenter_id.working_state,
'views': {
'workorder': self.env.ref('mrp_workorder.mrp_workorder_view_form_tablet').id,
@@ -570,8 +553,7 @@ class MrpProductionWorkcenterLine(models.Model):
return {
'duration': self.duration,
'position': bisect_left(last30op, self.duration),
# which position regarded other workorders ranked by duration
'position': bisect_left(last30op, self.duration), # which position regarded other workorders ranked by duration
'quality_score': score,
'show_rainbow': show_rainbow,
}

View File

@@ -1,44 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Manufacturing Order for Planing view -->
<record id="mrp_production_tree_view_planning" model="ir.ui.view">
<field name="name">mrp.production.tree.inherit.planning</field>
<field name="model">mrp.production</field>
<field name="arch" type="xml">
<tree default_order="date_planned_start asc" decoration-info="state=='confirmed'"
decoration-danger="date_planned_start&lt;current_date and state not in ('done','cancel')"
decoration-muted="state in ('done','cancel')" string="Manufacturing Orders" name="Production">
<field name="message_needaction" invisible="1"/>
<field name="name"/>
<field name="date_planned_start"/>
<field name="product_id"/>
<field name="product_qty" sum="Total Qty" string="Quantity"/>
<field name="product_uom_id" string="Unit of Measure" options="{'no_open':True,'no_create':True}"
groups="uom.group_uom"/>
<field name="reservation_state" string="Availability"/>
<field name="origin"/>
<field name="state"/>
</tree>
</field>
</record>
<!-- Manufacturing Order for Planing view -->
<record id="mrp_production_tree_view_planning" model="ir.ui.view">
<field name="name">mrp.production.tree.inherit.planning</field>
<field name="model">mrp.production</field>
<field name="arch" type="xml">
<tree default_order="date_planned_start asc" decoration-info="state=='confirmed'" decoration-danger="date_planned_start&lt;current_date and state not in ('done','cancel')" decoration-muted="state in ('done','cancel')" string="Manufacturing Orders" name="Production">
<field name="message_needaction" invisible="1"/>
<field name="name"/>
<field name="date_planned_start"/>
<field name="product_id"/>
<field name="product_qty" sum="Total Qty" string="Quantity"/>
<field name="product_uom_id" string="Unit of Measure" options="{'no_open':True,'no_create':True}" groups="uom.group_uom"/>
<field name="reservation_state" string="Availability"/>
<field name="origin"/>
<field name="state"/>
</tree>
</field>
</record>
<!-- <record id="mrp_production_form_inherit_planning" model="ir.ui.view">-->
<!-- <field name="name">mrp.production.form_inherit_planning</field>-->
<!-- <field name="model">mrp.production</field>-->
<!-- <field name="inherit_id" ref="mrp.mrp_production_form_view"/>-->
<!-- <field name="arch" type="xml">-->
<!-- <xpath expr="div[hasclass('oe_chatter')]" position="replace">-->
<!-- &lt;!&ndash; 这里放置替换后的内容 &ndash;&gt;-->
<!-- </xpath>-->
<!-- <xpath expr="//notebook" position="after">-->
<!-- <div class="oe_chatter">-->
<!-- <field name="message_follower_ids"/>-->
<!-- <field name="activity_ids"/>-->
<!-- <field name="message_ids"/>-->
<!-- </div>-->
<!-- </xpath>-->
<!-- </field>-->
<!-- </record>-->
<!-- <record id="mrp_production_form_inherit_planning" model="ir.ui.view">-->
<!-- <field name="name">mrp.production.form_inherit_planning</field>-->
<!-- <field name="model">mrp.production</field>-->
<!-- <field name="inherit_id" ref="mrp.mrp_production_form_view"/>-->
<!-- <field name="arch" type="xml">-->
<!-- <xpath expr="div[hasclass('oe_chatter')]" position="replace">-->
<!-- &lt;!&ndash; 这里放置替换后的内容 &ndash;&gt;-->
<!-- </xpath>-->
<!-- <xpath expr="//notebook" position="after">-->
<!-- <div class="oe_chatter">-->
<!-- <field name="message_follower_ids"/>-->
<!-- <field name="activity_ids"/>-->
<!-- <field name="message_ids"/>-->
<!-- </div>-->
<!-- </xpath>-->
<!-- </field>-->
<!-- </record>-->
<record id="mrp_production_view_search_inherit_planning" model="ir.ui.view">
<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="arch" type="xml">
<filter name="filter_planned" position="attributes">
<attribute name="domain">[('is_planned', '=', True), ('date_planned_start', '!=', False),
('date_planned_finished', '!=', False)]
</attribute>
<attribute name="domain">[('is_planned', '=', True), ('date_planned_start', '!=', False), ('date_planned_finished', '!=', False)]</attribute>
</filter>
</field>
</record>
@@ -56,33 +51,30 @@
<record id="production_order_unplan_server_action" model="ir.actions.server">
<field name="name">Unplan orders</field>
<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="state">code</field>
<field name="code">records.button_unplan()</field>
</record>
<record id="mrp.act_product_mrp_production_workcenter" model="ir.actions.act_window">
<field name="domain">[('bom_id', '!=', False), ('bom_id.operation_ids.workcenter_id', '=', active_id),
('date_planned_start', '!=', False), ('date_planned_finished', '!=', False)]
</field>
<field name="domain">[('bom_id', '!=', False), ('bom_id.operation_ids.workcenter_id', '=', active_id), ('date_planned_start', '!=', False), ('date_planned_finished', '!=', False)]</field>
<field name="view_id" ref="mrp_production_tree_view_planning"/>
</record>
<menuitem id="mrp_workorder_menu_planning"
name="Work Orders"
sequence="2"
parent="mrp.mrp_planning_menu_root"
groups="mrp.group_mrp_routings"/>
name="Work Orders"
sequence="2"
parent="mrp.mrp_planning_menu_root"
groups="mrp.group_mrp_routings"/>
<menuitem id="menu_mrp_workorder_production"
name="Planning by Production"
sequence="1"
action="mrp.action_mrp_workorder_production"
parent="mrp_workorder_menu_planning"/>
name="Planning by Production"
sequence="1"
action="mrp.action_mrp_workorder_production"
parent="mrp_workorder_menu_planning"/>
<menuitem id="menu_mrp_workorder_workcenter"
name="Planning by Workcenter"
sequence="2"
action="mrp_workorder.action_mrp_workorder_dependencies_workcenter"
parent="mrp_workorder_menu_planning"/>
name="Planning by Workcenter"
sequence="2"
action="mrp_workorder.action_mrp_workorder_dependencies_workcenter"
parent="mrp_workorder_menu_planning"/>
</odoo>

View File

@@ -27,13 +27,6 @@
</field>
</page>
</page>
<xpath expr="//sheet" position="after">
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="activity_ids"/>
<field name="message_ids" options="{'post_refresh': 'recipients'}"/>
</div>
</xpath>
</field>
</record>

View File

@@ -1050,13 +1050,3 @@ msgstr "工作中心故障"
#: model:ir.model.fields,field_description:quality.field_quality_point_test_type__active
msgid "active"
msgstr "有效"
#. module: quality
#: model:quality.point.test_type,name:quality.test_type_instructions
msgid "Instructions"
msgstr "使用说明"
#. module: quality
#: model:quality.point.test_type,name:quality.test_type_picture
msgid "Take a Picture"
msgstr "照片"

View File

@@ -15,7 +15,7 @@ class TestType(models.Model):
_description = "Quality Control Test Type"
# Used instead of selection field in order to hide a choice depending on the view.
name = fields.Char('Name', required=True,translate=True)
name = fields.Char('Name', required=True)
technical_name = fields.Char('Technical name', required=True)
active = fields.Boolean('active', default=True)

View File

@@ -1185,14 +1185,3 @@ msgstr "请先进行质量检查!"
#: model_terms:ir.ui.view,arch_db:quality_control.quality_alert_team_view_form
msgid "e.g. The QA Masters"
msgstr "例如QA大师"
#. module: quality_control
#: model:quality.point.test_type,name:quality_control.test_type_passfail
msgid "Pass - Fail"
msgstr "通过-失败"
#. module: quality_control
#: model:quality.point.test_type,name:quality_control.test_type_measure
msgid "Measure"
msgstr "测量"

View File

@@ -6,4 +6,3 @@ from . import stock_move
from . import stock_move_line
from . import stock_picking
from . import stock_lot
from . import product_category

View File

@@ -1,24 +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)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 702 B

View File

@@ -1024,7 +1024,7 @@
<menuitem
id="menu_quality_root"
name="Quality"
web_icon="quality_control,static/description/质量.png"
web_icon="quality_control,static/description/icon.svg"
sequence="150"
groups="quality.group_quality_user"/>
@@ -1033,7 +1033,7 @@
name="Overview"
action="quality_alert_team_action"
parent="menu_quality_root"
sequence="5" active="False"/>
sequence="5"/>
<menuitem
id="menu_quality_control"

View File

@@ -1,3 +1,2 @@
pystrich
cpca
pycryptodome==3.20

View File

@@ -35,7 +35,6 @@
],
'web.assets_backend': [
'sf_base/static/src/scss/*.scss',
'sf_base/static/src/js/*.js',
],
},

View File

@@ -38,17 +38,3 @@ class Manufacturing_Connect(http.Controller):
res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
logging.info('get_maintenance_tool_groups_Info error:%s' % e)
return json.JSONEncoder().encode(res)
class MultiInheritController():
_sub_classes = []
def __init_subclass__(cls):
"""
多继承解决多个字类时方法调用super的问题
"""
super().__init_subclass__()
if len(cls._sub_classes) > 0 and cls not in cls._sub_classes:
cls.__bases__ = (cls._sub_classes[-1],)
if cls not in cls._sub_classes:
cls._sub_classes.append(cls)

View File

@@ -5,4 +5,3 @@ from . import fixture
from . import functional_fixture
from . import tool_other_features
from . import basic_parameters_fixture
from . import ir_sequence

View File

@@ -394,11 +394,3 @@ class MachineToolCategory(models.Model):
active = fields.Boolean('有效', default=True)
category = fields.Selection([('shukong', u'数控'), ('putong', u'普通')], string=u'机床类别',
default='shukong')
class MachiningAccuracy(models.Model):
_name = 'sf.machining.accuracy'
_description = '加工精度'
name = fields.Char('一般公差', index=True)
standard_tolerance = fields.Char(string="标准公差")
sync_id = fields.Char('同步ID')

View File

@@ -13,7 +13,7 @@ class BasicParametersFixture(models.Model):
diameter = fields.Float('直径(mm)', digits=(16, 2))
# '零点卡盘' 字段
weight = fields.Float('重量(kg)', digits=(16, 2))
weight = fields.Float('重量(mm)', digits=(16, 2))
orientation_dish_diameter = fields.Float('定位盘直径(mm)', digits=(16, 2))
clamping_diameter = fields.Float('装夹直径(mm)', digits=(16, 2))
clamping_num = fields.Selection([('1', '1'), ('2', '2'), ('4', '4'), ('6', '6'), ('8', '8')], string='装夹单元数')

View File

@@ -61,10 +61,12 @@ class MrsMaterialModel(models.Model):
supplier_ids = fields.One2many('sf.supplier.sort', 'materials_model_id', string='供应商')
active = fields.Boolean('有效', default=True)
@api.constrains("gain_way")
def _check_supplier_ids(self):
for item in self:
if item.gain_way in ('外协', '采购') and not item.supplier_ids:
@api.onchange('gain_way')
def _check_gain_way(self):
if not self.gain_way:
raise UserError("请选择获取方式")
if self.gain_way in ['外协', '采购']:
if not self.supplier_ids:
raise UserError("请添加供应商")
@@ -84,21 +86,17 @@ class MrsProductionProcessCategory(models.Model):
class MrsProductionProcess(models.Model):
_name = 'sf.production.process'
_description = '表面工艺'
order = 'sequence asc'
code = fields.Char("编码")
name = fields.Char('名称')
remark = fields.Text("备注")
sequence = fields.Integer('排序')
# processing_order_ids = fields.One2many('sf.processing.order', 'production_process_id', string='工序')
partner_process_ids = fields.Many2many('res.partner', 'process_ids', '加工工厂')
active = fields.Boolean('有效', default=True)
parameter_ids = fields.One2many('sf.production.process.parameter', 'process_id', string='可选参数')
category_id = fields.Many2one('sf.production.process.category', string='表面工艺类别')
category_id = fields.Many2one('sf.production.process.category')
# workcenter_ids = fields.Many2many('mrp.workcenter', 'rel_workcenter_process', required=True)
processing_day = fields.Float('加工天数/d')
travel_day = fields.Float('路途天数/d')
sequence = fields.Integer('排序')
# class MrsProcessingTechnology(models.Model):
# _name = 'sf.processing.technology'
@@ -145,12 +143,8 @@ class MrsProductionProcessParameter(models.Model):
is_check = fields.Boolean(default=False)
# price = fields.Float('单价')
process_id = fields.Many2one('sf.production.process', string='表面工艺')
process_description = fields.Char(string='工艺描述')
materials_model_ids = fields.Many2many('sf.materials.model', 'applicable_material', string='适用材料')
processing_day = fields.Float('加工天数/d')
travel_day = fields.Float('路途天数/d')
active = fields.Boolean('有效', default=True)
processing_mm = fields.Char('加工厚度/mm')
def name_get(self):
result = []

View File

@@ -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='日期期间',
)

View File

@@ -321,7 +321,7 @@ class ToolInventory(models.Model):
prefix = fields.Char('前缀')
postfix = fields.Char('后缀')
diameter = fields.Float('直径(mm)')
angle = fields.Float('R角(mm)',default=0)
angle = fields.Float('R角(mm)')
tool_length = fields.Float('刀具总长(mm)')
blade_length = fields.Float('避空长/刃长(mm)')
knife_head_name = fields.Char('刀头名称')
@@ -331,7 +331,7 @@ class ToolInventory(models.Model):
work_material = fields.Selection([('', ''), ('', '')], string='加工材料')
life_span = fields.Float('寿命(min)')
tool_groups_id = fields.Many2one('sf.tool.groups', string='刀具组', required=True)
tool_groups_id = fields.Many2one('sf.tool.groups', string='刀具组')
active = fields.Boolean('已归档', default=True)

View 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')

View File

@@ -21,9 +21,8 @@ class ToolMaterialsBasicParameters(models.Model):
neck_length = fields.Float('颈部长度(mm)')
handle_diameter = fields.Float('柄部直径(mm)')
handle_length = fields.Float('柄部长度(mm)')
blade_tip_diameter = fields.Float('刀尖直径(mm)')
blade_tip_working_size = fields.Char('刀尖倒角度)', size=20)
tip_r_size = fields.Float('刀尖R角(mm)',default=0)
blade_tip_diameter = fields.Integer('刀尖直径(mm)')
blade_tip_working_size = fields.Char('刀尖处理尺寸(R半径mm/倒角度)', size=20)
blade_tip_taper = fields.Integer('刀尖锥度(°)')
blade_diameter = fields.Float('刃部直径(mm)')
blade_length = fields.Float('刃部长度(mm)')
@@ -38,7 +37,7 @@ class ToolMaterialsBasicParameters(models.Model):
width = fields.Float('宽度(mm)')
cutting_blade_length = fields.Float('切削刃长(mm)')
relief_angle = fields.Integer('后角(°)')
blade_tip_circular_arc_radius = fields.Char('刀尖圆弧半径(mm)', size=20,default='0')
blade_tip_circular_arc_radius = fields.Char('刀尖圆弧半径(mm)', size=20)
inscribed_circle_diameter = fields.Float('内接圆直径IC/D(mm)')
install_aperture_diameter = fields.Float('安装孔直径(mm)')
chip_breaker_groove = fields.Selection([('', ''), ('单面', '单面'), ('双面', '双面')],

View File

@@ -11,8 +11,8 @@ access_sf_machine_control_system,sf_machine_control_system,model_sf_machine_cont
access_sf_machine_control_system_admin,sf_machine_control_system_admin,model_sf_machine_control_system,base.group_system,1,1,1,0
access_sf_production_process_group_sale_director,sf_production_process_group_sale_director,model_sf_production_process,sf_base.group_sale_director,1,0,0,0
access_sf_production_process_group_sale_salemanager,sf_production_process_group_sale_salemanager,model_sf_production_process,sf_base.group_sale_salemanager,1,0,0,0
access_res_partner_category_group_sale_salemanager,res_partner_category_group_sale_salemanager,base.model_res_partner_category,sf_base.group_sale_salemanager,1,1,1,0
access_res_partner_category_group_sale_director,res_partner_category_group_sale_director,base.model_res_partner_category,sf_base.group_sale_director,1,1,1,0
access_res_partner_category_group_sale_salemanager,res_partner_category_group_sale_salemanager,base.model_res_partner_category,sf_base.group_sale_salemanager,1,0,1,0
access_res_partner_category_group_sale_director,res_partner_category_group_sale_director,base.model_res_partner_category,sf_base.group_sale_director,1,0,1,0
access_sf_production_process,sf_production_process,model_sf_production_process,base.group_user,1,1,1,0
access_sf_production_process_admin,sf_production_process_admin,model_sf_production_process,base.group_system,1,1,1,0
access_sf_production_materials,sf_production_materials,model_sf_production_materials,base.group_user,1,1,1,0
@@ -242,12 +242,3 @@ access_sf_fixture_materials_basic_parameters_group_sf_stock_manager,sf_fixture_m
access_sf_multi_mounting_type_group_sf_stock_manager,sf_multi_mounting_type_group_sf_stock_manager,model_sf_multi_mounting_type,sf_base.group_sf_stock_manager,1,0,0,0
access_sf_machine_brand_group_sf_stock_manager,sf_machine_brand_group_sf_stock_manager,model_sf_machine_brand,sf_base.group_sf_stock_manager,1,0,0,0
access_sf_cutting_tool_type_group_sf_stock_manager,sf_cutting_tool_type_group_sf_stock_manager,model_sf_cutting_tool_type,sf_base.group_sf_stock_manager,1,0,0,0
access_sf_cutting_tool_material_group_plan_dispatch,sf_cutting_tool_material_group_plan_dispatch,model_sf_cutting_tool_material,sf_base.group_plan_dispatch,1,0,0,0
access_sf_functional_cutting_tool_model_group_plan_dispatch,sf_functional_cutting_tool_model_group_plan_dispatch,model_sf_functional_cutting_tool_model,sf_base.group_plan_dispatch,1,0,0,0
access_sf_cutting_tool_type_group_plan_dispatch,sf_cutting_tool_type_group_plan_dispatch,model_sf_cutting_tool_type,sf_base.group_plan_dispatch,1,0,0,0
access_sf_machining_accuracy,sf_machining_accuracy,model_sf_machining_accuracy,base.group_user,1,0,0,0
access_sf_machining_accuracy_admin,sf_machining_accuracy_admin,model_sf_machining_accuracy,base.group_system,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
11 access_sf_machine_control_system_admin sf_machine_control_system_admin model_sf_machine_control_system base.group_system 1 1 1 0
12 access_sf_production_process_group_sale_director sf_production_process_group_sale_director model_sf_production_process sf_base.group_sale_director 1 0 0 0
13 access_sf_production_process_group_sale_salemanager sf_production_process_group_sale_salemanager model_sf_production_process sf_base.group_sale_salemanager 1 0 0 0
14 access_res_partner_category_group_sale_salemanager res_partner_category_group_sale_salemanager base.model_res_partner_category sf_base.group_sale_salemanager 1 1 0 1 0
15 access_res_partner_category_group_sale_director res_partner_category_group_sale_director base.model_res_partner_category sf_base.group_sale_director 1 1 0 1 0
16 access_sf_production_process sf_production_process model_sf_production_process base.group_user 1 1 1 0
17 access_sf_production_process_admin sf_production_process_admin model_sf_production_process base.group_system 1 1 1 0
18 access_sf_production_materials sf_production_materials model_sf_production_materials base.group_user 1 1 1 0
242
243
244

View File

@@ -1,62 +0,0 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { barcodeGenericHandlers } from '@barcodes/barcode_handlers';
import { patch } from "@web/core/utils/patch";
// 定义新的 clickOnButton 函数
function customClickOnButton(selector) {
console.log("This is the custom clickOnButton function!");
const buttons = document.body.querySelectorAll(selector);
let length = buttons.length;
if (length > 0) {
buttons[length - 1].click();
} else {
console.warn(`Button with selector ${selector} not found`);
}
}
patch(barcodeGenericHandlers, "start", {
start(env, { ui, barcode, notification }) {
// 使用新定义的 clickOnButton 函数
const COMMANDS = {
"O-CMD.EDIT": () => customClickOnButton(".o_form_button_edit"),
"O-CMD.DISCARD": () => customClickOnButton(".o_form_button_cancel"),
"O-CMD.SAVE": () => customClickOnButton(".o_form_button_save"),
"O-CMD.PREV": () => customClickOnButton(".o_pager_previous"),
"O-CMD.NEXT": () => customClickOnButton(".o_pager_next"),
"O-CMD.PAGER-FIRST": () => updatePager("first"),
"O-CMD.PAGER-LAST": () => updatePager("last"),
"O-CMD.CONFIRM": () => customClickOnButton(".jikimo_button_confirm"),
"O-CMD.FLUSHED": () => customClickOnButton(".jikimo_button_flushed"),
};
barcode.bus.addEventListener("barcode_scanned", (ev) => {
const barcode = ev.detail.barcode;
if (barcode.startsWith("O-BTN.")) {
let targets = [];
try {
targets = getVisibleElements(ui.activeElement, `[barcode_trigger=${barcode.slice(6)}]`);
} catch (_e) {
console.warn(`Barcode '${barcode}' is not valid`);
}
for (let elem of targets) {
elem.click();
}
}
if (barcode.startsWith("O-CMD.")) {
const fn = COMMANDS[barcode];
if (fn) {
fn();
} else {
notification.add(env._t("Barcode: ") + `'${barcode}'`, {
title: env._t("Unknown barcode command"),
type: "danger"
});
}
}
});
}
})

View File

@@ -1,42 +0,0 @@
/** @odoo-module **/
import { registry } from '@web/core/registry';
import { formView } from '@web/views/form/form_view';
import { FormController } from '@web/views/form/form_controller';
import { listView } from '@web/views/list/list_view';
import { ListController } from '@web/views/list/list_controller'
import { onRendered, onMounted } from "@odoo/owl";
export class RemoveFocusFormController extends FormController {
setup() {
super.setup();
onMounted(() => {
this.__owl__.bdom.el.querySelectorAll(':focus').forEach(element => element.blur());
})
}
}
registry.category('views').add('remove_focus_form_view', {
...formView,
Controller: RemoveFocusFormController,
});
export class RemoveFocusListController extends ListController {
setup() {
super.setup();
onMounted(() => {
this.__owl__.bdom.el.querySelectorAll(':focus').forEach(element => element.blur());
})
}
}
registry.category('views').add('remove_focus_list_view', {
...listView,
Controller: RemoveFocusListController,
});

View File

@@ -159,6 +159,9 @@ td.o_required_modifier {
display:inline;
}
.diameter{
display: flex !important;
justify-content: flex-start !important;
align-items: center !important;
}
.o_address_format {
display: flex !important;

View File

@@ -109,7 +109,7 @@
<field name="name">form.sf.machine_tool.type</field>
<field name="model">sf.machine_tool.type</field>
<field name="arch" type="xml">
<form string="机床型号" delete="0">
<form string="机床型号" delete="0">
<sheet>
<div class="oe_title">
<h1>
@@ -129,28 +129,31 @@
<field name="machine_tool_picture" widget="image" nolabel="1"/>
</group>
</group>
<group string="加工能力">
<group string="加工能力">
<div>
<field name='jg_image_id' widget="custom_many2many_checkboxes">
<tree>
<field name="name"/>
<field name="image" widget="image"/>
<field name='jg_image_id' widget="custom_many2many_checkboxes">
</tree>
</field>
<tree>
<field name="name"/>
<field name="image" widget="image"
options="{'size': [100, 100], 'click enlarge': True}"/>
</tree>
</field>
</div>
</group>
<group string="冷却方式">
<div>
<field name='lq_image_id' widget="custom_many2many_checkboxes">
<field name='lq_image_id' widget="custom_many2many_checkboxes">
<tree>
<field name="name"/>
<field name="image" widget="image"/>
<tree>
<field name="name"/>
<field name="image" widget="image"
options="{'size': [100, 100], 'click enlarge': True}"/>
</tree>
</field>
</tree>
</field>
</div>
</group>
@@ -175,7 +178,7 @@
<field name="workbench_H" class="o_address_zip" required="1"
options="{'format': false}"/>
</div>
<field name="workpiece_load"/>
<field name="workpiece_load"/>
<label for="machine_tool_L" string="机床尺寸(mm)"/>
<div class="test_model">
<label for="machine_tool_L" string="长"/>
@@ -189,7 +192,7 @@
<field name="machine_tool_H" class="o_address_zip"
options="{'format': false}"/>
</div>
<label for="T_trough_num" string="T型槽尺寸:"/>
<label for="T_trough_num" string="T型槽尺寸:"/>
<div class="test_model">
<label for="T_trough_num" string="槽数"/>
<field name="T_trough_num" class="o_address_zip"
@@ -202,20 +205,20 @@
<field name="T_trough_distance" class="o_address_zip"
options="{'format': false}"/>
</div>
<!-- <field name="feed_speed" required="1"/>-->
<!-- <label for="precision_min" string="X轴定位精度(mm)"/>-->
<!-- <div class="test_model">-->
<!-- <label for="precision_min" string="最小(min)"/>-->
<!-- <field name="precision_min" class="o_address_zip" required="1"-->
<!-- options="{'format': false}"/>-->
<!-- <span>&amp;nbsp;</span>-->
<!-- <label for="precision_max" string="最大(max)"/>-->
<!-- <field name="precision_max" class="o_address_zip" required="1"-->
<!-- options="{'format': false}"/>-->
<!-- </div>-->
<!-- <field name="feed_speed" required="1"/>-->
<!-- <label for="precision_min" string="X轴定位精度(mm)"/>-->
<!-- <div class="test_model">-->
<!-- <label for="precision_min" string="最小(min)"/>-->
<!-- <field name="precision_min" class="o_address_zip" required="1"-->
<!-- options="{'format': false}"/>-->
<!-- <span>&amp;nbsp;</span>-->
<!-- <label for="precision_max" string="最大(max)"/>-->
<!-- <field name="precision_max" class="o_address_zip" required="1"-->
<!-- options="{'format': false}"/>-->
<!-- </div>-->
<!-- <field name="lead_screw" required="1"/>-->
<!-- <field name="guide_rail" required="1"/>-->
<!-- <field name="lead_screw" required="1"/>-->
<!-- <field name="guide_rail" required="1"/>-->
<field name="number_of_axles" required="1" widget="radio"
options="{'horizontal': true}"/>
<label for="x_axis" string="加工行程(mm)"
@@ -255,7 +258,7 @@
</group>
<group string="主轴">
<field name="taper_type_id" required="1"/>
<label for="distance_min" string="主轴端面-工作台距离(mm)"/>
<label for="distance_min" string="主轴端面-工作台距离(mm)"/>
<div class="test_model">
<label for="distance_min" string="最小(min)"/>
<field name="distance_min" class="o_address_zip"
@@ -265,7 +268,7 @@
<field name="distance_max" class="o_address_zip"
options="{'format': false}"/>
</div>
<field name="rotate_speed" string="主轴最高转速(r/min)"
<field name="rotate_speed" string="主轴最高转速(r/min)"
options="{'format': false}"/>
<field name="spindle_center_distance"/>
<field name="spindle_continuous_power"/>
@@ -283,50 +286,50 @@
<page string="进给/精度参数">
<group>
<group string="进给参数">
<field name="X_axis_rapid_traverse_speed"/>
<field name="Y_axis_rapid_traverse_speed"/>
<field name="Z_axis_rapid_traverse_speed"/>
<field name="a_axis_rapid_traverse_speed"/>
<field name="b_axis_rapid_traverse_speed"/>
<field name="c_axis_rapid_traverse_speed"/>
<field name="straight_cutting_feed_rate"/>
<field name="rotary_cutting_feed_rate"/>
<field name="X_axis_rapid_traverse_speed"/>
<field name="Y_axis_rapid_traverse_speed"/>
<field name="Z_axis_rapid_traverse_speed"/>
<field name="a_axis_rapid_traverse_speed"/>
<field name="b_axis_rapid_traverse_speed"/>
<field name="c_axis_rapid_traverse_speed"/>
<field name="straight_cutting_feed_rate"/>
<field name="rotary_cutting_feed_rate"/>
</group>
<group string="精度参数">
<field name="X_precision"/>
<field name="X_precision_repeat"/>
<field name="Y_precision"/>
<field name="Y_precision_repeat"/>
<field name="Z_precision"/>
<field name="Z_precision_repeat"/>
<field name="a_precision"/>
<field name="a_precision_repeat"/>
<field name="b_precision"/>
<field name="b_precision_repeat"/>
<field name="c_precision"/>
<field name="c_precision_repeat"/>
<field name="X_precision"/>
<field name="X_precision_repeat"/>
<field name="Y_precision"/>
<field name="Y_precision_repeat"/>
<field name="Z_precision"/>
<field name="Z_precision_repeat"/>
<field name="a_precision"/>
<field name="a_precision_repeat"/>
<field name="b_precision"/>
<field name="b_precision_repeat"/>
<field name="c_precision"/>
<field name="c_precision_repeat"/>
</group>
</group>
</page>
<page string="刀库参数">
<group>
<page string="刀库参数">
<group>
<group string="刀具">
<!-- <field name="knife_type" required="1"/>-->
<!-- <field name="knife_type" required="1"/>-->
<field name="number_of_knife_library" required="1" options="{'format': false}"/>
<!-- <field name="tool_speed" required="1"/>-->
<!-- <field name="tool_speed" required="1"/>-->
<field name="tool_full_diameter_max"/>
<field name="tool_perimeter_diameter_max"/>
<field name="tool_long_max"/>
<!-- <label for="tool_diameter_min" string="刀具刀径(mm)"/>-->
<!-- <div class="test_model">-->
<!-- <label for="tool_diameter_min" string="最小(min)"/>-->
<!-- <field name="tool_diameter_min" class="o_address_zip" required="1"-->
<!-- options="{'format': false}"/>-->
<!-- <span>&amp;nbsp;</span>-->
<!-- <label for="tool_diameter_max" string="最大(max)"/>-->
<!-- <field name="tool_diameter_max" class="o_address_zip" required="1"-->
<!-- options="{'format': false}"/>-->
<!-- </div>-->
<!-- <label for="tool_diameter_min" string="刀具刀径(mm)"/>-->
<!-- <div class="test_model">-->
<!-- <label for="tool_diameter_min" string="最小(min)"/>-->
<!-- <field name="tool_diameter_min" class="o_address_zip" required="1"-->
<!-- options="{'format': false}"/>-->
<!-- <span>&amp;nbsp;</span>-->
<!-- <label for="tool_diameter_max" string="最大(max)"/>-->
<!-- <field name="tool_diameter_max" class="o_address_zip" required="1"-->
<!-- options="{'format': false}"/>-->
<!-- </div>-->
<field name="tool_quality_max"/>
<field name="T_tool_time"/>
<field name="C_tool_time"/>
@@ -614,23 +617,4 @@
<field name="res_model">sf.machine.control_system</field>
<field name="view_mode">tree</field>
</record>
#------------------加工精度------------------
<record model="ir.ui.view" id="tree_sf_machining_accuracy_view">
<field name="name">tree.sf.machining.accuracy</field>
<field name="model">sf.machining.accuracy</field>
<field name="arch" type="xml">
<tree string="加工精度" create="0" edit="0" delete="0">
<field name="name"/>
<field name="standard_tolerance"/>
</tree>
</field>
</record>
<record id="action_sf_machining_accuracy" model="ir.actions.act_window">
<field name="name">加工精度</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">sf.machining.accuracy</field>
<field name="view_mode">tree</field>
</record>
</odoo>

View File

@@ -12,10 +12,11 @@
</tree>
</field>
</record>
<record model="ir.ui.view" id="mrs_production_process_parameter_form">
<field name="model">sf.production.process.parameter</field>
<field name="arch" type="xml">
<form string="表面工艺可选参数" create="0" delete="0" >
<form string="表面工艺可选参数" create="0" delete="0">
<sheet>
<div class="oe_title">
<h1>
@@ -25,19 +26,14 @@
<group>
<group>
<field name="code" readonly="1"/>
<field name="process_id" attrs="{'readonly': [('code', '!=', False)]}"/>
<field name="process_description" attrs="{'readonly': [('code', '!=', False)]}"/>
<field name="process_id" readonly="1"/>
<field name="gain_way"/>
</group>
<group>
<field name="processing_day" attrs="{'readonly': [('code', '!=', False)]}"/>
<field name="travel_day" attrs="{'readonly': [('code', '!=', False)]}"/>
<field name="processing_mm" attrs="{'readonly': [('code', '!=', False)]}"/>
</group>
</group>
<notebook>
<page string="适用材料">
<field name="materials_model_ids" attrs="{'readonly': [('code', '!=', False)]}"></field>
<field name="materials_model_ids"></field>
</page>
</notebook>
</sheet>
@@ -52,7 +48,7 @@
<search>
<filter name="filter_active" string="已归档" domain="[('active','=',False)]"/>
<field name="name" string="名称" filter_domain="[('name','ilike',self)]"/>
<field name="code" string="编码" filter_domain="[('code','ilike',self)]"/>
<field name="code" string="编码" filter_domain="[('codeNum','ilike',self)]"/>
<searchpanel class="account_root">
<field name="process_id" icon="fa-filter"/>
</searchpanel>
@@ -140,7 +136,7 @@
<field name="model">sf.production.process.category</field>
<field name="arch" type="xml">
<tree string="表面工艺类别" default_order="sequence, id" create="0" edit="0" delete="1">
<field name="sequence" widget="handle" string="序号" readonly="1"/>
<field name="sequence" widget="handle" string="序号"/>
<field name="code"/>
<field name="name" string="名称"/>
</tree>
@@ -163,8 +159,7 @@
<record model="ir.ui.view" id="sf_production_process_tree">
<field name="model">sf.production.process</field>
<field name="arch" type="xml">
<tree string="表面工艺" create="0" edit="0" delete="0">
<field name="sequence" string="加工顺序" readonly="1"/>
<tree string="表面工艺" create="0" edit="0" delete="1">
<field name="code"/>
<field name="name" string="名称"/>
<field name="remark"/>
@@ -175,7 +170,7 @@
<record model="ir.ui.view" id="sf_production_process_form">
<field name="model">sf.production.process</field>
<field name="arch" type="xml">
<form string="表面工艺" create="0" delete="0">
<form string="表面工艺" create="0" edit="1" delete="1">
<sheet>
<div class="oe_title">
<h1>
@@ -184,46 +179,41 @@
</div>
<group>
<group>
<field name="code" readonly="1"/>
<field name="category_id" readonly="1"/>
<field name="code"/>
</group>
<group>
<field name="processing_day" readonly="1"/>
<field name="travel_day" readonly="1"/>
</group>
</group>
<notebook>
<page string="可选参数" >
<field name="parameter_ids" >
<tree force_save="1" create="0">
<field name="code" readonly="1" force_save="1"/>
<field name="name" readonly="1"/>
<field name="gain_way"/>
<field name='process_id' default="default"/>
</tree>
<form>
<sheet>
<group>
<notebook>
<page string="可选参数">
<field name="parameter_ids">
<tree force_save="1">
<field name="code" readonly="1" force_save="1"/>
<field name="name"/>
<field name="gain_way"/>
<field name='process_id' default="default"/>
</tree>
<form>
<sheet>
<group>
<field name="code"/>
<field name="name" string="参数名"/>
<group>
<field name="code"/>
<field name="name" string="参数名"/>
</group>
<group>
<field name='process_id'/>
<field name="gain_way"/>
</group>
</group>
<group>
<field name='process_id'/>
<field name="gain_way"/>
</group>
</group>
<notebook>
<page string="适用材料">
<field name="materials_model_ids"/>
</page>
</notebook>
</sheet>
</form>
</field>
</page>
<notebook>
<page string="适用材料">
<field name="materials_model_ids"/>
</page>
</notebook>
</sheet>
</form>
</field>
</page>
</notebook>
</notebook>
</group>
<group>
<group>
<field name="remark"/>
@@ -261,7 +251,7 @@
<group>
<group>
<field name="materials_no" readonly="1" force_save="1"/>
<field name="gain_way" required="0"/>
<field name="gain_way" required="1"/>
<field name="tensile_strength" required="1"/>
<field name="hardness" required="1"/>
<field name="density" readonly="1"/>
@@ -280,9 +270,9 @@
<notebook>
<page string="供应商">
<field name='supplier_ids' class="supplier_ids_set_css">
<tree editable='bottom' delete="1">
<tree editable='bottom'>
<field name="sequence" widget="handle" string="序号"/>
<field name="partner_id" string="名称" options="{'no_create': True}"/>
<field name="partner_id" string="名称"/>
</tree>
</field>
</page>

View File

@@ -171,7 +171,7 @@
<field name="width"/>
<field name="height"/>
<field name="diameter"/>
<field name="weight" string="重量(kg)"/>
<field name="weight"/>
<field name="orientation_dish_diameter"/>
<field name="clamping_diameter"/>
<field name="clamping_num"/>
@@ -197,7 +197,7 @@
<field name="width"/>
<field name="height"/>
<field name="diameter"/>
<field name="weight" string="重量(kg)"/>
<field name="weight"/>
<field name="clamping_diameter"/>
<field name="connector_diameter"/>
<field name="chucking_power_max"/>
@@ -220,7 +220,7 @@
<field name="length"/>
<field name="width"/>
<field name="height"/>
<field name="weight" string="重量(kg)"/>
<field name="weight"/>
<field name="gripper_length_min"/>
<field name="gripper_width_min"/>
<field name="gripper_height_min"/>
@@ -248,7 +248,7 @@
<field name="length"/>
<field name="width"/>
<field name="height"/>
<field name="weight" string="重量(kg)"/>
<field name="weight"/>
<field name="gripper_length_min"/>
<field name="gripper_width_min"/>
<field name="gripper_height_min"/>
@@ -278,7 +278,7 @@
<field name="width"/>
<field name="height"/>
<field name="height_tolerance_value"/>
<field name="weight" string="重量(kg)"/>
<field name="weight"/>
<field name="gripper_length_min"/>
<field name="gripper_width_min"/>
<field name="gripper_height_min"/>
@@ -307,7 +307,7 @@
<field name="length"/>
<field name="width"/>
<field name="height"/>
<field name="weight" string="重量(kg)"/>
<field name="weight"/>
<field name="gripper_length_min"/>
<field name="gripper_width_min"/>
<field name="gripper_height_min"/>
@@ -335,7 +335,7 @@
<field name="width"/>
<field name="height"/>
<field name="diameter"/>
<field name="weight" string="重量(kg)"/>
<field name="weight"/>
<field name="gripper_length_min"/>
<field name="gripper_width_min"/>
<field name="gripper_height_min"/>

View File

@@ -141,18 +141,12 @@
sequence="1"
action="action_sf_machine_brand"/>
<menuitem
id="menu_sf_machining_accuracy"
parent="menu_sf_base"
name="加工精度"
sequence="1"
action="action_sf_machining_accuracy"/>
<menuitem
id="menu_sf_machine_control_system"
parent="menu_sf_base"
name="数控系统"
sequence="2"
sequence="1"
action="action_sf_machine_control_system"/>

View File

@@ -15,7 +15,6 @@
<field name="handle_length"/>
<field name="blade_tip_diameter"/>
<field name="blade_tip_working_size"/>
<field name="tip_r_size"/>
<field name="blade_tip_taper"/>
<field name="blade_diameter"/>
<field name="blade_length"/>
@@ -96,7 +95,6 @@
<field name="handle_length"/>
<field name="blade_tip_diameter"/>
<field name="blade_tip_working_size"/>
<field name="tip_r_size"/>
<field name="blade_tip_taper"/>
<field name="blade_diameter"/>
<field name="blade_length"/>
@@ -141,7 +139,6 @@
</group>
<group attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')]}">
<field name="blade_tip_working_size"/>
<field name="tip_r_size"/>
<field name="blade_tip_diameter" class="diameter"/>
<field name="blade_tip_taper"/>
<field name="blade_helix_angle"/>

View File

@@ -80,10 +80,10 @@
<field name="name">sf.cutter.function.tree</field>
<field name="model">sf.functional.cutting.tool.model</field>
<field name="arch" type="xml">
<tree string="功能刀具类型" create="0" delete="0" edit="1" editable="bottom">
<field name="name" string="名称" readonly="1"/>
<field name="code" readonly="1"/>
<field name="remark" readonly="1"/>
<tree string="功能刀具类型" create="0" delete="0" edit="1">
<field name="name" string="名称"/>
<field name="code"/>
<field name="remark"/>
</tree>
</field>
</record>
@@ -222,7 +222,6 @@
<field name="handle_diameter" class="diameter"/>
<field name="handle_length"/>
<field name="blade_tip_working_size" class="du"/>
<field name="tip_r_size"/>
<field name="blade_tip_diameter" class="diameter"/>
<field name="blade_tip_taper" class="du"/>
<field name="blade_helix_angle" class="du"/>
@@ -556,9 +555,9 @@
<field name="model">sf.tool.inventory</field>
<field name="arch" type="xml">
<tree string="功能刀具清单" create="1" edit="1" delete="0" editable="bottom">
<field name="name" attrs="{'readonly': [('id', '!=', False)]}"/>
<field name="name"/>
<field name="functional_cutting_tool_model_id"/>
<field name="tool_groups_id" required="1" attrs="{'readonly': [('id', '!=', False)]}"/>
<field name="tool_groups_id"/>
<field name="work_material"/>
<field name="life_span"/>
<field name="prefix" optional="hide"/>
@@ -578,7 +577,7 @@
</field>
</record>
<record model="ir.ui.view" id="view_cutting_tool_inventory_search">
<record model="ir.ui.view" id="view_cutting_tool_material_search">
<field name="name">sf.tool.inventory.search</field>
<field name="model">sf.tool.inventory</field>
<field name="arch" type="xml">

View File

@@ -21,7 +21,6 @@ class Http(models.AbstractModel):
def _auth_method_sf_token(cls):
# 从headers.environ中获取对方传过来的token,timestamp,加密的校验字符串
datas = request.httprequest.headers.environ
_logger.info('datas:%s' % datas)
if 'HTTP_TOKEN' in datas:
_logger.info('token:%s' % datas['HTTP_TOKEN'])
# 查询密钥
@@ -36,7 +35,7 @@ class Http(models.AbstractModel):
post_time = int(datas['HTTP_TIMESTAMP'])
datetime_post = datetime.fromtimestamp(post_time)
datetime_now = datetime.now().replace(microsecond=0)
datetime_del = datetime_now + timedelta(seconds=30)
datetime_del = datetime_now + timedelta(seconds=5)
if datetime_post > datetime_del:
raise AuthenticationError('请求已过期')
check_str = '%s%s%s' % (datas['HTTP_TOKEN'], post_time, factory_secret.sf_secret_key)

View File

@@ -5,7 +5,7 @@ import requests
import cpca
# from odoo.exceptions import UserError
# from odoo.exceptions import ValidationError
from odoo import api, fields, models, _
from odoo import api, fields, models
from odoo.exceptions import ValidationError
_logger = logging.getLogger(__name__)
@@ -14,7 +14,7 @@ _logger = logging.getLogger(__name__)
class JdEclp(models.Model):
_inherit = 'stock.picking'
senderNickName = fields.Char(string='寄件工厂简称', required=True, default='XT')
senderNickName = fields.Char(string='寄件工厂简称', required=True, default='MW')
# receiverName = fields.Char(string='收件人姓名')
# receiverMobile = fields.Char(string='收件人电话')
@@ -67,10 +67,9 @@ class JdEclp(models.Model):
"""
判断是否为出库单
"""
for record in self:
if record.name:
is_check_out = record.name.split('/')
record.check_out = is_check_out[1]
if self.name:
is_check_out = self.name.split('/')
self.check_out = is_check_out[1]
@api.depends('carrier_tracking_ref')
def query_bill_pdf(self):
@@ -149,7 +148,7 @@ class JdEclp(models.Model):
},
}
_logger.info('准备调接口1')
url1 = config['bfm_url_new'] + '/api/create/jd/order'
url1 = config['bfm_url'] + '/api/create/jd/order'
requests.post(url1, json=json1, data=None)
_logger.info('调用成功1')
_logger.info('准备调接口2')
@@ -158,31 +157,18 @@ class JdEclp(models.Model):
'orderNo': self.origin,
},
}
url2 = config['bfm_url_new'] + '/api/get/jd/no'
url2 = config['bfm_url'] + '/api/get/jd/no'
response = requests.post(url2, json=json2, data=None)
# _logger.info('调用成功2', response.json()['result']['wbNo'])
tem_ret = response.json().get('result')
if not tem_ret:
raise ValidationError('京东物流返回异常,请联系管理员')
self.carrier_tracking_ref = response.json()['result'].get('wbNo')
if not self.carrier_tracking_ref:
raise ValidationError('物流下单未成功,请联系管理员')
self.carrier_tracking_ref = response.json()['result']['wbNo']
self.is_bill = True
self.logistics_status = '1'
notification = {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'title': _('成功'),
'type': 'success',
'message': '物流下单成功',
'sticky': False,
'next': {'type': 'ir.actions.client', 'tag': 'reload'}
}
}
# # 京东物流下单后,销售订单状态改为待收货
# self.env['sale.order'].search([('name', '=', self.origin)]).write({'scheduled_status': 'to receive'})
return notification
# else:
# raise UserError("选择京东物流才能下单呦")
def get_bill(self):
"""
@@ -196,7 +182,7 @@ class JdEclp(models.Model):
'no': self.origin,
},
}
url1 = config['bfm_url_new'] + '/api/create/jd/bill'
url1 = config['bfm_url'] + '/api/create/jd/bill'
response = requests.post(url1, json=json1, data=None)
# _logger.info('调用成功2', response.json())

View File

@@ -1,9 +1,7 @@
import traceback
from datetime import datetime
import logging
import requests
from odoo.exceptions import UserError
from odoo import fields, models, _
from odoo import fields, models
_logger = logging.getLogger(__name__)
@@ -16,51 +14,26 @@ class StatusChange(models.Model):
def action_confirm(self):
# 在原有方法执行前记录日志和执行其他操作
logging.info('函数已经执行=============')
server_product_none = []
for order in self.order_line:
gain_way_no = order.product_template_id.model_process_parameters_ids.filtered(lambda a: not a.gain_way)
if gain_way_no:
process_parameters = [item.name for item in gain_way_no]
raise UserError(
_("请先至【制造】-【配置】中【表面工艺可选参数】为【%s】填写获取方式", ", ".join(process_parameters)))
for item in order.product_template_id.model_process_parameters_ids:
if item.gain_way == '外协':
server_product = self.env['product.template'].search(
[('server_product_process_parameters_id', '=', item.id),
('detailed_type', '=', 'service')])
if not server_product:
server_product_none.append(item.name)
if server_product_none:
raise UserError(_("请先至【产品】中创建【表面工艺参数】为【%s】的服务产品", ", ".join(server_product_none)))
# 使用super()来调用原始方法(在本例中为'sale.order'模型的'action_confirm'方法)
try:
res = super(StatusChange, self).action_confirm()
# 原有方法执行后进行额外的操作如调用外部API
process_start_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
config = self.env['res.config.settings'].get_values()
json1 = {
'params': {
'model_name': 'jikimo.process.order',
'field_name': 'name',
'default_code': self.default_code,
'state': '加工中',
'process_start_time': process_start_time,
},
}
url1 = config['bfm_url_new'] + '/api/get/state/get_order'
ret = requests.post(url1, json=json1, data=None)
ret = ret.json()
if not ret.get('error'):
logging.info('接口已经执行=============')
else:
traceback_error = traceback.format_exc()
logging.error("bfm订单状态同步失败:%s" % traceback_error)
raise UserError('工厂加工同步订单状态到bfm失败')
except UserError as e:
traceback_error = traceback.format_exc()
logging.error("工厂加工同步订单状态失败:%s " % traceback_error)
raise UserError(e)
res = super(StatusChange, self).action_confirm()
# 原有方法执行后进行额外的操作如调用外部API
process_start_time = str(datetime.now())
config = self.env['res.config.settings'].get_values()
json1 = {
'params': {
'model_name': 'jikimo.process.order',
'field_name': 'name',
'default_code': self.default_code,
'state': '加工中',
'process_start_time': process_start_time,
},
}
url1 = config['bfm_url'] + '/api/get/state/get_order'
requests.post(url1, json=json1, data=None)
logging.info('接口已经执行=============')
return res
def action_cancel(self):
@@ -81,7 +54,7 @@ class StatusChange(models.Model):
'state': '待派单',
},
}
url1 = config['bfm_url_new'] + '/api/get/state/cancel_order'
url1 = config['bfm_url'] + '/api/get/state/cancel_order'
requests.post(url1, json=json1, data=None)
return res
@@ -229,12 +202,12 @@ class FinishStatusChange(models.Model):
[('id', 'child_of', self.picking_type_id.warehouse_id.view_location_id.id),
('usage', '!=', 'supplier')])
if self.env['stock.move'].search([
('state', 'in', ['confirmed', 'partially_available', 'waiting', 'assigned']),
('product_qty', '>', 0),
('location_id', 'in', wh_location_ids),
('move_orig_ids', '=', False),
('picking_id', 'not in', self.ids),
('product_id', 'in', lines.product_id.ids)], limit=1):
('state', 'in', ['confirmed', 'partially_available', 'waiting', 'assigned']),
('product_qty', '>', 0),
('location_id', 'in', wh_location_ids),
('move_orig_ids', '=', False),
('picking_id', 'not in', self.ids),
('product_id', 'in', lines.product_id.ids)], limit=1):
action = self.action_view_reception_report()
action['context'] = {'default_picking_ids': self.ids}
return action

View File

@@ -32,7 +32,7 @@
<field name="is_bill" invisible="True"/>
<field name="logistics_status" invisible="True"/>
<field name="logistics_way" invisible="True"/>
<button string="物流下单" name="create_order" type="object" confirm="是否确认物流下单" class="btn-primary"
<button string="京东物流下单" name="create_order" type="object" confirm="是否确认物流下单" class="btn-primary"
attrs="{'invisible': ['|', '|', '|', ('check_out', '!=', 'OUT'), ('state', '!=', 'assigned'), ('is_bill', '=', True), ('logistics_way', '=', '自提')]}"/>
<button string="获取物流面单" name="get_bill" type="object" confirm="是否获取物流面单" class="btn-primary"
attrs="{'invisible': ['|', '|', '|', '|', ('check_out', '!=', 'OUT'), ('state', '!=', 'assigned'), ('logistics_status', '=', '2'), ('is_bill', '=', False), ('logistics_way', '=', '自提')]}"/>
@@ -45,50 +45,42 @@
<field name="model">stock.picking</field>
<field name="inherit_id" ref="delivery.view_picking_withcarrier_out_form"/>
<field name="arch" type="xml">
<field name="location_id" position="after">
<field name="logistics_status" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="logistics_way" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
</field>
</field>
</record>
<record id="tracking_only_view" model="ir.ui.view">
<field name="name">tracking only</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.view_picking_form"/>
<field name="arch" type="xml">
<xpath expr="//form//sheet//notebook//page[@name='operations']" position="after">
<page string="发货信息" name="tracking">
<group>
<group>
<field name="senderNickName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="expressItemName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="grossWeight" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="grossVolume" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="deliveryType" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverMobile" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverProvinceName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverCityName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverCountyName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverTownName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverCompany" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="remark" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="pickupBeginTime" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
</group>
<group>
<field name="logistics_status"/>
<field name="carrier_id"/>
<field name="carrier_tracking_ref"/>
<field name="bill_show" attrs="{'invisible': [('check_out', '!=', 'OUT')]}" string='面单下载'/>
<field name="bill_show" widget="pdf_viewer" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
</group>
</group>
</page>
<xpath expr="//group//field[@name='carrier_id']" position="after">
<!-- <field name="senderNickName" domain="[('self.name', 'like', '%OUT%')]"/> -->
<field name="senderNickName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="expressItemName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="deliveryType" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverMobile" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverProvinceName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverCityName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverCountyName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverTownName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverCompany" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="remark" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="grossWeight" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="grossVolume" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="pickupBeginTime" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="bill_show" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="logistics_status"/>
</xpath>
<xpath expr="//group//field[@name='group_id']" position="after">
<field name="bill_show" widget="pdf_viewer" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
</xpath>
<!-- <xpath expr="//group[@name='other_infos']" position="after"> -->
<!-- <div> -->
<!-- <button string="京东物流下单" name="create_order" type="object" confirm="是否确认物流下单" class="btn-primary"/> -->
<!-- </div> -->
<!-- <div> -->
<!-- <button string="获取物流面单" name="get_bill" type="object" confirm="是否获取物流面单" class="btn-primary"/> -->
<!-- </div> -->
<!-- </xpath> -->
</field>
</record>
</odoo>

View File

@@ -10,7 +10,7 @@
""",
'category': 'sf',
'website': 'https://www.sf.jikimo.com',
'depends': ['sf_base', 'mrp_subcontracting', 'purchase_stock', 'uom'],
'depends': ['sf_base', 'web_widget_model_viewer', 'mrp_subcontracting', 'purchase_stock', 'uom', ],
'data': [
'data/product_data.xml',
'data/uom_data.xml',

Some files were not shown because too many files have changed in this diff Show More