Compare commits

..

4 Commits

Author SHA1 Message Date
WEB许何哲\xuhez
2b7f4c3f06 看板样式修改 2023-10-20 17:18:46 +08:00
WEB许何哲\xuhez
26de811174 看板样式修改 2023-10-20 16:33:00 +08:00
WEB许何哲\xuhez
d023848c70 Merge branch 'develop' into feature/sf看板样式统一
# Conflicts:
#	jikimo_frontend/static/src/scss/custom_style.scss
2023-10-20 16:31:40 +08:00
WEB许何哲\xuhez
a109c0fb39 看板样式修改 2023-10-20 16:29:57 +08:00
362 changed files with 10922 additions and 24320 deletions

View File

@@ -10,9 +10,9 @@
""", """,
'category': 'sf', 'category': 'sf',
'website': 'https://www.sf.jikimo.com', 'website': 'https://www.sf.jikimo.com',
'depends': ['web', 'purchase', 'base_setup'], 'depends': ['web'],
'data': [ 'data': [
'views/bye_odoo.xml',
], ],
'demo': [ 'demo': [
], ],
@@ -22,24 +22,11 @@
], ],
'web.assets_backend': [ 'web.assets_backend': [
'jikimo_frontend/static/src/fields/custom_many2many_checkboxes/*', 'jikimo_frontend/static/src/fields/custom_many2many_checkboxes/*',
'jikimo_frontend/static/src/fields/Many2OneRadioField/*',
# 移除odoo相关标识
'jikimo_frontend/static/src/bye_odoo/*',
'jikimo_frontend/static/src/scss/custom_style.scss', 'jikimo_frontend/static/src/scss/custom_style.scss',
# 'jikimo_frontend/static/src/views/list_nums/list_nbCols.js', # 'jikimo_frontend/static/src/views/list_nums/list_nbCols.js',
'jikimo_frontend/static/src/views/list_nums/list_nums.xml', 'jikimo_frontend/static/src/views/list_nums/list_nums.xml',
'jikimo_frontend/static/src/views/list_nums/list_nums2.xml', 'jikimo_frontend/static/src/views/list_nums/list_nums2.xml',
'jikimo_frontend/static/src/views/list_nums/list_nums3.xml', 'jikimo_frontend/static/src/views/list_nums/list_nums3.xml',
'jikimo_frontend/static/src/js/custom_form_status_indicator.js',
'jikimo_frontend/static/src/js/custom_image_temp.js',
'jikimo_frontend/static/src/scss/rowno_in_tree.scss',
# 'jikimo_frontend/static/src/views/list_nums/list_render.xml',
# 'jikimo_frontend/static/src/list/list_up_down_button.xml',
# 'jikimo_frontend/static/src/list/custom_import.js',
# 'jikimo_frontend/static/src/list/custom_width.js',
'jikimo_frontend/static/src/views/list_nums/extent_purchase.xml',
'jikimo_frontend/static/src/css/list_border_styles.css',
], ],
}, },

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="partner_demo_company" model="res.partner">
<field name="name">JKM</field>
<field name="street">B-25</field>
<field name="city">USA</field>
<!-- Use the correct reference or actual ID for the country -->
<field name="country_id" ref="base.bd"/>
<field name="zip">1229</field>
<field name="phone">+8801-712901764</field>
<field name="email">info@kolpolok.com</field>
<field name="website">www.kolpoloktechnologies.com</field>
</record>
<record id="demo_company" model="res.company">
<field name="name">Custom</field>
<field name="logo" type="base64" file="kolpolok_custom_title_and_favicon/static/src/img/favicon.ico"/>
<field name="favicon" type="base64" file="kolpolok_custom_title_and_favicon/static/src/img/favicon.ico"/>
<field name="partner_id" ref="partner_demo_company"/>
</record>
</data>
</odoo>

View File

@@ -1,16 +0,0 @@
/** @odoo-module **/
import { UserMenu } from "@web/webclient/user_menu/user_menu";
import { patch } from "@web/core/utils/patch";
import { registry } from "@web/core/registry";
const userMenuRegistry = registry.category("user_menuitems");
patch(UserMenu.prototype, "legion_hide_odoo.UserMenu", {
setup() {
this._super.apply(this, arguments);
userMenuRegistry.remove("documentation");
userMenuRegistry.remove("support");
userMenuRegistry.remove("odoo_account");
},
});

View File

@@ -1,11 +0,0 @@
/** @odoo-module **/
import { WebClient } from "@web/webclient/webclient";
import { patch } from "web.utils";
patch(WebClient.prototype, "kolpolok_custom_title_and_favicon.WebClient", {
setup() {
this._super();
this.title.setParts({ zopenerp: "JIKIMO" });
},
});

View File

@@ -1,3 +0,0 @@
.o_list_renderer .o_list_table tbody > tr > td:not(.o_list_record_selector):not(.o_handle_cell):not(.o_list_button):not(.o_list_record_remove){
border:1px solid #dee2e6 !important;
}

View File

@@ -1,3 +0,0 @@
.many2one_radio_field {
display: inline-block;
}

View File

@@ -1,53 +0,0 @@
/** @odoo-module **/
import { RadioField } from "@web/views/fields/radio/radio_field"; // 导入单选按钮组件
import { registry } from "@web/core/registry";
export class Many2OneRadioField extends RadioField {
// 你可以重写或者添加一些方法和属性
// 例如你可以重写setup方法来添加一些事件监听器或者初始化一些变量
setup() {
super.setup(); // 调用父类的setup方法
// 你自己的代码
}
onImageClick(event) {
// 放大图片逻辑
// 获取图片元素
const img = event.target;
const close = img.nextSibling;
// 实现放大图片逻辑
// 比如使用 CSS 放大
img.parentElement.classList.add('zoomed');
close.classList.add('img_close');
}
onCloseClick(event) {
const close = event.target;
const img = close.previousSibling;
img.parentElement.classList.remove('zoomed');
close.classList.remove('img_close');
}
get items() {
return Many2OneRadioField.getItems(this.props.name, this.props.record);
}
static getItems(fieldName, record) {
switch (record.fields[fieldName].type) {
case "selection":
return record.fields[fieldName].selection;
case "many2one": {
const value = record.preloadedData[fieldName] || [];
return value.map((item) => [item.id, item.display_name, item.image]);
}
default:
return [];
}
}
}
Many2OneRadioField.template = "jikimo_frontend.Many2OneRadioField";
// MyCustomWidget.supportedTypes = ['many2many'];
registry.category("fields").add("many2one_radio", Many2OneRadioField);

View File

@@ -1,35 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="jikimo_frontend.Many2OneRadioField" owl="1">
<div
role="radiogroup"
t-attf-class="o_{{ props.orientation }}"
t-att-aria-label="string"
>
<t t-foreach="items" t-as="item" t-key="item[0]">
<div class="form-check o_radio_item many2one_radio_field" aria-atomic="true">
<input
type="radio"
class="form-check-input o_radio_input"
t-att-checked="item[0] === value"
t-att-disabled="props.readonly"
t-att-name="id"
t-att-data-value="item[0]"
t-att-data-index="item_index"
t-att-id="`${id}_${item[0]}`"
t-on-change="() => this.onChange(item)"
/>
<label class="form-check-label o_form_label" t-att-for="`${id}_${item[0]}`" t-esc="item[1]" />
<div t-on-dblclick="onImageClick">
<t>
<img t-att-src="item[2]" width="50" height="50"/>
<div class="close" t-on-click="onCloseClick">×</div>
</t>
</div>
</div>
</t>
</div>
</t>
</templates>

View File

@@ -15,24 +15,23 @@ 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);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -1,210 +0,0 @@
/** @odoo-module */
import {patch} from '@web/core/utils/patch';
// import { Dialog } from "@web/core/dialog/dialog";
import {_t} from "@web/core/l10n/translation";
import {FormStatusIndicator} from "@web/views/form/form_status_indicator/form_status_indicator";
import {ListRenderer} from "@web/views/list/list_renderer";
import {Field} from "@web/views/fields/field";
var Dialog = require('web.Dialog');
// var {patch} = require("web.utils") 这句话也行
const filedRequiredList = {
// 设备大模块
'control_system_id': { multiple: false, noLabel: false },
'workbench_L': { multiple: true, noLabel: false },
'number_of_axles': { multiple: true, noLabel: false },
'x_axis': { multiple: true, noLabel: false },
'number_of_knife_library': { multiple: false, noLabel: false },
'brand_id': { multiple: false, noLabel: false },
'type_id': { multiple: false, noLabel: false },
'taper_type_id': { multiple: false, noLabel: false },
'eq_maintenance_id': { multiple: false, noLabel: false },
'overhaul_id': { multiple: false, noLabel: false },
'overhaul_period': { multiple: false, noLabel: false },
'maintenance_equipment_category_id': { multiple: false, noLabel: false },
'maintenance_type': { multiple: false, noLabel: false },
// 销售大模块
'partner_id': { multiple: false, noLabel: false },
'validity_date': { multiple: false, noLabel: false },
'vat': { multiple: false, noLabel: false },
'phone': { multiple: false, noLabel: false },
'mobile': { multiple: false, noLabel: false },
'email': { multiple: false, noLabel: false },
'category_id': { multiple: false, noLabel: false },
'radio_field_1_person': { multiple: false, noLabel: true },
// 采购大模块
'date_order': { multiple: false, noLabel: false },
'picking_type_id': { multiple: false, noLabel: false },
// 制造大模块
'production_line_id': { multiple: false, noLabel: false },
'date_approve': { multiple: false, noLabel: false },
'date_planned_start': { multiple: false, noLabel: false },
'date_planned_finished': { multiple: false, noLabel: false },
}
const tableRequiredList = [
'product_template_id', 'product_uom_qty', 'price_unit','product_id','product_qty',
'name', 'fault_type', 'maintenance_standards', 'Period'
]
patch(FormStatusIndicator.prototype, 'jikimo_frontend.FormStatusIndicator', {
// 你可以重写或者添加一些方法和属性
async _onDiscardChanges() {
// var self = this;
Dialog.confirm(this, _t("Are you sure you want to discard changes?"), {
title: _t("Discard Changes"),
// confirm_callback: function () {
// self.model.discardChanges(self.handle);
// },
});
},
async discard() {
// if (window.confirm("Are you sure you want to discard changes?")) {
// await this.props.discard();
// }
// const result = await this._confirmDiscardChange();
await this._confirmDiscardChange();
await this.props.discard();
},
_confirmDiscardChange() {
var self = this;
var def = new Promise(function (resolve, reject) {
var message = _t("请确认是否要舍弃之前的更改?");
var dialog = Dialog.confirm(self, message, {
title: _t("Warning"),
confirm_callback: resolve.bind(self, true),
cancel_callback: reject,
});
dialog.on('closed', self, reject);
});
return def;
},
}
);
patch(Field.prototype, 'jikimo_frontend.Field', {
setup() {
owl.onMounted(this.setRequired);
return this._super(...arguments);
},
setRequired() {
const id = this.props.id
const isRequired = filedRequiredList[id]
if(id == 'number_of_axles') {
console.log(isRequired)
}
if(isRequired) {
let dom;
dom = $(`label[for=${id}]`)
if(isRequired.multiple && dom.length > 1) {
dom = dom.eq(-1)
dom = dom.parent().parent().next().find('label')
}
if(isRequired.noLabel) {
dom = dom.parent().parent()
}
let t = dom.html()
t = '<i class="c* r" style="color: red;margin-left: -4px">*</i>' + t
dom.html(t)
}
}
})
patch(ListRenderer.prototype, 'jikimo_frontend.ListRenderer', {
setup(){
owl.onMounted(() => {
this.activeElement = this.uiService.activeElement;
this.setRequired()
})
return this._super(...arguments);
},
setRequired() {
this.allColumns.forEach(_ => {
if( tableRequiredList.indexOf(_.name) >= 0 ) {
const dom = $(`th[data-name=${_.name}]`)
dom.addClass('addRequired')
}
})
try {
const dom = this.tableRef.el
if(dom ) {
const tfoot = $(dom).children('tfoot')
const tbooy = $(dom).children('tbody')
if(tfoot.length) {
const tfoot_tr = tfoot.children().eq(0)
const tbody_tr = tbooy.children().eq(0)
if(tfoot_tr.children().length < tbody_tr.children().length) {
tfoot_tr.prepend('<td class="prepend">')
}
}
}
} catch (e) {
console.log(e)
}
}
})
$(function () {
document.addEventListener('click', function () {
const dom = $('.o_form_status_indicator_buttons ')
if (dom) {
const dom1 = dom.children().eq(0)
const dom2 = dom.children().eq(1)
if (!dom1.text()) {
dom1.append('保存')
dom2.append('取消')
}
}
})
function customRequired() {
let timer = null
let timer_count = 0
clearInterval(timer)
timer = setInterval(() => {
timer_count++
const dom = $('.custom_required')
let tableDom = $('.table_custom_required')
if (tableDom.length) {
tableDom = tableDom.eq(0).parents('tr').children('.table_custom_required')
tableDom.each(function () {
const i = $(this).index()
const requiredDom = $(this).parents('table').find('thead').find('th').eq(i).find('span').eq(0)
const t = requiredDom.text().replace('*', '')
requiredDom.html('<i style="color: red;margin-left: -4px">*</i>' + t)
})
clearInterval(timer)
}
if (dom.length) {
dom.each(function () {
const requiredDom = $(this).parent().prev().find('label')
let t = requiredDom.html()
if (t && t.indexOf('c*') < 0) {
t = '<i class="c*" style="color: red;margin-left: -4px">*</i>' + t
}
requiredDom.html(t)
})
clearInterval(timer)
}
if (timer_count == 20) {
clearInterval(timer)
}
}, 500)
}
var currentUrl = location.href
const listenerUrl = setInterval(() => {
const isChange = currentUrl != location.href
if (isChange) {
currentUrl = location.href
customRequired()
}
}, 500)
customRequired()
})

View File

@@ -1,32 +0,0 @@
/** @odoo-module **/
import {patch} from '@web/core/utils/patch';
import { url } from "@web/core/utils/urls";
import { ImageField, imageCacheKey } from '@web/views/fields/image/image_field';
patch(ImageField.prototype, 'jikimo_frontend/static/src/js/custom_image.js', {
// 你可以重写或者添加一些方法和属性
getUrl(previewFieldName) {
console.log('666666666666666666666666666666666')
if (this.state.isValid && this.props.value) {
if (1) {
if (!this.rawCacheKey) {
this.rawCacheKey = this.props.record.data.__last_update;
}
return url("/web/image", {
model: this.props.record.resModel,
id: this.props.record.resId,
field: previewFieldName,
unique: imageCacheKey(this.rawCacheKey),
});
} else {
// Use magic-word technique for detecting image type
const magic = fileTypeMagicWordMap[this.props.value[0]] || "png";
return `data:image/${magic};base64,${this.props.value}`;
}
}
return placeholder;
}
}
);

View File

@@ -1,45 +0,0 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { url } from "@web/core/utils/urls";
import { ImageField, imageCacheKey } from '@web/views/fields/image/image_field';
import { isBinarySize } from "@web/core/utils/binary";
export const fileTypeMagicWordMap = {
"/": "jpg",
R: "gif",
i: "png",
P: "svg+xml",
};
const placeholder = "/web/static/img/placeholder.png";
export class CustomImageField extends ImageField {
setup() {
super.setup();
// this.dialog = useService("dialog");
}
getUrl(previewFieldName) {
console.log('8888888888886666666666666666666')
if (this.state.isValid && this.props.value) {
if (isBinarySize(this.props.value) || this.props.value.length < 50) {
if (!this.rawCacheKey) {
this.rawCacheKey = this.props.record.data.__last_update;
}
return url("/web/image", {
model: this.props.record.resModel,
id: this.props.record.resId,
field: previewFieldName,
unique: imageCacheKey(this.rawCacheKey),
});
} else {
// Use magic-word technique for detecting image type
const magic = fileTypeMagicWordMap[this.props.value[0]] || "png";
return `data:image/${magic};base64,${this.props.value}`;
}
}
return placeholder;
}
}
registry.category("fields").add("custom_image", CustomImageField);

View File

@@ -1,95 +0,0 @@
/** @odoo-module */
import {patch} from '@web/core/utils/patch';
import {ListRenderer} from "@web/views/list/list_renderer";
// var {patch} = require("web.utils") 这句话也行
patch(ListRenderer.prototype, 'jikimo_frontend.ListRenderer', {
// 你可以重写或者添加一些方法和属性
// The following code manipulates the DOM directly to avoid having to wait for a
// render + patch which would occur on the next frame and cause flickering.
freezeColumnWidths() {
// console.log('ccccccccccccccccccccccccccc')
if (!this.keepColumnWidths) {
this.columnWidths = null;
}
const table = this.tableRef.el;
const headers = [...table.querySelectorAll("thead th:not(.o_list_actions_header)")];
const column_num = headers.length;
if (!this.columnWidths || !this.columnWidths.length) {
// no column widths to restore
// Set table layout auto and remove inline style to make sure that css
// rules apply (e.g. fixed width of record selector)
table.style.tableLayout = "auto";
headers.forEach((th) => {
th.style.width = null;
th.style.maxWidth = null;
});
this.setDefaultColumnWidths(column_num);
// Squeeze the table by applying a max-width on largest columns to
// ensure that it doesn't overflow
this.columnWidths = this.computeColumnWidthsFromContent();
table.style.tableLayout = "fixed";
}
headers.forEach((th, index) => {
if (!th.style.width) {
th.style.width = `${Math.floor(this.columnWidths[index])}px`;
}
});
},
setDefaultColumnWidths(column_num) {
// const bbb = this.state.columns[0].name
const widths = this.state.columns.map((col) =>
this.calculateColumnWidth(col));
// const sumOfRelativeWidths = (widths
// .filter(({ type }) => type === "relative")
// .reduce((sum, { value }) => sum + value, 0));
// 获取数组的最后一项
const lastItem = widths[widths.length - 1];
// 复制最后一项
const newItem = { ...lastItem };
// 将新的对象添加到数组的末尾
widths.push(newItem);
// 判断销售的sequence
// if (this.state.columns[0].name === "sequence") {
// widths[1] = { type: "relative", value: 0.1 };
// }
// 判断 this.state.columns 是否存在且长度大于零
if (this.state.columns && this.state.columns.length > 0
&& this.state.columns[0].name === "sequence") {
widths[1] = { type: "relative", value: 0.1 };
}
// 1 because nth-child selectors are 1-indexed,
// 2 when the first column contains
// the checkboxes to select records.
const columnOffset = this.hasSelectors ? 2 : 1;
widths.forEach(({ type, value }, width) => {
const headerEl = this.tableRef.el.querySelector(
`th:nth-child(${width + columnOffset})`);
if (type === "absolute") {
if (this.isEmpty) {
headerEl.style.width = value;
} else {
headerEl.style.minWidth = value;
}
} else if (type === "relative" && this.isEmpty) {
headerEl.style.width = `${((value / column_num) * 100
).toFixed(2)}%`;
}
});
},
}
);

View File

@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates>
<t t-name="list_up_down_button" t-inherit="web.ListView.Buttons" t-inherit-mode="extension" owl="1">
<xpath expr="//t[@t-if='nbTotal and !nbSelected and activeActions.exportXlsx and isExportEnable and !env.isSmall']" position="before">
<!-- 新增的导入文件按钮 -->
<!-- <button type="button" class="btn btn-secondary fa fa-upload o_list_import_file" data-tooltip="导入文件" aria-label="Import File" title="" t-on-click="onDirectImportData"/> -->
<!-- <button type="button" class="btn btn-secondary fa fa-upload o_list_import_file" data-tooltip="导入文件" aria-label="Import File" title="" t-on-click="onDirectImportData"/> -->
<!-- <button type="button" class="btn btn-secondary fa fa-download o_list_export_xlsx" data-tooltip="导出全部" aria-label="导出全部" t-on-click="onDirectExportData"/> -->
<button type="button" class="btn btn-secondary o_list_export_xlsx" data-tooltip="导出全部" aria-label="导出全部" t-on-click="onDirectExportData">导出全部</button>
<!-- <button type="button" t-component="base_import.ImportRecords" class="btn btn-secondary o_list_export_xlsx" data-tooltip="导入数据" aria-label="导入数据" t-on-click="importRecords">导入数据</button> -->
<!-- <button type="button" class="btn btn-secondary o_list_export_xlsx" data-tooltip="导入数据" aria-label="导入数据" t-on-click="importRecords">导入数据</button> -->
<!-- <t t-component="base_import.ImportRecords"> -->
<!-- <button t-on-click="importRecords" type="button" class="btn btn-secondary o_list_export_xlsx" data-tooltip="导入数据" aria-label="导入数据">导入数据</button> -->
<!-- </t> -->
</xpath>
<xpath expr="//t[@t-if='nbTotal and !nbSelected and activeActions.exportXlsx and isExportEnable and !env.isSmall']" position="replace">
</xpath>
</t>
</templates>

View File

@@ -8,16 +8,9 @@
white-space: nowrap; white-space: nowrap;
} }
div:has(.o_required_modifier) > label::before {
content: '*' !important;
color: red !important;
padding: 0 4px !important;
vertical-align: top !important;
font-size: unset !important;
}
.my-image div { .my-image div {
width: 110px !important; width: 110px !important;
height: 110px !important; height: 110px !important;
} }
@@ -79,9 +72,9 @@ td.o_required_modifier {
} }
.oe_kanban_card.kanban_color_1 { .oe_kanban_card.kanban_color_1 {
background-color: #fff !important; background-color: #27FEA9 !important;
opacity: 0.7; opacity: 0.7;
color: #777; color: #fff;
} }
.oe_kanban_card.kanban_color_3 { .oe_kanban_card.kanban_color_3 {
@@ -135,7 +128,7 @@ td.o_required_modifier {
.text-truncate { .text-truncate {
overflow: unset !important; overflow: unset !important;
text-overflow: unset !important; text-overflow: unset !important;
//white-space: nowrap!important; white-space: unset !important;
} }
.o_list_renderer .o_list_table tbody > tr > td:not(.o_list_record_selector):not(.o_handle_cell):not(.o_list_button):not(.o_list_record_remove) { .o_list_renderer .o_list_table tbody > tr > td:not(.o_list_record_selector):not(.o_handle_cell):not(.o_list_button):not(.o_list_record_remove) {
@@ -205,8 +198,8 @@ div[class="o_content o_component_with_search_panel"] img[name="equipment_image"]
div[class="o_content o_component_with_search_panel"] .o_kanban_card_content button { div[class="o_content o_component_with_search_panel"] .o_kanban_card_content button {
position: absolute; position: absolute;
//top: -52px; top: -52px;
//left: -55px; left: 3rem;
width: 80px; width: 80px;
} }
@@ -253,16 +246,16 @@ div[class="o_content o_component_with_search_panel"] .show_state span {
font-size: 12px; font-size: 12px;
} }
//div[class="o_content o_component_with_search_panel"] .o_kanban_primary_right > .row { div[class="o_content o_component_with_search_panel"] .o_kanban_primary_right > .row {
// position: absolute; position: absolute;
// top: 55px; top: 55px;
// right: 43.5%; right: 43.5%;
//} }
//------------------------------------------ //------------------------------------------
.test_model > .o_form_label { .test_model > .o_form_label {
margin-left: 4px !important; margin-left: 4px !important;
//line-height: 0 !important; line-height: 0 !important;
} }
@media screen and (min-width: 1200px) { @media screen and (min-width: 1200px) {
@@ -270,10 +263,10 @@ div[class="o_content o_component_with_search_panel"] .show_state span {
right: 52%; right: 52%;
} }
//div[class="o_content o_component_with_search_panel"] .o_kanban_card_content button { div[class="o_content o_component_with_search_panel"] .o_kanban_card_content button {
//
// left: -95px; left: -4.4rem;
//} }
} }
@@ -318,177 +311,27 @@ div[class="o_content o_component_with_search_panel"] .show_state span {
.o_horizontal_separator { .o_horizontal_separator {
font-size: 1.5rem; font-size: 1.5rem;
} }
//
//.o_field_widget input[class='o_input'] { .o_field_widget input[class='o_input'] {
//text-align: center text-align: center
//} }
div:has(.o_required_modifier) > label::before { div:has(.o_required_modifier) > label::before {
position: absolute; position: absolute;
left: 24px; left: -3px;
} }
//.o_form_view .o_form_label { .o_form_view .o_form_label {
// position: relative; position: relative;
// width: 9rem; width: 9rem;
// overflow: hidden; overflow: hidden;
// text-overflow: ellipsis; text-overflow: ellipsis;
// white-space: nowrap; white-space: nowrap;
// padding-left: 1rem; padding-left: 1rem;
//}
//
//.o_form_view .o_form_label:hover {
// white-space: normal;
// overflow: visible;
//}
.o_form_view {
.o_form_sheet_bg .o_form_sheet {
//max-width: none !important;
width: auto !important;
max-width: 98% !important;
}
.o_FormRenderer_chatterContainer {
max-width: none;
}
} }
.o_form_view .o_form_label:hover {
// 2023-11-16 hy 新增 white-space: normal;
.o_kanban_card_content .btn-group { overflow: visible;
position: unset;
} }
.o_kanban_card_content .btn-group button{
top: 100px;
left: 168px;
}
.o_kanban_primary_right {
position: absolute;
top: 40px;
left: 168px;
padding: 0;
display: flex;
flex-wrap: wrap;
box-sizing: border-box;
.row {
width: 50%;
margin: 0;
>div {
padding: 0;
width: unset;
margin-right: 10px;
}
}
}
.oe_kanban_details li.o_text_overflow {
display: block;
}
.o_stock_kanban .o_kanban_card_content {
.row {
align-items: center;
.o_kanban_primary_left, .o_kanban_primary_right {
display: block;
}
.o_kanban_primary_right {
position: unset;
}
}
}
// 机床换刀申请表格宽度设置
.o_list_table_ungrouped {
min-width: 1089px;
}
// 加工能力\冷却方式 竖列展示改为横列展示
.processingMethod {
.o_cell.flex-grow-1.flex-sm-grow-0 {
width: 100%!important;
}
}
@media (min-width: 576px) {
.o_inner_group.processingMethod {
grid-template-columns: auto;
}
}
// 设置所有表格序号列padding为0
.o_form_view .o_notebook > .tab-content > .tab-pane > :first-child:not(.o_group) .o_field_x2many.o_field_x2many_list tr > :first-child, .o_form_view .o_notebook > .tab-content > .tab-pane > :first-child.o_invisible_modifier + .o_field_widget .o_field_x2many.o_field_x2many_list tr > :first-child {
padding: 0;
text-align: center;
}
// 设置剩余number类型数据表格列 left
.o_list_renderer .o_list_table thead .o_list_number_th {
text-align:left;
}
.o_list_renderer .o_list_table tbody > tr > td:not(.o_list_record_selector).o_list_number {
text-align: left;
}
.o_list_renderer .flex-row-reverse {
flex-direction: unset!important;
}
.o_list_renderer .flex-row-reverse > .text-end {
text-align: left!important;
}
// 设置modal弹窗样式
.modal.o_technical_modal {
.modal-lg {
@media (min-width: 992px) {
max-width: 1200px;
}
@media (min-width: 576px) {
.o_form_view .o_inner_group {
grid-template-columns: auto;
}
}
}
}
// 更改表格底部按钮样式
.o_list_renderer .o_field_x2many_list_row_add a,.treeHeaderBtn,.o_x2m_control_panel .o_cp_buttons .btn{
display: inline-block;
margin: 5px 0;
font-size: 14px;
color: #71639e;
border: 1px solid #71639e;
padding: 0.2rem 0.6rem;
font-size: 1.08333333rem;
border-radius: 0.25rem;
transition: all .3s;
}
.o_list_renderer .o_field_x2many_list_row_add a:hover,.treeHeaderBtn:hover,.o_x2m_control_panel .o_cp_buttons .btn:hover{
background: #71639e;
color: #fff
}
// 修改时间输入框宽度
.o_datepicker_input.o_input.datetimepicker-input {
width: 200px;
}
.o_form_view .o_form_editable .o_row > .o_field_widget, .o_form_view .o_form_editable .o_row > .o_field_widget.o_field_float_time {
width: auto !important;
flex: unset;
}
.addRequired {
padding-left: calc(0.3rem + 2px)!important;
}
.addRequired:before {
content: '*';
color: red;
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
}
.o_list_renderer .o_list_table tfoot .o_list_number {
text-align: left;
}

View File

@@ -1,4 +0,0 @@
.row_no {
width: 35px !important;
vertical-align: middle;
}

View File

@@ -1,7 +0,0 @@
<templates>
<t t-name="purchase.PurchaseListView" t-inherit="web.ListRenderer" t-inherit-mode="primary" owl="1">
<xpath expr="//div[hasclass('o_list_renderer')]" position="before">
<PurchaseDashBoard />
</xpath>
</t>
</templates>

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

@@ -5,7 +5,7 @@
<t t-name="og.web.ListRenderer" t-inherit="web.ListRenderer" t-inherit-mode="extension"> <t t-name="og.web.ListRenderer" t-inherit="web.ListRenderer" t-inherit-mode="extension">
<xpath expr="//table/thead/tr/th[@t-if='hasSelectors']" position="before"> <xpath expr="//table/thead/tr/th[@t-if='hasSelectors']" position="before">
<th class="row_no"><i class="fa fa-list-ol"/></th> <th><i class="fa fa-list-ol"/></th>
</xpath> </xpath>
</t> </t>

View File

@@ -1,47 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<template>
<t
t-name="rowno_in_tree.ListRenderer"
t-inherit="web.ListRenderer"
t-inherit-mode="extension"
owl="1"
>
<xpath expr="//table/thead/tr/th[@t-if='hasSelectors']" position="before">
<th class="row_no"><i class="fa fa-list-ol"/></th>
</xpath>
<xpath expr="//div/table/tfoot/tr/td" position="before">
<td />
</xpath>
</t>
<t
t-name="rowno_in_tree.add_number"
t-inherit="web.ListRenderer.Rows"
t-inherit-mode="extension"
owl="1"
>
<xpath expr="//t[@t-foreach='list.records']" position="before">
<t t-set="RowNumber" t-value="1" />
</xpath>
<xpath
expr="//t[@t-call='{{ constructor.recordRowTemplate }}']"
position="after"
>
<t t-set="RowNumber" t-value="RowNumber+1" />
</xpath>
</t>
<t
t-name="rowno_in_tree.ListRenderer.RecordRowNumber"
t-inherit="web.ListRenderer.RecordRow"
t-inherit-mode="extension"
owl="1"
>
<xpath expr="//td[@class='o_list_record_selector']" position="before">
<td tabindex="-1">
<span t-esc="RowNumber" />
</td>
</xpath>
</t>
</template>

View File

@@ -1,35 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- 修改页面头部图标及文字 -->
<template id="favicon_icon" inherit_id="web.layout" name="Web layout">
<!-- change the title with reliance partner -->
<xpath expr="//head//title" position="before">
<title t-esc="'JIKIMO'"/>
</xpath>
<!-- change the default favicon icon with -->
<xpath expr="//head//link[@rel='shortcut icon']" position="replace">
<link type="image/x-icon" rel="shortcut icon" href="/jikimo_frontend/static/src/img/jikimo-logo.ico"/>
</xpath>
</template>
<!-- hide 登录页面 powerd by odoo 及管理数据库 -->
<template id="login_page_layout" inherit_id="web.login_layout" name="Login Page Layout">
<xpath expr="//div[@class='card-body']//div[last()]" position="replace"></xpath>
</template>
<!-- 隐藏odoo版本信息 -->
<record id="jikimo_res_config_settings_view_form" model="ir.ui.view">
<field name="name">jikimo.res.config.settings.view.form.inherit.base.setup</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="base_setup.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@id='about']" position="replace">
</xpath>
</field>
</record>
</data>
</odoo>

View File

@@ -1,14 +0,0 @@
# -*- coding: utf-8 -*-
from . import models
from odoo import api, SUPERUSER_ID
def uninstall_hook(cr, registry):
# 使用cr来执行数据库操作
with api.Environment.manage():
env = api.Environment(cr, SUPERUSER_ID, {})
# 执行数据清理操作
access_rights = env['access.right'].search([])
access_rights.unlink()
followers = env['mail.followers'].search([('res_model', '=', 'access.right')])
followers.unlink()

View File

@@ -1,32 +0,0 @@
# -*- coding: utf-8 -*-
{
'name': '机企猫 隐藏项目',
'version': '16.0.1.0.0',
'category': 'Extra Tools, Productivity',
'summary': """ Can hide options from user """,
'description': """ By using this module we can hide the options like create,
delete,export,and archive/un archive in the model which we want. Here we
are also able to select the user groups except Administrator which we want
to apply the above hiding functionality """,
'author': '机企猫-MGW',
'company': '机企猫',
'depends': ['base_setup', 'mail'],
'data': [
'security/security.xml',
'security/ir.model.access.csv',
'views/model_access_rights_views.xml',
],
'assets': {
'web.assets_backend': [
'jikimo_hide_options/static/src/js/form_controller.js',
'jikimo_hide_options/static/src/js/list_controller.js',
'jikimo_hide_options/static/src/js/kanban_controller.js'
]
},
'images': ['static/description/banner.jpg'],
'license': 'LGPL-3',
'installable': True,
'auto_install': False,
'application': False,
'uninstall_hook': 'uninstall_hook',
}

View File

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

View File

@@ -1,107 +0,0 @@
# -*- coding: utf-8 -*-
from odoo import api, fields, models, _
class ModelAccessRights(models.Model):
"""This class is used to detect, which all options want to hide from the
specified group and model"""
_name = 'access.right'
_inherit = 'mail.thread'
_description = 'Manage Modules Access Control'
_rec_name = 'model_id'
model_id = fields.Many2one('ir.model', ondelete='cascade', required=True,
help="select the model")
groups_id = fields.Many2one('res.groups', required=True,
help="select the group")
is_delete = fields.Boolean(string="Delete", help="hide the delete option")
is_export = fields.Boolean(string="Export",
help="hide the 'Export All'"
" option from list view")
is_create_or_update = fields.Boolean(string="Create/Update",
help="hide the create option from list"
" as well as form view")
is_archive = fields.Boolean(string="Archive/UnArchive",
help="hide the archive option")
@api.model
def hide_buttons(self):
"""This function contains a query that detects which all options want
to hide, in which model,and to which user groups"""
access_right_rec = self.sudo().search_read([], ['model_id', 'is_delete',
'is_export',
'is_create_or_update',
'is_archive',
'groups_id'])
for dic in access_right_rec:
model = self.env['ir.model'].sudo().browse(dic['model_id'][0]).model
group_name = self.env['ir.model.data'].sudo().search([
('model', '=', 'res.groups'),
('res_id', '=', dic['groups_id'][0])
]).name
module_name = self.env['ir.model.data'].sudo().search([
('model', '=', 'res.groups'),
('res_id', '=', dic['groups_id'][0])
]).module
dic.update({
'model': model,
'group_name': group_name,
'module': module_name
})
return access_right_rec
# @api.model
# def hide_buttons(self):
# """This function contains a query that detects which all options want
# to hide, in which model,and to which user groups"""
# access_right_rec = self.sudo().search_read([], ['model_id', 'is_delete',
# 'is_export',
# 'is_create_or_update',
# 'is_archive',
# 'groups_id'])
# for dic in access_right_rec:
# model = self.env['ir.model'].sudo().browse(dic['model_id']).model
# group_name = self.env['ir.model.data'].sudo().search([
# ('model', '=', 'res.groups'),
# ('res_id', '=', dic['groups_id'])
# ]).name
# module_name = self.env['ir.model.data'].sudo().search([
# ('model', '=', 'res.groups'),
# ('res_id', '=', dic['groups_id'])
# ]).module
# dic.update({
# 'model': model,
# 'group_name': group_name,
# 'module': module_name
# })
# return access_right_rec
# class AccessRightCleanup(models.Model):
# _name = 'access.right.cleanup' # 定义一个新的模型名
# _description = 'Access Right Cleanup'
# @api.model
# def _module_uninstall(self):
# """在模块卸载时执行清理操作"""
# super(AccessRightCleanup, self)._module_uninstall()
# # 这里执行你的清理逻辑
#
# # 获取access.right模型的所有记录
# access_rights = self.env['access.right'].search([])
# for access_right in access_rights:
# # 删除access.right模型的所有记录
# access_right.unlink()
#
# # 查找所有关联到access.right模型的关注者记录
# followers = self.env['mail.followers'].search([('res_model', '=', 'access.right')])
# for follower in followers:
# # 删除关注者记录
# follower.unlink()
#
# # # 示例:删除自定义数据表(确保先检查外键约束等)
# # self.env.cr.execute('DROP TABLE IF EXISTS access_right CASCADE;')
#
# # 其他清理工作...

View File

@@ -1,353 +0,0 @@
# -*- coding: utf-8 -*-
from collections import defaultdict
from operator import attrgetter
from odoo import api, _
from odoo.exceptions import UserError
from odoo.models import BaseModel, _unlink, LOG_ACCESS_COLUMNS, \
INSERT_BATCH_SIZE, SQL_DEFAULT
# from odoo.tools import OrderedSet, split_every, attrgetter, clean_context
from odoo.tools import OrderedSet, split_every, clean_context
@api.model
def _create(self, data_list):
""" Create records from the stored field values in ``data_list``. """
assert data_list
cr = self.env.cr
# insert rows in batches of maximum INSERT_BATCH_SIZE
ids = [] # ids of created records
other_fields = OrderedSet() # non-column fields
for data_sublist in split_every(INSERT_BATCH_SIZE, data_list):
stored_list = [data['stored'] for data in data_sublist]
fnames = sorted({name for stored in stored_list for name in stored})
columns = []
rows = [[] for _ in stored_list]
for fname in fnames:
field = self._fields[fname]
if field.column_type:
columns.append(fname)
for stored, row in zip(stored_list, rows):
if fname in stored:
colval = field.convert_to_column(stored[fname], self,
stored)
if field.translate is True and colval:
if 'en_US' not in colval.adapted:
colval.adapted['en_US'] = next(
iter(colval.adapted.values()))
row.append(colval)
else:
row.append(SQL_DEFAULT)
else:
other_fields.add(field)
if field.type == 'properties':
# force calling fields.create for properties field because
# we might want to update the parent definition
other_fields.add(field)
if not columns:
# manage the case where we create empty records
columns = ['id']
for row in rows:
row.append(SQL_DEFAULT)
header = ", ".join(f'"{column}"' for column in columns)
template = ", ".join("%s" for _ in rows)
cr.execute(
f'INSERT INTO "{self._table}" ({header}) VALUES {template} RETURNING "id"',
[tuple(row) for row in rows],
)
ids.extend(id_ for id_, in cr.fetchall())
# put the new records in cache, and update inverse fields, for many2one
#
# cachetoclear is an optimization to avoid modified()'s cost until other_fields are processed
cachetoclear = []
records = self.browse(ids)
inverses_update = defaultdict(list) # {(field, value): ids}
common_set_vals = set(
LOG_ACCESS_COLUMNS + [self.CONCURRENCY_CHECK_FIELD, 'id',
'parent_path'])
for data, record in zip(data_list, records):
data['record'] = record
# DLE P104: test_inherit.py, test_50_search_one2many
vals = dict(
{k: v for d in data['inherited'].values() for k, v in d.items()},
**data['stored'])
set_vals = common_set_vals.union(vals)
for field in self._fields.values():
if field.type in ('one2many', 'many2many'):
self.env.cache.set(record, field, ())
elif field.related and not field.column_type:
self.env.cache.set(record, field,
field.convert_to_cache(None, record))
# DLE P123: `test_adv_activity`, `test_message_assignation_inbox`, `test_message_log`, `test_create_mail_simple`, ...
# Set `mail.message.parent_id` to False in cache so it doesn't do the useless SELECT when computing the modified of `child_ids`
# in other words, if `parent_id` is not set, no other message `child_ids` are impacted.
# + avoid the fetch of fields which are False. e.g. if a boolean field is not passed in vals and as no default set in the field attributes,
# then we know it can be set to False in the cache in the case of a create.
elif field.name not in set_vals and not field.compute:
self.env.cache.set(record, field,
field.convert_to_cache(None, record))
for fname, value in vals.items():
field = self._fields[fname]
if field.type in ('one2many', 'many2many'):
cachetoclear.append((record, field))
else:
cache_value = field.convert_to_cache(value, record)
self.env.cache.set(record, field, cache_value)
if field.type in ('many2one', 'many2one_reference') and \
self.pool.field_inverses[field]:
inverses_update[(field, cache_value)].append(record.id)
for (field, value), record_ids in inverses_update.items():
field._update_inverses(self.browse(record_ids), value)
# update parent_path
records._parent_store_create()
# protect fields being written against recomputation
protected = [(data['protected'], data['record']) for data in data_list]
with self.env.protecting(protected):
# mark computed fields as todo
records.modified(self._fields, create=True)
if other_fields:
# discard default values from context for other fields
others = records.with_context(clean_context(self._context))
for field in sorted(other_fields, key=attrgetter('_sequence')):
field.create([
(other, data['stored'][field.name])
for other, data in zip(others, data_list)
if field.name in data['stored']
])
# mark fields to recompute
records.modified([field.name for field in other_fields],
create=True)
# if value in cache has not been updated by other_fields, remove it
for record, field in cachetoclear:
if self.env.cache.contains(record,
field) and not self.env.cache.get(
record, field):
self.env.cache.remove(record, field)
# check Python constraints for stored fields
records._validate_fields(
name for data in data_list for name in data['stored'])
records.check_access_rule('create')
# This is used to restrict the access right to create a record
current_model_id = self.env['ir.model'].sudo().search(
[('model', '=', self._name)]).id
# access_right_rec = self.env['access.right'].sudo().search_read(
# [('model_id', '=', current_model_id)],
# ['model_id', 'is_create_or_update',
# 'groups_id'])
# if access_right_rec and not self.env.is_admin():
# for rec in access_right_rec:
# group_name = self.env['ir.model.data'].sudo().search([
# ('model', '=', 'res.groups'),
# ('res_id', '=', rec['groups_id'][0])
# ]).name
# module_name = self.env['ir.model.data'].sudo().search([
# ('model', '=', 'res.groups'),
# ('res_id', '=', rec['groups_id'][0])
# ]).module
# group = module_name + "." + group_name
# if self.env.user.has_group(group):
# if rec['is_create_or_update']:
# raise UserError('You are restricted from performing this'
# ' operation. Please contact the'
# ' administrator.')
# 检查 'access.right' 模型是否存在于环境中
if 'access.right' in self.env:
access_right_rec = self.env['access.right'].sudo().search_read(
[('model_id', '=', current_model_id)],
['model_id', 'is_create_or_update', 'groups_id']
)
# 如果找到相关记录,并且当前用户不是管理员
if access_right_rec and not self.env.is_admin():
for rec in access_right_rec:
# 获取与权限相关的用户组信息
group_data = self.env['ir.model.data'].sudo().search_read(
[('model', '=', 'res.groups'), ('res_id', '=', rec['groups_id'][0])],
['name', 'module']
)
# 如果找到了用户组数据
if group_data:
group_name = group_data[0]['name']
module_name = group_data[0]['module']
group_xml_id = f"{module_name}.{group_name}"
# 检查当前用户是否属于该组
if self.env.user.has_group(group_xml_id):
# 如果该用户组被限制创建或更新操作
if rec['is_create_or_update']:
raise UserError(
_("You are restricted from performing this operation. Please contact the administrator."))
else:
# 如果 'access.right' 模型不存在,可以在这里定义备选逻辑
# 例如,记录日志、发送通知或者简单地跳过这部分逻辑
pass
return records
@api.model
def unlink(self):
""" unlink()
Deletes the records in ``self``.
:raise AccessError: if the user is not allowed to delete all the given records
:raise UserError: if the record is default property for other records
"""
if not self:
return True
self.check_access_rights('unlink')
self.check_access_rule('unlink')
from odoo.addons.base.models.ir_model import MODULE_UNINSTALL_FLAG
for func in self._ondelete_methods:
# func._ondelete is True if it should be called during uninstallation
if func._ondelete or not self._context.get(MODULE_UNINSTALL_FLAG):
func(self)
# TOFIX: this avoids an infinite loop when trying to recompute a
# field, which triggers the recomputation of another field using the
# same compute function, which then triggers again the computation
# of those two fields
for field in self._fields.values():
self.env.remove_to_compute(field, self)
self.env.flush_all()
cr = self._cr
Data = self.env['ir.model.data'].sudo().with_context({})
Defaults = self.env['ir.default'].sudo()
Property = self.env['ir.property'].sudo()
Attachment = self.env['ir.attachment'].sudo()
ir_property_unlink = Property
ir_model_data_unlink = Data
ir_attachment_unlink = Attachment
# mark fields that depend on 'self' to recompute them after 'self' has
# been deleted (like updating a sum of lines after deleting one line)
with self.env.protecting(self._fields.values(), self):
self.modified(self._fields, before=True)
for sub_ids in cr.split_for_in_conditions(self.ids):
records = self.browse(sub_ids)
# Check if the records are used as default properties.
refs = [f'{self._name},{id_}' for id_ in sub_ids]
if Property.search(
[('res_id', '=', False), ('value_reference', 'in', refs)],
limit=1):
raise UserError(
_('Unable to delete this document because it is used as a default property'))
# Delete the records' properties.
ir_property_unlink |= Property.search([('res_id', 'in', refs)])
query = f'DELETE FROM "{self._table}" WHERE id IN %s'
cr.execute(query, (sub_ids,))
# Removing the ir_model_data reference if the record being deleted
# is a record created by xml/csv file, as these are not connected
# with real database foreign keys, and would be dangling references.
#
# Note: the following steps are performed as superuser to avoid
# access rights restrictions, and with no context to avoid possible
# side-effects during admin calls.
data = Data.search(
[('model', '=', self._name), ('res_id', 'in', sub_ids)])
ir_model_data_unlink |= data
# For the same reason, remove the defaults having some of the
# records as value
Defaults.discard_records(records)
# For the same reason, remove the relevant records in ir_attachment
# (the search is performed with sql as the search method of
# ir_attachment is overridden to hide attachments of deleted
# records)
query = 'SELECT id FROM ir_attachment WHERE res_model=%s AND res_id IN %s'
cr.execute(query, (self._name, sub_ids))
ir_attachment_unlink |= Attachment.browse(
row[0] for row in cr.fetchall())
# invalidate the *whole* cache, since the orm does not handle all
# changes made in the database, like cascading delete!
self.env.invalidate_all(flush=False)
if ir_property_unlink:
ir_property_unlink.unlink()
if ir_model_data_unlink:
ir_model_data_unlink.unlink()
if ir_attachment_unlink:
ir_attachment_unlink.unlink()
# DLE P93: flush after the unlink, for recompute fields depending on
# the modified of the unlink
self.env.flush_all()
# auditing: deletions are infrequent and leave no trace in the database
_unlink.info('User #%s deleted %s records with IDs: %r', self._uid,
self._name, self.ids)
# This is used to restrict the access right to unlink a record
current_model_id = self.env['ir.model'].sudo().search(
[('model', '=', self._name)]).id
# access_right_rec = self.env['access.right'].sudo().search_read(
# [('model_id', '=', current_model_id)], ['model_id', 'is_delete',
# 'groups_id'])
# if access_right_rec and not self.env.is_admin():
# for rec in access_right_rec:
# group_name = self.env['ir.model.data'].sudo().search([
# ('model', '=', 'res.groups'),
# ('res_id', '=', rec['groups_id'][0])
# ]).name
# module_name = self.env['ir.model.data'].sudo().search([
# ('model', '=', 'res.groups'),
# ('res_id', '=', rec['groups_id'][0])
# ]).module
# group = module_name + "." + group_name
# if self.env.user.has_group(group):
# if rec['is_delete']:
# raise UserError(_('You are restricted from performing this'
# ' operation. Please contact the'
# ' administrator.'))
# 检查 'access.right' 模型是否存在于环境中
if 'access.right' in self.env:
# current_model_id = self.env['ir.model'].sudo().search([('model', '=', self._name)]).id
access_right_rec = self.env['access.right'].sudo().search_read(
[('model_id', '=', current_model_id)], ['model_id', 'is_delete', 'groups_id']
)
if access_right_rec and not self.env.is_admin():
for rec in access_right_rec:
group_data = self.env['ir.model.data'].sudo().search_read(
[('model', '=', 'res.groups'), ('res_id', '=', rec['groups_id'][0])],
['name', 'module']
)
if group_data:
group_name = group_data[0]['name']
module_name = group_data[0]['module']
group_xml_id = f"{module_name}.{group_name}"
if self.env.user.has_group(group_xml_id) and rec['is_delete']:
raise UserError(
_('You are restricted from performing this operation. Please contact the administrator.'))
else:
# 如果 'access.right' 模型不存在,可以在这里定义备选逻辑
pass
return True
BaseModel._create = _create
BaseModel.unlink = unlink

View File

@@ -1,2 +0,0 @@
id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
access_access_right,access.access.right,model_access_right,jikimo_hide_options.model_access_rights_groups_configure_model_access,1,1,1,1
1 id name model_id/id group_id/id perm_read perm_write perm_create perm_unlink
2 access_access_right access.access.right model_access_right jikimo_hide_options.model_access_rights_groups_configure_model_access 1 1 1 1

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--Add a group named Configure Model Access in res.groups-->
<odoo>
<record id="model_access_rights_groups_configure_model_access" model="res.groups">
<field name="name">配置隐藏项目</field>
<field name="category_id" ref="base.module_category_usability"/>
<field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
</record>
</odoo>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 310 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 576 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 733 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 911 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 673 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 878 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 653 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 905 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 839 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 427 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 627 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 988 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 589 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 967 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 237 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 219 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -1,596 +0,0 @@
<div style="background-color: #714B67; height: 810px; width: 100%; padding: 15px; position: relative;">
<!-- TITLE BAR -->
<div class="d-flex align-items-center justify-content-between"
style="border-bottom: 1px solid #875A7B; padding: 15px; display: flex; justify-content: space-between; align-items: center;">
<img src="assets/misc/cybrosys-logo.png" width="42" height="42" style="width: 42px; height: 42px;" />
<div>
<div
style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Community
</div>
<div
style="color: #875A7B; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Enterprise
</div>
<div
style="color: #017E84; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Odoo.sh
</div>
</div>
</div>
<!-- END OF TITLE BAR -->
<div class="container">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12">
<!-- APP HERO -->
<h1 style="color: #FFFFFF; font-weight: bolder; font-size: 50px; text-align: center; margin-top: 50px;">
Hide Create|Delete|Archive|Export Options - Model Wise</h1>
<p style="color:#FFFFFF; padding: 8px 15px; text-align: center; font-size: 24px;">Hide Create, Delete, Archive, Export Options in Models</p>
<!-- END OF APP HERO -->
<img src="assets/screenshots/hero.gif" class="img-responsive"
style="width: 100%; margin-left: auto; margin-right: auto;" />
</div>
</div>
</div>
</div>
<!-- NAVIGATION SECTION -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px; margin-top: 300px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/compass.png" />
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Explore This
Module</h2>
</div>
<div class="row my-4" style="font-family: 'Montserrat', sans-serif;">
<div class="col-sm-12 col-md-6 my-3">
<a href="#overview">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Overview</span>
<span
style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">Learn
more about this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36" />
</div>
</a>
</div>
<div class="col-sm-12 col-md-6 my-3">
<a href="#features">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Features</span>
<span
style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View
features of this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36" />
</div>
</a>
</div>
<div class="col-sm-12 col-md-6 my-3">
<a href="#screenshots">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Screenshots</span>
<span
style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View
screenshots of this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36" />
</div>
</a>
</div>
</div>
<!-- END OF NAVIGATION SECTION -->
<!-- OVERVIEW SECTION -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="overview">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/pie-chart.png" />
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Overview
</h2>
</div>
<div class="row" style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;">
<div class="col-sm-12 py-4">
By using this module we can hide the options like create,delete,export,and archive/un archive in the model
which we want. Here we are also able to select the user groups except Administrator which we want to apply the
above hiding functionality </div>
</div>
<!-- END OF OVERVIEW SECTION -->
<!-- FEATURES SECTION -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="features">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/features.png" />
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Features
</h2>
</div>
<div class="row" style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;">
<div class="col-sm-12 col-md-6">
<div class="d-flex align-items-center" style="margin-top: 40px; margin-bottom: 40px">
<img src="assets/misc/check-box.png" class="mr-2" />
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> Easily hide the options like Create,Delete,Export and Archive/UnArchive</span>
</div>
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2" />
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Can hide the options for specific model</span>
</div>
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2" />
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Can hide the options for specific user group</span>
</div>
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2" />
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">No additional configuration needed</span>
</div>
</div>
</div>
<!-- END OF FEATURES SECTION -->
<!-- SCREENSHOTS SECTION -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="screenshots">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/pictures.png" />
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Screenshots
</h2>
</div>
<div class="row">
<div class="col-sm-12">
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> Go to Settings > Users and there you can see the Configure Model Access, by enabling that
option and refresh the page, you can see a new menu named 'Restrict Access Rights'</h3>
<img src="assets/screenshots/model_access_right_01.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> User in the Purchase module</h3>
<img src="assets/screenshots/model_access_right_02.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Select the Model, Groups and the options which we want to hide</h3>
<img src="assets/screenshots/model_access_right_03.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> We can see Create option is hidden in purchase.order to those who are User
in purchase module</h3>
<img src="assets/screenshots/model_access_right_04.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">User in Project module</h3>
<img src="assets/screenshots/model_access_right_05.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> By default, we can see Export and Archive/UnArchive options</h3>
<img src="assets/screenshots/model_access_right_06.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> Select the options which we want to hide</h3>
<img src="assets/screenshots/model_access_right_07.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> Export and Archive/UnArchive functionality are hidden</h3>
<img src="assets/screenshots/model_access_right_08.png" class="img-thumbnail">
</div>
</div>
</div>
<!-- END OF SCREENSHOTS SECTION -->
<!-- RELATED PRODUCTS -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/categories.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Related
Products
</h2>
</div>
<div class="row">
<div class="col-sm-12">
<div id="demo1" class="row carousel slide" data-ride="carousel">
<!-- The slideshow -->
<div class="carousel-inner" style="padding: 30px;">
<div class="carousel-item" style="min-height: 198.656px;">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/openai_odoo_base/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/1.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/woo_commerce/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/l2.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/shopify_odoo_connector/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/l3.png">
</div>
</a>
</div>
</div>
<div class="carousel-item active"
style="min-height: 198.656px;">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/hr_zk_attendance/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/l4.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/whatsapp_redirect/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/l5.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/openai_website_product_media/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/l6.png">
</div>
</a>
</div>
</div>
</div>
<!-- Left and right controls -->
<a class="carousel-control-prev" href="#demo1" data-slide="prev"
style="width:35px; color:#000"> <span
class="carousel-control-prev-icon"><i
class="fa fa-chevron-left"
style="font-size:24px"></i></span>
</a> <a class="carousel-control-next" href="#demo1"
data-slide="next" style="width:35px; color:#000">
<span class="carousel-control-next-icon"><i
class="fa fa-chevron-right"
style="font-size:24px"></i></span>
</a>
</div>
</div>
</div>
<!-- END OF RELATED PRODUCTS -->
<!-- OUR SERVICES -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/star.png" />
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Our Services
</h2>
</div>
<div class="container my-5">
<div class="row">
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #1dd1a1 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/cogs.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Customization</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #ff6b6b !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/wrench.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Implementation</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #6462CD !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/lifebuoy.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Support</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #ffa801 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/user.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Hire
Odoo
Developer</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #54a0ff !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/puzzle.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Integration</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #6d7680 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/update.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Migration</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #786fa6 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/consultation.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Consultancy</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #f8a5c2 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/training.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Implementation</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #e6be26 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/license.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Licensing Consultancy</h6>
</div>
</div>
</div>
<!-- END OF OUR SERVICES -->
<!-- OUR INDUSTRIES -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/corporate.png" />
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Our
Industries
</h2>
</div>
<div class="container my-5">
<div class="row">
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/trading-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Trading
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Easily procure
and
sell your products</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/pos-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
POS
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Easy
configuration
and convivial experience</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/education-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Education
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
A platform for
educational management</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/manufacturing-black.png" class="img-responsive mb-3" height="48px"
width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Manufacturing
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Plan, track and
schedule your operations</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/ecom-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
E-commerce &amp; Website
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Mobile
friendly,
awe-inspiring product pages</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/service-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Service Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Keep track of
services and invoice</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/restaurant-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Restaurant
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Run your bar or
restaurant methodically</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/hotel-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Hotel Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
An
all-inclusive
hotel management application</p>
</div>
</div>
</div>
</div>
<!-- END OF OUR INDUSTRIES -->
<!-- SUPPORT -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/customer-support.png" />
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Support
</h2>
</div>
<div class="container mt-5">
<div class="row">
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4"
style="background-color: #714B67; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="assets/misc/support.png" height="48" width="48" style="width: 42px; height: 42px;" />
</div>
<div>
<h4>Need Help?</h4>
<p style="line-height: 100%;">Got questions or need help? Get in touch.</p>
<a href="mailto:odoo@cybrosys.com">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">
odoo@cybrosys.com</p>
</a>
</div>
</div>
</div>
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4"
style="background-color: #2AC44D; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="assets/misc/whatsapp.png" height="52" width="52" style="width: 52px; height: 52px;" />
</div>
<div>
<h4>WhatsApp</h4>
<p style="line-height: 100%;">Say hi to us on WhatsApp!</p>
<a href="https://api.whatsapp.com/send?phone=918606827707">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">+91 86068
27707</p>
</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 my-5 d-flex justify-content-center align-items-center">
<img src="assets/misc/logo.png" width="144" height="31"
style="width:144px; height: 31px; margin-top: 40px;" />
</div>
</div>
</div>
<!-- END OF SUPPORT -->

View File

@@ -1,46 +0,0 @@
/** @odoo-module */
/**
* This file will used to hide the selected options from the form view
*/
import { FormController} from "@web/views/form/form_controller";
import { patch} from "@web/core/utils/patch";
var rpc = require('web.rpc');
const { onWillStart} = owl;
patch(FormController.prototype, 'jikimo_hide_options/static/src/js/form_controller.js.FormController', {
/**
* This function will used to hide the selected options from the form view
*/
setup() {
this._super();
onWillStart(async () => {
var self = this
var result;
await rpc.query({
model: 'access.right',
method: 'hide_buttons',
}).then(function(data) {
result = data;
});
for (var i = 0; i < result.length; i++) {
var group = result[i].module + "." + result[i].group_name
if (self.props.resModel == result[i].model) {
if (await self.user.hasGroup(group)) {
if (!this.user.isAdmin) {
if (result[i].is_create_or_update) {
self.canCreate = false
}
if (result[i].is_delete) {
this.archInfo.activeActions.delete = false
}
if (result[i].is_archive) {
self.archiveEnabled = false
} else {
self.archiveEnabled = true;
}
}
}
}
}
});
}
});

View File

@@ -1,42 +0,0 @@
/** @odoo-module */
/**
* This file will used to hide the selected options from the list view
*/
import { KanbanController } from '@web/views/kanban/kanban_controller';
import { patch} from "@web/core/utils/patch";
var rpc = require('web.rpc');
const {onWillStart} = owl;
patch(KanbanController.prototype, 'jikimo_hide_options/static/src/js/list_controller.js.KanbanController', {
/**
* This function will used to hide the selected options from the Kanban view
*/
setup() {
this._super();
onWillStart(async () => {
var self = this
var result;
await rpc.query({
model: 'access.right',
method: 'hide_buttons',
}).then(function(data) {
result = data;
});
for (var i = 0; i < result.length; i++) {
var group = result[i].module + "." + result[i].group_name
if (self.props.resModel == result[i].model) {
if (await self.model.user.hasGroup(group)) {
if (!self.model.user.isAdmin) {
if (result[i].is_create_or_update) {
self.props.archInfo.activeActions.create=false
self.props.archInfo.activeActions.edit=false
}
if (result[i].is_delete) {
self.props.archInfo.activeActions.delete=false
}
}
}
}
}
});
}
});

View File

@@ -1,50 +0,0 @@
/** @odoo-module */
/**
* This file will used to hide the selected options from the list view
*/
import { ListController} from '@web/views/list/list_controller';
import { patch} from "@web/core/utils/patch";
var rpc = require('web.rpc');
const {onWillStart} = owl;
patch(ListController.prototype, 'jikimo_hide_options/static/src/js/list_controller.js.ListController', {
/**
* This function will used to hide the selected options from the list view
*/
setup() {
this._super();
onWillStart(async () => {
var self = this
var result;
await rpc.query({
model: 'access.right',
method: 'hide_buttons',
}).then(function(data) {
result = data;
});
for (var i = 0; i < result.length; i++) {
var group = result[i].module + "." + result[i].group_name
if (self.props.resModel == result[i].model) {
if (await self.userService.hasGroup(group)) {
if (!this.userService.isAdmin) {
if (result[i].is_create_or_update) {
self.activeActions.create = false;
}
if (result[i].is_export) {
self.isExportEnable = false
self.isExportEnable = false
}
if (result[i].is_delete) {
self.activeActions.delete = false;
}
if (result[i].is_archive) {
self.archiveEnabled = false;
} else {
self.archiveEnabled = true;
}
}
}
}
}
});
}
});

View File

@@ -1,58 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Action for the menu Restrict Model Access-->
<record id="access_right_action" model="ir.actions.act_window">
<field name="name">隐藏项目</field>
<field name="res_model">access.right</field>
<field name='view_mode'>tree,form</field>
</record>
<!-- Tree view for the model access.right-->
<record id="access_right_view_tree" model="ir.ui.view">
<field name="name">access.right.view.tree</field>
<field name="model">access.right</field>
<field name="arch" type="xml">
<tree>
<field name="model_id" string="模型"/>
<field name="groups_id" string="用户组"/>
<field name="is_delete" string="删除"/>
<field name="is_export" string="导出"/>
<field name="is_create_or_update" string="创建或更新"/>
<field name="is_archive" string="归档"/>
</tree>
</field>
</record>
<!-- Form view for the model access.right-->
<record id="access_right_view_form" model="ir.ui.view">
<field name="name">access.right.view.form</field>
<field name="model">access.right</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<group>
<field name="model_id" string="模型"/>
<field name="groups_id" string="用户组"/>
</group>
<group>
<field name="is_delete" string="删除"/>
<field name="is_export" string="导出"/>
<field name="is_create_or_update" string="创建或更新"/>
<field name="is_archive" string="归档"/>
</group>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="message_ids"/>
</div>
</form>
</field>
</record>
<!-- Creating a menu named Restrict Model Access-->
<menuitem id="access_right_menu"
name="隐藏项目"
parent="base.menu_administration"
action="access_right_action"
sequence="6"
groups="jikimo_hide_options.model_access_rights_groups_configure_model_access"/>
</odoo>

View File

@@ -23,7 +23,7 @@ html .o_web_client > .o_action_manager > .o_action {
} }
.o_form_view { .o_form_view {
//background-color: unset !important; background-color: unset !important;
min-height: unset !important; min-height: unset !important;
} }

View File

@@ -38,9 +38,9 @@
<xpath expr="//field[@name='state']" position="after"> <xpath expr="//field[@name='state']" position="after">
<field name="production_state" invisible="1"/> <field name="production_state" invisible="1"/>
</xpath> </xpath>
<!-- <xpath expr="//button[@name='action_open_wizard']" position="after">--> <xpath expr="//button[@name='action_open_wizard']" position="after">
<!-- <button name="open_tablet_view" type="object" icon="fa-tablet" title="Open Tablet View" context="{'from_production_order': True}" attrs="{'invisible': ['|', ('production_state', 'in', ('draft', 'cancel', 'done')), ('state', '=', 'done')]}"/>--> <button name="open_tablet_view" type="object" icon="fa-tablet" title="Open Tablet View" context="{'from_production_order': True}" attrs="{'invisible': ['|', ('production_state', 'in', ('draft', 'cancel', 'done')), ('state', '=', 'done')]}"/>
<!-- </xpath>--> </xpath>
</field> </field>
</record> </record>

View File

@@ -4,14 +4,14 @@ csv_internal_sep = ,
data_dir = /var/lib/odoo data_dir = /var/lib/odoo
db_host = 172.17.0.2 db_host = 172.17.0.2
db_maxconn = 64 db_maxconn = 64
db_name = sf_t2cs_003 db_name = sf_cs_dev937
db_password = sf db_password = sf
db_port = 5432 db_port = 5432
db_sslmode = prefer db_sslmode = prefer
db_template = template0 db_template = template0
db_user = sf db_user = sf
dbfilter = dbfilter =
without_demo = all demo = {}
email_from = False email_from = False
from_filter = False from_filter = False
geoip_database = /usr/share/GeoIP/GeoLite2-City.mmdb geoip_database = /usr/share/GeoIP/GeoLite2-City.mmdb
@@ -56,6 +56,7 @@ test_tags = None
;transient_age_limit = 1.0 ;transient_age_limit = 1.0
;translate_modules = ['all'] ;translate_modules = ['all']
unaccent = False unaccent = False
upgrade_path = upgrade_path =
without_demo = False
workers = 0 workers = 0

View File

@@ -263,8 +263,6 @@ class QualityCheck(models.Model):
picture = fields.Binary('Picture', attachment=True) picture = fields.Binary('Picture', attachment=True)
additional_note = fields.Text( additional_note = fields.Text(
'Additional Note', help="Additional remarks concerning this check.") 'Additional Note', help="Additional remarks concerning this check.")
report_result = fields.Char('检测结果', readonly=True)
report_pdf = fields.Binary('检测报告', readonly=True)
def _compute_alert_count(self): def _compute_alert_count(self):
alert_data = self.env['quality.alert'].read_group([('check_id', 'in', self.ids)], ['check_id'], ['check_id']) alert_data = self.env['quality.alert'].read_group([('check_id', 'in', self.ids)], ['check_id'], ['check_id'])
@@ -410,5 +408,3 @@ class QualityAlert(models.Model):
domain = [('team_ids', '=', False)] domain = [('team_ids', '=', False)]
stage_ids = stages._search(domain, order=order, access_rights_uid=SUPERUSER_ID) stage_ids = stages._search(domain, order=order, access_rights_uid=SUPERUSER_ID)
return stages.browse(stage_ids) return stages.browse(stage_ids)

View File

@@ -9,10 +9,8 @@ access_quality_point_user,quality.point,quality.model_quality_point,quality.grou
access_quality_point_test_type_user,quality.point.test_type,quality.model_quality_point_test_type,quality.group_quality_user,1,0,0,0 access_quality_point_test_type_user,quality.point.test_type,quality.model_quality_point_test_type,quality.group_quality_user,1,0,0,0
access_quality_check_stock_user,quality.check,quality.model_quality_check,stock.group_stock_user,1,1,1,0 access_quality_check_stock_user,quality.check,quality.model_quality_check,stock.group_stock_user,1,1,1,0
access_stock_lot_user,stock.lot,stock.model_stock_lot,quality.group_quality_user,1,0,0,0 access_stock_lot_user,stock.lot,stock.model_stock_lot,quality.group_quality_user,1,0,0,0
access_stock_pack_user,stock.move.line,stock.model_stock_move_line,quality.group_quality_user,1,0,0,0 access_stock_pack_user,stock.move.line,stock.model_stock_move_line,quality.group_quality_user,1,0,0,0
access_stock_picking_group_quality_user,stock_picking_group_quality_user,stock.model_stock_picking,quality.group_quality_user,1,0,0,0 access_stock_picking,stock.move.line,stock.model_stock_picking,quality.group_quality_user,1,0,0,0
access_quality_alert_team_manager,quality.alert.team,quality.model_quality_alert_team,quality.group_quality_manager,1,1,1,1 access_quality_alert_team_manager,quality.alert.team,quality.model_quality_alert_team,quality.group_quality_manager,1,1,1,1
access_quality_check_manager,quality.check,quality.model_quality_check,quality.group_quality_manager,1,1,1,1 access_quality_check_manager,quality.check,quality.model_quality_check,quality.group_quality_manager,1,1,1,1
access_quality_alert_manager,quality.alert,quality.model_quality_alert,quality.group_quality_manager,1,1,1,1 access_quality_alert_manager,quality.alert,quality.model_quality_alert,quality.group_quality_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
9 access_quality_point_test_type_user quality.point.test_type quality.model_quality_point_test_type quality.group_quality_user 1 0 0 0
10 access_quality_check_stock_user quality.check quality.model_quality_check stock.group_stock_user 1 1 1 0
11 access_stock_lot_user stock.lot stock.model_stock_lot quality.group_quality_user 1 0 0 0
access_stock_pack_user stock.move.line stock.model_stock_move_line quality.group_quality_user 1 0 0 0
12 access_stock_picking_group_quality_user access_stock_pack_user stock_picking_group_quality_user stock.move.line stock.model_stock_picking stock.model_stock_move_line quality.group_quality_user 1 0 0 0
13 access_quality_alert_team_manager access_stock_picking quality.alert.team stock.move.line quality.model_quality_alert_team stock.model_stock_picking quality.group_quality_manager quality.group_quality_user 1 1 0 1 0 1 0
access_quality_check_manager quality.check quality.model_quality_check quality.group_quality_manager 1 1 1 1
14 access_quality_alert_manager access_quality_alert_team_manager quality.alert quality.alert.team quality.model_quality_alert quality.model_quality_alert_team quality.group_quality_manager 1 1 1 1
15 access_quality_reason_manager access_quality_check_manager quality.reason quality.check quality.model_quality_reason quality.model_quality_check quality.group_quality_manager 1 1 1 1
16 access_quality_tag_manager access_quality_alert_manager quality.tag quality.alert quality.model_quality_tag quality.model_quality_alert quality.group_quality_manager 1 1 1 1

View File

@@ -7,15 +7,10 @@
<field name="model">quality.point</field> <field name="model">quality.point</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form> <form>
<header>
</header>
<sheet> <sheet>
<div class="oe_button_box" name="button_box"/> <div class="oe_button_box" name="button_box"/>
<widget name="web_ribbon" title="Archived" bg_color="bg-danger" <widget name="web_ribbon" title="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
attrs="{'invisible': [('active', '=', True)]}"/> <h2><field name="name" readonly="1"/></h2>
<h2>
<field name="name" readonly="1"/>
</h2>
<group> <group>
<group> <group>
<field name="active" invisible="1"/> <field name="active" invisible="1"/>
@@ -38,14 +33,13 @@
<field name="note" placeholder="Describe the quality check to do..."/> <field name="note" placeholder="Describe the quality check to do..."/>
</page> </page>
<page string="Notes" name="Notes"> <page string="Notes" name="Notes">
<field name="reason" string="Note" <field name="reason" string="Note" placeholder="Describe why you need to perform this quality check..."/>
placeholder="Describe why you need to perform this quality check..."/>
</page> </page>
</notebook> </notebook>
</sheet> </sheet>
<div class="oe_chatter"> <div class="oe_chatter">
<field name="message_follower_ids"/> <field name="message_follower_ids"/>
<field name="message_ids"/> <field name="message_ids"/>
</div> </div>
</form> </form>
</field> </field>
@@ -91,18 +85,17 @@
<filter name="filter_date_close" date="date_close"/> <filter name="filter_date_close" date="date_close"/>
<separator/> <separator/>
<filter string="Late Activities" name="activities_overdue" <filter string="Late Activities" name="activities_overdue"
domain="[('my_activity_date_deadline', '&lt;', context_today().strftime('%Y-%m-%d'))]" domain="[('my_activity_date_deadline', '&lt;', context_today().strftime('%Y-%m-%d'))]"
help="Show all records which has next action date is before today"/> help="Show all records which has next action date is before today"/>
<filter string="Today Activities" name="activities_today" <filter string="Today Activities" name="activities_today"
domain="[('my_activity_date_deadline', '=', context_today().strftime('%Y-%m-%d'))]"/> domain="[('my_activity_date_deadline', '=', context_today().strftime('%Y-%m-%d'))]"/>
<filter string="Future Activities" name="activities_upcoming_all" <filter string="Future Activities" name="activities_upcoming_all"
domain="[('my_activity_date_deadline', '&gt;', context_today().strftime('%Y-%m-%d'))]"/> domain="[('my_activity_date_deadline', '&gt;', context_today().strftime('%Y-%m-%d'))]"/>
<group expand="0" string="Group By"> <group expand="0" string="Group By">
<filter string="Stage" name="groupby_stage" domain="[]" context="{'group_by': 'stage_id'}"/> <filter string="Stage" name="groupby_stage" domain="[]" context="{'group_by': 'stage_id'}"/>
<filter string="Responsible" name="groupby_user" domain="[]" context="{'group_by': 'user_id'}"/> <filter string="Responsible" name="groupby_user" domain="[]" context="{'group_by': 'user_id'}"/>
<filter string="Root Cause" name="groupby_reason" domain="[]" context="{'group_by': 'reason_id'}"/> <filter string="Root Cause" name="groupby_reason" domain="[]" context="{'group_by': 'reason_id'}"/>
<filter string="Creation Date" name="groupby_createmonth" domain="[]" <filter string="Creation Date" name="groupby_createmonth" domain="[]" context="{'group_by': 'create_date'}"/>
context="{'group_by': 'create_date'}"/>
<filter string="Quality Team" name="groupby_team_id" domain="[]" context="{'group_by': 'team_id'}"/> <filter string="Quality Team" name="groupby_team_id" domain="[]" context="{'group_by': 'team_id'}"/>
</group> </group>
</search> </search>
@@ -129,4 +122,4 @@
</record> </record>
<!-- js stuff --> <!-- js stuff -->
</odoo> </odoo>

View File

@@ -32,9 +32,7 @@
<field name="tag_ids"/> <field name="tag_ids"/>
</div> </div>
<div> <div>
<strong> <strong><field name="product_tmpl_id"/></strong>
<field name="product_tmpl_id"/>
</strong>
</div> </div>
<div> <div>
<field name="display_name"/> <field name="display_name"/>
@@ -67,28 +65,20 @@
<field name="company_id" invisible="1"/> <field name="company_id" invisible="1"/>
<field name="product_id" invisible="1"/> <field name="product_id" invisible="1"/>
<div class="oe_button_box"> <div class="oe_button_box">
<button name="action_see_check" type="object" attrs="{'invisible': [('check_id', '=', False)]}" <button name="action_see_check" type="object" attrs="{'invisible': [('check_id', '=', False)]}" class="oe_stat_button" icon="fa-check-square-o">
class="oe_stat_button" icon="fa-check-square-o">
<div class="o_field_widget o_stat_info"> <div class="o_field_widget o_stat_info">
<span class="o_stat_value"> <span class="o_stat_value"><field name="check_id" readonly="1"/></span>
<field name="check_id" readonly="1"/>
</span>
<span class="o_stat_text">Quality Check</span> <span class="o_stat_text">Quality Check</span>
</div> </div>
</button> </button>
</div> </div>
<div class="oe_title"> <div class="oe_title"><h1><field name="name" readonly="1"/></h1></div>
<h1>
<field name="name" readonly="1"/>
</h1>
</div>
<group> <group>
<group> <group>
<field name="title"/> <field name="title"/>
<field name="product_tmpl_id"/> <field name="product_tmpl_id"/>
<field name="product_id" groups="product.group_product_variant"/> <field name="product_id" groups="product.group_product_variant"/>
<field name="lot_id" context="{'default_product_id': product_id}" <field name="lot_id" context="{'default_product_id': product_id}" groups="stock.group_production_lot"/>
groups="stock.group_production_lot"/>
<field name="picking_id"/> <field name="picking_id"/>
</group> </group>
<group> <group>
@@ -154,25 +144,25 @@
</record> </record>
<record id="quality_alert_view_pivot" model="ir.ui.view"> <record id="quality_alert_view_pivot" model="ir.ui.view">
<field name="name">quality.alert.view.pivot</field> <field name="name">quality.alert.view.pivot</field>
<field name="model">quality.alert</field> <field name="model">quality.alert</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<pivot string="Quality Alert Analysis" sample="1"> <pivot string="Quality Alert Analysis" sample="1">
<field name="stage_id" type="col"/> <field name="stage_id" type="col"/>
<field name="team_id" type="row"/> <field name="team_id" type="row"/>
</pivot> </pivot>
</field> </field>
</record> </record>
<record id="quality_alert_view_graph" model="ir.ui.view"> <record id="quality_alert_view_graph" model="ir.ui.view">
<field name="name">quality.alert.view.graph</field> <field name="name">quality.alert.view.graph</field>
<field name="model">quality.alert</field> <field name="model">quality.alert</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<graph string="Quality Alert Analysis" sample="1"> <graph string="Quality Alert Analysis" sample="1">
<field name="reason_id"/> <field name="reason_id"/>
<field name="stage_id"/> <field name="stage_id"/>
</graph> </graph>
</field> </field>
</record> </record>
<record id="quality_alert_view_calendar" model="ir.ui.view"> <record id="quality_alert_view_calendar" model="ir.ui.view">
@@ -196,8 +186,7 @@
<field name="view_mode">kanban,tree,form,pivot,graph,calendar</field> <field name="view_mode">kanban,tree,form,pivot,graph,calendar</field>
<field name="domain">[('team_id', '=', active_id)]</field> <field name="domain">[('team_id', '=', active_id)]</field>
<field name="context">{'default_team_id': active_id, <field name="context">{'default_team_id': active_id,
'search_default_team_id': [active_id]} 'search_default_team_id': [active_id]}</field>
</field>
</record> </record>
<record id="quality_alert_action_check" model="ir.actions.act_window"> <record id="quality_alert_action_check" model="ir.actions.act_window">
@@ -206,7 +195,7 @@
<field name="view_mode">kanban,tree,form,pivot,graph,calendar</field> <field name="view_mode">kanban,tree,form,pivot,graph,calendar</field>
<field name="help" type="html"> <field name="help" type="html">
<p class="o_view_nocontent_smiling_face"> <p class="o_view_nocontent_smiling_face">
Create a new quality alert Create a new quality alert
</p> </p>
</field> </field>
</record> </record>
@@ -223,35 +212,24 @@
</record> </record>
<!-- QUALITY.CHECK --> <!-- QUALITY.CHECK -->
<record id="quality_check_view_form" model="ir.ui.view"> <record id="quality_check_view_form" model="ir.ui.view">
<field name="name">quality.check.view.form</field> <field name="name">quality.check.view.form</field>
<field name="model">quality.check</field> <field name="model">quality.check</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form> <form>
<header> <header>
<button name="do_pass" type="object" class="btn-primary" <button name="do_pass" type="object" class="btn-primary" attrs="{'invisible': [('quality_state', '!=', 'none')]}" string="Pass" data-hotkey="q"/>
attrs="{'invisible': [('quality_state', '!=', 'none')]}" string="Pass" data-hotkey="q"/> <button name="do_pass" type="object" attrs="{'invisible': [('quality_state', '!=', 'fail')]}" groups="quality.group_quality_manager" string="Pass" data-hotkey="q"/>
<button name="do_pass" type="object" attrs="{'invisible': [('quality_state', '!=', 'fail')]}" <button name="do_fail" type="object" class="btn-primary" attrs="{'invisible': [('quality_state', '!=', 'none')]}" string="Fail" data-hotkey="w"/>
groups="quality.group_quality_manager" string="Pass" data-hotkey="q"/> <button name="do_fail" type="object" attrs="{'invisible': [('quality_state', '!=', 'pass')]}" groups="quality.group_quality_manager" string="Fail" data-hotkey="w"/>
<button name="do_fail" type="object" class="btn-primary" <button name="do_measure" type="object" attrs="{'invisible': ['|', ('test_type', '!=', 'measure'), ('quality_state', '!=', 'none')]}" string="Measure" data-hotkey="v"/>
attrs="{'invisible': [('quality_state', '!=', 'none')]}" string="Fail" data-hotkey="w"/> <button name="do_alert" type="object" attrs="{'invisible': ['|', ('alert_ids', '!=', []), ('quality_state', '!=', 'pass')]}" string="Create Alert" data-hotkey="g"/>
<button name="do_fail" type="object" attrs="{'invisible': [('quality_state', '!=', 'pass')]}" <button name="do_alert" type="object" class="btn-primary" attrs="{'invisible': ['|', ('alert_ids', '!=', []), ('quality_state', '!=', 'fail')]}" string="Create Alert" data-hotkey="g"/>
groups="quality.group_quality_manager" string="Fail" data-hotkey="w"/>
<button name="do_measure" type="object"
attrs="{'invisible': ['|', ('test_type', '!=', 'measure'), ('quality_state', '!=', 'none')]}"
string="Measure" data-hotkey="v"/>
<button name="do_alert" type="object"
attrs="{'invisible': ['|', ('alert_ids', '!=', []), ('quality_state', '!=', 'pass')]}"
string="Create Alert" data-hotkey="g"/>
<button name="do_alert" type="object" class="btn-primary"
attrs="{'invisible': ['|', ('alert_ids', '!=', []), ('quality_state', '!=', 'fail')]}"
string="Create Alert" data-hotkey="g"/>
<field name="quality_state" widget="statusbar"/> <field name="quality_state" widget="statusbar"/>
</header> </header>
<sheet> <sheet>
<div class="oe_button_box" name="button_box"> <div class="oe_button_box" name="button_box">
<button name="action_see_alerts" icon="fa-bell" type="object" class="oe_stat_button" <button name="action_see_alerts" icon="fa-bell" type="object" class="oe_stat_button" attrs="{'invisible': [('alert_count', '=', 0)]}">
attrs="{'invisible': [('alert_count', '=', 0)]}">
<field name="alert_count" string="Alerts" widget="statinfo"/> <field name="alert_count" string="Alerts" widget="statinfo"/>
</button> </button>
</div> </div>
@@ -264,27 +242,21 @@
<field name="move_line_id" invisible="1"/> <field name="move_line_id" invisible="1"/>
<field name="product_tracking" invisible="1"/> <field name="product_tracking" invisible="1"/>
<field name="is_lot_tested_fractionally" invisible="1"/> <field name="is_lot_tested_fractionally" invisible="1"/>
<field name="lot_name" <field name="lot_name" attrs="{'invisible': ['|', ('product_tracking', '=', 'none'), '|', ('show_lot_text', '=', False), '|', ('measure_on', '!=', 'move_line'), ('move_line_id', '=', False)]}"/>
attrs="{'invisible': ['|', ('product_tracking', '=', 'none'), '|', ('show_lot_text', '=', False), '|', ('measure_on', '!=', 'move_line'), ('move_line_id', '=', False)]}"/> <field name="lot_id" attrs="{'invisible': ['|', ('product_tracking', '=', 'none'), '|', ('show_lot_text', '=', True), ('measure_on', '!=', 'move_line')]}"/>
<field name="lot_id"
attrs="{'invisible': ['|', ('product_tracking', '=', 'none'), '|', ('show_lot_text', '=', True), ('measure_on', '!=', 'move_line')]}"/>
<label for="qty_line" attrs="{'invisible': [('move_line_id', '=', False)]}"/> <label for="qty_line" attrs="{'invisible': [('move_line_id', '=', False)]}"/>
<div class="o_row" attrs="{'invisible': [('move_line_id', '=', False)]}"> <div class="o_row" attrs="{'invisible': [('move_line_id', '=', False)]}">
<field name="qty_line"/> <field name="qty_line"/>
<field name="uom_id"/> <field name="uom_id"/>
</div> </div>
<label for="qty_to_test" <label for="qty_to_test" attrs="{'invisible': ['|', ('move_line_id', '=', False), '|', ('measure_on', '!=', 'move_line'), ('is_lot_tested_fractionally', '=', False)]}"/>
attrs="{'invisible': ['|', ('move_line_id', '=', False), '|', ('measure_on', '!=', 'move_line'), ('is_lot_tested_fractionally', '=', False)]}"/> <div class="o_row" attrs="{'invisible': ['|', ('move_line_id', '=', False), '|', ('measure_on', '!=', 'move_line'), ('is_lot_tested_fractionally', '=', False)]}">
<div class="o_row" <field name="qty_to_test"/>
attrs="{'invisible': ['|', ('move_line_id', '=', False), '|', ('measure_on', '!=', 'move_line'), ('is_lot_tested_fractionally', '=', False)]}">
<field name="qty_to_test"/>
<field name="uom_id"/> <field name="uom_id"/>
</div> </div>
<label for="qty_tested" <label for="qty_tested" attrs="{'invisible': ['|', ('measure_on', '!=', 'move_line'), ('is_lot_tested_fractionally', '=', False)]}"/>
attrs="{'invisible': ['|', ('measure_on', '!=', 'move_line'), ('is_lot_tested_fractionally', '=', False)]}"/> <div class="o_row" attrs="{'invisible': ['|', ('measure_on', '!=', 'move_line'), ('is_lot_tested_fractionally', '=', False)]}">
<div class="o_row" <field name="qty_tested" attrs="{'readonly': [('quality_state', '!=', 'none')]}"/>
attrs="{'invisible': ['|', ('measure_on', '!=', 'move_line'), ('is_lot_tested_fractionally', '=', False)]}">
<field name="qty_tested" attrs="{'readonly': [('quality_state', '!=', 'none')]}"/>
<field name="uom_id"/> <field name="uom_id"/>
</div> </div>
<field name="test_type" invisible="1"/> <field name="test_type" invisible="1"/>
@@ -292,32 +264,26 @@
<field name="alert_ids" invisible="1"/> <field name="alert_ids" invisible="1"/>
</group> </group>
<group> <group>
<field name="picking_id" <field name="picking_id" attrs="{'invisible': [('quality_state', 'in', ('pass', 'fail')), ('picking_id', '=', False)]}"/>
attrs="{'invisible': [('quality_state', 'in', ('pass', 'fail')), ('picking_id', '=', False)]}"/>
<field name="point_id"/> <field name="point_id"/>
<field string="Type" name="test_type_id" options="{'no_open': True, 'no_create': True}" <field string="Type" name="test_type_id" options="{'no_open': True, 'no_create': True}" attrs="{'readonly': [('point_id', '!=', False)]}"/>
attrs="{'readonly': [('point_id', '!=', False)]}"/>
<field name="control_date" invisible="1"/> <field name="control_date" invisible="1"/>
<field name="team_id"/> <field name="team_id"/>
<field name="company_id" groups="base.group_multi_company"/> <field name="company_id" groups="base.group_multi_company"/>
<field name="user_id" string="Control Person" invisible="1"/> <field name="user_id" string="Control Person" invisible="1"/>
<field name="partner_id" string="Partner" <field name="partner_id" string="Partner" attrs="{'invisible': [('partner_id', '=', False)]}"/>
attrs="{'invisible': [('partner_id', '=', False)]}"/>
</group> </group>
</group> </group>
<group attrs="{'invisible': [('test_type', '!=', 'picture')]}"> <group attrs="{'invisible': [('test_type', '!=', 'picture')]}">
<field name="picture" widget="image"/> <field name="picture" widget="image"/>
</group> </group>
<notebook> <notebook>
<page string="Notes" name="notes"> <page string="Notes" name="notes">
<group> <group>
<field name="report_result"/> <field string="Instructions" name="note"/>
<field name="report_pdf" widget="pdf_viewer"/> <field string="Notes" name="additional_note"/>
<field string="Instructions" name="note"/> </group>
<field string="Notes" name="additional_note"/> </page>
</group>
</page>
</notebook> </notebook>
</sheet> </sheet>
<div class="oe_chatter"> <div class="oe_chatter">
@@ -345,30 +311,18 @@
<div t-attf-class="oe_kanban_card oe_kanban_global_click"> <div t-attf-class="oe_kanban_card oe_kanban_global_click">
<div class="row"> <div class="row">
<div class="col-6"> <div class="col-6">
<strong> <strong><span><t t-esc="record.name.value"/></span></strong>
<span>
<t t-esc="record.name.value"/>
</span>
</strong>
</div> </div>
<div class="col-6"> <div class="col-6">
<strong> <strong><span t-attf-class="float-end text-end badge #{['none'].indexOf(record.quality_state.raw_value) > -1 ? 'text-bg-secondary' : ['fail'].indexOf(record.quality_state.raw_value) > -1 ? 'text-bg-danger' : ['done'].indexOf(record.quality_state.raw_value) > -1 ? 'text-bg-primary' : 'text-bg-success'}"><t t-esc="record.quality_state.value"/></span></strong>
<span t-attf-class="float-end text-end badge #{['none'].indexOf(record.quality_state.raw_value) > -1 ? 'text-bg-secondary' : ['fail'].indexOf(record.quality_state.raw_value) > -1 ? 'text-bg-danger' : ['done'].indexOf(record.quality_state.raw_value) > -1 ? 'text-bg-primary' : 'text-bg-success'}">
<t t-esc="record.quality_state.value"/>
</span>
</strong>
</div> </div>
</div> </div>
<div class="row text-muted"> <div class="row text-muted">
<div class="col-8"> <div class="col-8">
<span> <span><t t-esc="record.product_id.value"/></span>
<t t-esc="record.product_id.value"/>
</span>
</div> </div>
<div class="col-4"> <div class="col-4">
<span> <span><t t-esc="record.lot_id.value"/></span>
<t t-esc="record.lot_id.value"/>
</span>
</div> </div>
</div> </div>
<div class="oe_kanban_bottom_right float-end"> <div class="oe_kanban_bottom_right float-end">
@@ -396,8 +350,7 @@
<field name="user_id" string="Checked By" optional="show" widget='many2one_avatar_user'/> <field name="user_id" string="Checked By" optional="show" widget='many2one_avatar_user'/>
<field name="point_id" optional="hide"/> <field name="point_id" optional="hide"/>
<field name="team_id" optional="show"/> <field name="team_id" optional="show"/>
<field name="quality_state" optional="show" widget='badge' decoration-success="quality_state == 'pass'" <field name="quality_state" optional="show" widget='badge' decoration-success="quality_state == 'pass'" decoration-info="quality_state == 'none'" decoration-danger="quality_state == 'fail'"/>
decoration-info="quality_state == 'none'" decoration-danger="quality_state == 'fail'"/>
<field name="company_id" groups="base.main_company"/> <field name="company_id" groups="base.main_company"/>
</tree> </tree>
</field> </field>
@@ -415,14 +368,14 @@
</record> </record>
<record id="quality_check_view_pivot" model="ir.ui.view"> <record id="quality_check_view_pivot" model="ir.ui.view">
<field name="name">quality.check.view.pivot</field> <field name="name">quality.check.view.pivot</field>
<field name="model">quality.check</field> <field name="model">quality.check</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<pivot string="Quality Check Analysis" sample="1"> <pivot string="Quality Check Analysis" sample="1">
<field name="control_date" type="col" interval="day"/> <field name="control_date" type="col" interval="day"/>
<field name="product_id" type="row"/> <field name="product_id" type="row"/>
</pivot> </pivot>
</field> </field>
</record> </record>
<record id="quality_check_view_search" model="ir.ui.view"> <record id="quality_check_view_search" model="ir.ui.view">
@@ -430,8 +383,7 @@
<field name="model">quality.check</field> <field name="model">quality.check</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search> <search>
<field name="product_id" string="Product" <field name="product_id" string="Product" filter_domain="['|', ('product_id', 'ilike', self), ('lot_id', 'ilike', self)]"/>
filter_domain="['|', ('product_id', 'ilike', self), ('lot_id', 'ilike', self)]"/>
<field name="picking_id"/> <field name="picking_id"/>
<field name="lot_id"/> <field name="lot_id"/>
<field name="team_id"/> <field name="team_id"/>
@@ -474,11 +426,10 @@
</field> </field>
<field name="help" type="html"> <field name="help" type="html">
<p class="o_view_nocontent_smiling_face"> <p class="o_view_nocontent_smiling_face">
No quality check found No quality check found
</p> </p><p>
<p> Define Quality Control Points in order to automatically generate
Define Quality Control Points in order to automatically generate quality checks at the right logistic operation: transfers, manufacturing orders.
quality checks at the right logistic operation: transfers, manufacturing orders.
</p> </p>
</field> </field>
</record> </record>
@@ -507,11 +458,10 @@
<field name="view_mode">tree,kanban,form,pivot,graph</field> <field name="view_mode">tree,kanban,form,pivot,graph</field>
<field name="help" type="html"> <field name="help" type="html">
<p class="o_view_nocontent_smiling_face"> <p class="o_view_nocontent_smiling_face">
No quality check found No quality check found
</p> </p><p>
<p> Define Quality Control Points in order to automatically generate
Define Quality Control Points in order to automatically generate quality checks at the right logistic operation: transfers, manufacturing orders.
quality checks at the right logistic operation: transfers, manufacturing orders.
</p> </p>
</field> </field>
</record> </record>
@@ -535,25 +485,17 @@
<field name="inherit_id" ref="stock.product_template_form_view_procurement_button"/> <field name="inherit_id" ref="stock.product_template_form_view_procurement_button"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//button[@name='action_view_related_putaway_rules']" position="after"> <xpath expr="//button[@name='action_view_related_putaway_rules']" position="after">
<button name="action_see_quality_control_points" type="object" class="oe_stat_button" icon="fa-list" <button name="action_see_quality_control_points" type="object" class="oe_stat_button" icon="fa-list" attrs="{'invisible':[('type', 'not in', ['product', 'consu'])]}" groups="quality.group_quality_user">
attrs="{'invisible':[('type', 'not in', ['product', 'consu'])]}"
groups="quality.group_quality_user">
<field string="Quality Points" name="quality_control_point_qty" widget="statinfo"/> <field string="Quality Points" name="quality_control_point_qty" widget="statinfo"/>
</button> </button>
<button name="action_see_quality_checks" type="object" class="oe_stat_button" icon="fa-check" <button name="action_see_quality_checks" type="object" class="oe_stat_button" icon="fa-check" attrs="{'invisible':['|', ('type', 'not in', ['product', 'consu']), ('quality_pass_qty', '=', 0),('quality_fail_qty', '=', 0)]}" groups="quality.group_quality_user">
attrs="{'invisible':['|', ('type', 'not in', ['product', 'consu']), ('quality_pass_qty', '=', 0),('quality_fail_qty', '=', 0)]}"
groups="quality.group_quality_user">
<div class="o_field_widget o_stat_info mr4"> <div class="o_field_widget o_stat_info mr4">
<span class="o_stat_text">Pass:</span> <span class="o_stat_text">Pass:</span>
<span class="o_stat_text">Fail:</span> <span class="o_stat_text">Fail:</span>
</div> </div>
<div class="o_field_widget o_stat_info"> <div class="o_field_widget o_stat_info">
<span class="o_stat_value"> <span class="o_stat_value"><field name="quality_pass_qty"/></span>
<field name="quality_pass_qty"/> <span class="o_stat_value"><field name="quality_fail_qty"/></span>
</span>
<span class="o_stat_value">
<field name="quality_fail_qty"/>
</span>
</div> </div>
</button> </button>
</xpath> </xpath>
@@ -567,25 +509,17 @@
<field name="inherit_id" ref="stock.product_form_view_procurement_button"/> <field name="inherit_id" ref="stock.product_form_view_procurement_button"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//button[@name='action_view_related_putaway_rules']" position="after"> <xpath expr="//button[@name='action_view_related_putaway_rules']" position="after">
<button name="action_see_quality_control_points" type="object" icon="fa-list" class="oe_stat_button" <button name="action_see_quality_control_points" type="object" icon="fa-list" class="oe_stat_button" attrs="{'invisible':[('type', 'not in', ['product', 'consu'])]}" groups="quality.group_quality_user">
attrs="{'invisible':[('type', 'not in', ['product', 'consu'])]}"
groups="quality.group_quality_user">
<field string="Quality Points" name="quality_control_point_qty" widget="statinfo"/> <field string="Quality Points" name="quality_control_point_qty" widget="statinfo"/>
</button> </button>
<button name="action_see_quality_checks" type="object" class="oe_stat_button" icon="fa-check" <button name="action_see_quality_checks" type="object" class="oe_stat_button" icon="fa-check" groups="quality.group_quality_user" attrs="{'invisible':[ ('quality_pass_qty', '=', 0),('quality_fail_qty', '=', 0)]}" >
groups="quality.group_quality_user"
attrs="{'invisible':[ ('quality_pass_qty', '=', 0),('quality_fail_qty', '=', 0)]}">
<div class="o_field_widget o_stat_info mr4"> <div class="o_field_widget o_stat_info mr4">
<span class="o_stat_text">Pass:</span> <span class="o_stat_text">Pass:</span>
<span class="o_stat_text">Fail:</span> <span class="o_stat_text">Fail:</span>
</div> </div>
<div class="o_field_widget o_stat_info"> <div class="o_field_widget o_stat_info">
<span class="o_stat_value"> <span class="o_stat_value"><field name="quality_pass_qty"/></span>
<field name="quality_pass_qty"/> <span class="o_stat_value"><field name="quality_fail_qty"/></span>
</span>
<span class="o_stat_value">
<field name="quality_fail_qty"/>
</span>
</div> </div>
</button> </button>
</xpath> </xpath>
@@ -599,8 +533,8 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//div[@name='button_box']" position="inside"> <xpath expr="//div[@name='button_box']" position="inside">
<button name="%(quality_check_action_production_lot)d" type="action" <button name="%(quality_check_action_production_lot)d" type="action"
attrs="{'invisible': [('quality_check_qty', '=', 0)]}" attrs="{'invisible': [('quality_check_qty', '=', 0)]}"
icon="fa-check" class="oe_stat_button" groups="quality.group_quality_user"> icon="fa-check" class="oe_stat_button" groups="quality.group_quality_user">
<field string="Quality Checks" name="quality_check_qty" widget="statinfo"/> <field string="Quality Checks" name="quality_check_qty" widget="statinfo"/>
</button> </button>
</xpath> </xpath>
@@ -623,36 +557,24 @@
<templates> <templates>
<t t-name="kanban-box"> <t t-name="kanban-box">
<div t-attf-class="#{kanban_color(record.color.raw_value)}"> <div t-attf-class="#{kanban_color(record.color.raw_value)}">
<span class="oe_kanban_color_help" <span class="oe_kanban_color_help" t-attf-title="In #{kanban_getcolorname(record.color.raw_value)}" role="img" t-attf-aria-label="In #{kanban_getcolorname(record.color.raw_value)}"/>
t-attf-title="In #{kanban_getcolorname(record.color.raw_value)}" role="img"
t-attf-aria-label="In #{kanban_getcolorname(record.color.raw_value)}"/>
<div t-attf-class="o_kanban_card_header"> <div t-attf-class="o_kanban_card_header">
<div class="o_kanban_card_header_title"> <div class="o_kanban_card_header_title">
<div class="o_primary"> <div class="o_primary"><field name="name"/></div>
<field name="name"/>
</div>
<div t-if="record.alias_name.value and record.alias_domain.value"> <div t-if="record.alias_name.value and record.alias_domain.value">
<small><i class="fa fa-envelope-o" role="img" aria-label="Domain alias" <small><i class="fa fa-envelope-o" role="img" aria-label="Domain alias" title="Domain alias"></i>&amp;nbsp; <field name="alias_id"/></small>
title="Domain alias"></i>&amp;nbsp;
<field name="alias_id"/>
</small>
</div> </div>
</div> </div>
</div> </div>
<div class="container o_kanban_card_content"> <div class="container o_kanban_card_content">
<div class="row"> <div class="row">
<div class="col-6 o_kanban_primary_left"> <div class="col-6 o_kanban_primary_left">
<button class="btn btn-primary" name="%(quality_alert_action_team)d" <button class="btn btn-primary" name="%(quality_alert_action_team)d" type="action">
type="action"> <span><field name="alert_count"/> Quality Alerts</span>
<span>
<field name="alert_count"/>
Quality Alerts
</span>
</button> </button>
</div> </div>
<div class="col-6 o_kanban_primary_right"> <div class="col-6 o_kanban_primary_right">
<a class="oe_kanban_stock_picking_type_list" <a class="oe_kanban_stock_picking_type_list" name="%(quality_check_action_team)d" type="action">
name="%(quality_check_action_team)d" type="action">
<field name="check_count"/> <field name="check_count"/>
Checks In Progress Checks In Progress
</a> </a>
@@ -663,14 +585,11 @@
<div t-if="widget.editable" role="menuitem"> <div t-if="widget.editable" role="menuitem">
<a class="dropdown-item ps-0" type="edit">Configuration</a> <a class="dropdown-item ps-0" type="edit">Configuration</a>
</div> </div>
<div t-if="widget.editable" role="menuitem" aria-haspopup="true" <div t-if="widget.editable" role="menuitem" aria-haspopup="true" class="o_no_padding_kanban_colorpicker">
class="o_no_padding_kanban_colorpicker">
<ul class="oe_kanban_colorpicker" data-field="color" role="popup"/> <ul class="oe_kanban_colorpicker" data-field="color" role="popup"/>
</div> </div>
</div> </div>
<a class="o_kanban_manage_toggle_button o_left" href="#"> <a class="o_kanban_manage_toggle_button o_left" href="#"><i class="fa fa-ellipsis-v" role="img" aria-label="Manage" title="Manage"/></a>
<i class="fa fa-ellipsis-v" role="img" aria-label="Manage" title="Manage"/>
</a>
</div> </div>
</t> </t>
</templates> </templates>
@@ -683,7 +602,6 @@
<field name="model">quality.alert.team</field> <field name="model">quality.alert.team</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form> <form>
<header></header>
<sheet> <sheet>
<div class="oe_title"> <div class="oe_title">
<label for="name" string="Team Name"/> <label for="name" string="Team Name"/>
@@ -696,14 +614,13 @@
<label for="alias_name" string="Email Alias"/> <label for="alias_name" string="Email Alias"/>
<div name="alias_def"> <div name="alias_def">
<field name="alias_id" class="oe_read_only oe_inline" <field name="alias_id" class="oe_read_only oe_inline"
string="Email Alias" required="0"/> string="Email Alias" required="0"/>
<div class="oe_edit_only oe_inline" name="edit_alias" style="display: inline;"> <div class="oe_edit_only oe_inline" name="edit_alias" style="display: inline;" >
<field name="alias_name" class="oe_inline"/>@ <field name="alias_name" class="oe_inline"/>@<field name="alias_domain" class="oe_inline" readonly="1"/>
<field name="alias_domain" class="oe_inline" readonly="1"/>
</div> </div>
</div> </div>
<field name="alias_contact" class="oe_inline" groups="base.group_no_one" <field name="alias_contact" class="oe_inline" groups="base.group_no_one"
string="Accept Emails From"/> string="Accept Emails From"/>
</group> </group>
<group> <group>
<field name="company_id" groups="base.group_multi_company"/> <field name="company_id" groups="base.group_multi_company"/>
@@ -740,9 +657,7 @@
<div t-attf-class="oe_kanban_content oe_kanban_global_click"> <div t-attf-class="oe_kanban_content oe_kanban_global_click">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<strong> <strong><field name="name"/></strong>
<field name="name"/>
</strong>
</div> </div>
</div> </div>
</div> </div>
@@ -756,15 +671,14 @@
<field name="name">Quality Overview</field> <field name="name">Quality Overview</field>
<field name="res_model">quality.alert.team</field> <field name="res_model">quality.alert.team</field>
<field name="view_mode">kanban,form</field> <field name="view_mode">kanban,form</field>
<field name="view_id" ref="quality_alert_team_dashboard_view_kanban"/> <field name="view_id" ref="quality_alert_team_dashboard_view_kanban" />
<field name="help" type="html"> <field name="help" type="html">
<p class="o_view_nocontent_empty_folder"> <p class="o_view_nocontent_empty_folder">
</p><p>
Quality Teams group the different quality alerts/checks
according to the roles (teams) that need them.
</p> </p>
<p> </field>
Quality Teams group the different quality alerts/checks
according to the roles (teams) that need them.
</p>
</field>
</record> </record>
<record id="quality_alert_team_action_config" model="ir.actions.act_window"> <record id="quality_alert_team_action_config" model="ir.actions.act_window">
@@ -801,9 +715,9 @@
<field name="res_model">quality.tag</field> <field name="res_model">quality.tag</field>
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
<field name="help" type="html"> <field name="help" type="html">
<p class="o_view_nocontent_smiling_face"> <p class="o_view_nocontent_smiling_face">
Add a new tag Add a new tag
</p> </p>
</field> </field>
</record> </record>
@@ -832,9 +746,7 @@
<t t-name="kanban-box"> <t t-name="kanban-box">
<div t-attf-class="oe_kanban_global_click"> <div t-attf-class="oe_kanban_global_click">
<div> <div>
<strong> <strong><field name="name"/></strong>
<field name="name"/>
</strong>
</div> </div>
</div> </div>
</t> </t>
@@ -850,9 +762,8 @@
<field name="help" type="html"> <field name="help" type="html">
<p class="o_view_nocontent_smiling_face"> <p class="o_view_nocontent_smiling_face">
Create a new quality alert stage Create a new quality alert stage
</p> </p><p>
<p> Quality Alert stages define the different steps a quality alert should go through.
Quality Alert stages define the different steps a quality alert should go through.
</p> </p>
</field> </field>
</record> </record>
@@ -904,19 +815,9 @@
<templates> <templates>
<t t-name="kanban-box"> <t t-name="kanban-box">
<div t-attf-class="oe_kanban_card oe_kanban_global_click"> <div t-attf-class="oe_kanban_card oe_kanban_global_click">
<div> <div><strong><t t-esc="record.name.value"/></strong></div>
<strong> <div><strong>Products :</strong> <t t-esc="record.product_ids.value"/></div>
<t t-esc="record.name.value"/> <div><strong>Operations :</strong> <t t-esc="record.picking_type_ids.value"/></div>
</strong>
</div>
<div>
<strong>Products :</strong>
<t t-esc="record.product_ids.value"/>
</div>
<div>
<strong>Operations :</strong>
<t t-esc="record.picking_type_ids.value"/>
</div>
</div> </div>
</t> </t>
</templates> </templates>
@@ -934,54 +835,39 @@
<field string="Quality Checks" name="check_count" widget="statinfo"/> <field string="Quality Checks" name="check_count" widget="statinfo"/>
</button> </button>
<button name="action_see_spc_control" type="object" class="oe_stat_button" <button name="action_see_spc_control" type="object" class="oe_stat_button"
attrs="{'invisible': ['|', ('check_count', '=', 0), ('test_type', '!=', 'measure')]}"> attrs="{'invisible': ['|', ('check_count', '=', 0), ('test_type', '!=', 'measure')]}">
<span class="fa fa-2x" data-icon="&#x2211;" style="padding-left: 10px;" role="img" <span class="fa fa-2x" data-icon="&#x2211;" style="padding-left: 10px;" role="img" aria-label="Statistics" title="Statistics"/>
aria-label="Statistics" title="Statistics"/>
<div class="o_field_widget o_stat_info mr4"> <div class="o_field_widget o_stat_info mr4">
<span class="o_stat_text">AVG:</span> <span class="o_stat_text">AVG:</span>
<span class="o_stat_text">STD:</span> <span class="o_stat_text">STD:</span>
</div> </div>
<div class="o_field_widget o_stat_info"> <div class="o_field_widget o_stat_info">
<span class="o_stat_value"> <span class="o_stat_value"><field name="average"/></span>
<field name="average"/> <span class="o_stat_value"><field name="standard_deviation"/></span>
</span>
<span class="o_stat_value">
<field name="standard_deviation"/>
</span>
</div> </div>
</button> </button>
</xpath> </xpath>
<xpath expr="//page[@name='instructions']" position="after"> <xpath expr="//page[@name='instructions']" position="after">
<page string="Message If Failure" name="message_if_failure" <page string="Message If Failure" name="message_if_failure"
attrs="{'invisible': [('test_type', 'in', ['picture', 'instructions', 'register_consumed_materials', 'print_label'])]}"> attrs="{'invisible': [('test_type', 'in', ['picture', 'instructions', 'register_consumed_materials', 'print_label'])]}">
<field name="failure_message"/> <field name="failure_message"/>
</page> </page>
</xpath> </xpath>
<xpath expr="//field[@name='test_type']" position="before"> <xpath expr="//field[@name='test_type']" position="before">
<field name="measure_on"/> <field name="measure_on"/>
<field name="measure_frequency_type" string="Control Frequency"/> <field name="measure_frequency_type" string="Control Frequency"/>
<label for="measure_frequency_value" string="" <label for="measure_frequency_value" string="" attrs="{'invisible': [('measure_frequency_type', '=', 'all')]}"/>
attrs="{'invisible': [('measure_frequency_type', '=', 'all')]}"/>
<div class="o_row" attrs="{'invisible': [('measure_frequency_type', '=', 'all')]}"> <div class="o_row" attrs="{'invisible': [('measure_frequency_type', '=', 'all')]}">
<span attrs="{'invisible': [('measure_frequency_type', '=', 'all')]}">Every</span> <span attrs="{'invisible': [('measure_frequency_type', '=', 'all')]}">Every </span>
<field name="measure_frequency_value" nolabel="1" <field name="measure_frequency_value" nolabel="1" attrs="{'invisible': [('measure_frequency_type', '!=', 'random')]}"/>
attrs="{'invisible': [('measure_frequency_type', '!=', 'random')]}"/> <label for="measure_frequency_value" string="% of Operations" attrs="{'invisible': ['|', ('measure_on', '=', 'move_line'), ('measure_frequency_type', '!=', 'random')]}"/>
<label for="measure_frequency_value" string="% of Operations" <label for="measure_frequency_value" string="% of Transfers" attrs="{'invisible': ['|', ('measure_on', '!=', 'move_line'), ('measure_frequency_type', '!=', 'random')]}"/>
attrs="{'invisible': ['|', ('measure_on', '=', 'move_line'), ('measure_frequency_type', '!=', 'random')]}"/> <field name="measure_frequency_unit_value" string="Frequency" nolabel="1" attrs="{'invisible': [('measure_frequency_type', '!=', 'periodical')]}"/>
<label for="measure_frequency_value" string="% of Transfers" <field name="measure_frequency_unit" attrs="{'invisible': [('measure_frequency_type', '!=', 'periodical')], 'required': [('measure_frequency_type', '=', 'periodical')]}"/>
attrs="{'invisible': ['|', ('measure_on', '!=', 'move_line'), ('measure_frequency_type', '!=', 'random')]}"/>
<field name="measure_frequency_unit_value" string="Frequency" nolabel="1"
attrs="{'invisible': [('measure_frequency_type', '!=', 'periodical')]}"/>
<field name="measure_frequency_unit"
attrs="{'invisible': [('measure_frequency_type', '!=', 'periodical')], 'required': [('measure_frequency_type', '=', 'periodical')]}"/>
</div> </div>
<field name="is_lot_tested_fractionally" attrs="{'invisible': [('measure_on', '!=', 'move_line')]}" <field name="is_lot_tested_fractionally" attrs="{'invisible': [('measure_on', '!=', 'move_line')]}" string="Partial Transfer Test"/>
string="Partial Transfer Test"/> <label for="testing_percentage_within_lot" attrs="{'invisible': ['|', ('measure_on', '!=', 'move_line'), ('is_lot_tested_fractionally', '!=', True)]}" string="Percentage"/>
<label for="testing_percentage_within_lot" <div class="o_row" attrs="{'invisible': ['|', ('measure_on', '!=', 'move_line'), ('is_lot_tested_fractionally', '!=', True)]}">
attrs="{'invisible': ['|', ('measure_on', '!=', 'move_line'), ('is_lot_tested_fractionally', '!=', True)]}"
string="Percentage"/>
<div class="o_row"
attrs="{'invisible': ['|', ('measure_on', '!=', 'move_line'), ('is_lot_tested_fractionally', '!=', True)]}">
<field name="testing_percentage_within_lot" nolabel="1"/> <field name="testing_percentage_within_lot" nolabel="1"/>
<label for="testing_percentage_within_lot" string="%"/> <label for="testing_percentage_within_lot" string="%"/>
</div> </div>
@@ -990,15 +876,12 @@
<label for="norm" attrs="{'invisible': [('test_type', '!=', 'measure')]}"/> <label for="norm" attrs="{'invisible': [('test_type', '!=', 'measure')]}"/>
<div class="o_row" attrs="{'invisible': [('test_type', '!=', 'measure')]}"> <div class="o_row" attrs="{'invisible': [('test_type', '!=', 'measure')]}">
<field name="norm" attrs="{'required': [('test_type', '=', 'measure')]}"/> <field name="norm" attrs="{'required': [('test_type', '=', 'measure')]}"/>
<field name="norm_unit" string="Unit of Measure" <field name="norm_unit" string="Unit of Measure" attrs="{'required': [('test_type', '=', 'measure')]}"/>
attrs="{'required': [('test_type', '=', 'measure')]}"/>
</div> </div>
<label for="tolerance_min" string="Tolerance" attrs="{'invisible': [('test_type', '!=', 'measure')]}"/> <label for="tolerance_min" string="Tolerance" attrs="{'invisible': [('test_type', '!=', 'measure')]}"/>
<div attrs="{'invisible': [('test_type', '!=', 'measure')]}" class="o_row"> <div attrs="{'invisible': [('test_type', '!=', 'measure')]}" class="o_row">
<span>from</span> <span>from </span> <field name="tolerance_min"/>
<field name="tolerance_min"/> <span>to </span> <field name="tolerance_max"/>
<span>to</span>
<field name="tolerance_max"/>
</div> </div>
</xpath> </xpath>
</field> </field>
@@ -1011,96 +894,95 @@
<field name="search_view_id" ref="quality_point_view_search"/> <field name="search_view_id" ref="quality_point_view_search"/>
<field name="help" type="html"> <field name="help" type="html">
<p class="o_view_nocontent_smiling_face"> <p class="o_view_nocontent_smiling_face">
No quality control point found No quality control point found
</p> </p><p>
<p> Quality control points define the quality checks which should be
Quality control points define the quality checks which should be performed at each operation, for your different products.
performed at each operation, for your different products.
</p> </p>
</field> </field>
</record> </record>
<!-- Menu structure--> <!-- Menu structure-->
<menuitem <menuitem
id="menu_quality_root" id="menu_quality_root"
name="Quality" name="Quality"
web_icon="quality_control,static/description/icon.svg" web_icon="quality_control,static/description/icon.svg"
sequence="150" sequence="150"
groups="quality.group_quality_user"/> groups="quality.group_quality_user"/>
<menuitem <menuitem
id="menu_quality_dashboard" id="menu_quality_dashboard"
name="Overview" name="Overview"
action="quality_alert_team_action" action="quality_alert_team_action"
parent="menu_quality_root" parent="menu_quality_root"
sequence="5"/> sequence="5"/>
<menuitem <menuitem
id="menu_quality_control" id="menu_quality_control"
name="Quality Control" name="Quality Control"
parent="menu_quality_root" parent="menu_quality_root"
sequence="15"/> sequence="15"/>
<menuitem <menuitem
id="menu_quality_control_points" id="menu_quality_control_points"
name="Control Points" name="Control Points"
parent="menu_quality_control" parent="menu_quality_control"
action="quality_point_action" action="quality_point_action"
groups="quality.group_quality_manager" groups="quality.group_quality_manager"
sequence="17"/> sequence="17"/>
<menuitem <menuitem
id="menu_quality_checks" id="menu_quality_checks"
name="Quality Checks" name="Quality Checks"
action="quality_check_action_main" action="quality_check_action_main"
parent="menu_quality_control" parent="menu_quality_control"
sequence="18"/> sequence="18"/>
<menuitem <menuitem
id="menu_quality_alert" id="menu_quality_alert"
name="Quality Alerts" name="Quality Alerts"
action="quality_alert_action_check" action="quality_alert_action_check"
parent="menu_quality_control" parent="menu_quality_control"
sequence="20"/> sequence="20"/>
<menuitem <menuitem
id="menu_quality_configuration" id="menu_quality_configuration"
name="Configuration" name="Configuration"
groups="quality.group_quality_manager" groups="quality.group_quality_manager"
parent="menu_quality_root" parent="menu_quality_root"
sequence="25"/> sequence="25"/>
<menuitem <menuitem
id="menu_quality_config_alert_team" id="menu_quality_config_alert_team"
name="Quality Teams" name="Quality Teams"
action="quality_alert_team_action_config" action="quality_alert_team_action_config"
parent="menu_quality_configuration" parent="menu_quality_configuration"
sequence="5"/> sequence="5"/>
<menuitem <menuitem
id="menu_quality_config_alert_stage" id="menu_quality_config_alert_stage"
name="Quality Alert Stages" name="Quality Alert Stages"
action="quality_alert_stage_action" action="quality_alert_stage_action"
parent="menu_quality_configuration" parent="menu_quality_configuration"
groups="base.group_no_one" groups="base.group_no_one"
sequence="15"/> sequence="15"/>
<menuitem <menuitem
id="menu_config_quality_tags" id="menu_config_quality_tags"
name="Quality Tags" name="Quality Tags"
groups="base.group_no_one" groups="base.group_no_one"
action="quality_tag_action" action="quality_tag_action"
parent="menu_quality_configuration" parent="menu_quality_configuration"
sequence="25"/> sequence="25"/>
<menuitem <menuitem
id="menu_quality_reporting" id="menu_quality_reporting"
name="Reporting" name="Reporting"
groups="quality.group_quality_manager" groups="quality.group_quality_manager"
parent="menu_quality_root" parent="menu_quality_root"
sequence="20"/> sequence="20"/>
<menuitem <menuitem
id="menu_quality_alert_report" id="menu_quality_alert_report"
action="quality_alert_action_report" action="quality_alert_action_report"
parent="menu_quality_reporting" parent="menu_quality_reporting"
sequence="6"/> sequence="6"/>
<menuitem <menuitem
id="menu_quality_check_report" id="menu_quality_check_report"
action="quality_check_action_report" action="quality_check_action_report"
parent="menu_quality_reporting" parent="menu_quality_reporting"
sequence="5"/> sequence="5"/>
</odoo> </odoo>

View File

@@ -1,3 +1,2 @@
from . import models from . import models
from . import commons from . import commons
from . import controllers

View File

@@ -10,7 +10,7 @@
""", """,
'category': 'sf', 'category': 'sf',
'website': 'https://www.sf.jikimo.com', 'website': 'https://www.sf.jikimo.com',
'depends': ['base', 'mrp_workorder', 'sale', 'purchase', 'sales_team'], 'depends': ['account', 'base', 'mrp_workorder', 'sale'],
'data': [ 'data': [
'security/group_security.xml', 'security/group_security.xml',
'security/ir.model.access.csv', 'security/ir.model.access.csv',
@@ -19,12 +19,9 @@
'views/fixture_view.xml', 'views/fixture_view.xml',
'views/functional_fixture_view.xml', 'views/functional_fixture_view.xml',
'views/menu_view.xml', 'views/menu_view.xml',
'views/tool_views.xml', "views/tool_views.xml",
'views/tool_basic_param.xml', "views/tool_menu.xml",
'views/tool_menu.xml',
'views/menu_fixture_view.xml', 'views/menu_fixture_view.xml',
'views/change_base_view.xml',
'views/Printer.xml',
], ],
'demo': [ 'demo': [

View File

@@ -1,28 +0,0 @@
from odoo import models, fields
class Printer(models.Model):
_name = 'printer'
_description = 'Printer'
name = fields.Char(string='名称', required=True)
ip_address = fields.Char(string='IP 地址', required=True)
port = fields.Integer(string='端口', default=9100)
class TableStyle(models.Model):
_name = 'table.style'
_description = '标签样式'
name = fields.Char(string='名称', required=True)
# todo
class PrinterConfiguration(models.Model):
_name = 'printer.configuration'
_description = 'Printer Configuration'
name = fields.Char(string='名称', required=True)
printer_id = fields.Many2one('printer', string='打印机')
model = fields.Many2one('ir.model', string='模型名称')
# # 其他相关字段...

View File

@@ -1,2 +1 @@
from . import common from. import common
from . import Printer

View File

@@ -1,14 +1,14 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import time, datetime
import hashlib
from odoo import models from odoo import models
import socket import time
import hashlib
class Common(models.Model): class Common(models.Model):
_name = 'sf.sync.common' _name = 'sf.sync.common'
_description = u'公用类' _description = u'公用类'
def get_headers(self, token, secret_key): def get_headers(self,token, secret_key):
''' '''
获取requests中的heardes参数 获取requests中的heardes参数
''' '''
@@ -20,75 +20,4 @@ class Common(models.Model):
'checkstr': check_sf_str} 'checkstr': check_sf_str}
return headers return headers
def get_add_time(self, parse_time):
"""
把时间增加8小时
:return:
"""
dt = datetime.datetime.strptime(parse_time, "%Y-%m-%d %H:%M:%S")
d = dt + datetime.timedelta(hours=8)
nTime = d.strftime("%Y-%m-%d %H:%M:%S")
return nTime
class PrintingUtils(models.AbstractModel):
_name = 'printing.utils'
_description = 'Utility class for printing functionalities'
def generate_zpl_code(self, code):
# 实现生成ZPL代码的逻辑
# 初始化ZPL代码字符串
zpl_code = "^XA\n"
zpl_code += "^CW1,E:SIMSUN.TTF^FS\n"
zpl_code += "^CI28\n"
# 设置二维码位置
zpl_code += "^FO50,50\n" # 调整二维码位置,使其与资产编号在同一行
zpl_code += f"^BQN,2,6^FDLM,B0093{code}^FS\n"
# 设置资产编号文本位置
zpl_code += "^FO300,60\n" # 资产编号文本的位置,与二维码在同一行
zpl_code += "^A1N,45,45^FD编码名称: ^FS\n"
# 设置{code}文本位置
# 假设{code}文本需要位于资产编号和二维码下方,中间位置
# 设置{code}文本位置并启用自动换行
zpl_code += "^FO300,120\n" # {code}文本的起始位置
zpl_code += "^FB400,4,0,L,0\n" # 定义一个宽度为500点的文本框最多4行左对齐
zpl_code += f"^A1N,40,40^FD{code}^FS\n"
# 在{code}文本框周围绘制线框
# 假设线框的外部尺寸为宽度500点高度200点
# zpl_code += "^FO300,110^GB500,200,2^FS\n" # 绘制线框边框粗细为2点
zpl_code += "^PQ1,0,1,Y\n"
zpl_code += "^XZ\n"
return zpl_code
def send_to_printer(self, host, port, zpl_code):
# 实现发送ZPL代码到打印机的逻辑
# 将ZPL代码转换为字节串
print('zpl_code', zpl_code)
zpl_bytes = zpl_code.encode('utf-8')
print(zpl_bytes)
# 创建socket对象
mysocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
mysocket.connect((host, port)) # 连接到打印机
mysocket.send(zpl_bytes) # 发送ZPL代码
print("ZPL code sent to printer successfully.")
except Exception as e:
print(f"Error with the connection: {e}")
finally:
mysocket.close() # 关闭连接
def print_qr_code(self, lot_name, host, port):
# 实现打印二维码的逻辑
# 这里需要传入 lot_name 参数,因为我们不能直接访问 self.lot_id.name
zpl_code = self.generate_zpl_code(lot_name)
# 发送ZPL代码到打印机
# host = "192.168.50.110" # 可以作为参数传入,或者在此配置
# port = 9100 # 可以作为参数传入,或者在此配置
self.send_to_printer(host, port, zpl_code)

View File

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

View File

@@ -1,40 +0,0 @@
# -*- coding: utf-8 -*-
import logging
import json
import base64
from odoo import http
from odoo.http import request
class Manufacturing_Connect(http.Controller):
@http.route('/AutoDeviceApi/MachineToolGroup', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
cors="*")
def get_maintenance_tool_groups_Info(self, **kw):
"""
机床刀具组接口
:param kw:
:return:
"""
logging.info('get_maintenance_tool_groups_Info:%s' % kw)
try:
datas = request.httprequest.data
ret = json.loads(datas)
# ret = json.loads(ret['result'])
logging.info('DeviceId:%s' % ret)
tool_groups = request.env['sf.tool.groups'].sudo().search([])
res = {'Succeed': True, 'Datas': []}
if tool_groups:
for item in tool_groups:
device_id = ''
for equipment_id in item.equipment_ids:
device_id = '%s,%s' % (device_id, equipment_id.name)
res['Datas'].append({
'GroupName': item.name,
'DeviceId': device_id
})
except Exception as e:
res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
logging.info('get_maintenance_tool_groups_Info error:%s' % e)
return json.JSONEncoder().encode(res)

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