Compare commits
1 Commits
feature/72
...
feature/72
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d580f47885 |
@@ -35,6 +35,7 @@
|
|||||||
],
|
],
|
||||||
'web.assets_backend': [
|
'web.assets_backend': [
|
||||||
'sf_base/static/src/scss/*.scss',
|
'sf_base/static/src/scss/*.scss',
|
||||||
|
'sf_base/static/src/js/*.js',
|
||||||
],
|
],
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|||||||
62
sf_base/static/src/js/custom_barcode_handlers.js
Normal file
62
sf_base/static/src/js/custom_barcode_handlers.js
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/** @odoo-module **/
|
||||||
|
|
||||||
|
import { registry } from "@web/core/registry";
|
||||||
|
import { barcodeGenericHandlers } from '@barcodes/barcode_handlers';
|
||||||
|
import { patch } from "@web/core/utils/patch";
|
||||||
|
|
||||||
|
// 定义新的 clickOnButton 函数
|
||||||
|
function customClickOnButton(selector) {
|
||||||
|
console.log("This is the custom clickOnButton function!");
|
||||||
|
|
||||||
|
const buttons = document.body.querySelectorAll(selector);
|
||||||
|
|
||||||
|
let length = buttons.length;
|
||||||
|
if (length > 0) {
|
||||||
|
buttons[length - 1].click();
|
||||||
|
} else {
|
||||||
|
console.warn(`Button with selector ${selector} not found`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
patch(barcodeGenericHandlers, "start", {
|
||||||
|
start(env, { ui, barcode, notification }) {
|
||||||
|
// 使用新定义的 clickOnButton 函数
|
||||||
|
const COMMANDS = {
|
||||||
|
"O-CMD.EDIT": () => customClickOnButton(".o_form_button_edit"),
|
||||||
|
"O-CMD.DISCARD": () => customClickOnButton(".o_form_button_cancel"),
|
||||||
|
"O-CMD.SAVE": () => customClickOnButton(".o_form_button_save"),
|
||||||
|
"O-CMD.PREV": () => customClickOnButton(".o_pager_previous"),
|
||||||
|
"O-CMD.NEXT": () => customClickOnButton(".o_pager_next"),
|
||||||
|
"O-CMD.PAGER-FIRST": () => updatePager("first"),
|
||||||
|
"O-CMD.PAGER-LAST": () => updatePager("last"),
|
||||||
|
"O-CMD.CONFIRM": () => customClickOnButton(".jikimo_button_confirm"),
|
||||||
|
"O-CMD.FLUSHED": () => customClickOnButton(".jikimo_button_flushed"),
|
||||||
|
};
|
||||||
|
|
||||||
|
barcode.bus.addEventListener("barcode_scanned", (ev) => {
|
||||||
|
const barcode = ev.detail.barcode;
|
||||||
|
if (barcode.startsWith("O-BTN.")) {
|
||||||
|
let targets = [];
|
||||||
|
try {
|
||||||
|
targets = getVisibleElements(ui.activeElement, `[barcode_trigger=${barcode.slice(6)}]`);
|
||||||
|
} catch (_e) {
|
||||||
|
console.warn(`Barcode '${barcode}' is not valid`);
|
||||||
|
}
|
||||||
|
for (let elem of targets) {
|
||||||
|
elem.click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (barcode.startsWith("O-CMD.")) {
|
||||||
|
const fn = COMMANDS[barcode];
|
||||||
|
if (fn) {
|
||||||
|
fn();
|
||||||
|
} else {
|
||||||
|
notification.add(env._t("Barcode: ") + `'${barcode}'`, {
|
||||||
|
title: env._t("Unknown barcode command"),
|
||||||
|
type: "danger"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
42
sf_base/static/src/js/remove_focus.js
Normal file
42
sf_base/static/src/js/remove_focus.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/** @odoo-module **/
|
||||||
|
|
||||||
|
import { registry } from '@web/core/registry';
|
||||||
|
|
||||||
|
import { formView } from '@web/views/form/form_view';
|
||||||
|
import { FormController } from '@web/views/form/form_controller';
|
||||||
|
|
||||||
|
import { listView } from '@web/views/list/list_view';
|
||||||
|
import { ListController } from '@web/views/list/list_controller'
|
||||||
|
|
||||||
|
import { onRendered, onMounted } from "@odoo/owl";
|
||||||
|
|
||||||
|
export class RemoveFocusFormController extends FormController {
|
||||||
|
setup() {
|
||||||
|
super.setup();
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
this.__owl__.bdom.el.querySelectorAll(':focus').forEach(element => element.blur());
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registry.category('views').add('remove_focus_form_view', {
|
||||||
|
...formView,
|
||||||
|
Controller: RemoveFocusFormController,
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export class RemoveFocusListController extends ListController {
|
||||||
|
setup() {
|
||||||
|
super.setup();
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
this.__owl__.bdom.el.querySelectorAll(':focus').forEach(element => element.blur());
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registry.category('views').add('remove_focus_list_view', {
|
||||||
|
...listView,
|
||||||
|
Controller: RemoveFocusListController,
|
||||||
|
});
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
""",
|
""",
|
||||||
'category': 'sf',
|
'category': 'sf',
|
||||||
'website': 'https://www.sf.jikimo.com',
|
'website': 'https://www.sf.jikimo.com',
|
||||||
'depends': ['sf_plan','jikimo_printing'],
|
'depends': ['sf_plan','jikimo_printing'],
|
||||||
'data': [
|
'data': [
|
||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
'data/stock_route_group.xml',
|
'data/stock_route_group.xml',
|
||||||
|
|||||||
@@ -222,15 +222,10 @@ class SfDemandPlan(models.Model):
|
|||||||
line_ids = self.line_ids.filtered(lambda p: p.status == '30')
|
line_ids = self.line_ids.filtered(lambda p: p.status == '30')
|
||||||
sum_product_uom_qty = sum(line_ids.mapped('plan_uom_qty'))
|
sum_product_uom_qty = sum(line_ids.mapped('plan_uom_qty'))
|
||||||
customer_location_id = self.env['ir.model.data']._xmlid_to_res_id('stock.stock_location_customers')
|
customer_location_id = self.env['ir.model.data']._xmlid_to_res_id('stock.stock_location_customers')
|
||||||
check_overdelivery_allowed = False
|
if not self.overdelivery_allowed and line_ids.filtered(lambda p: p.location_id.id == customer_location_id):
|
||||||
for line in line_ids:
|
if float_compare(sum_product_uom_qty, self.product_uom_qty,
|
||||||
if line.location_id.id == customer_location_id:
|
precision_rounding=self.product_id.uom_id.rounding) == 1:
|
||||||
if not self.overdelivery_allowed:
|
raise ValidationError(f"已禁止向合作伙伴/客户超量发货,请更换“补货原因”或将“可超量发货”设置为“是”。")
|
||||||
if float_compare(sum_product_uom_qty, self.product_uom_qty,
|
|
||||||
precision_rounding=line.product_id.uom_id.rounding) == 1:
|
|
||||||
check_overdelivery_allowed = True
|
|
||||||
if check_overdelivery_allowed:
|
|
||||||
raise ValidationError(f"已禁止向合作伙伴/客户超量发货,请更换“补货原因”或将“可超量发货”设置为“是”。")
|
|
||||||
elif float_compare(sum_product_uom_qty, self.product_uom_qty,
|
elif float_compare(sum_product_uom_qty, self.product_uom_qty,
|
||||||
precision_rounding=self.product_id.uom_id.rounding) == 1:
|
precision_rounding=self.product_id.uom_id.rounding) == 1:
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -7,17 +7,39 @@ from odoo.tools import float_compare
|
|||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from odoo.exceptions import UserError
|
from odoo.exceptions import UserError
|
||||||
import re
|
import re
|
||||||
|
#本地环境问题 不加报错
|
||||||
|
class ProductCategory(models.Model):
|
||||||
|
_inherit = 'product.category'
|
||||||
|
|
||||||
|
negative_inventory_allowed = fields.Boolean(string="允许负库存", default=False)
|
||||||
|
|
||||||
|
class StockPicking(models.Model):
|
||||||
|
_inherit = 'stock.picking'
|
||||||
|
|
||||||
|
whether_show_quality_check = fields.Boolean(string="是否显示质检")
|
||||||
|
|
||||||
|
class ProductTemplate(models.Model):
|
||||||
|
_inherit = 'product.template'
|
||||||
|
|
||||||
|
blank_type = fields.Selection([
|
||||||
|
('圆料', '圆料'),
|
||||||
|
('方料', '方料'),
|
||||||
|
], string='坯料分类')
|
||||||
|
|
||||||
|
blank_precision = fields.Selection([
|
||||||
|
('精坯', '精坯'),
|
||||||
|
('粗坯', '粗坯'),
|
||||||
|
], string='坯料类型')
|
||||||
|
|
||||||
class SfProductionDemandPlan(models.Model):
|
class SfProductionDemandPlan(models.Model):
|
||||||
_name = 'sf.production.demand.plan'
|
_name = 'sf.production.demand.plan'
|
||||||
_description = 'sf_production_demand_plan'
|
_description = 'sf_production_demand_plan'
|
||||||
|
|
||||||
def get_location_id(self):
|
def get_location_id(self):
|
||||||
customer_location_id = self.env['ir.model.data']._xmlid_to_res_id('stock.stock_location_customers')
|
stock_location = self.env['stock.location'].sudo().search([('name', '=', '客户')], limit=1)
|
||||||
return customer_location_id
|
return stock_location.id
|
||||||
|
|
||||||
priority = fields.Selection(related='demand_plan_id.priority', string='优先级', store=True)
|
priority = fields.Selection(related='demand_plan_id.priority', string='优先级')
|
||||||
status = fields.Selection([
|
status = fields.Selection([
|
||||||
('10', '草稿'),
|
('10', '草稿'),
|
||||||
('20', '待确认'),
|
('20', '待确认'),
|
||||||
@@ -34,7 +56,7 @@ class SfProductionDemandPlan(models.Model):
|
|||||||
company_id = fields.Many2one(
|
company_id = fields.Many2one(
|
||||||
related='sale_order_id.company_id',
|
related='sale_order_id.company_id',
|
||||||
store=True, index=True, precompute=True)
|
store=True, index=True, precompute=True)
|
||||||
customer_name = fields.Char('客户', related='sale_order_id.customer_name', store=True)
|
customer_name = fields.Char('客户', related='sale_order_id.customer_name')
|
||||||
order_remark = fields.Text(related='sale_order_id.remark',
|
order_remark = fields.Text(related='sale_order_id.remark',
|
||||||
string="订单备注", store=True)
|
string="订单备注", store=True)
|
||||||
glb_url = fields.Char(related='sale_order_line_id.glb_url', string='glb文件地址')
|
glb_url = fields.Char(related='sale_order_line_id.glb_url', string='glb文件地址')
|
||||||
@@ -83,7 +105,7 @@ class SfProductionDemandPlan(models.Model):
|
|||||||
related='product_id.blank_precision')
|
related='product_id.blank_precision')
|
||||||
unit_number = fields.Float('单件用量', digits=(16, 3), related='product_id.unit_number')
|
unit_number = fields.Float('单件用量', digits=(16, 3), related='product_id.unit_number')
|
||||||
embryo_long = fields.Char('坯料尺寸(mm)', related='demand_plan_id.embryo_long')
|
embryo_long = fields.Char('坯料尺寸(mm)', related='demand_plan_id.embryo_long')
|
||||||
materials_id = fields.Char('材料', related='demand_plan_id.materials_id', store=True)
|
materials_id = fields.Char('材料', related='demand_plan_id.materials_id')
|
||||||
model_machining_precision = fields.Selection(related='product_id.model_machining_precision', string='精度')
|
model_machining_precision = fields.Selection(related='product_id.model_machining_precision', string='精度')
|
||||||
model_process_parameters_ids = fields.Many2many(related='demand_plan_id.model_process_parameters_ids',
|
model_process_parameters_ids = fields.Many2many(related='demand_plan_id.model_process_parameters_ids',
|
||||||
string='表面工艺', )
|
string='表面工艺', )
|
||||||
@@ -127,12 +149,6 @@ class SfProductionDemandPlan(models.Model):
|
|||||||
string='字段自制类型只读'
|
string='字段自制类型只读'
|
||||||
)
|
)
|
||||||
|
|
||||||
is_processing = fields.Boolean(
|
|
||||||
string='正在处理中',
|
|
||||||
default=False,
|
|
||||||
help='用于防止重复点击按钮'
|
|
||||||
)
|
|
||||||
|
|
||||||
# hide_action_open_mrp_production = fields.Boolean(
|
# hide_action_open_mrp_production = fields.Boolean(
|
||||||
# string='显示待工艺确认按钮',
|
# string='显示待工艺确认按钮',
|
||||||
# compute='_compute_hid_button',
|
# compute='_compute_hid_button',
|
||||||
@@ -613,6 +629,11 @@ class SfProductionDemandPlan(models.Model):
|
|||||||
filtered_plan = self.filtered(lambda mo: mo.status == '30')
|
filtered_plan = self.filtered(lambda mo: mo.status == '30')
|
||||||
if not filtered_plan:
|
if not filtered_plan:
|
||||||
raise UserError(_("没有需要下达的计划!"))
|
raise UserError(_("没有需要下达的计划!"))
|
||||||
|
check_overdelivery_allowed = False
|
||||||
|
if not self.demand_plan_id.overdelivery_allowed:
|
||||||
|
customer_location_id = self.env['ir.model.data']._xmlid_to_res_id('stock.stock_location_customers')
|
||||||
|
if self.location_id.id == customer_location_id:
|
||||||
|
check_overdelivery_allowed = True
|
||||||
# 按产品分组并计算总数
|
# 按产品分组并计算总数
|
||||||
product_data = {}
|
product_data = {}
|
||||||
for plan in filtered_plan:
|
for plan in filtered_plan:
|
||||||
@@ -660,15 +681,9 @@ class SfProductionDemandPlan(models.Model):
|
|||||||
'default_demand_plan_line_id': self.ids,
|
'default_demand_plan_line_id': self.ids,
|
||||||
'default_release_message': warning_message,
|
'default_release_message': warning_message,
|
||||||
}}
|
}}
|
||||||
else:
|
|
||||||
for demand_plan_line_id in filtered_plan:
|
|
||||||
demand_plan_line_id.action_confirm()
|
|
||||||
|
|
||||||
def button_release_plan(self):
|
def button_release_plan(self):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
if self.is_processing:
|
|
||||||
return
|
|
||||||
self.is_processing = True
|
|
||||||
check_overdelivery_allowed = False
|
check_overdelivery_allowed = False
|
||||||
if not self.demand_plan_id.overdelivery_allowed:
|
if not self.demand_plan_id.overdelivery_allowed:
|
||||||
customer_location_id = self.env['ir.model.data']._xmlid_to_res_id('stock.stock_location_customers')
|
customer_location_id = self.env['ir.model.data']._xmlid_to_res_id('stock.stock_location_customers')
|
||||||
@@ -695,9 +710,9 @@ class SfProductionDemandPlan(models.Model):
|
|||||||
self.action_confirm()
|
self.action_confirm()
|
||||||
|
|
||||||
def action_confirm(self):
|
def action_confirm(self):
|
||||||
|
"""
|
||||||
#确认需求计划行,创建 BOM、触发库存规则,并更新状态。
|
确认需求计划行,创建 BOM、触发库存规则,并更新状态。
|
||||||
|
"""
|
||||||
# 将当前需求计划行 ID 写入上下文,便于后续方法使用
|
# 将当前需求计划行 ID 写入上下文,便于后续方法使用
|
||||||
self = self.with_context(demand_plan_line_id=self.id)
|
self = self.with_context(demand_plan_line_id=self.id)
|
||||||
|
|
||||||
@@ -717,9 +732,9 @@ class SfProductionDemandPlan(models.Model):
|
|||||||
|
|
||||||
|
|
||||||
def _get_embryo_template_by_supply_method(self):
|
def _get_embryo_template_by_supply_method(self):
|
||||||
|
"""
|
||||||
#根据供货方式返回对应的胚料模板 product.template 记录。
|
根据供货方式返回对应的胚料模板 product.template 记录。
|
||||||
|
"""
|
||||||
supply_map = {
|
supply_map = {
|
||||||
'automation': self.env.ref('sf_dlm.product_embryo_sf_self_machining').sudo(),
|
'automation': self.env.ref('sf_dlm.product_embryo_sf_self_machining').sudo(),
|
||||||
'outsourcing': self.env.ref('sf_dlm.product_embryo_sf_outsource').sudo(),
|
'outsourcing': self.env.ref('sf_dlm.product_embryo_sf_outsource').sudo(),
|
||||||
@@ -734,9 +749,9 @@ class SfProductionDemandPlan(models.Model):
|
|||||||
|
|
||||||
|
|
||||||
def mrp_bom_create(self):
|
def mrp_bom_create(self):
|
||||||
|
"""
|
||||||
#创建 BOM(包含胚料与成品 BOM),用于后续生产或采购流程。
|
创建 BOM(包含胚料与成品 BOM),用于后续生产或采购流程。
|
||||||
|
"""
|
||||||
# 如果同一计划中已有对应的 BOM 可复用,则直接使用
|
# 如果同一计划中已有对应的 BOM 可复用,则直接使用
|
||||||
if self.supply_method in ('automation', 'manual'):
|
if self.supply_method in ('automation', 'manual'):
|
||||||
line_ids = self.demand_plan_id.line_ids.filtered(
|
line_ids = self.demand_plan_id.line_ids.filtered(
|
||||||
@@ -807,7 +822,7 @@ class SfProductionDemandPlan(models.Model):
|
|||||||
embryo_template = self._get_embryo_template_by_supply_method()
|
embryo_template = self._get_embryo_template_by_supply_method()
|
||||||
embryo_key = self.supply_method
|
embryo_key = self.supply_method
|
||||||
|
|
||||||
# 获取批次追踪方式
|
# 获取批次追踪方式 依据模版
|
||||||
tracking_method = embryo_template.tracking
|
tracking_method = embryo_template.tracking
|
||||||
|
|
||||||
# 创建胚料产品(无 BOM 产品)
|
# 创建胚料产品(无 BOM 产品)
|
||||||
@@ -820,6 +835,9 @@ class SfProductionDemandPlan(models.Model):
|
|||||||
product
|
product
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if isinstance(embryo_product, models.Model): # 确保返回的是记录而非错误码
|
||||||
|
embryo_product.write({'tracking': tracking_method})
|
||||||
|
|
||||||
if embryo_product == -3:
|
if embryo_product == -3:
|
||||||
raise UserError('该订单模型的材料型号暂未设置获取方式和供应商,请先配置再进行分配')
|
raise UserError('该订单模型的材料型号暂未设置获取方式和供应商,请先配置再进行分配')
|
||||||
|
|
||||||
@@ -851,9 +869,9 @@ class SfProductionDemandPlan(models.Model):
|
|||||||
|
|
||||||
|
|
||||||
def _action_launch_stock_rule(self):
|
def _action_launch_stock_rule(self):
|
||||||
|
"""
|
||||||
#触发库存规则(如采购、生产),并确认相关拣货单。
|
触发库存规则(如采购、生产),并确认相关拣货单。
|
||||||
|
"""
|
||||||
procurements = []
|
procurements = []
|
||||||
|
|
||||||
group_id = self.sale_order_id.procurement_group_id
|
group_id = self.sale_order_id.procurement_group_id
|
||||||
@@ -903,9 +921,9 @@ class SfProductionDemandPlan(models.Model):
|
|||||||
|
|
||||||
|
|
||||||
def _prepare_procurement_group_vals(self):
|
def _prepare_procurement_group_vals(self):
|
||||||
|
"""
|
||||||
#构造创建 procurement group 所需的字段。
|
构造创建 procurement group 所需的字段。
|
||||||
|
"""
|
||||||
return {
|
return {
|
||||||
'name': self.sale_order_id.name,
|
'name': self.sale_order_id.name,
|
||||||
'move_type': self.sale_order_id.picking_policy,
|
'move_type': self.sale_order_id.picking_policy,
|
||||||
@@ -915,9 +933,9 @@ class SfProductionDemandPlan(models.Model):
|
|||||||
|
|
||||||
|
|
||||||
def _prepare_procurement_values(self, group_id=False):
|
def _prepare_procurement_values(self, group_id=False):
|
||||||
|
"""
|
||||||
#构造单个 procurement 请求所需的字段字典。
|
构造单个 procurement 请求所需的字段字典。
|
||||||
|
"""
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
|
|
||||||
# 交货日期与计划日期
|
# 交货日期与计划日期
|
||||||
@@ -942,6 +960,4 @@ class SfProductionDemandPlan(models.Model):
|
|||||||
}
|
}
|
||||||
|
|
||||||
return values
|
return values
|
||||||
|
|
||||||
def button_plan_detail(self):
|
|
||||||
pass
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
'category': 'sf',
|
'category': 'sf',
|
||||||
'website': 'https://www.sf.jikimo.com',
|
'website': 'https://www.sf.jikimo.com',
|
||||||
'depends': ['sf_base', 'sf_maintenance', 'web_widget_model_viewer', 'sf_warehouse', 'jikimo_attachment_viewer',
|
'depends': ['sf_base', 'sf_maintenance', 'web_widget_model_viewer', 'sf_warehouse', 'jikimo_attachment_viewer',
|
||||||
'jikimo_sale_multiple_supply_methods', 'product', 'jikimo_tree_header_buttons_always_visible'],
|
'jikimo_sale_multiple_supply_methods', 'product'],
|
||||||
'data': [
|
'data': [
|
||||||
'data/cron_data.xml',
|
'data/cron_data.xml',
|
||||||
'data/stock_data.xml',
|
'data/stock_data.xml',
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ class ReSaleOrder(models.Model):
|
|||||||
'glb_url': item['glb_url'],
|
'glb_url': item['glb_url'],
|
||||||
'remark': item.get('remark'),
|
'remark': item.get('remark'),
|
||||||
'embryo_redundancy_id': item.get('embryo_redundancy_id'),
|
'embryo_redundancy_id': item.get('embryo_redundancy_id'),
|
||||||
'is_incoming_material': True if item.get('incoming_size') else False,
|
'is_incoming_material': True if item.get('embryo_redundancy_id') else False,
|
||||||
'manual_quotation': item.get('manual_quotation'),
|
'manual_quotation': item.get('manual_quotation'),
|
||||||
'model_id': item['model_id'],
|
'model_id': item['model_id'],
|
||||||
'delivery_end_date': item['delivery_end_date']
|
'delivery_end_date': item['delivery_end_date']
|
||||||
@@ -287,7 +287,7 @@ class ResaleOrderLine(models.Model):
|
|||||||
check_status = fields.Selection(related='order_id.check_status')
|
check_status = fields.Selection(related='order_id.check_status')
|
||||||
remark = fields.Char('备注')
|
remark = fields.Char('备注')
|
||||||
|
|
||||||
is_incoming_material = fields.Boolean('客供料', store=True)
|
is_incoming_material = fields.Boolean('客供料', compute='_compute_is_incoming_material', store=True)
|
||||||
embryo_redundancy_id = fields.Many2one('sf.embryo.redundancy', '坯料冗余')
|
embryo_redundancy_id = fields.Many2one('sf.embryo.redundancy', '坯料冗余')
|
||||||
manual_quotation = fields.Boolean('人工编程', default=False)
|
manual_quotation = fields.Boolean('人工编程', default=False)
|
||||||
model_url = fields.Char('模型文件地址')
|
model_url = fields.Char('模型文件地址')
|
||||||
|
|||||||
Reference in New Issue
Block a user