Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/修改刀具标准库部分字段类型

This commit is contained in:
jinling.yang
2023-11-28 17:09:10 +08:00
51 changed files with 859 additions and 539 deletions

View File

@@ -11,24 +11,22 @@ export class Many2OneRadioField extends RadioField {
// 你自己的代码 // 你自己的代码
} }
onImageClick(event) { onImageClick(event) {
// 放大图片逻辑 // 放大图片逻辑
// 获取图片元素 // 获取图片元素
const img = event.target; const img = event.target;
const close = img.nextSibling const close = img.nextSibling;
// 实现放大图片逻辑 // 实现放大图片逻辑
// 比如使用 CSS 放大 // 比如使用 CSS 放大
img.parentElement.classList.add('zoomed'); img.parentElement.classList.add('zoomed');
close.classList.add('img_close') close.classList.add('img_close');
} }
onCloseClick(event) { onCloseClick(event) {
const close = event.target; const close = event.target;
const img = close.previousSibling const img = close.previousSibling;
img.parentElement.classList.remove('zoomed') img.parentElement.classList.remove('zoomed');
close.classList.remove('img_close') close.classList.remove('img_close');
} }
get items() { get items() {
@@ -47,10 +45,9 @@ export class Many2OneRadioField extends RadioField {
return []; return [];
} }
} }
} }
Many2OneRadioField.template = "jikimo_frontend.Many2OneRadioField" Many2OneRadioField.template = "jikimo_frontend.Many2OneRadioField";
// MyCustomWidget.supportedTypes = ['many2many']; // MyCustomWidget.supportedTypes = ['many2many'];
registry.category("fields").add("many2one_radio", Many2OneRadioField); registry.category("fields").add("many2one_radio", Many2OneRadioField);

View File

@@ -15,23 +15,24 @@ export class MyCustomWidget extends Many2ManyCheckboxesField {
// 放大图片逻辑 // 放大图片逻辑
// 获取图片元素 // 获取图片元素
const img = event.target; const img = event.target;
const close = img.nextSibling const close = img.nextSibling;
// 实现放大图片逻辑 // 实现放大图片逻辑
// 比如使用 CSS 放大 // 比如使用 CSS 放大
img.parentElement.classList.add('zoomed'); img.parentElement.classList.add('zoomed');
close.classList.add('img_close') close.classList.add('img_close');
} }
onCloseClick(event) { onCloseClick(event) {
const close = event.target; const close = event.target;
const img = close.previousSibling const img = close.previousSibling;
img.parentElement.classList.remove('zoomed') img.parentElement.classList.remove('zoomed');
close.classList.remove('img_close') close.classList.remove('img_close');
} }
} }
MyCustomWidget.template = "jikimo_frontend.MyCustomWidget" MyCustomWidget.template = "jikimo_frontend.MyCustomWidget";
// MyCustomWidget.supportedTypes = ['many2many']; // MyCustomWidget.supportedTypes = ['many2many'];
registry.category("fields").add("custom_many2many_checkboxes", MyCustomWidget); registry.category("fields").add("custom_many2many_checkboxes", MyCustomWidget);

View File

@@ -3,7 +3,7 @@
import {patch} from '@web/core/utils/patch'; import {patch} from '@web/core/utils/patch';
// import { Dialog } from "@web/core/dialog/dialog"; // import { Dialog } from "@web/core/dialog/dialog";
import {_t} from "@web/core/l10n/translation"; import {_t} from "@web/core/l10n/translation";
import {FormStatusIndicator} from "@web/views/form/form_status_indicator/form_status_indicator" import {FormStatusIndicator} from "@web/views/form/form_status_indicator/form_status_indicator";
var Dialog = require('web.Dialog'); var Dialog = require('web.Dialog');
// var {patch} = require("web.utils") 这句话也行 // var {patch} = require("web.utils") 这句话也行

View File

@@ -1,7 +1,7 @@
/** @odoo-module */ /** @odoo-module */
import {patch} from '@web/core/utils/patch'; import {patch} from '@web/core/utils/patch';
import {ListRenderer} from "@web/views/list/list_renderer" import {ListRenderer} from "@web/views/list/list_renderer";
// var {patch} = require("web.utils") 这句话也行 // var {patch} = require("web.utils") 这句话也行
@@ -17,7 +17,7 @@ patch(ListRenderer.prototype, 'jikimo_frontend.ListRenderer', {
const table = this.tableRef.el; const table = this.tableRef.el;
const headers = [...table.querySelectorAll("thead th:not(.o_list_actions_header)")]; const headers = [...table.querySelectorAll("thead th:not(.o_list_actions_header)")];
const column_num = headers.length const column_num = headers.length;
if (!this.columnWidths || !this.columnWidths.length) { if (!this.columnWidths || !this.columnWidths.length) {
// no column widths to restore // no column widths to restore
@@ -66,8 +66,8 @@ patch(ListRenderer.prototype, 'jikimo_frontend.ListRenderer', {
// } // }
// 判断 this.state.columns 是否存在且长度大于零 // 判断 this.state.columns 是否存在且长度大于零
if (this.state.columns && this.state.columns.length > 0 && if (this.state.columns && this.state.columns.length > 0
this.state.columns[0].name === "sequence") { && this.state.columns[0].name === "sequence") {
widths[1] = { type: "relative", value: 0.1 }; widths[1] = { type: "relative", value: 0.1 };
} }

View File

@@ -8,4 +8,4 @@ patch(ListRenderer.prototype, '/jikimo_frontend/static/src/views/list_nums/list_
const nbCols = this._super(...arguments); const nbCols = this._super(...arguments);
return nbCols + 1; return nbCols + 1;
} }
}); });

View File

@@ -10,10 +10,10 @@
""", """,
'category': 'sf', 'category': 'sf',
'website': 'https://www.sf.cs.jikimo.com', 'website': 'https://www.sf.cs.jikimo.com',
'depends': ['sf_base'], 'depends': ['sf_base', 'delivery'],
'data': [ 'data': [
'views/res_partner_view.xml', 'views/res_partner_view.xml',
# 'views/view.xml', 'views/view.xml',
'report/bill_report.xml', 'report/bill_report.xml',
], ],
'demo': [ 'demo': [

View File

@@ -3,9 +3,9 @@ import logging
from datetime import datetime from datetime import datetime
import requests import requests
import cpca import cpca
from odoo.exceptions import UserError # from odoo.exceptions import UserError
from odoo.exceptions import ValidationError # from odoo.exceptions import ValidationError
from odoo import api, fields, models, SUPERUSER_ID, _ from odoo import api, fields, models
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@@ -40,9 +40,22 @@ class JdEclp(models.Model):
# bill = fields.Many2one('ir.attachment', string='物流面单', compute='query_bill_pdf') # bill = fields.Many2one('ir.attachment', string='物流面单', compute='query_bill_pdf')
# bill_show = fields.Binary(string='物流面单展示', readonly=True, related='self.bill.datas') # bill_show = fields.Binary(string='物流面单展示', readonly=True, related='self.bill.datas')
bill_show = fields.Binary(string='物流面单展示', readonly=True) bill_show = fields.Binary(string='物流面单展示', readonly=True)
check_out = fields.Char(string='查询是否为出库单', compute='_check_is_out')
@api.depends('name')
def _check_is_out(self):
"""
判断是否为出库单
"""
if self.name:
is_check_out = self.name.split('/')
self.check_out = is_check_out[1]
@api.depends('carrier_tracking_ref') @api.depends('carrier_tracking_ref')
def query_bill_pdf(self): def query_bill_pdf(self):
"""
查询物流面单并赋值给bill
"""
self.bill = self.env['ir.attachment'].sudo().search([('name', '=', self.carrier_tracking_ref)]) self.bill = self.env['ir.attachment'].sudo().search([('name', '=', self.carrier_tracking_ref)])
@api.depends('origin') @api.depends('origin')
@@ -77,12 +90,12 @@ class JdEclp(models.Model):
self.receiverTownName = self.receiverTownName self.receiverTownName = self.receiverTownName
except Exception as e: except Exception as e:
print(f"Error address is none: {e}") print(f"Error address is none: {e}")
pass
def create_order(self): def create_order(self):
# sale_order_id = self.env['sale.order'].search([('name', '=', self.origin)]) # sale_order_id = self.env['sale.order'].search([('name', '=', self.origin)])
# if self.carrier_id == '京东物流': # if self.carrier_id == '京东物流':
config = self.env['res.config.settings'].get_values()
createTime = str(datetime.now()) createTime = str(datetime.now())
json1 = { json1 = {
'params': { 'params': {
@@ -106,7 +119,7 @@ class JdEclp(models.Model):
}, },
} }
_logger.info('准备调接口1') _logger.info('准备调接口1')
url1 = 'https://bfm.cs.jikimo.com/api/create/jd/order' url1 = config['bfm_url'] + '/api/create/jd/order'
requests.post(url1, json=json1, data=None) requests.post(url1, json=json1, data=None)
_logger.info('调用成功1') _logger.info('调用成功1')
_logger.info('准备调接口2') _logger.info('准备调接口2')
@@ -115,7 +128,7 @@ class JdEclp(models.Model):
'orderNo': self.origin, 'orderNo': self.origin,
}, },
} }
url2 = 'https://bfm.cs.jikimo.com/api/get/jd/no' url2 = config['bfm_url'] + '/api/get/jd/no'
response = requests.post(url2, json=json2, data=None) response = requests.post(url2, json=json2, data=None)
# _logger.info('调用成功2', response.json()['result']['wbNo']) # _logger.info('调用成功2', response.json()['result']['wbNo'])
self.carrier_tracking_ref = response.json()['result']['wbNo'] self.carrier_tracking_ref = response.json()['result']['wbNo']
@@ -124,12 +137,16 @@ class JdEclp(models.Model):
# raise UserError("选择京东物流才能下单呦") # raise UserError("选择京东物流才能下单呦")
def get_bill(self): def get_bill(self):
"""
获取物流面单
"""
config = self.env['res.config.settings'].get_values()
json1 = { json1 = {
'params': { 'params': {
'no': self.origin, 'no': self.origin,
}, },
} }
url1 = 'https://bfm.cs.jikimo.com/api/create/jd/bill' url1 = config['bfm_url'] + '/api/create/jd/bill'
response = requests.post(url1, json=json1, data=None) response = requests.post(url1, json=json1, data=None)
# _logger.info('调用成功2', response.json()) # _logger.info('调用成功2', response.json())
@@ -152,5 +169,3 @@ class JdEclp(models.Model):
# 'model_name': 'stock.picking', # 'model_name': 'stock.picking',
}) })
_logger.info(attachment) _logger.info(attachment)
# _logger.info(attachment.datas)
# _logger.info(attachment.datas_fname)

View File

@@ -3,7 +3,6 @@ import logging
import requests import requests
from odoo import fields, models from odoo import fields, models
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@@ -203,17 +202,17 @@ class FinishStatusChange(models.Model):
[('id', 'child_of', self.picking_type_id.warehouse_id.view_location_id.id), [('id', 'child_of', self.picking_type_id.warehouse_id.view_location_id.id),
('usage', '!=', 'supplier')]) ('usage', '!=', 'supplier')])
if self.env['stock.move'].search([ if self.env['stock.move'].search([
('state', 'in', ['confirmed', 'partially_available', 'waiting', 'assigned']), ('state', 'in', ['confirmed', 'partially_available', 'waiting', 'assigned']),
('product_qty', '>', 0), ('product_qty', '>', 0),
('location_id', 'in', wh_location_ids), ('location_id', 'in', wh_location_ids),
('move_orig_ids', '=', False), ('move_orig_ids', '=', False),
('picking_id', 'not in', self.ids), ('picking_id', 'not in', self.ids),
('product_id', 'in', lines.product_id.ids)], limit=1): ('product_id', 'in', lines.product_id.ids)], limit=1):
action = self.action_view_reception_report() action = self.action_view_reception_report()
action['context'] = {'default_picking_ids': self.ids} action['context'] = {'default_picking_ids': self.ids}
return action return action
out_start_time = str(datetime.now()) # out_start_time = str(datetime.now())
json2 = { json2 = {
'params': { 'params': {
'model_name': 'jikimo.process.order', 'model_name': 'jikimo.process.order',

View File

@@ -1,5 +1,31 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<odoo> <odoo>
<record id="add_check_out_view_picking_form" model="ir.ui.view">
<field name="name">增加一个check_out字段</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//div[@name='button_box']" position="inside">
<field name="check_out" invisible="True"/>
</xpath>
</field>
</record>
<record id="custom_view_picking_form" model="ir.ui.view">
<field name="name">物流</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.view_picking_form"/>
<field name="arch" type="xml">
<xpath expr="//form//header//button[@name='action_assign']" position="after">
<button string="京东物流下单" name="create_order" type="object" confirm="是否确认物流下单" class="btn-primary"
attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<button string="获取物流面单" name="get_bill" type="object" confirm="是否获取物流面单" class="btn-primary"
attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
</xpath>
</field>
</record>
<record id="tracking_view" model="ir.ui.view"> <record id="tracking_view" model="ir.ui.view">
<field name="name">tracking</field> <field name="name">tracking</field>
<field name="model">stock.picking</field> <field name="model">stock.picking</field>
@@ -7,45 +33,33 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//group//field[@name='carrier_id']" position="after"> <xpath expr="//group//field[@name='carrier_id']" position="after">
<!-- <field name="senderNickName" domain="[('self.name', 'like', '%OUT%')]"/> --> <!-- <field name="senderNickName" domain="[('self.name', 'like', '%OUT%')]"/> -->
<field name="senderNickName" attrs="{'invisible': [('name', 'like', '%OUT%')]}"/> <field name="senderNickName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="expressItemName" attrs="{'invisible': [('name', 'like', '%OUT%')]}"/> <field name="expressItemName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="deliveryType" attrs="{'invisible': [('name', 'like', '%OUT%')]}"/> <field name="deliveryType" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverName" attrs="{'invisible': [('name', 'like', '%OUT%')]}"/> <field name="receiverName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverMobile" attrs="{'invisible': [('name', 'like', '%OUT%')]}"/> <field name="receiverMobile" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverProvinceName" attrs="{'invisible': [('name', 'like', '%OUT%')]}"/> <field name="receiverProvinceName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverCityName" attrs="{'invisible': [('name', 'like', '%OUT%')]}"/> <field name="receiverCityName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverCountyName" attrs="{'invisible': [('name', 'like', '%OUT%')]}"/> <field name="receiverCountyName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverTownName" attrs="{'invisible': [('name', 'like', '%OUT%')]}"/> <field name="receiverTownName" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="receiverCompany" attrs="{'invisible': [('name', 'like', '%OUT%')]}"/> <field name="receiverCompany" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="remark" attrs="{'invisible': [('name', 'like', '%OUT%')]}"/> <field name="remark" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="grossWeight"/> <field name="grossWeight" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="grossVolume"/> <field name="grossVolume" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="pickupBeginTime"/> <field name="pickupBeginTime" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
<field name="bill"/> <field name="bill_show" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
</xpath> </xpath>
<xpath expr="//group//field[@name='group_id']" position="after"> <xpath expr="//group//field[@name='group_id']" position="after">
<field name="bill_show" widget="pdf_viewer"/> <field name="bill_show" widget="pdf_viewer" attrs="{'invisible': [('check_out', '!=', 'OUT')]}"/>
</xpath> </xpath>
<xpath expr="//group[@name='other_infos']" position="after"> <!-- <xpath expr="//group[@name='other_infos']" position="after"> -->
<!-- <group>--> <!-- <div> -->
<div> <!-- <button string="京东物流下单" name="create_order" type="object" confirm="是否确认物流下单" class="btn-primary"/> -->
<button string="京东物流下单" name="create_order" type="object" confirm="是否确认物流下单" class="btn-primary"/> <!-- </div> -->
</div> <!-- <div> -->
<!-- <button string="获取物流面单" name="get_bill" type="object" confirm="是否获取物流面单" class="btn-primary"/> -->
<!-- </group>--> <!-- </div> -->
<!-- <group>--> <!-- </xpath> -->
<div>
<button string="获取物流面单" name="get_bill" type="object" confirm="是否获取物流面单" class="btn-primary"/>
</div>
<!-- </group>-->
</xpath>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -1,20 +1,15 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os import os
import time
import json import json
import base64 import base64
import shutil
import logging import logging
import hashlib
from io import BytesIO from io import BytesIO
from zipfile import ZipFile from zipfile import ZipFile
from datetime import datetime, timedelta from datetime import datetime, timedelta
import requests import requests
from odoo.http import request from odoo.http import request
from odoo import fields, models, api, _ from odoo import fields, models, api
from odoo.exceptions import UserError from odoo.exceptions import UserError
from odoo.exceptions import MissingError
from odoo.exceptions import ValidationError
from odoo.addons.sf_machine_connect.models import py2opcua, ftp_operate from odoo.addons.sf_machine_connect.models import py2opcua, ftp_operate
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@@ -470,7 +465,7 @@ class WorkCenterBarcode(models.Model):
raise UserError('NC下发执行超时, 请检查下发状态') raise UserError('NC下发执行超时, 请检查下发状态')
def get__state(self): def get__state(self):
pay_time = str(datetime.now()) # pay_time = str(datetime.now())
json = { json = {
'params': { 'params': {
'model_name': 'jikimo.process.order', 'model_name': 'jikimo.process.order',
@@ -538,7 +533,7 @@ class WorkCenterBarcode(models.Model):
action1 = json.dumps(action) action1 = json.dumps(action)
return action1 return action1
else: else:
return False return None
def cnc_file_download(self): def cnc_file_download(self):
""" """

View File

@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os
import logging import logging
from ftplib import FTP from ftplib import FTP
@@ -20,7 +19,6 @@ class FTP_P(FTP):
cmd = 'LIST' cmd = 'LIST'
templist = [] templist = []
tempdic = {} tempdic = {}
func = None
if args[-1:] and type(args[-1]) != type(''): if args[-1:] and type(args[-1]) != type(''):
args, func = args[:-1], args[-1] args, func = args[:-1], args[-1]
for arg in args: for arg in args:

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import logging import logging
from odoo import api, fields, models, _ from odoo import api, fields, models
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)

View File

@@ -97,13 +97,12 @@ export class CodeField extends Component {
} else { } else {
if (records[0].state === '占用') { if (records[0].state === '占用') {
// console.log('此托盘已占用,请检查') // console.log('此托盘已占用,请检查')
alert('此托盘已占用,请检查') alert('此托盘已占用,请检查');
} else { } else {
// console.log('此托盘已损坏,请登记') // console.log('此托盘已损坏,请登记')
alert('此托盘已损坏,请登记') alert('此托盘已损坏,请登记');
} }
} }
} else { } else {
const searchInput = this.autocompleteContainerRef.el.querySelector("input"); const searchInput = this.autocompleteContainerRef.el.querySelector("input");
searchInput.value = barcode; searchInput.value = barcode;
@@ -114,7 +113,7 @@ export class CodeField extends Component {
} }
} }
} }
CodeField.template = 'sf_machine_connect.CodeField' CodeField.template = 'sf_machine_connect.CodeField';
// Register the field in the registry // Register the field in the registry
CodeField.props = standardFieldProps; CodeField.props = standardFieldProps;
registry.category("fields").add("code", CodeField); registry.category("fields").add("code", CodeField);

View File

@@ -48,4 +48,4 @@ odoo.define('my_module.barcode_handler', function (require) {
return { return {
BarcodeHandlerField: BarcodeHandlerField, BarcodeHandlerField: BarcodeHandlerField,
}; };
}); });

View File

@@ -8,7 +8,7 @@ const { Component, xml } = owl;
export class BarcodeHandlerField extends Component { export class BarcodeHandlerField extends Component {
setup() { setup() {
this.actionService = useService("action") this.actionService = useService("action");
const barcode = useService("barcode"); const barcode = useService("barcode");
// this.rpc = useService("rpc"); // this.rpc = useService("rpc");
// useBus(barcode.bus, "barcode_scanned", this.onBarcodeScanned.bind(this)); // useBus(barcode.bus, "barcode_scanned", this.onBarcodeScanned.bind(this));
@@ -18,7 +18,7 @@ export class BarcodeHandlerField extends Component {
// const { data } = await this.env.services.rpc('/web/dataset/call_kw', params); // const { data } = await this.env.services.rpc('/web/dataset/call_kw', params);
const response = await this.env.services.rpc('/web/dataset/call_kw', params); const response = await this.env.services.rpc('/web/dataset/call_kw', params);
// return response // return response
const responseObject = JSON.parse(response) const responseObject = JSON.parse(response);
return responseObject; return responseObject;
} }
@@ -58,8 +58,7 @@ export class BarcodeHandlerField extends Component {
} else { } else {
// console.error("Barcode not found or RPC call failed."); // console.error("Barcode not found or RPC call failed.");
} }
} };
} }
BarcodeHandlerField.template = xml``; BarcodeHandlerField.template = xml``;

View File

@@ -2,15 +2,11 @@
import base64 import base64
import logging import logging
import os import os
import json
import hashlib
import time
from datetime import datetime from datetime import datetime
import requests from odoo import fields, models
from odoo import fields, models, api, _ # from odoo.exceptions import ValidationError
from odoo.exceptions import ValidationError
from odoo.exceptions import UserError from odoo.exceptions import UserError
from odoo.addons.sf_machine_connect.models import py2opcua, ftp_operate from odoo.addons.sf_machine_connect.models import ftp_operate
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)

View File

@@ -1,6 +1,6 @@
# -*-coding:utf-8-*- # -*-coding:utf-8-*-
from odoo import api, fields, models, SUPERUSER_ID, _ from odoo import api, fields, models
from odoo.exceptions import UserError
class SfEquipmentSaintenanceStandards(models.Model): class SfEquipmentSaintenanceStandards(models.Model):

View File

@@ -1,10 +1,10 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import json import json
import base64 import base64
from datetime import date, datetime, timedelta from datetime import timedelta
import requests import requests
from odoo.addons.sf_base.commons.common import Common from odoo.addons.sf_base.commons.common import Common
from odoo import api, fields, models, SUPERUSER_ID, _ from odoo import api, fields, models, _
from odoo.exceptions import UserError from odoo.exceptions import UserError

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import base64 import base64
from odoo import api, fields, models, SUPERUSER_ID, _ from odoo import api, fields, models, _
from odoo.exceptions import UserError from odoo.exceptions import UserError

View File

@@ -41,14 +41,6 @@
], ],
'qweb': [ 'qweb': [
], ],
'assets': {
'web.assets_backend': [
'sf_manufacturing/static/src/js/kanban_change.js',
'sf_manufacturing/static/src/scss/kanban_change.scss',
'sf_manufacturing/static/src/xml/kanban_change.xml',
],
},
'license': 'LGPL-3', 'license': 'LGPL-3',
'installable': True, 'installable': True,
'application': False, 'application': False,

View File

@@ -1,4 +1,4 @@
from odoo import fields, models, api from odoo import fields, models
class ModelType(models.Model): class ModelType(models.Model):

View File

@@ -616,7 +616,7 @@ class CNCprocessing(models.Model):
logging.info('folder_name:%s' % folder_name) logging.info('folder_name:%s' % folder_name)
serverdir = os.path.join('/tmp', folder_name, 'return', processing_panel) serverdir = os.path.join('/tmp', folder_name, 'return', processing_panel)
logging.info('serverdir:%s' % serverdir) logging.info('serverdir:%s' % serverdir)
for root, dirs, files in os.walk(serverdir): for root, files in os.walk(serverdir):
for f in files: for f in files:
logging.info('f:%s' % f) logging.info('f:%s' % f)
if os.path.splitext(f)[1] == ".pdf": if os.path.splitext(f)[1] == ".pdf":

View File

@@ -5,7 +5,7 @@ import logging
import json import json
from re import split as regex_split from re import split as regex_split
from re import findall as regex_findall from re import findall as regex_findall
from datetime import datetime, timedelta from datetime import datetime
import requests import requests
from odoo import SUPERUSER_ID, _, api, fields, models from odoo import SUPERUSER_ID, _, api, fields, models
from odoo.tools import float_compare from odoo.tools import float_compare
@@ -149,8 +149,8 @@ class StockRule(models.Model):
raise ProcurementException(errors) raise ProcurementException(errors)
for company_id, productions_values in productions_values_by_company.items(): for company_id, productions_values in productions_values_by_company.items():
# create the MO as SUPERUSER because the current user may not have the rights to do it (mto product # create the MO as SUPERUSER because the current user may not have the rights to do it
# launched by a sale for example) # (mto product launched by a sale for example)
'''创建制造订单''' '''创建制造订单'''
productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company(company_id).create( productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company(company_id).create(
productions_values) productions_values)
@@ -201,18 +201,17 @@ class StockRule(models.Model):
sale_order = self.env['sale.order'].sudo().search([('name', '=', production.origin)]) sale_order = self.env['sale.order'].sudo().search([('name', '=', production.origin)])
if sale_order: if sale_order:
bb = sale_order.deadline_of_delivery self.env['sf.production.plan'].sudo().with_company(company_id). \
productions = self.env['sf.production.plan'].with_user(SUPERUSER_ID).sudo().with_company(company_id). \ create({
create({ 'name': production.name,
'name': production.name, 'order_deadline': sale_order.deadline_of_delivery,
'order_deadline': sale_order.deadline_of_delivery, 'production_id': production.id,
'production_id': production.id, 'date_planned_start': production.date_planned_start,
'date_planned_start': production.date_planned_start, 'origin': production.origin,
'origin': production.origin, 'product_qty': production.product_qty,
'product_qty': production.product_qty, 'product_id': production.product_id.id,
'product_id': production.product_id.id, 'state': 'draft',
'state': 'draft', })
})
return True return True

View File

@@ -17,16 +17,10 @@ class CustomKanbanController extends KanbanController {
this.workOrders = await this.getAllWorkOrders(); this.workOrders = await this.getAllWorkOrders();
// this.workOrdersNew = this.workOrders; // this.workOrdersNew = this.workOrders;
// console.log('lines222222222', this.workOrders); // console.log('lines222222222', this.workOrders);
//
// console.log(typeof this.workOrders); // console.log(typeof this.workOrders);
// console.log(Array.isArray(this.workOrders)); // console.log(Array.isArray(this.workOrders));
//
// console.log(this.workOrders.every(order => // console.log(this.workOrders.every(order =>
// typeof order === 'object' && order.id !== undefined)); // typeof order === 'object' && order.id !== undefined));
// var aDiv = document.getElementsByClassName('o_kanban_record') // var aDiv = document.getElementsByClassName('o_kanban_record')
// for (var i = 0; i < aDiv.length; i++) { // for (var i = 0; i < aDiv.length; i++) {
// console.log(aDiv[i]) // console.log(aDiv[i])
@@ -37,8 +31,7 @@ class CustomKanbanController extends KanbanController {
buttonClick(ev) { buttonClick(ev) {
const button = ev.currentTarget; const button = ev.currentTarget;
const id = button.getAttribute('data-id'); const id = button.getAttribute('data-id');
// console.log('true_id', id);
console.log('true_id', id);
// const context = {production_line_show: 'shengchanxian1'} // const context = {production_line_show: 'shengchanxian1'}
this.env.services.rpc('/web/dataset/call_kw', { this.env.services.rpc('/web/dataset/call_kw', {
model: 'mrp.workcenter', model: 'mrp.workcenter',
@@ -58,8 +51,8 @@ class CustomKanbanController extends KanbanController {
// console.log('response', response); // console.log('response', response);
location.reload(); location.reload();
window.onload = function () { window.onload = function () {
button.classList.add('choose') button.classList.add('choose');
} };
}); });
}); });
} }
@@ -82,8 +75,6 @@ class CustomKanbanController extends KanbanController {
// 你可以在这里处理响应,例如将其存储在控制器的状态中 // 你可以在这里处理响应,例如将其存储在控制器的状态中
return response; return response;
} }
} }
CustomKanbanController.template = "sf_manufacturing.CustomKanbanView1"; CustomKanbanController.template = "sf_manufacturing.CustomKanbanView1";
@@ -94,4 +85,4 @@ export const customKanbanView = {
}; };
// Register it to the views registry // Register it to the views registry
registry.category("views").add("custom_kanban1", customKanbanView); registry.category("views").add("custom_kanban1", customKanbanView);

View File

@@ -16,6 +16,7 @@
'depends': ['sf_manufacturing'], 'depends': ['sf_manufacturing'],
'data': [ 'data': [
'security/ir.model.access.csv', 'security/ir.model.access.csv',
# 'security/rules.xml',
'views/view.xml', 'views/view.xml',
], ],

View File

@@ -11,6 +11,7 @@ from odoo.exceptions import UserError, ValidationError
class sf_production_plan(models.Model): class sf_production_plan(models.Model):
_name = 'sf.production.plan' _name = 'sf.production.plan'
_description = 'sf_production_plan' _description = 'sf_production_plan'
_inherit = ['mail.thread']
_order = 'create_date desc' _order = 'create_date desc'
state = fields.Selection([ state = fields.Selection([
@@ -20,6 +21,7 @@ class sf_production_plan(models.Model):
('finished', '已完成') ('finished', '已完成')
], string='工单状态', tracking=True) ], string='工单状态', tracking=True)
name = fields.Char(string='工单编号') name = fields.Char(string='工单编号')
active = fields.Boolean(string='已归档', default=True)
# selected = fields.Boolean(default=False) # selected = fields.Boolean(default=False)
# order_number = fields.Char(string='订单号') # order_number = fields.Char(string='订单号')
order_deadline = fields.Datetime(string='订单交期') order_deadline = fields.Datetime(string='订单交期')
@@ -49,6 +51,26 @@ class sf_production_plan(models.Model):
sequence = fields.Integer(string='序号', copy=False, readonly=True, index=True) sequence = fields.Integer(string='序号', copy=False, readonly=True, index=True)
current_operation_name = fields.Char(string='当前工序名称', size=64, default='生产计划') current_operation_name = fields.Char(string='当前工序名称', size=64, default='生产计划')
# @api.model
# def _search(self, args, offset=0, limit=None, order=None, count=False, access_rights_uid=None):
# """
# 默认修改筛选
# """
# return super(sf_production_plan, self.with_context(active_test=False))._search(
# args, offset, limit, order, count, access_rights_uid)
def archive(self):
"""
归档
"""
self.write({'active': False})
def unarchive(self):
"""
取消归档
"""
self.write({'active': True})
@api.model @api.model
def get_import_templates(self): def get_import_templates(self):
"""returns the xlsx import template file""" """returns the xlsx import template file"""

View File

@@ -1,8 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_sf_production_plan,sf.production.plan,model_sf_production_plan,base.group_user,1,1,1,1 access_sf_production_plan,sf.production.plan,model_sf_production_plan,base.group_user,1,0,0,0
access_sf_machine_schedule,sf.machine.schedule,model_sf_machine_schedule,base.group_user,1,1,1,1 access_sf_production_plan_for_dispatch,sf.production.plan for dispatch,model_sf_production_plan,sf_base.group_plan_dispatch,1,1,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_sf_production_plan sf.production.plan model_sf_production_plan base.group_user 1 1 0 1 0 1 0
3 access_sf_machine_schedule access_sf_production_plan_for_dispatch sf.machine.schedule sf.production.plan for dispatch model_sf_machine_schedule model_sf_production_plan base.group_user sf_base.group_plan_dispatch 1 1 1 1 0

View File

@@ -0,0 +1,9 @@
<odoo>
<record id="plan_order_rule_own" model="ir.rule">
<field name="name">Own Orders Only</field>
<field name="model_id" ref="model_sf_production_plan"/>
<field name="groups" eval="[(4, ref('sf_base.group_plan_dispatch'))]"/>
<!-- <field name="domain_force">[('user_id', '=', user.id)]</field> -->
<field name="domain_force">[('create_uid', '=', user.id)]</field>
</record>
</odoo>

View File

@@ -6,9 +6,6 @@
<field name="model">sf.production.plan</field> <field name="model">sf.production.plan</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="订单计划"> <tree string="订单计划">
<!-- <field name="selected" widget="boolean_toggle"/> -->
<!-- sequence、pl_no、pl_name、quantity、plan_start_time、plan_end_time、actual_start_time、actual_end_time、state、create_uid、create_date -->
<!-- <field name="sequence"/> -->
<field name="state" widget="badge" decoration-warning="state == 'draft'" decoration-success="state == 'done'"/> <field name="state" widget="badge" decoration-warning="state == 'draft'" decoration-success="state == 'done'"/>
<field name="name"/> <field name="name"/>
<field name="origin"/> <field name="origin"/>
@@ -18,8 +15,8 @@
<field name="date_planned_start"/> <field name="date_planned_start"/>
<field name="date_planned_finished"/> <field name="date_planned_finished"/>
<field name="schedule_setting"/> <field name="schedule_setting"/>
<button name="do_production_schedule" class="btn schedule_done" string="生产排程" type="object" attrs="{'invisible': [('state', 'not in', ['draft'])]}"/> <button name="do_production_schedule" class="btn schedule_done" string="生产排程" type="object" attrs="{'invisible': [('state', 'not in', ['draft'])]}" groups="sf_base.group_plan_dispatch"/>
<button name="cancel_production_schedule" class="btn schedule_cancel" string="取消排程" type="object" attrs="{'invisible': [('state', 'not in', ['done'])]}"/> <button name="cancel_production_schedule" class="btn schedule_cancel" string="取消排程" type="object" attrs="{'invisible': [('state', 'not in', ['done'])]}" groups="sf_base.group_plan_dispatch"/>
</tree> </tree>
</field> </field>
</record> </record>
@@ -31,8 +28,11 @@
<form string="订单计划"> <form string="订单计划">
<header> <header>
<!-- <button string="执行排程" name="do_production_schedule" type="object" class="oe_highlight" icon="fa-step-forward"/> --> <!-- <button string="执行排程" name="do_production_schedule" type="object" class="oe_highlight" icon="fa-step-forward"/> -->
<button string="执行排程" name="do_production_schedule" type="object" class="oe_highlight" options='{"calendar_view": true, "date_begin": "2020-01-01", "date_end": "2020-12-31"}'/> <button string="执行排程" name="do_production_schedule" type="object" class="oe_highlight" options='{"calendar_view": true, "date_begin": "2020-01-01", "date_end": "2020-12-31"}' groups="sf_base.group_plan_dispatch"/>
<button string="取消排程" name="cancel_production_schedule" type="object" class="oe_highlight"/> <button string="取消排程" name="cancel_production_schedule" type="object" class="oe_highlight" groups="sf_base.group_plan_dispatch"/>
<button name="archive" type="object" string="归档" icon="fa-archive" class="oe_highlight" attrs="{'invisible': [('active', '=', False)]}"/>
<button name="unarchive" type="object" string="取消归档" icon="fa-archive" class="oe_highlight" attrs="{'invisible': [('active', '=', True)]}"/>
<!-- <button string="销售单" name="test_sale_order" type="object" class="oe_highlight"/> --> <!-- <button string="销售单" name="test_sale_order" type="object" class="oe_highlight"/> -->
<!-- <button string="测试流程" name="liucheng_cs" type="object" class="oe_highlight"/> --> <!-- <button string="测试流程" name="liucheng_cs" type="object" class="oe_highlight"/> -->
<field name="state" widget="statusbar" statusbar_visible="draft,done,processing,finished"/> <field name="state" widget="statusbar" statusbar_visible="draft,done,processing,finished"/>
@@ -45,6 +45,7 @@
</div> </div>
<group> <group>
<group string="基本信息"> <group string="基本信息">
<field name="active" invisible="1"/>
<field name="production_id" widget="many2one_button"/> <field name="production_id" widget="many2one_button"/>
<field name="product_id"/> <field name="product_id"/>
<field name="origin"/> <field name="origin"/>
@@ -60,6 +61,17 @@
<field name="actual_end_time"/> <field name="actual_end_time"/>
<field name="state"/> <field name="state"/>
<field name="shift" widget="time"/> <field name="shift" widget="time"/>
<!-- Chatter -->
<!-- <div class="oe_chatter"> -->
<!-- <field name="message_follower_ids" widget="mail_followers"/> -->
<!-- <field name="message_ids" widget="mail_thread"/> -->
<!-- <field name="activity_ids"/> -->
<!-- </div> -->
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="message_ids"/>
</div>
</group> </group>
<!-- <group string="规格信息" col="1"> --> <!-- <group string="规格信息" col="1"> -->
<!-- <group col="3"> --> <!-- <group col="3"> -->
@@ -104,6 +116,9 @@
<field name="model">sf.production.plan</field> <field name="model">sf.production.plan</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="订单计划"> <search string="订单计划">
<!-- Your other filters go here -->
<filter name="archived" string="已归档" domain="[('active','=',False)]"/>
<filter name="not archived" string="未归档" domain="[('active','=',True)]"/>
<field name="name"/> <field name="name"/>
<field name="product_qty"/> <field name="product_qty"/>
<field name="date_planned_start"/> <field name="date_planned_start"/>
@@ -261,6 +276,7 @@
name="计划" name="计划"
sequence="150" sequence="150"
action="sf_production_plan_action" action="sf_production_plan_action"
groups="sf_base.group_plan_dispatch"
/> />
<!-- <record model="ir.ui.menu" id="mrp_custom_menu" inherit_id="mrp.menu_mrp_manufacturing"> --> <!-- <record model="ir.ui.menu" id="mrp_custom_menu" inherit_id="mrp.menu_mrp_manufacturing"> -->

View File

@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from odoo import models, fields, api, _ from odoo import models, fields
class SfQualityPoint(models.Model): class SfQualityPoint(models.Model):

View File

@@ -2,7 +2,7 @@
import logging import logging
from odoo.modules import get_resource_path from odoo.modules import get_resource_path
from odoo import fields, models, api from odoo import fields, models, api
# from quatotion import readSql, feature_recognize, auto_quatotion from quatotion import readSql, feature_recognize, auto_quatotion
__author__ = 'jinling.yang' __author__ = 'jinling.yang'
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@@ -24,14 +24,14 @@ class AutoQuatotion(models.Model):
def get_process_time_db_path(self): def get_process_time_db_path(self):
return get_resource_path('sf_sale', 'models', 'process_time.db') return get_resource_path('sf_sale', 'models', 'process_time.db')
# def get_auto_quatotion(self, stp_url, feature_full_path, process_time_db_path, model_code): def get_auto_quatotion(self, stp_url, feature_full_path, process_time_db_path, model_code):
# ''' '''
# 通过打包好的.so库 通过打包好的.so库
# 以调用autoQuatotion库中Quatotion类 以调用autoQuatotion库中Quatotion类
# 初始化后调用类的analyseShape方法对模型文件进行价格预测 初始化后调用类的analyseShape方法对模型文件进行价格预测
# ''' '''
# # 初始化自动报价类(输入特征数据库和加工时间数据库) # 初始化自动报价类(输入特征数据库和加工时间数据库)
# reader = auto_quatotion.Quatotion(feature_full_path, process_time_db_path) reader = auto_quatotion.Quatotion(feature_full_path, process_time_db_path)
# # 获取价格、加工时间、尺寸、XYZ、翻面次数 # 获取价格、加工时间、尺寸、XYZ、翻面次数
# feature_info = reader.analyseShape(stp_url, InfoJson={}) feature_info = reader.analyseShape(stp_url, InfoJson={})
# return feature_info return feature_info

View File

@@ -10,12 +10,10 @@
""", """,
'category': 'sf', 'category': 'sf',
'website': 'https://www.sf.jikimo.com', 'website': 'https://www.sf.jikimo.com',
'depends': ['sf_base', 'sf_manufacturing'], 'depends': ['sf_manufacturing'],
'data': [ 'data': [
# 'security/group_security.xml', 'security/group_security.xml',
'security/ir.model.access.csv', 'security/ir.model.access.csv',
# 'views/tool_base_views.xml',
# # 'views/menu_view.xml',
'wizard/wizard_view.xml', 'wizard/wizard_view.xml',
'views/tool_base_views.xml', 'views/tool_base_views.xml',
'views/menu_view.xml', 'views/menu_view.xml',

View File

@@ -6,11 +6,6 @@ from odoo import SUPERUSER_ID
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
# class FunctionalCuttingToolEntity(models.Model):
# _name = 'sf.functional.cutting.tool.entity'
# _inherit = 'sf.functional.cutting.tool'
# _inherits = {'sf.functional.cutting.tool': 'sf_functional_cutting_tool_entity_id'}
# _description = '功能刀具管理'
class FunctionalCuttingToolEntity(models.Model): class FunctionalCuttingToolEntity(models.Model):
_name = 'sf.functional.cutting.tool.entity' _name = 'sf.functional.cutting.tool.entity'
_description = '功能刀具列表' _description = '功能刀具列表'
@@ -30,7 +25,7 @@ class FunctionalCuttingToolEntity(models.Model):
tool_loading_length = fields.Float(string='装刀长(mm)', readonly=True) tool_loading_length = fields.Float(string='装刀长(mm)', readonly=True)
functional_tool_length = fields.Float(string='伸出长(mm)', readonly=True) functional_tool_length = fields.Float(string='伸出长(mm)', readonly=True)
effective_length = fields.Float(string='有效长(mm)', readonly=True) effective_length = fields.Float(string='有效长(mm)', readonly=True)
tool_room_num = fields.Integer(string='刀具房数量', readonly=True, ) tool_room_num = fields.Integer(string='刀具房数量', readonly=True)
line_edge_knife_library_num = fields.Integer(string='线边刀库数量', readonly=True) line_edge_knife_library_num = fields.Integer(string='线边刀库数量', readonly=True)
machine_knife_library_num = fields.Integer(string='机内刀库数量', readonly=True) machine_knife_library_num = fields.Integer(string='机内刀库数量', readonly=True)
max_lifetime_value = fields.Integer(string='最大寿命值(min)', readonly=True) max_lifetime_value = fields.Integer(string='最大寿命值(min)', readonly=True)
@@ -41,16 +36,16 @@ class FunctionalCuttingToolEntity(models.Model):
current_location_id = fields.Many2one('stock.location', string='当前位置', readonly=True) current_location_id = fields.Many2one('stock.location', string='当前位置', readonly=True)
image = fields.Binary('图片', readonly=True) image = fields.Binary('图片', readonly=True)
@api.depends('current_location_id') # @api.depends('current_location_id')
def _compute_location_num(self): # def _compute_location_num(self):
""" # """
计算库存位置数量 # 计算库存位置数量
""" # """
for obj in self: # for obj in self:
if obj.current_location_id.name in ('组装后', '刀具房'): # if obj.current_location_id.name in ('组装后', '刀具房'):
obj.tool_room_num = 1 # obj.tool_room_num = 1
obj.line_edge_knife_library_num = 0 # obj.line_edge_knife_library_num = 0
obj.machine_knife_library_num = 0 # obj.machine_knife_library_num = 0
@api.model @api.model
def _read_group_mrs_cutting_tool_type_id(self, categories, domain, order): def _read_group_mrs_cutting_tool_type_id(self, categories, domain, order):
@@ -117,6 +112,14 @@ class FunctionalCuttingToolEntity(models.Model):
result['domain'] = [('lot_id', '=', self.barcode_id.id), ('qty_done', '>', 0)] result['domain'] = [('lot_id', '=', self.barcode_id.id), ('qty_done', '>', 0)]
return result return result
def open_safety_stock(self):
action = self.env.ref('sf_tool_management.sf_real_time_distribution_of_functional_tools_view_act')
result = action.read()[0]
result['domain'] = [('name', '=', self.name), ('diameter', '=', self.functional_tool_diameter),
('knife_tip_r_angle', '=', self.knife_tip_r_angle),
('coarse_middle_thin', '=', self.coarse_middle_thin)]
return result
class FunctionalToolWarning(models.Model): class FunctionalToolWarning(models.Model):
_name = 'sf.functional.tool.warning' _name = 'sf.functional.tool.warning'
@@ -177,113 +180,74 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
_name = 'sf.real.time.distribution.of.functional.tools' _name = 'sf.real.time.distribution.of.functional.tools'
_description = '功能刀具安全库存' _description = '功能刀具安全库存'
functional_cutting_tool_id = fields.Many2one('sf.functional.cutting.tool.entity', '功能刀具', readonly=True) name = fields.Char('功能刀具名称')
mrs_cutting_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', readonly=True, sf_cutting_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型',
group_expand='_read_mrs_cutting_tool_type_ids', group_expand='_read_mrs_cutting_tool_type_ids', store=True)
store=True, diameter = fields.Integer(string='刀具直径(mm)')
compute='_compute_functional_cutting_tool_ids') knife_tip_r_angle = fields.Float(string='刀尖R角(mm)')
tool_stock_num = fields.Integer(string='刀具房数量')
side_shelf_num = fields.Integer(string='线边刀库数量')
on_tool_stock_num = fields.Integer(string='机内刀库数量')
tool_stock_total = fields.Integer(string='当前库存量', readonly=True, compute='_compute_tool_stock_total')
min_stock_num = fields.Integer('最低库存量')
max_stock_num = fields.Integer('最高库存量')
batch_replenishment_num = fields.Integer('批次补货量')
unit = fields.Char('单位')
image = fields.Binary('图片')
coarse_middle_thin = fields.Selection([("1", ""), ('2', ''), ('3', '')], string='粗/中/精')
whether_standard_knife = fields.Boolean(string='是否标准刀', default=True)
# 能力特征信息
suitable_machining_method_ids = fields.Many2many(
'maintenance.equipment.image', 'rel_machining_product_template_distribution', '适合加工方式',
domain=[('type', '=', '加工能力')],
related='sf_functional_cutting_tool_entity_ids.suitable_machining_method_ids')
blade_tip_characteristics_id = fields.Many2many(
'maintenance.equipment.image', 'rel_blade_tip_product_template_distribution', '刀尖特征',
domain=[('type', '=', '刀尖特征')],
related='sf_functional_cutting_tool_entity_ids.blade_tip_characteristics_id')
handle_type_ids = fields.Many2many(
'maintenance.equipment.image', 'rel_handle_product_template_distribution', '柄部类型',
domain=[('type', '=', '柄部类型')], related='sf_functional_cutting_tool_entity_ids.handle_type_ids')
cutting_direction_ids = fields.Many2many(
'maintenance.equipment.image', 'rel_cutting_product_template_distribution', '走刀方向',
domain=[('type', '=', '走刀方向')], related='sf_functional_cutting_tool_entity_ids.cutting_direction_ids')
suitable_coolant_ids = fields.Many2many(
'maintenance.equipment.image', 'rel_coolant_product_template_distribution', '适合冷却液',
domain=[('type', '=', '冷却液')], related='sf_functional_cutting_tool_entity_ids.suitable_coolant_ids')
sf_functional_cutting_tool_entity_ids = fields.Many2many('sf.functional.cutting.tool.entity',
'sf_functional_cutting_tool_entity_ref',
string='功能刀具列表信息', readonly=True)
@api.model @api.model
def _read_mrs_cutting_tool_type_ids(self, categories, domain, order): def _read_mrs_cutting_tool_type_ids(self, categories, domain, order):
mrs_cutting_tool_type_ids = categories._search([], order=order, access_rights_uid=SUPERUSER_ID) mrs_cutting_tool_type_ids = categories._search([], order=order, access_rights_uid=SUPERUSER_ID)
return categories.browse(mrs_cutting_tool_type_ids) return categories.browse(mrs_cutting_tool_type_ids)
@api.depends('functional_cutting_tool_id')
def _compute_functional_cutting_tool_ids(self):
for record in self:
if record:
record.mrs_cutting_tool_type_id = record.functional_cutting_tool_id.mrs_cutting_tool_type_id.id
barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号', readonly=True)
name = fields.Char('名称', invisible=True, readonly=True)
functional_tool_name_id = fields.Many2one('product.product', string='功能刀具名称', readonly=True)
# 整体式刀具型号
cutting_tool_integral_model_id = fields.Many2one(
'product.product', string='整体式刀具型号', readonly=True,
domain=[('cutting_tool_material_id', '=', '整体式刀具')],
related='functional_cutting_tool_id.cutting_tool_integral_model_id')
# 刀片型号
cutting_tool_blade_model_id = fields.Many2one(
'product.product', string='刀片型号', readonly=True,
domain=[('cutting_tool_material_id', '=', '刀片')],
related='functional_cutting_tool_id.cutting_tool_blade_model_id')
# 刀杆型号
cutting_tool_cutterbar_model_id = fields.Many2one(
'product.product', string='刀杆型号', readonly=True,
domain=[('cutting_tool_material_id', '=', '刀杆')],
related='functional_cutting_tool_id.cutting_tool_cutterbar_model_id')
# 刀盘型号
cutting_tool_cutterpad_model_id = fields.Many2one(
'product.product', string='刀盘型号', readonly=True,
domain=[('cutting_tool_material_id', '=', '刀盘')],
related='functional_cutting_tool_id.cutting_tool_cutterpad_model_id')
# 刀柄型号
cutting_tool_cutterhandle_model_id = fields.Many2one(
'product.product', string='刀柄型号', readonly=True,
domain=[('cutting_tool_material_id', '=', '刀柄')],
related='functional_cutting_tool_id.cutting_tool_cutterhandle_model_id')
# 夹头型号
cutting_tool_cutterhead_model_id = fields.Many2one(
'product.product', string='夹头型号', readonly=True,
domain=[('cutting_tool_material_id', '=', '夹头')],
related='functional_cutting_tool_id.cutting_tool_cutterhead_model_id')
diameter = fields.Float('直径(mm)', readonly=True)
tool_grade = fields.Selection([('1', 'P1'), ('2', 'P2'), ('3', 'P3'), ('4', 'P4'), ('5', 'P5'), ('6', 'P6')],
string='刀具等级', readonly=True)
machining_accuracy = fields.Float('加工精度(mm)', readonly=True)
tool_length = fields.Float('装刀长(mm)', readonly=True)
blade_number = fields.Integer('刃数', readonly=True)
integral_blade_length = fields.Float('整体刃长(mm)', readonly=True)
effective_blade_length = fields.Float('有效刃长(mm)', readonly=True)
max_life = fields.Float('最大寿命值', readonly=True)
is_standard = fields.Selection([('1', ''), ('0', '')], '是否标准刀', readonly=True,
compute='_compute_functional_cutting_tool_id')
applicable_range = fields.Char('适用范围', readonly=True)
image = fields.Binary('图片', readonly=True)
@api.depends('functional_cutting_tool_id')
def _compute_functional_cutting_tool_id(self):
if self.functional_cutting_tool_id:
self.tool_grade = self.functional_cutting_tool_id.tool_grade
self.is_standard = self.functional_cutting_tool_id.is_standard
# 功能刀具实时分布
tool_stock_num = fields.Integer(string='刀具房库存数量', readonly=False)
side_shelf_num = fields.Integer(string='线边货架货架数量', readonly=False)
on_tool_stock_num = fields.Integer(string='机内刀库库存数量', readonly=False)
tool_stock_total = fields.Integer(string='合计(库存)', readonly=True, compute='_compute_tool_stock_total')
return_reuse_num_re = fields.Integer(string='归还再用数量(精)', readonly=False)
return_reuse_num_co = fields.Integer(string='归还再用数量(粗)', readonly=False)
return_processing_num = fields.Integer(string='归还需磨削数量', readonly=False)
return_total = fields.Integer(string='合计(归还)', readonly=True, compute='_compute_return_total')
total = fields.Integer(string='总计', readonly=True, compute='_compute_total')
remark = fields.Char(string='备注/说明', readonly=False)
@api.depends('tool_stock_num', 'side_shelf_num', 'on_tool_stock_num') @api.depends('tool_stock_num', 'side_shelf_num', 'on_tool_stock_num')
def _compute_tool_stock_total(self): def _compute_tool_stock_total(self):
for record in self: for record in self:
if record: if record:
self.tool_stock_total = record.tool_stock_num + record.side_shelf_num + record.on_tool_stock_num self.tool_stock_total = record.tool_stock_num + record.side_shelf_num + record.on_tool_stock_num
@api.depends('return_reuse_num_re', 'return_reuse_num_co', 'return_processing_num') def create_or_edit_safety_stock(self, vals, sf_functional_cutting_tool_entity_ids):
def _compute_return_total(self): """
for record in self: 根据传入的信息新增或者更新功能刀具安全库存的信息
if record: """
self.return_total = (record.return_reuse_num_re + record.return_reuse_num_co + print(vals)
record.return_processing_num) # 根据功能刀具名称、直径或尖刀R角、粗/中/精查询该功能刀具是否已经存在
record = self.env['sf.real.time.distribution.of.functional.tools'].search(
@api.depends('tool_stock_total', 'return_total') [('name', '=', vals['name']), ('sf_cutting_tool_type_id', '=', vals['sf_cutting_tool_type_id']),
def _compute_total(self): ('diameter', '=', vals['diameter']), ('knife_tip_r_angle', '=', vals['knife_tip_r_angle']),
for record in self: ('coarse_middle_thin', '=', vals['coarse_middle_thin'])])
if record: print(record)
self.total = record.tool_stock_total + record.return_total if len(record) > 0:
for obj in record:
obj.write({'sf_functional_cutting_tool_entity_ids': [(4, sf_functional_cutting_tool_entity_ids.id)]})
else:
vals['sf_functional_cutting_tool_entity_ids'] = sf_functional_cutting_tool_entity_ids.ids
self.env['sf.real.time.distribution.of.functional.tools'].create(vals)
class MachineTableToolChangingApply(models.Model): class MachineTableToolChangingApply(models.Model):
@@ -292,6 +256,7 @@ class MachineTableToolChangingApply(models.Model):
_order = 'cutter_spacing_code_id' _order = 'cutter_spacing_code_id'
name = fields.Char('名称', related='maintenance_equipment_id.name', store=True) name = fields.Char('名称', related='maintenance_equipment_id.name', store=True)
# 设备信息
maintenance_equipment_id = fields.Many2one('maintenance.equipment', string='CNC机床', required=True, readonly=False, maintenance_equipment_id = fields.Many2one('maintenance.equipment', string='CNC机床', required=True, readonly=False,
domain=[('category_id.equipment_type', '=', '机床')]) domain=[('category_id.equipment_type', '=', '机床')])
production_line_id = fields.Many2one('sf.production.line', string='生产线', readonly=True, production_line_id = fields.Many2one('sf.production.line', string='生产线', readonly=True,
@@ -301,6 +266,7 @@ class MachineTableToolChangingApply(models.Model):
machine_tool_code = fields.Char(string='机台号', store=True, invisible=True, readonly=True) machine_tool_code = fields.Char(string='机台号', store=True, invisible=True, readonly=True)
cutter_spacing_code_id = fields.Many2one('maintenance.equipment.tool', string='刀位号', readonly=False, cutter_spacing_code_id = fields.Many2one('maintenance.equipment.tool', string='刀位号', readonly=False,
required=True, domain="[('equipment_id', '=', maintenance_equipment_id)]") required=True, domain="[('equipment_id', '=', maintenance_equipment_id)]")
# 功能刀具信息
functional_tool_name = fields.Char(string='刀具名称', related='functional_tool_name_id.name', store=True) functional_tool_name = fields.Char(string='刀具名称', related='functional_tool_name_id.name', store=True)
barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号', store=True, barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号', store=True,
domain=[('product_id.name', '=', '功能刀具')], domain=[('product_id.name', '=', '功能刀具')],
@@ -406,20 +372,7 @@ class MachineTableToolChangingApply(models.Model):
machine_table_tool_changing_apply.write( machine_table_tool_changing_apply.write(
{'status': '1', {'status': '1',
'sf_functional_tool_assembly_id': sf_functional_tool_assembly}) 'sf_functional_tool_assembly_id': sf_functional_tool_assembly.id})
# def new_assembly_task(self, vals):
# """
# 新建组装任务
# :param vals:
# :return:
# """
# # 增加设置直径的值
# tool_changing_apply = self.env['sf.machine.table.tool.changing.apply'].search(
# [('name', '=', vals['name'])])
# vals['functional_tool_diameter'] = tool_changing_apply.diameter
#
# self.env['sf.functional.tool.assembly'].create(vals)
def revocation_1(self): def revocation_1(self):
""" """
@@ -537,7 +490,7 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
class FunctionalToolAssembly(models.Model): class FunctionalToolAssembly(models.Model):
_name = 'sf.functional.tool.assembly' _name = 'sf.functional.tool.assembly'
_description = '功能刀具组装' _description = '功能刀具组装'
_order = 'use_tool_time asc' _order = 'use_tool_time asc'
@api.depends('functional_tool_name') @api.depends('functional_tool_name')

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from odoo import fields, models, api, SUPERUSER_ID from odoo import fields, models, api, SUPERUSER_ID
from odoo.exceptions import ValidationError # from odoo.exceptions import ValidationError
# 刀具物料搜索 # 刀具物料搜索

View File

@@ -61,6 +61,16 @@
</span> </span>
</div> </div>
</button> </button>
<button class="oe_stat_button"
name="open_safety_stock"
icon="fa-list-ul"
type="object">
<div class="o_field_widget o_stat_info">
<span>
安全库存
</span>
</div>
</button>
</div> </div>
<div class="oe_title"> <div class="oe_title">
<h1> <h1>
@@ -264,126 +274,96 @@
</record> </record>
<!-- =====================================功能刀具实时分布============================================================= --> <!-- =====================================功能刀具安全库存=================================================== -->
<record id="sf_real_time_distribution_of_functional_tools_view_tree" model="ir.ui.view"> <record id="sf_real_time_distribution_of_functional_tools_view_tree" model="ir.ui.view">
<field name="name">功能刀具实时分布</field> <field name="name">功能刀具安全库存</field>
<field name="model">sf.real.time.distribution.of.functional.tools</field> <field name="model">sf.real.time.distribution.of.functional.tools</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree create="0" edit="0" delete="0"> <tree create="0" edit="0" delete="0">
<field name="barcode_id"/> <field name="name"/>
<field name="functional_tool_name_id"/> <field name="sf_cutting_tool_type_id" invisible="True"/>
<field name="mrs_cutting_tool_type_id"/> <field name="diameter"/>
<field name="cutting_tool_integral_model_id" optional="hide"/> <field name="knife_tip_r_angle"/>
<field name="cutting_tool_blade_model_id" optional="hide"/> <field name="coarse_middle_thin"/>
<field name="cutting_tool_cutterbar_model_id" optional="hide"/>
<field name="cutting_tool_cutterpad_model_id" optional="hide"/>
<field name="cutting_tool_cutterhandle_model_id" optional="hide"/>
<field name="cutting_tool_cutterhead_model_id" optional="hide"/>
<field name="tool_stock_num"/> <field name="tool_stock_num"/>
<field name="side_shelf_num"/> <field name="side_shelf_num"/>
<field name="on_tool_stock_num"/> <field name="on_tool_stock_num"/>
<field name="tool_stock_total"/> <field name="tool_stock_total"/>
<field name="return_reuse_num_re" optional="hide"/> <field name="min_stock_num"/>
<field name="return_reuse_num_co" optional="hide"/> <field name="max_stock_num"/>
<field name="return_processing_num" optional="hide"/> <field name="batch_replenishment_num"/>
<field name="return_total" optional="hide"/> <field name="unit"/>
<field name="total" optional="hide"/>
<field name="remark"/>
</tree> </tree>
</field> </field>
</record> </record>
<record id="sf_real_time_distribution_of_functional_tools_view_form" model="ir.ui.view"> <record id="sf_real_time_distribution_of_functional_tools_view_form" model="ir.ui.view">
<field name="name">功能刀具实时分布</field> <field name="name">功能刀具安全库存</field>
<field name="model">sf.real.time.distribution.of.functional.tools</field> <field name="model">sf.real.time.distribution.of.functional.tools</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form create="0" edit="0" delete="0"> <form create="0" edit="0" delete="0">
<sheet> <sheet>
<div class="oe_title"> <div class="oe_title">
<h1> <h1>
<field name="barcode_id" readonly="1"/> <field name="name"/>
</h1> </h1>
</div> </div>
<group> <group>
<group> <group>
<field name="functional_tool_name_id" invisible="False"/> <field name="sf_cutting_tool_type_id"/>
<field name="mrs_cutting_tool_type_id"/> <field name="diameter"/>
<field name="knife_tip_r_angle"/>
<field name="cutting_tool_integral_model_id" <field name="coarse_middle_thin"/>
options="{'no_create': True, 'no_quick_create': True}" <field name="whether_standard_knife"/>
attrs="{'invisible': [('cutting_tool_blade_model_id', '!=', False)]}"
/>
<field name="cutting_tool_blade_model_id"
options="{'no_create': True, 'no_quick_create': True}"
attrs="{'invisible': [('cutting_tool_integral_model_id', '!=', False)]}"
/>
<field name="cutting_tool_cutterbar_model_id"
options="{'no_create': True, 'no_quick_create': True}"
attrs="{'invisible': ['|',('cutting_tool_cutterpad_model_id','!=',False),('cutting_tool_blade_model_id', '=', False)]}"
/>
<field name="cutting_tool_cutterpad_model_id"
options="{'no_create': True, 'no_quick_create': True}"
attrs="{'invisible': ['|',('cutting_tool_cutterbar_model_id','!=',False),('cutting_tool_blade_model_id', '=', False)]}"
/>
<field name="cutting_tool_cutterhandle_model_id"
options="{'no_create': True, 'no_quick_create': True}"/>
<field name="cutting_tool_cutterhead_model_id"
options="{'no_create': True, 'no_quick_create': True}"/>
</group> </group>
<group> <group>
<field name="image" nolabel="1" widget="image"/> <field name="image" widget='image'/>
</group>
</group>
<group col="1">
<group string="适合加工方式">
<field name="suitable_machining_method_ids" string=""
widget="custom_many2many_checkboxes"
domain="[('id','in',suitable_machining_method_ids)]"/>
</group>
<group>
<group string="刀尖特征">
<field name="blade_tip_characteristics_id" string=""
widget="custom_many2many_checkboxes"
domain="[('id','in',blade_tip_characteristics_id)]"/>
</group>
<group string="柄部类型">
<field name="handle_type_ids" string="" widget="custom_many2many_checkboxes"
domain="[('id','in',handle_type_ids)]"/>
</group>
</group>
<group>
<group string="走刀方向">
<field name="cutting_direction_ids" string="" widget="custom_many2many_checkboxes"
domain="[('id','in',cutting_direction_ids)]"/>
</group>
<group string="适合冷却液">
<field name="suitable_coolant_ids" string="" widget="custom_many2many_checkboxes"
domain="[('id','in',suitable_coolant_ids)]"/>
</group>
</group> </group>
</group> </group>
<notebook> <notebook>
<page string="实时分布信息"> <page string="刀具信息">
<group> <field name="sf_functional_cutting_tool_entity_ids" widget="many2many">
<group> <tree>
<group> <field name="barcode_id"/>
<field name="tool_stock_num"/> <field name="functional_tool_name_id"/>
<field name="return_reuse_num_re"/> <field name="new_former"/>
</group> <field name="tool_loading_length"/>
<group> <field name="functional_tool_length"/>
<field name="side_shelf_num"/> <field name="effective_length"/>
<field name="return_reuse_num_co"/> <field name="max_lifetime_value"/>
</group> <field name="alarm_value"/>
</group> <field name="used_value"/>
<group> <field name="functional_tool_status"/>
<group> </tree>
<field name="on_tool_stock_num"/> </field>
<field name="return_processing_num"/>
</group>
<group>
<field name="tool_stock_total"/>
<field name="return_total"/>
<field name="total"/>
</group>
</group>
</group>
</page>
<page string="参数信息">
<group>
<group>
<field name="diameter"/>
<field name="tool_grade"/>
<field name="machining_accuracy"/>
<field name="tool_length"/>
<field name="blade_number"/>
</group>
<group>
<field name="integral_blade_length"/>
<field name="effective_blade_length"/>
<field name="max_life"/>
<field name="is_standard" default="false"/>
<field name="applicable_range"/>
</group>
</group>
</page>
<page string="其他信息">
<group>
<field name="remark"/>
</group>
</page> </page>
</notebook> </notebook>
</sheet> </sheet>
@@ -392,28 +372,31 @@
</record> </record>
<record id="sf_real_time_distribution_of_functional_tools_view_search" model="ir.ui.view"> <record id="sf_real_time_distribution_of_functional_tools_view_search" model="ir.ui.view">
<field name="name">功能刀具实时分布</field> <field name="name">功能刀具安全库存</field>
<field name="model">sf.real.time.distribution.of.functional.tools</field> <field name="model">sf.real.time.distribution.of.functional.tools</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search> <search>
<field name="barcode_id"/> <field name="name"/>
<field name="functional_tool_name_id"/> <field name="sf_cutting_tool_type_id" invisible="True"/>
<field name="mrs_cutting_tool_type_id"/> <field name="diameter"/>
<field name="cutting_tool_integral_model_id" optional="hide"/> <field name="knife_tip_r_angle"/>
<field name="cutting_tool_blade_model_id" optional="hide"/> <field name="tool_stock_num"/>
<field name="cutting_tool_cutterbar_model_id" optional="hide"/> <field name="side_shelf_num"/>
<field name="cutting_tool_cutterpad_model_id" optional="hide"/> <field name="on_tool_stock_num"/>
<field name="cutting_tool_cutterhandle_model_id" optional="hide"/> <field name="tool_stock_total"/>
<field name="cutting_tool_cutterhead_model_id" optional="hide"/> <field name="min_stock_num"/>
<field name="max_stock_num"/>
<field name="batch_replenishment_num"/>
<field name="unit"/>
<searchpanel> <searchpanel>
<field name="mrs_cutting_tool_type_id" enable_counters="1" icon="fa-building"/> <field name="sf_cutting_tool_type_id" enable_counters="1" icon="fa-building"/>
</searchpanel> </searchpanel>
</search> </search>
</field> </field>
</record> </record>
<record id="sf_real_time_distribution_of_functional_tools_view_act" model="ir.actions.act_window"> <record id="sf_real_time_distribution_of_functional_tools_view_act" model="ir.actions.act_window">
<field name="name">功能刀具实时分布</field> <field name="name">功能刀具安全库存</field>
<field name="type">ir.actions.act_window</field> <field name="type">ir.actions.act_window</field>
<field name="res_model">sf.real.time.distribution.of.functional.tools</field> <field name="res_model">sf.real.time.distribution.of.functional.tools</field>
<field name="view_mode">tree,form,search</field> <field name="view_mode">tree,form,search</field>

View File

@@ -57,12 +57,10 @@ class ToolChangeRequirementInformation(models.TransientModel):
确认换刀申请(按键) 确认换刀申请(按键)
:return: :return:
""" """
print('已运行')
record = self.env['sf.machine.table.tool.changing.apply'].search( record = self.env['sf.machine.table.tool.changing.apply'].search(
[('maintenance_equipment_id', '=', self.maintenance_equipment_id.id), [('maintenance_equipment_id', '=', self.maintenance_equipment_id.id),
('cutter_spacing_code_id', '=', self.cutter_spacing_code_id.id) ('cutter_spacing_code_id', '=', self.cutter_spacing_code_id.id)
]) ])
print('运行record_1')
# 功能刀具组装创建新任务(new_assembly_task) # 功能刀具组装创建新任务(new_assembly_task)
sf_functional_tool_assembly = self.env['sf.functional.tool.assembly'].sudo().create({ sf_functional_tool_assembly = self.env['sf.functional.tool.assembly'].sudo().create({
@@ -86,13 +84,11 @@ class ToolChangeRequirementInformation(models.TransientModel):
'reason_for_applying': self.reason_for_applying, 'reason_for_applying': self.reason_for_applying,
'sf_machine_table_tool_changing_apply_id': record.id 'sf_machine_table_tool_changing_apply_id': record.id
}) })
print('sf_functional_tool_assembly:', sf_functional_tool_assembly)
# 修改机床换刀申请状态 # 修改机床换刀申请状态
record.write({ record.write({
'status': '1', 'status': '1',
'sf_functional_tool_assembly_id': sf_functional_tool_assembly 'sf_functional_tool_assembly_id': sf_functional_tool_assembly.id
}) })
print('运行成功')
# 关闭弹出窗口 # 关闭弹出窗口
return {'type': 'ir.actions.act_window_close'} return {'type': 'ir.actions.act_window_close'}
@@ -186,7 +182,9 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
# 功能刀具组装信息 # 功能刀具组装信息
# 整体式刀具型号 # 整体式刀具型号
integral_code_id = fields.Many2one('stock.lot', string='整体式刀具序列号', integral_code_id = fields.Many2one('stock.lot', string='整体式刀具序列号',
domain=[('product_id.cutting_tool_material_id.name', '=', '整体式刀具')]) domain=[('product_id.cutting_tool_material_id.name', '=', '整体式刀具'),
('quant_ids.location_id.name', 'in', ['刀具房']),
('quant_ids.quantity', '>', 0)])
cutting_tool_integral_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='整体式刀具型号', cutting_tool_integral_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='整体式刀具型号',
readonly=True) readonly=True)
integral_name = fields.Char('整体式刀具名称', readonly=True) integral_name = fields.Char('整体式刀具名称', readonly=True)
@@ -194,14 +192,18 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
# 刀片型号 # 刀片型号
blade_code_id = fields.Many2one('stock.lot', '刀片序列号', blade_code_id = fields.Many2one('stock.lot', '刀片序列号',
domain=[('product_id.cutting_tool_material_id.name', '=', '刀片')]) domain=[('product_id.cutting_tool_material_id.name', '=', '刀片'),
('quant_ids.location_id.name', 'in', ['刀具房']),
('quant_ids.quantity', '>', 0)])
cutting_tool_blade_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀片型号', readonly=True) cutting_tool_blade_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀片型号', readonly=True)
blade_name = fields.Char('刀片名称', readonly=True) blade_name = fields.Char('刀片名称', readonly=True)
sf_tool_brand_id_2 = fields.Many2one('sf.machine.brand', '刀片品牌', readonly=True) sf_tool_brand_id_2 = fields.Many2one('sf.machine.brand', '刀片品牌', readonly=True)
# 刀杆型号 # 刀杆型号
bar_code_id = fields.Many2one('stock.lot', '刀杆序列号', bar_code_id = fields.Many2one('stock.lot', '刀杆序列号',
domain=[('product_id.cutting_tool_material_id.name', '=', '刀杆')]) domain=[('product_id.cutting_tool_material_id.name', '=', '刀杆'),
('quant_ids.location_id.name', 'in', ['刀具房']),
('quant_ids.quantity', '>', 0)])
cutting_tool_cutterbar_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀杆型号', cutting_tool_cutterbar_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀杆型号',
readonly=True) readonly=True)
bar_name = fields.Char('刀杆名称', readonly=True) bar_name = fields.Char('刀杆名称', readonly=True)
@@ -209,7 +211,9 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
# 刀盘型号 # 刀盘型号
pad_code_id = fields.Many2one('stock.lot', '刀盘序列号', pad_code_id = fields.Many2one('stock.lot', '刀盘序列号',
domain=[('product_id.cutting_tool_material_id.name', '=', '刀盘')]) domain=[('product_id.cutting_tool_material_id.name', '=', '刀盘'),
('quant_ids.location_id.name', 'in', ['刀具房']),
('quant_ids.quantity', '>', 0)])
cutting_tool_cutterpad_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀盘型号', cutting_tool_cutterpad_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀盘型号',
readonly=True) readonly=True)
pad_name = fields.Char('刀盘名称', readonly=True) pad_name = fields.Char('刀盘名称', readonly=True)
@@ -217,7 +221,9 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
# 刀柄型号 # 刀柄型号
handle_code_id = fields.Many2one('stock.lot', '刀柄序列号', required=True, handle_code_id = fields.Many2one('stock.lot', '刀柄序列号', required=True,
domain=[('product_id.cutting_tool_material_id.name', '=', '刀柄')]) domain=[('product_id.cutting_tool_material_id.name', '=', '刀柄'),
('quant_ids.location_id.name', 'in', ['刀具房']),
('quant_ids.quantity', '>', 0)])
cutting_tool_cutterhandle_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀柄型号', cutting_tool_cutterhandle_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀柄型号',
readonly=True) readonly=True)
handle_name = fields.Char('刀柄名称', readonly=True) handle_name = fields.Char('刀柄名称', readonly=True)
@@ -225,7 +231,9 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
# 夹头型号 # 夹头型号
chuck_code_id = fields.Many2one('stock.lot', '夹头序列号', required=True, chuck_code_id = fields.Many2one('stock.lot', '夹头序列号', required=True,
domain=[('product_id.cutting_tool_material_id.name', '=', '夹头')]) domain=[('product_id.cutting_tool_material_id.name', '=', '夹头'),
('quant_ids.location_id.name', 'in', ['刀具房']),
('quant_ids.quantity', '>', 0)])
cutting_tool_cutterhead_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='夹头型号', cutting_tool_cutterhead_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='夹头型号',
readonly=True) readonly=True)
chuck_name = fields.Char('夹头名称', readonly=True, compute='_compute_auto_fill') chuck_name = fields.Char('夹头名称', readonly=True, compute='_compute_auto_fill')
@@ -339,6 +347,7 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
功能刀具组装 功能刀具组装
:return: :return:
""" """
# 获取组装单对象
functional_tool_assembly = self.env['sf.functional.tool.assembly'].search([ functional_tool_assembly = self.env['sf.functional.tool.assembly'].search([
('assembly_order_code', '=', self.assembly_order_code), ('assembly_order_code', '=', self.assembly_order_code),
('machine_tool_name_id', '=', self.machine_tool_name_id.id), ('machine_tool_name_id', '=', self.machine_tool_name_id.id),
@@ -348,29 +357,45 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
# 对物料做必填判断 # 对物料做必填判断
self.materials_must_be_judged() self.materials_must_be_judged()
product_id = self.env['product.product'].search([('name', '=', '功能刀具')])
# 创建组装入库单 # 创建组装入库单
# 创建功能刀具批次/序列号记录 # 创建功能刀具批次/序列号记录
stock_lot = self.create_assemble_warehouse_receipt(functional_tool_assembly) stock_lot = product_id.create_assemble_warehouse_receipt(self.id, functional_tool_assembly)
# 创建刀具组装入库单 # 创建刀具组装入库单
self.create_stocking_picking(stock_lot) self.create_stocking_picking(stock_lot)
# 封装功能刀具数据 # 刀具物料出库
desc_1 = self.get_desc_1(stock_lot) if self.integral_code_id:
product_id.tool_material_stock_moves(self.integral_code_id)
if self.blade_code_id:
product_id.tool_material_stock_moves(self.blade_code_id)
if self.bar_code_id:
product_id.tool_material_stock_moves(self.bar_code_id)
if self.pad_code_id:
product_id.tool_material_stock_moves(self.pad_code_id)
if self.handle_code_id:
product_id.tool_material_stock_moves(self.handle_code_id)
if self.chuck_code_id:
product_id.tool_material_stock_moves(self.chuck_code_id)
# 创建功能刀具列表记录 # ============================创建功能刀具列表、安全库存记录===============================
# 封装功能刀具数据 # 封装功能刀具数据
desc_2 = self.get_desc_2(stock_lot, functional_tool_assembly) desc_2 = self.get_desc_2(stock_lot, functional_tool_assembly)
# 创建功能刀具列表、功能刀具预警、功能刀具实时分布、功能刀具出入库记录 # 创建功能刀具列表记录
record_1 = self.env['sf.functional.cutting.tool.entity'].create(desc_2) record_1 = self.env['sf.functional.cutting.tool.entity'].create(desc_2)
# self.env['sf.real.time.distribution.of.functional.tools'].create({ # 创建安全库存信息
# 'functional_cutting_tool_id': record_1.id self.env['sf.real.time.distribution.of.functional.tools'].create_or_edit_safety_stock({
# }) 'name': self.after_assembly_functional_tool_name,
# self.env['sf.inbound.and.outbound.records.of.functional.tools'].create({ 'sf_cutting_tool_type_id': self.after_assembly_functional_tool_type_id.id,
# 'functional_cutting_tool_id': record_1.id 'diameter': self.after_assembly_functional_tool_diameter,
# }) 'knife_tip_r_angle': self.after_assembly_knife_tip_r_angle,
'coarse_middle_thin': self.after_assembly_coarse_middle_thin,
}, record_1)
# =====================修改功能刀具组装单、机床换刀申请、CAM工单程序用刀计划的状态==============
# 封装功能刀具数据
desc_1 = self.get_desc_1(stock_lot)
# 修改功能刀具组装单信息 # 修改功能刀具组装单信息
functional_tool_assembly.write(desc_1) functional_tool_assembly.write(desc_1)
if functional_tool_assembly.sf_machine_table_tool_changing_apply_id: if functional_tool_assembly.sf_machine_table_tool_changing_apply_id:
# 修改机床换刀申请的状态 # 修改机床换刀申请的状态
self.env['sf.machine.table.tool.changing.apply'].sudo().search([ self.env['sf.machine.table.tool.changing.apply'].sudo().search([
@@ -414,71 +439,6 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
# 将刀具组装入库单的状态更改为就绪 # 将刀具组装入库单的状态更改为就绪
picking_id.action_confirm() picking_id.action_confirm()
def create_assemble_warehouse_receipt(self, functional_tool_assembly):
"""
创建功能刀具批次/序列号记录
"""
product_id = self.env['product.product'].search([('name', '=', '功能刀具')])
stock_lot = self.env['stock.lot'].create({
'name': self.get_stock_lot_name(),
'product_id': product_id.id,
'company_id': self.env.company.id
})
# 创建功能刀具该批次/序列号 库存移动和移动历史
self.create_stock_quant(product_id, stock_lot, functional_tool_assembly)
return stock_lot
def create_stock_quant(self, product_id, stock_lot, functional_tool_assembly):
"""
创建功能刀具该批次/序列号 库存移动和移动历史
"""
# 获取位置对象
stock_location_id = self.env['stock.location'].search([('name', '=', '组装后')])
location_inventory_id = self.env['stock.location'].search([('name', '=', 'Inventory adjustment')])
# 创建库存移动
stock_move_id = self.env['stock.move'].create({
'name': '功能刀具组装出库',
'product_id': product_id.id,
'location_id': location_inventory_id.id,
'location_dest_id': stock_location_id.id,
'product_uom_qty': 1.00,
'state': 'done'
})
# 创建移动历史
stock_move_line_id = self.env['stock.move.line'].create({
'product_id': product_id.id,
'functional_tool_name_id': functional_tool_assembly.id,
'lot_id': stock_lot.id,
'move_id': stock_move_id.id,
'install_tool_time': fields.Datetime.now(),
'qty_done': 1.0,
'state': 'done'
})
return stock_move_id, stock_move_line_id
def get_stock_lot_name(self):
"""
生成功能刀具序列号
"""
code = 'JKM-T-' + str(self.functional_tool_type_id.code) + '-' + str(self.functional_tool_diameter) + '-'
new_time = fields.Date.today()
code += str(new_time) + '-'
stock_lot_id = self.env['stock.lot'].sudo().search(
[('name', 'like', new_time), ('product_id.name', '=', '功能刀具')],
limit=1,
order="id desc"
)
if not stock_lot_id:
num = "%03d" % 1
else:
m = int(stock_lot_id.name[-3:]) + 1
num = "%03d" % m
return code + str(num)
def get_desc_1(self, stock_lot): def get_desc_1(self, stock_lot):
return { return {
'barcode_id': stock_lot.id, 'barcode_id': stock_lot.id,
@@ -543,3 +503,90 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
'cut_number': self.cut_number, 'cut_number': self.cut_number,
'current_location_id': stock_lot.quant_ids.location_id.ids[-1], 'current_location_id': stock_lot.quant_ids.location_id.ids[-1],
} }
class ProductProduct(models.Model):
_inherit = 'product.product'
def create_assemble_warehouse_receipt(self, tool_assembly_order_id, functional_tool_assembly):
"""
创建功能刀具批次/序列号记录
"""
product_id = self.env['product.product'].search([('name', '=', '功能刀具')])
stock_lot = self.env['stock.lot'].create({
'name': self.get_stock_lot_name(tool_assembly_order_id),
'product_id': product_id.id,
'company_id': self.env.company.id
})
# 获取位置对象
location_inventory_id = self.env['stock.location'].search([('name', '=', 'Production')])
stock_location_id = self.env['stock.location'].search([('name', '=', '组装后')])
# 创建功能刀具该批次/序列号 库存移动和移动历史
stock_lot.create_stock_quant(location_inventory_id, stock_location_id, functional_tool_assembly.id)
return stock_lot
def get_stock_lot_name(self, tool_assembly_order_id):
"""
生成功能刀具序列号
"""
tool_assembly_order = self.env['sf.functional.tool.assembly.order'].search(
[('id', '=', tool_assembly_order_id)])
code = 'JKM-T-' + str(tool_assembly_order.after_assembly_functional_tool_type_id.code) + '-' + str(
tool_assembly_order.after_assembly_functional_tool_diameter) + '-'
new_time = fields.Date.today()
code += str(new_time) + '-'
stock_lot_id = self.env['stock.lot'].sudo().search(
[('name', 'like', new_time), ('product_id.name', '=', '功能刀具')],
limit=1,
order="id desc"
)
if not stock_lot_id:
num = "%03d" % 1
else:
m = int(stock_lot_id.name[-3:]) + 1
num = "%03d" % m
return code + str(num)
def tool_material_stock_moves(self, tool_material):
"""
对刀具物料进行库存移动到 刀具组装位置
"""
# 获取位置对象
location_inventory_id = tool_material.quant_ids.location_id[-1]
print(location_inventory_id)
stock_location_id = self.env['stock.location'].search([('name', '=', '刀具组装位置')])
# 创建功能刀具该批次/序列号 库存移动和移动历史
tool_material.create_stock_quant(location_inventory_id, stock_location_id, None)
class StockLot(models.Model):
_inherit = 'stock.lot'
def create_stock_quant(self, location_inventory_id, stock_location_id, functional_tool_assembly_id):
"""
对功能刀具组装过程的功能刀具和刀具物料进行库存移动,以及创建移动历史
"""
# 创建库存移动记录
stock_move_id = self.env['stock.move'].create({
'name': '功能刀具组装',
'product_id': self.product_id.id,
'location_id': location_inventory_id.id,
'location_dest_id': stock_location_id.id,
'product_uom_qty': 1.00,
'state': 'done'
})
# 创建移动历史记录
stock_move_line_id = self.env['stock.move.line'].create({
'product_id': self.product_id.id,
'functional_tool_name_id': functional_tool_assembly_id,
'lot_id': self.id,
'move_id': stock_move_id.id,
'install_tool_time': fields.Datetime.now(),
'qty_done': 1.0,
'state': 'done'
})
return stock_move_id, stock_move_line_id

View File

@@ -13,8 +13,9 @@
'depends': ['stock', 'web', ], 'depends': ['stock', 'web', ],
'data': [ 'data': [
# 'security/group_security.xml', # 'security/group_security.xml',
# 'security/ir.model.access.csv', 'security/ir.model.access.csv',
'views/view.xml', 'views/view.xml',
'views/shelf_location.xml',
], ],
'demo': [ 'demo': [
], ],

View File

@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import logging from odoo import api, fields, models
from odoo import SUPERUSER_ID, _, api, fields, models
from odoo.osv import expression from odoo.osv import expression
@@ -12,10 +11,13 @@ class SfLocation(models.Model):
barcode = fields.Char('Barcode', copy=False, size=15) barcode = fields.Char('Barcode', copy=False, size=15)
# 仓库类别selection库区、库位、货位 # 仓库类别selection库区、库位、货位
# location_type = fields.Selection([
# ('库区', '库区'),
# ('货架', '货架'),
# ('货位', '货位')
# ], string='存储类型')
location_type = fields.Selection([ location_type = fields.Selection([
('库区', '库区'), ('库区', '库区')
('货架', '货架'),
('货位', '货位')
], string='存储类型') ], string='存储类型')
# 库区类型selection拣货区、存货区、收货区、退货区、次品区 # 库区类型selection拣货区、存货区、收货区、退货区、次品区
area_type = fields.Selection([ area_type = fields.Selection([
@@ -25,6 +27,10 @@ class SfLocation(models.Model):
('退货区', '退货区'), ('退货区', '退货区'),
('次品区', '次品区') ('次品区', '次品区')
], string='库区类型') ], string='库区类型')
# 当前位置
current_location_id = fields.Many2one('sf.shelf.location', string='当前位置')
# 目的位置
destination_location_id = fields.Many2one('sf.shelf.location', string='目的位置')
# 存储类型selection库区、货架 # 存储类型selection库区、货架
# storage_type = fields.Selection([ # storage_type = fields.Selection([
# ('库区', '库区'), # ('库区', '库区'),
@@ -207,6 +213,108 @@ class SfLocation(models.Model):
# + str(j + 1) # + str(j + 1)
class ShelfLocation(models.Model):
_name = 'sf.shelf.location'
_description = '货架货位'
name = fields.Char('名称', required=True, size=20)
barcode = fields.Char('编码', copy=False, size=15)
# 仓库类别selection库区、库位、货位
location_type = fields.Selection([
('货架', '货架'),
('货位', '货位')
], string='存储类型')
# 绑定库区
location_id = fields.Many2one('stock.location', string='所属库区', domain=[('location_type', '=', '库区')])
# 产品类别 关联product.category
product_type = fields.Many2many('product.category', string='产品类别')
# 货架独有字段通道、方向、货架高度m、货架层数、层数容量
channel = fields.Char(string='通道')
direction = fields.Selection([
('R', 'R'),
('L', 'L')
], string='方向')
shelf_height = fields.Float(string='货架高度(m)')
shelf_layer = fields.Integer(string='货架层数')
layer_capacity = fields.Integer(string='层数容量')
# 货位独有字段:货位状态、产品(关联产品对象)、产品序列号(关联产品序列号对象)
location_status = fields.Selection([
('空闲', '空闲'),
('占用', '占用'),
('禁用', '禁用')
], string='货位状态', default='空闲')
# product_id = fields.Many2one('product.template', string='产品')
product_id = fields.Many2one('product.product', string='产品', compute='_compute_product_id', readonly=True)
product_sn_id = fields.Many2one('stock.lot', string='产品序列号')
hide_shelf = fields.Boolean(compute='_compute_hide_what', string='隐藏货架')
hide_location = fields.Boolean(compute='_compute_hide_what', string='隐藏货位')
@api.depends('product_sn_id')
def _compute_product_id(self):
"""
根据产品序列号,获取产品
"""
for record in self:
if record.product_sn_id:
record.product_id = record.product_sn_id.product_id
record.location_status = '占用'
else:
record.product_id = False
# record.location_status = '空闲'
@api.depends('location_type')
def _compute_hide_what(self):
"""
根据仓库类别,隐藏不需要的字段
:return:
"""
for record in self:
record.hide_shelf = False
record.hide_location = False
if record.location_type and record.location_type == '货架':
record.hide_shelf = True
elif record.location_type and record.location_type == '货位':
record.hide_location = True
else:
pass
# 生成货位
def create_location(self):
"""
当仓库类型为货架时,自动生成其下面的货位,数量为货架层数*层数容量
"""
if self.location_type == '货架':
for i in range(self.shelf_layer):
for j in range(self.layer_capacity):
self.create({
'name': self.name + '-' + str(i + 1) + '' + '-' + str(j + 1) + '位置',
'location_id': self.id,
'location_type': '货位',
'barcode': self.generate_barcode(i, j),
'location_status': '空闲'
})
def generate_barcode(self, i, j):
"""
生成货位条码
"""
# 这里是你生成barcode的代码
# area_type_barcode = self.location_id.barcode
area_type_barcode = self.barcode
i_str = str(i + 1).zfill(3) # 确保是两位数如果不足两位左侧补0
j_str = str(j + 1).zfill(3) # 确保是两位数如果不足两位左侧补0
return area_type_barcode + self.channel + self.direction + '-' + self.barcode + '-' + i_str + '-' + j_str
# def generate_barcode(self, i, j):
# # 这里是你生成barcode的代码
# area_type_barcode = self.location_id.barcode
# return area_type_barcode + self.channel + self.direction + '-' + self.barcode + '-' + str(i + 1) + '-'
# + str(j + 1)
class SfProcurementGroup(models.Model): class SfProcurementGroup(models.Model):
_inherit = 'procurement.group' _inherit = 'procurement.group'

View File

@@ -1,4 +1,4 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_stock_location,stock.location,model_stock_location,base.group_user,1,1,1,1 access_sf_shelf_location,sf.shelf.location,model_sf_shelf_location,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 access_stock_location access_sf_shelf_location stock.location sf.shelf.location model_stock_location model_sf_shelf_location base.group_user 1 1 1 1
3
4

View File

@@ -1,12 +1,11 @@
odoo.define('sf_warehouse.custom_kanban', function (require) { odoo.define('sf_warehouse.custom_kanban', function (require) {
"use strict" "use strict";
var KanbanRenderer = require('web.KanbanRenderer'); var KanbanRenderer = require('web.KanbanRenderer');
KanbanRenderer.include({ KanbanRenderer.include({
_render: function () { _render: function () {
var self = this; var self = this;
return this._super.apply(this, arguments).then(function () { return this._super.apply(this, arguments).then(function () {
var colorGuide = $('<div class="color-guide"> \ var colorGuide = $('<div class="color-guide"> \
<span class="color-guide-item" style="background-color: red;"></span> \ <span class="color-guide-item" style="background-color: red;"></span> \
<span class="color-guide-item" style="background-color: green;"></span> \ <span class="color-guide-item" style="background-color: green;"></span> \
@@ -16,5 +15,4 @@ odoo.define('sf_warehouse.custom_kanban', function (require) {
}); });
}, },
}); });
});
});

View File

@@ -1,9 +1,7 @@
/** @odoo-module **/ /** @odoo-module **/
import { registry } from "@web/core/registry"; import {registry} from "@web/core/registry";
import { CharField } from '@web/views/fields/char/char_field'; import {CharField} from '@web/views/fields/char/char_field';
// 继承CharField组件实现自定义组件:当光标聚焦于输入框时,选中输入框内容 // 继承CharField组件实现自定义组件:当光标聚焦于输入框时,选中输入框内容
class CustomChar extends CharField { class CustomChar extends CharField {
@@ -20,7 +18,7 @@ class CustomChar extends CharField {
// 当光标聚焦于输入框时,选中输入框内容 // 当光标聚焦于输入框时,选中输入框内容
this.input.el.addEventListener('focus', function () { this.input.el.addEventListener('focus', function () {
this.select(); this.select();
}) });
} }
@@ -72,13 +70,10 @@ class CustomChar extends CharField {
// } // }
// } // }
// this.$input.on('focus', function () { // this.$input.on('focus', function () {
// $(this).select(); // $(this).select();
// }); // });
// 当光标聚焦于输入框时,选中输入框内容 // 当光标聚焦于输入框时,选中输入框内容
} }
registry.category("fields").add("custom_char", CustomChar); registry.category("fields").add("custom_char", CustomChar);

View File

@@ -1,8 +1,8 @@
/** @odoo-module */ /** @odoo-module */
import { KanbanController } from "@web/views/kanban/kanban_controller"; import {KanbanController} from "@web/views/kanban/kanban_controller";
import { kanbanView } from "@web/views/kanban/kanban_view"; import {kanbanView} from "@web/views/kanban/kanban_view";
import { registry } from "@web/core/registry"; import {registry} from "@web/core/registry";
// the controller usually contains the Layout and the renderer. // the controller usually contains the Layout and the renderer.
class CustomKanbanController extends KanbanController { class CustomKanbanController extends KanbanController {
@@ -18,4 +18,4 @@ export const customKanbanView = {
}; };
// Register it to the views registry // Register it to the views registry
registry.category("views").add("custom_kanban", customKanbanView); registry.category("views").add("custom_kanban", customKanbanView);

View File

@@ -1,8 +1,7 @@
/** @odoo-module **/ /** @odoo-module **/
import { registry } from "@web/core/registry"; import {registry} from "@web/core/registry";
import { Many2OneField } from '@web/views/fields/many2one/many2one_field'; import {Many2OneField} from '@web/views/fields/many2one/many2one_field';
// 继承FieldMany2One组件实现自定义组件:当光标聚焦于输入框时,选中输入框内容 // 继承FieldMany2One组件实现自定义组件:当光标聚焦于输入框时,选中输入框内容
@@ -17,14 +16,14 @@ class CustomMany2One extends Many2OneField {
// console.log('CustomMany2One.setup11111111111111'); // console.log('CustomMany2One.setup11111111111111');
super.setup(); super.setup();
} }
onMounted() { onMounted() {
// console.log('CustomMany2One.onMounted1'); // console.log('CustomMany2One.onMounted1');
// 当光标聚焦于输入框时,选中输入框内容 // 当光标聚焦于输入框时,选中输入框内容
this.input.el.addEventListener('focus', function () { this.input.el.addEventListener('focus', function () {
this.select(); this.select();
}) });
} }
} }
registry.category("fields").add("custom_many2one", CustomMany2One); registry.category("fields").add("custom_many2one", CustomMany2One);

View File

@@ -0,0 +1,201 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="view_shelf_location_tree" model="ir.ui.view">
<field name="name">Shelf Location tree</field>
<field name="model">sf.shelf.location</field>
<field name="arch" type="xml">
<tree string="Shelf Location">
<field name="name" string="名称"/>
<field name="barcode" string="编码"/>
<field name="location_type"/>
</tree>
</field>
</record>
<record id="view_shelf_location_form" model="ir.ui.view">
<field name="name">Shelf Location form</field>
<field name="model">sf.shelf.location</field>
<field name="arch" type="xml">
<form string="Shelf Location">
<header>
<button string="生成货位" name="create_location" type="object" class="oe_highlight" attrs="{'invisible': [('hide_shelf', '=', False)]}"/>
</header>
<sheet>
<group>
<field name="hide_shelf" invisible="1"/>
<field name="hide_location" invisible="1"/>
<field name="name" string="名称"/>
<field name="barcode" string="编码"/>
<field name="location_type"/>
<field name="location_id"/>
<field name="channel" attrs="{'invisible': [('hide_shelf', '=', False)], 'required': [('hide_shelf', '!=', False)]}"/>
<field name="direction" attrs="{'invisible': [('hide_shelf', '=', False)], 'required': [('hide_shelf', '!=', False)]}"/>
<field name="product_sn_id" attrs="{'invisible': [('hide_location', '=', False)], 'required': [('hide_location', '!=', False), ('location_status', '=', '空闲')]}"/>
<!-- <field name="product_type" widget="many2many_tags"/> -->
<field name="shelf_height" attrs="{'invisible': [('hide_shelf', '=', False)], 'required': [('hide_shelf', '!=', False)]}"/>
<field name="shelf_layer" attrs="{'invisible': [('hide_shelf', '=', False)], 'required': [('hide_shelf', '!=', False)]}"/>
<field name="layer_capacity" attrs="{'invisible': [('hide_shelf', '=', False)], 'required': [('hide_shelf', '!=', False)]}"/>
<field name="product_id" attrs="{'invisible': [('hide_location', '=', False)], 'required': [('hide_location', '!=', False), ('location_status', '=', '占用')]}"/>
<field name="location_status" attrs="{'invisible': [('hide_location', '=', False)], 'required': [('hide_location', '!=', False)]}"/>
</group>
</sheet>
</form>
</field>
</record>
<!-- 自己生成 -->
<!-- <record id="view_shelf_location_search" model="ir.ui.view"> -->
<!-- <field name="name">Shelf Location</field> -->
<!-- <field name="model">sf.shelf.location</field> -->
<!-- <field name="arch" type="xml"> -->
<!-- <search string="Shelf Location"> -->
<!-- <field name="name" string="名称"/> -->
<!-- <field name="barcode" string="编码"/> -->
<!-- <field name="location_type"/> -->
<!-- <field name="channel"/> -->
<!-- <field name="direction"/> -->
<!-- <field name="shelf_height"/> -->
<!-- <field name="shelf_layer"/> -->
<!-- <field name="layer_capacity"/> -->
<!-- </search> -->
<!-- </field> -->
<!-- </record> -->
<!-- -->
<!-- <record id="view_shelf_location_kanban" model="ir.ui.view"> -->
<!-- <field name="name">Shelf Location</field> -->
<!-- <field name="model">sf.shelf.location</field> -->
<!-- <field name="arch" type="xml"> -->
<!-- <kanban class="o_kanban_mobile" js_class="custom_kanban"> -->
<!-- <field name="name"/> -->
<!-- <field name="barcode"/> -->
<!-- <field name="location_type"/> -->
<!-- <field name="channel"/> -->
<!-- <field name="direction"/> -->
<!-- <field name="shelf_height"/> -->
<!-- <field name="shelf_layer"/> -->
<!-- <field name="layer_capacity"/> -->
<!-- </kanban> -->
<!-- </field> -->
<!-- </record> -->
<!-- -->
<!-- <record id="action_shelf_location" model="ir.actions.act_window"> -->
<!-- <field name="name">Shelf Location</field> -->
<!-- <field name="res_model">sf.shelf.location</field> -->
<!-- <field name="view_mode">tree,form,kanban</field> -->
<!-- <field name="search_view_id" ref="view_shelf_location_search"/> -->
<!-- </record> -->
<!-- -->
<!-- <menuitem id="menu_shelf_location" name="Shelf Location" parent="sf_stock.menu_stock" sequence="1"/> -->
<!-- <menuitem id="menu_shelf_location_tree" name="Shelf Location" parent="menu_shelf_location" action="action_shelf_location" sequence="1"/> -->
<!-- <record id="view_location_search_sf_inherit" model="ir.ui.view"> -->
<!-- <field name="name">stock.location.search.sf.inherit</field> -->
<!-- <field name="model">stock.location</field> -->
<!-- <field name="inherit_id" ref="stock.view_location_search"/> -->
<!-- <field name="arch" type="xml"> -->
<!-- <xpath expr="//search[1]" position="inside"> -->
<!-- <searchpanel class="account_root"> -->
<!-- <field name="location_type" icon="fa-filter"/> -->
<!-- <field name="location_id" select="multi" domain="[('location_type', '=', '货架')]"/> -->
<!-- </searchpanel> -->
<!-- </xpath> -->
<!-- </field> -->
<!-- </record> -->
<!-- <record id="example_kanban_view" model="ir.ui.view"> -->
<!-- <field name="name">example.kanban</field> -->
<!-- <field name="model">stock.location</field> -->
<!-- <field name="arch" type="xml"> -->
<!-- <kanban class="o_kanban_mobile" js_class="custom_kanban"> -->
<!-- <templates> -->
<!-- <t t-name="kanban-box"> -->
<!-- <div t-attf-class="oe_kanban_card oe_kanban_global_click -->
<!-- #{record.location_status.raw_value == '空闲' ? 'kanban_color_1' : ''} -->
<!-- #{record.location_status.raw_value == '占用' ? 'kanban_color_2' : ''} -->
<!-- #{record.location_status.raw_value == '禁用' ? 'kanban_color_3' : ''}"> -->
<!-- --><!-- 标题 -->
<!-- <div class="o_kanban_card_header"> -->
<!-- <div class="o_kanban_card_header_title"> -->
<!-- <field name="name"/> -->
<!-- </div> -->
<!-- </div> -->
<!-- --><!-- 内容 -->
<!-- <div class="o_kanban_record_bottom"> -->
<!-- <field name="location_status"/> -->
<!-- </div> -->
<!-- <div class="o_kanban_record_bottom"> -->
<!-- <field name="product_sn_id"/> -->
<!-- <span> | </span> -->
<!-- <field name="product_id"/> -->
<!-- </div> -->
<!-- </div> -->
<!-- </t> -->
<!-- <t t-name="kanban-box"> -->
<!-- <div t-attf-class="oe_kanban_card oe_kanban_global_click -->
<!-- #{record.location_status.raw_value == '空闲' ? 'kanban_color_1' : ''} -->
<!-- #{record.location_status.raw_value == '占用' ? 'kanban_color_2' : ''} -->
<!-- #{record.location_status.raw_value == '禁用' ? 'kanban_color_3' : ''}"> -->
<!-- --><!-- --><!-- 看板内容 -->
<!-- </div> -->
<!-- <div t-attf-class="oe_kanban_card"> -->
<!-- --><!-- --><!-- 标题 -->
<!-- <div class="o_kanban_card_header"> -->
<!-- <div class="o_kanban_card_header_title"> -->
<!-- <field name="name"/> -->
<!-- </div> -->
<!-- </div> -->
<!-- --><!-- --><!-- 内容 -->
<!-- <div class="o_kanban_record_bottom"> -->
<!-- <field name="location_status"/> -->
<!-- </div> -->
<!-- <div class="o_kanban_record_bottom"> -->
<!-- <field name="product_sn_id"/> -->
<!-- <span> | </span> -->
<!-- <field name="product_id"/> -->
<!-- </div> -->
<!-- </div> -->
<!-- </t> -->
<!-- </templates> -->
<!-- </kanban> -->
<!-- </field> -->
<!-- </record> -->
<!-- <record id="kanban_action_id" model="ir.actions.act_window"> -->
<!-- <field name="name">货位状态</field> -->
<!-- <field name="type">ir.actions.act_window</field> -->
<!-- <field name="res_model">stock.location</field> -->
<!-- <field name="view_mode">kanban,form</field> -->
<!-- </record> -->
<record id="action_sf_shelf_location" model="ir.actions.act_window">
<field name="name">货架货位</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">sf.shelf.location</field>
<field name="view_mode">tree,form</field>
</record>
<!-- <record id="example_action" model="ir.actions.act_window"> -->
<!-- <field name="name">Example</field> -->
<!-- <field name="type">ir.actions.act_window</field> -->
<!-- <field name="res_model">stock.location</field> -->
<!-- <field name="view_mode">kanban</field> -->
<!-- <field name="searchpanel">true</field> -->
<!-- <field name="searchpanel_field_label">货架</field> -->
<!-- <field name="searchpanel_field_name">parent_id</field> -->
<!-- <field name="searchpanel_field_group_by">['parent_id']</field> -->
<!-- <field name="domain">[('location_type', '=', '货位')]</field> -->
<!-- </record> -->
<!-- <menuitem id="menu_stock_location" name="货位状态" parent="stock.menu_stock_root" -->
<!-- sequence="50" -->
<!-- action="kanban_action_id"/> -->
<menuitem id="menu_sf_shelf_location" name="货架货位" parent="stock.menu_warehouse_config"
sequence="2"
action="action_sf_shelf_location"/>
</data>
</odoo>

View File

@@ -32,6 +32,8 @@
<field name="product_sn_id" attrs="{'invisible': [('hide_location', '=', False)], 'required': [('hide_location', '!=', False), ('location_status', '=', '空闲')]}"/> <field name="product_sn_id" attrs="{'invisible': [('hide_location', '=', False)], 'required': [('hide_location', '!=', False), ('location_status', '=', '空闲')]}"/>
<!-- <field name="time_test" widget="timepicker"/>--> <!-- <field name="time_test" widget="timepicker"/>-->
<field name="area_type" attrs="{'invisible': [('hide_area', '=', False)], 'required': [('hide_area', '!=', False)]}"/> <field name="area_type" attrs="{'invisible': [('hide_area', '=', False)], 'required': [('hide_area', '!=', False)]}"/>
<field name="current_location_id" attrs="{'invisible': [('hide_area', '=', False)]}"/>
<field name="destination_location_id" attrs="{'invisible': [('hide_area', '=', False)]}"/>
</group> </group>
<group> <group>

View File

@@ -26,15 +26,15 @@ export class StepViewer extends Component {
model: this.props.record.resModel, model: this.props.record.resModel,
id: JSON.stringify(this.props.record.data['id']), id: JSON.stringify(this.props.record.data['id']),
field: this.props.name field: this.props.name
} };
url = url_props['base_url'].replace('http://', 'https://') + '/web/content/' + url_props['model'] + '/' + url_props['id'] + '/' + url_props['field'] + '?download=true' url = url_props['base_url'].replace('http://', 'https://') + '/web/content/' + url_props['model'] + '/' + url_props['id'] + '/' + url_props['field'] + '?download=true';
// url = 'http://localhost:8069'+'/web/content/'+url_props['model']+'/'+url_props['id']+'/'+url_props['field']+'?download=true' // url = 'http://localhost:8069'+'/web/content/'+url_props['model']+'/'+url_props['id']+'/'+url_props['field']+'?download=true'
// console.log('url111111', url) // console.log('url111111', url)
return url return url;
} else { } else {
url = "data:model/gltf-binary;base64," + this.props.value; url = "data:model/gltf-binary;base64," + this.props.value;
// console.log('url2', url) // console.log('url2', url)
return url return url;
// localStorage.setItem('url',url) // localStorage.setItem('url',url)
// let new_url = localStorage.getItem(('url')) // let new_url = localStorage.getItem(('url'))
// var oViewer = document.getElementsByTagName('model-viewer')[0]; // var oViewer = document.getElementsByTagName('model-viewer')[0];

View File

@@ -23,7 +23,6 @@ try:
import httpagentparser import httpagentparser
except ImportError: except ImportError:
pass pass
from time import gmtime, strftime
from odoo.addons.web.controllers import home from odoo.addons.web.controllers import home
from odoo.http import request from odoo.http import request
from odoo.exceptions import Warning from odoo.exceptions import Warning

View File

@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from odoo import models, fields, api, _ from odoo import models, fields
class LoginImage(models.Model): class LoginImage(models.Model):

View File

@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from odoo import api, fields, models, modules from odoo import api, fields, models
class ResConfigSettings(models.TransientModel): class ResConfigSettings(models.TransientModel):

View File

@@ -8,11 +8,9 @@ import werkzeug.exceptions
import werkzeug.utils import werkzeug.utils
import werkzeug.wrappers import werkzeug.wrappers
import werkzeug.wsgi import werkzeug.wsgi
from werkzeug.urls import url_parse
from odoo import http from odoo import http
from odoo.http import content_disposition, request from odoo.http import request
from odoo.tools.safe_eval import safe_eval, time
from odoo.addons.web.controllers.report import ReportController from odoo.addons.web.controllers.report import ReportController
from ..models.common import Common from ..models.common import Common

View File

@@ -18,4 +18,4 @@ class Common(models.Model):
tsclibrary.printlabelW("0", "1"); tsclibrary.printlabelW("0", "1");
tsclibrary.closeport(); tsclibrary.closeport();
except Exception as e: except Exception as e:
raise UserWarning("错误警告") raise UserWarning("错误警告:%s" % e)