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',
'website': 'https://www.sf.jikimo.com',
'depends': ['web', 'purchase', 'base_setup'],
'depends': ['web'],
'data': [
'views/bye_odoo.xml',
],
'demo': [
],
@@ -22,24 +22,11 @@
],
'web.assets_backend': [
'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/views/list_nums/list_nbCols.js',
'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_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 close = img.nextSibling;
const close = img.nextSibling
// 实现放大图片逻辑
// 比如使用 CSS 放大
img.parentElement.classList.add('zoomed');
close.classList.add('img_close');
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');
const img = close.previousSibling
img.parentElement.classList.remove('zoomed')
close.classList.remove('img_close')
}
}
MyCustomWidget.template = "jikimo_frontend.MyCustomWidget";
MyCustomWidget.template = "jikimo_frontend.MyCustomWidget"
// MyCustomWidget.supportedTypes = ['many2many'];
registry.category("fields").add("custom_many2many_checkboxes", MyCustomWidget);

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;
}
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 {
width: 110px !important;
height: 110px !important;
}
@@ -79,9 +72,9 @@ td.o_required_modifier {
}
.oe_kanban_card.kanban_color_1 {
background-color: #fff !important;
background-color: #27FEA9 !important;
opacity: 0.7;
color: #777;
color: #fff;
}
.oe_kanban_card.kanban_color_3 {
@@ -135,7 +128,7 @@ td.o_required_modifier {
.text-truncate {
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) {
@@ -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 {
position: absolute;
//top: -52px;
//left: -55px;
top: -52px;
left: 3rem;
width: 80px;
}
@@ -253,16 +246,16 @@ div[class="o_content o_component_with_search_panel"] .show_state span {
font-size: 12px;
}
//div[class="o_content o_component_with_search_panel"] .o_kanban_primary_right > .row {
// position: absolute;
// top: 55px;
// right: 43.5%;
//}
div[class="o_content o_component_with_search_panel"] .o_kanban_primary_right > .row {
position: absolute;
top: 55px;
right: 43.5%;
}
//------------------------------------------
.test_model > .o_form_label {
margin-left: 4px !important;
//line-height: 0 !important;
line-height: 0 !important;
}
@media screen and (min-width: 1200px) {
@@ -270,10 +263,10 @@ div[class="o_content o_component_with_search_panel"] .show_state span {
right: 52%;
}
//div[class="o_content o_component_with_search_panel"] .o_kanban_card_content button {
//
// left: -95px;
//}
div[class="o_content o_component_with_search_panel"] .o_kanban_card_content button {
left: -4.4rem;
}
}
@@ -318,177 +311,27 @@ div[class="o_content o_component_with_search_panel"] .show_state span {
.o_horizontal_separator {
font-size: 1.5rem;
}
//
//.o_field_widget input[class='o_input'] {
//text-align: center
//}
.o_field_widget input[class='o_input'] {
text-align: center
}
div:has(.o_required_modifier) > label::before {
position: absolute;
left: 24px;
left: -3px;
}
//.o_form_view .o_form_label {
// position: relative;
// width: 9rem;
// overflow: hidden;
// text-overflow: ellipsis;
// white-space: nowrap;
// 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 {
position: relative;
width: 9rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding-left: 1rem;
}
// 2023-11-16 hy 新增
.o_kanban_card_content .btn-group {
position: unset;
.o_form_view .o_form_label:hover {
white-space: normal;
overflow: visible;
}
.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);
return nbCols + 1;
}
});
});

View File

@@ -5,7 +5,7 @@
<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">
<th class="row_no"><i class="fa fa-list-ol"/></th>
<th><i class="fa fa-list-ol"/></th>
</xpath>
</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 {
//background-color: unset !important;
background-color: unset !important;
min-height: unset !important;
}

View File

@@ -38,9 +38,9 @@
<xpath expr="//field[@name='state']" position="after">
<field name="production_state" invisible="1"/>
</xpath>
<!-- <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')]}"/>-->
<!-- </xpath>-->
<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')]}"/>
</xpath>
</field>
</record>

View File

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

View File

@@ -263,8 +263,6 @@ class QualityCheck(models.Model):
picture = fields.Binary('Picture', attachment=True)
additional_note = fields.Text(
'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):
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)]
stage_ids = stages._search(domain, order=order, access_rights_uid=SUPERUSER_ID)
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_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_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_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
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="arch" type="xml">
<form>
<header>
</header>
<sheet>
<div class="oe_button_box" name="button_box"/>
<widget name="web_ribbon" title="Archived" bg_color="bg-danger"
attrs="{'invisible': [('active', '=', True)]}"/>
<h2>
<field name="name" readonly="1"/>
</h2>
<widget name="web_ribbon" title="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
<h2><field name="name" readonly="1"/></h2>
<group>
<group>
<field name="active" invisible="1"/>
@@ -38,14 +33,13 @@
<field name="note" placeholder="Describe the quality check to do..."/>
</page>
<page string="Notes" name="Notes">
<field name="reason" string="Note"
placeholder="Describe why you need to perform this quality check..."/>
<field name="reason" string="Note" placeholder="Describe why you need to perform this quality check..."/>
</page>
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="message_ids"/>
<field name="message_follower_ids"/>
<field name="message_ids"/>
</div>
</form>
</field>
@@ -91,18 +85,17 @@
<filter name="filter_date_close" date="date_close"/>
<separator/>
<filter string="Late Activities" name="activities_overdue"
domain="[('my_activity_date_deadline', '&lt;', context_today().strftime('%Y-%m-%d'))]"
help="Show all records which has next action date is before today"/>
domain="[('my_activity_date_deadline', '&lt;', context_today().strftime('%Y-%m-%d'))]"
help="Show all records which has next action date is before 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"
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">
<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="Root Cause" name="groupby_reason" domain="[]" context="{'group_by': 'reason_id'}"/>
<filter string="Creation Date" name="groupby_createmonth" domain="[]"
context="{'group_by': 'create_date'}"/>
<filter string="Creation Date" name="groupby_createmonth" domain="[]" context="{'group_by': 'create_date'}"/>
<filter string="Quality Team" name="groupby_team_id" domain="[]" context="{'group_by': 'team_id'}"/>
</group>
</search>
@@ -129,4 +122,4 @@
</record>
<!-- js stuff -->
</odoo>
</odoo>

View File

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

View File

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

View File

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

View File

@@ -1,14 +1,14 @@
# -*- coding: utf-8 -*-
import time, datetime
import hashlib
from odoo import models
import socket
import time
import hashlib
class Common(models.Model):
_name = 'sf.sync.common'
_description = u'公用类'
def get_headers(self, token, secret_key):
def get_headers(self,token, secret_key):
'''
获取requests中的heardes参数
'''
@@ -20,75 +20,4 @@ class Common(models.Model):
'checkstr': check_sf_str}
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