Compare commits

...

16 Commits

Author SHA1 Message Date
胡尧
4f000a6be4 修改采购申请相关欠单创建报错的问题 2025-06-18 10:56:22 +08:00
胡尧
376eb9e56f 采购申请按钮按照产品以及bom产品过滤 2025-06-18 10:34:34 +08:00
禹翔辉
1dfa22900d Accept Merge Request #2202: (feature/质检样式修改 -> develop)
Merge Request: 1、质检单类型为出厂检测报告时,隐藏通过状态下的不合格按钮;2、功能刀具组装检测BOM物料时过滤产品的追溯类型为不追溯的产品。

Created By: @禹翔辉
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2202
2025-06-17 11:50:01 +08:00
yuxianghui
0eeebf437a 1、质检单类型为出厂检测报告时,隐藏通过状态下的不合格按钮;2、功能刀具组装检测BOM物料时过滤产品的追溯类型为不追溯的产品。 2025-06-17 11:47:26 +08:00
管欢
397d4f29a1 Accept Merge Request #2201: (feature/齐套检查与下达生产 -> develop)
Merge Request: 不同产品调拨单就绪未过滤产品问题

Created By: @管欢
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @管欢
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2201
2025-06-17 11:21:00 +08:00
guanhuan
33205c5d29 不同产品调拨单就绪未过滤产品问题 2025-06-17 10:57:13 +08:00
hyyy
568f3e4f30 修改传参,增加提示,默认展示第一个文件 2025-06-17 09:58:53 +08:00
guanhuan
8c43fc2b76 打印方法修改 2025-06-17 09:41:08 +08:00
guanhuan
8960d3d07c Merge remote-tracking branch 'origin/feature/齐套检查与下达生产' into feature/齐套检查与下达生产 2025-06-16 17:42:40 +08:00
guanhuan
95b5c86242 投料齐套检查修改 2025-06-16 17:42:05 +08:00
hyyy
c2000aa9c5 修改字段名 2025-06-16 17:28:09 +08:00
hyyy
e29456bbf7 选择列表展示图片 2025-06-16 17:25:52 +08:00
禹翔辉
a2f8dc6cec Accept Merge Request #2200: (feature/平台下单优化_1 -> develop)
Merge Request: Merge branch 'feature/平台下单优化' into feature/平台下单优化_1

Created By: @禹翔辉
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2200
2025-06-16 16:06:06 +08:00
yuxianghui
fec095ca6b Merge branch 'feature/平台下单优化' into feature/平台下单优化_1 2025-06-16 16:03:53 +08:00
yuxianghui
aed33dbb35 1、内部下单:行明细增加交期等; 2、处理 bfm平台下单-填写了合同相关字段,未上传合同,合同的相关字段未传到sf销售订单 问题 2025-06-16 16:02:43 +08:00
guanhuan
dbe8c95558 打印页面增加筛选 2025-06-16 15:43:02 +08:00
19 changed files with 380 additions and 27 deletions

View File

@@ -6,3 +6,4 @@ from . import mrp_production
from . import purchase_order from . import purchase_order
from . import stock_rule from . import stock_rule
from . import stock_picking from . import stock_picking
from . import product_product

View File

@@ -12,9 +12,7 @@ class MrpProduction(models.Model):
if item.product_id.is_customer_provided: if item.product_id.is_customer_provided:
item.pr_mp_count = 0 item.pr_mp_count = 0
else: else:
# 由于采购申请合并了所有销售订单行的采购,所以不区分产品 pr_ids = item._get_purchase_request()
mrp_names = self.env['mrp.production'].search([('origin', '=', item.origin)]).mapped('name')
pr_ids = self.env['purchase.request'].sudo().search([('origin', 'in', mrp_names)])
item.pr_mp_count = len(pr_ids) item.pr_mp_count = len(pr_ids)
# pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', item.name), ('is_subcontract', '!=', 'True')]) # pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', item.name), ('is_subcontract', '!=', 'True')])
@@ -25,8 +23,7 @@ class MrpProduction(models.Model):
self.ensure_one() self.ensure_one()
# 由于采购申请合并了所有销售订单行的采购,所以不区分产品 # 由于采购申请合并了所有销售订单行的采购,所以不区分产品
mrp_names = self.env['mrp.production'].search([('origin', '=', self.origin)]).mapped('name') pr_ids = self._get_purchase_request()
pr_ids = self.env['purchase.request'].sudo().search([('origin', 'in', mrp_names)])
action = { action = {
'res_model': 'purchase.request', 'res_model': 'purchase.request',
@@ -44,3 +41,12 @@ class MrpProduction(models.Model):
'view_mode': 'tree,form', 'view_mode': 'tree,form',
}) })
return action return action
def _get_purchase_request(self):
"""获取跟制造订单相关的采购申请单(根据采购申请单行项目的产品匹配)"""
mrp_names = self.env['mrp.production'].search([('origin', '=', self.origin)]).mapped('name')
pr_ids = self.env['purchase.request'].sudo().search([('origin', 'in', mrp_names)])
product_list = self.product_id._get_product_include_bom()
pr_line_ids = pr_ids.line_ids.filtered(lambda l: l.product_id in product_list)
return pr_line_ids.mapped('request_id')

View File

@@ -0,0 +1,17 @@
from odoo import models
class ProductProduct(models.Model):
_inherit = 'product.product'
def _get_product_include_bom(self):
"""获取产品列表包括所有bom"""
self.ensure_one()
product_list = [self]
bom_ids = self.bom_ids
while (bom_ids):
bom_product_ids = bom_ids.bom_line_ids.mapped('product_id')
product_list.append(bom_product_ids)
bom_ids = bom_product_ids.bom_ids
return product_list

View File

@@ -42,6 +42,6 @@ class StockPicking(models.Model):
purchase_request_lines = self.move_ids.move_orig_ids.purchase_line_id.purchase_request_lines purchase_request_lines = self.move_ids.move_orig_ids.purchase_line_id.purchase_request_lines
if purchase_request_lines: if purchase_request_lines:
purchase_request_lines.move_dest_ids = [ purchase_request_lines.move_dest_ids = [
(4, x.id) for x in backorder_ids.move_ids if x.product_id.id == purchase_request_lines.product_id.id (4, x.id) for x in backorder_ids.move_ids if x.product_id.id in purchase_request_lines.mapped('product_id.id')
] ]
return res return res

View File

@@ -23,6 +23,7 @@
], ],
'web.assets_backend': [ 'web.assets_backend': [
'sf_demand_plan/static/src/scss/style.css', 'sf_demand_plan/static/src/scss/style.css',
'sf_demand_plan/static/src/js/print_demand.js',
] ]
}, },
'license': 'LGPL-3', 'license': 'LGPL-3',

View File

@@ -272,18 +272,15 @@ class SfProductionDemandPlan(models.Model):
else: else:
record.actual_end_date = None record.actual_end_date = None
@api.depends('sale_order_id.mrp_production_ids.move_raw_ids.forecast_availability', @api.depends('sale_order_id.mrp_production_ids.move_raw_ids.reserved_availability')
'sale_order_id.mrp_production_ids.move_raw_ids.quantity_done')
def _compute_material_check(self): def _compute_material_check(self):
for record in self: for record in self:
if record.sale_order_id and record.sale_order_id.mrp_production_ids: if record.sale_order_id and record.sale_order_id.mrp_production_ids:
manufacturing_orders = record.sale_order_id.mrp_production_ids.filtered( manufacturing_orders = record.sale_order_id.mrp_production_ids.filtered(
lambda mo: mo.product_id == record.product_id) lambda mo: mo.product_id == record.product_id)
if manufacturing_orders and manufacturing_orders.move_raw_ids: if manufacturing_orders and manufacturing_orders.move_raw_ids:
total_forecast_availability = sum(manufacturing_orders.mapped('move_raw_ids.forecast_availability')) total_reserved_availability = sum(manufacturing_orders.mapped('move_raw_ids.reserved_availability'))
total_quantity_done = sum(manufacturing_orders.mapped('move_raw_ids.quantity_done')) if float_compare(total_reserved_availability, record.product_uom_qty,
total_sum = total_forecast_availability + total_quantity_done
if float_compare(total_sum, record.product_uom_qty,
precision_rounding=record.product_id.uom_id.rounding) >= 0: precision_rounding=record.product_id.uom_id.rounding) >= 0:
record.material_check = '1' # 已齐套 record.material_check = '1' # 已齐套
else: else:
@@ -323,6 +320,7 @@ class SfProductionDemandPlan(models.Model):
'name': _("打印"), 'name': _("打印"),
'domain': [('demand_plan_id', 'in', self.ids)], 'domain': [('demand_plan_id', 'in', self.ids)],
'views': [[self.env.ref('sf_demand_plan.action_plan_print_tree').id, 'list']], 'views': [[self.env.ref('sf_demand_plan.action_plan_print_tree').id, 'list']],
'search_view_id': self.env.ref('sf_demand_plan.action_plan_print_search').id,
'target': 'new', 'target': 'new',
} }
@@ -503,7 +501,10 @@ class SfProductionDemandPlan(models.Model):
action = self.env["ir.actions.actions"]._for_xml_id("stock.action_picking_tree_all") action = self.env["ir.actions.actions"]._for_xml_id("stock.action_picking_tree_all")
picking_ids = None picking_ids = None
if self.supply_method in ('automation', 'manual'): if self.supply_method in ('automation', 'manual'):
picking_ids = self.sale_order_id.mrp_production_ids.mapped('picking_ids').filtered( mrp_production_ids = self.sale_order_id.mrp_production_ids.filtered(
lambda p: p.product_id.id == self.product_id.id
)
picking_ids = mrp_production_ids.mapped('picking_ids').filtered(
lambda p: p.state == 'assigned') lambda p: p.state == 'assigned')
elif self.supply_method in ('purchase', 'outsourcing'): elif self.supply_method in ('purchase', 'outsourcing'):
picking_ids = self.sale_order_id.picking_ids.filtered( picking_ids = self.sale_order_id.picking_ids.filtered(

View File

@@ -0,0 +1,215 @@
odoo.define('sf_demand.print_demand', function (require) {
"use strict";
var ListController = require('web.ListController');
var ListRenderer = require('web.ListRenderer');
var ListView = require('web.ListView');
var viewRegistry = require('web.view_registry');
var { url } = require("@web/core/utils/urls")
var CustomListRenderer = ListRenderer.extend({
_render: function () {
var self = this;
this.getParent()?.$buttons.hide();
return this._super.apply(this, arguments).then(function () {
// 添加图片预览容器到页面左侧
if (!$('.table-image-preview-container').length) {
self.$el.parent().addClass('custom-table-image-container')
self.$el.before(
`<div class="custom-preview-container">
<img class="table-image-preview-container" src="" />
<iframe class="table-image-preview-container" src=""/>
</div>`
);
self.$el.prepend(`
<div class="print-button-container" style="margin-bottom:10px;">
<button class="btn btn-primary o_print_custom">
<i class="fa fa-print"></i> 打印
</button>
<button class="btn btn-secondary o_cancel_custom">
取消
</button>
</div>
`);
}
});
},
start: function() {
setTimeout(() => {
this.$el.find('.o_data_row').eq(0).trigger('click')
}, 500);
return this._super();
},
events: _.extend({}, ListRenderer.prototype.events, {
'click .o_data_row': '_onCustomRowClick',
'click .o_print_custom': '_onPrintClick',
'click .o_cancel_custom': '_onCancelClick'
}),
_onCancelClick() {
this.getParent()?.getParent()?.dialogs.closeAll()
},
_onCustomRowClick: async function (ev) {
var self = this;
var $row = $(ev.currentTarget);
var index = $row.index();
var data = this.state.data[index];
if(data.fileData?.fileUrl) {
} else {
data.fileData = { }
if(data.res_id) {
// 正确获取 ORM 服务的方式
// var orm = this.getParent().getParent().env.services
const key = data.data.type == 1 ? 'machining_drawings' : 'cnc_worksheet'
const attachment = await this._rpc({
model: 'ir.binary',
method: 'attachment_info',
args: [
data.model,
data.res_id,
key
],
})
if (attachment) {
Object.assign(data.fileData, attachment)
this._getTypeInfo(attachment.mimetype, data.fileData)
}
const fileUrl = this.getFileUrl(data.fileData.attachment_type, data, key)
data.fileData.fileUrl = fileUrl
}
}
$('.table-image-preview-container').hide()
if(data.fileData.attachment_type == 'iframe') {
$('iframe.table-image-preview-container').attr('src', decodeURIComponent(data.fileData.fileUrl) ).show()
} else {
$('img.table-image-preview-container').attr('src', data.fileData.fileUrl).show()
}
},
getSelectedIds: function() {
return this.state.data.map(_ => {
return _.data.id
})
},
_onPrintClick(e) {
var print_ids = this.getSelectedIds();
this._rpc({
model: 'sf.demand.plan.print.wizard',
method: 'demand_plan_print',
args: [ print_ids ] ,
// context: this.state.getContext()
}).then((e) => {
this.getParent()?.getParent()?.env.services?.notification.notify( {
type: 'info',
message: e.message,
})
// self.do_notify("成功", "打印任务已发送到打印机");
}).catch(function(error) {
console.error("打印错误:", error);
// self.do_warn("打印失败", error.data.message || "未知错误");
}).finally(e => {
this.getParent().reload()
})
},
getFileUrl(attachment_type, data, key) {
let fileUrl
switch (attachment_type) {
case 'image':
const timer = +new Date()
fileUrl = url("/web/image", {
model: data.model,
id: data.res_id,
field: key,
unique: '',
timer
});
break;
case 'iframe':
const iframe_file_url = encodeURIComponent(
url("/web/content", {
model: data.model,
id: data.res_id,
field: key,
})
);
fileUrl = `${this.state.attachment_base}?file=${iframe_file_url}`;
case 'unknown':
fileUrl = encodeURIComponent(
url("/web/content", {
model: data.model,
id: data.res_id,
field: key,
})
);
}
return fileUrl
},
_getTypeInfo(type, data) {
switch (type) {
case 'application/pdf':
data.attachment_base = `/web/static/lib/pdfjs/web/viewer.html`;
data.attachment_type = 'iframe'
break;
case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document':
data.attachment_base = `/jikimo_attachment_viewer/static/lib/docxjs/viewer.html`;
data.attachment_type = 'iframe'
break;
case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
data.attachment_base = `/jikimo_attachment_viewer/static/lib/exceljs/viewer.html`;
data.attachment_type = 'iframe'
break;
case 'application/vnd.openxmlformats-officedocument.presentationml.presentation':
data.attachment_base = '';
data.attachment_type = 'unknown'
break;
case 'image/png':
case 'image/jpeg':
case 'image/jpg':
data.attachment_base = ''
data.attachment_type = 'image'
break;
default:
data.attachment_base = ''
data.attachment_type = 'unknown'
break;
}
}
});
var CustomListController = ListController.extend({
// 可以保留或移除,根据是否需要处理自定义事件
// 处理打印操作
// rpc.query({
// model: 'sf.demand.plan.print.wizard',
// method: 'demand_plan_print',
// args: [recordIds]
// }).then(function(result) {
// self.do_notify("成功", "打印任务已发送到打印机");
// // 刷新视图显示最新状态
// self.reload();
// }).catch(function(error) {
// self.do_warn("打印失败", error.data.message || "发生未知错误");
// });
});
var PrintDemand = ListView.extend({
config: _.extend({}, ListView.prototype.config, {
Renderer: CustomListRenderer,
Controller: CustomListController,
}),
});
viewRegistry.add('print_demand', PrintDemand);
return PrintDemand;
});

View File

@@ -9,3 +9,58 @@
.demand_plan_tree .o_list_table_ungrouped { .demand_plan_tree .o_list_table_ungrouped {
min-width: 1900px; min-width: 1900px;
} }
.o_selected_row {
background-color: #e6f7ff !important;
font-weight: bold;
}
.custom-table-image-container {
display: flex;
height: calc(95vh - 254px);
gap: 20px;
position: relative;
th.o_list_record_selector, td.o_list_record_selector{
display: none;
}
.custom-preview-container, .print_demand {
flex: 1;
max-width: 49%;
tbody {
tr:not(.o_data_row) {
display: none;
}
}
tfoot {
display: none;
}
}
.print_demand {
.table-responsive {
width: 100%;
overflow-x: auto!important;
}
}
.custom-preview-container {
background-color: #dadce0;
padding: 20px;
img {
max-width: 100%;
max-height: 100%;
}
iframe {
width: 100%;
height: 100%;
}
}
.o_print_custom, .o_cancel_custom {
position: absolute;
bottom: 20px;
right: 20px;
}
.o_print_custom {
right: 66px;
}
}

View File

@@ -30,8 +30,15 @@ class SfDemandPlanPrintWizard(models.TransientModel):
workorder_id = fields.Many2one('mrp.workorder', string='工单') workorder_id = fields.Many2one('mrp.workorder', string='工单')
cnc_worksheet = fields.Binary('程序单') cnc_worksheet = fields.Binary('程序单')
def demand_plan_print(self): @api.model
for record in self: def demand_plan_print(self, print_ids):
plan_print_ids = self.env['sf.demand.plan.print.wizard'].sudo().search(
[('id', 'in', print_ids)])
if not plan_print_ids:
return {'message': '记录不存在'}
success_records = []
failed_records = []
for record in plan_print_ids:
pdf_data = record.machining_drawings if record.type == '1' else record.cnc_worksheet pdf_data = record.machining_drawings if record.type == '1' else record.cnc_worksheet
if pdf_data: if pdf_data:
try: try:
@@ -46,9 +53,20 @@ class SfDemandPlanPrintWizard(models.TransientModel):
elif record.type == '2': elif record.type == '2':
c_num += 1 c_num += 1
record.demand_plan_id.print_count = f"T{t_num}C{c_num}" record.demand_plan_id.print_count = f"T{t_num}C{c_num}"
success_records.append({
'filename_url': record.filename_url,
})
except Exception as e: except Exception as e:
record.status = 'fail' record.status = 'fail'
_logger.error(f"文件{record.filename_url}打印失败: {str(e)}") _logger.error(f"文件{record.filename_url}打印失败: {str(e)}")
failed_records.append({
'filename_url': record.filename_url,
})
if failed_records:
message = f"成功打印 {len(success_records)} 个文件,失败 {len(failed_records)}"
else:
message = f"所有 {len(success_records)} 个文件打印成功"
return {'message': message}
class MrpWorkorder(models.Model): class MrpWorkorder(models.Model):

View File

@@ -4,14 +4,31 @@
<field name="name">sf.demand.plan.print.wizard.tree</field> <field name="name">sf.demand.plan.print.wizard.tree</field>
<field name="model">sf.demand.plan.print.wizard</field> <field name="model">sf.demand.plan.print.wizard</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="打印"> <tree string="打印" class="print_demand" js_class="print_demand" >
<field name="model_id"/> <field name="model_id"/>
<field name="filename_url"/> <field name="filename_url"/>
<field name="type"/> <field name="type"/>
<field name="machining_drawings" widget="adaptive_viewer"/> <field name="machining_drawings" attrs="{'column_invisible': True }"/>
<field name="cnc_worksheet" widget="pdf_viewer"/> <field name="cnc_worksheet" attrs="{'column_invisible': True }" />
<field name="status"/> <field name="status"/>
</tree> </tree>
</field> </field>
</record> </record>
<record id="action_plan_print_search" model="ir.ui.view">
<field name="name">sf.demand.plan.print.wizard.search</field>
<field name="model">sf.demand.plan.print.wizard</field>
<field name="arch" type="xml">
<search>
<field name="type"/>
<filter string="图纸" name="filter_type_1" domain="[('type', '=', '1')]"/>
<filter string="程序单" name="filter_type_2" domain="[('type', '=', '2')]"/>
<filter string="图纸、程序单" name="filter_type_all" domain="[('type', 'in', ('1','2'))]"/>
<separator/>
<group expand="0" string="Group By">
<filter name="group_by_type" string="类型" domain="[]" context="{'group_by': 'type'}"/>
</group>
</search>
</field>
</record>
</odoo> </odoo>

View File

@@ -10,6 +10,7 @@ class ResProductTemplate(models.Model):
model_name = fields.Char('模型名称') model_name = fields.Char('模型名称')
categ_type = fields.Selection( categ_type = fields.Selection(
[("成品", "成品"), ("胚料", "胚料"), ("原材料", "原材料")], string='产品的类别', related='categ_id.type', store=True) [("成品", "成品"), ("胚料", "胚料"), ("原材料", "原材料")], string='产品的类别', related='categ_id.type', store=True)
blank_type = fields.Selection([('圆料', '圆料'), ('方料', '方料')], string='坯料分类')
model_long = fields.Float('模型长[mm]', digits=(16, 3)) model_long = fields.Float('模型长[mm]', digits=(16, 3))
model_width = fields.Float('模型宽[mm]', digits=(16, 3)) model_width = fields.Float('模型宽[mm]', digits=(16, 3))
model_height = fields.Float('模型高[mm]', digits=(16, 3)) model_height = fields.Float('模型高[mm]', digits=(16, 3))
@@ -74,6 +75,7 @@ class ResProductTemplate(models.Model):
attachment = self.attachment_create(item['model_name'], item['model_data']) attachment = self.attachment_create(item['model_name'], item['model_data'])
vals = { vals = {
'name': '%s-%s-%s' % ('P', order_id.name, i), 'name': '%s-%s-%s' % ('P', order_id.name, i),
'blank_type': item.get('blank_type'),
'model_long': item['model_long'] + model_type.embryo_tolerance, 'model_long': item['model_long'] + model_type.embryo_tolerance,
'model_width': item['model_width'] + model_type.embryo_tolerance, 'model_width': item['model_width'] + model_type.embryo_tolerance,
'model_height': item['model_height'] + model_type.embryo_tolerance, 'model_height': item['model_height'] + model_type.embryo_tolerance,

View File

@@ -95,7 +95,7 @@
<page string="加工参数"> <page string="加工参数">
<group> <group>
<group string="模型"> <group string="模型">
<label for="model_long" string="尺寸[mm]"/> <label for="model_long" string="坯料尺寸[mm]"/>
<div class="o_address_format"> <div class="o_address_format">
<label for="model_long" string="长"/> <label for="model_long" string="长"/>
<field name="model_long" class="o_address_zip"/> <field name="model_long" class="o_address_zip"/>
@@ -104,6 +104,7 @@
<label for="model_height" string="高"/> <label for="model_height" string="高"/>
<field name="model_height" class="o_address_zip"/> <field name="model_height" class="o_address_zip"/>
</div> </div>
<field name="blank_type" readonly="1"/>
<field name="model_volume" string="体积[mm³]"/> <field name="model_volume" string="体积[mm³]"/>
<field name="product_model_type_id" string="模型类型"/> <field name="product_model_type_id" string="模型类型"/>
<field name="model_processing_panel" placeholder="例如R,U" string="加工面板" <field name="model_processing_panel" placeholder="例如R,U" string="加工面板"

View File

@@ -45,9 +45,8 @@ class JikimoSaleRoutePicking(Sf_Bf_Connect):
product.product_tmpl_id.is_customer_provided = True if item['embryo_redundancy_id'] else False product.product_tmpl_id.is_customer_provided = True if item['embryo_redundancy_id'] else False
order_id.with_user(request.env.ref("base.user_admin")).sale_order_create_line(product, item) order_id.with_user(request.env.ref("base.user_admin")).sale_order_create_line(product, item)
i += 1 i += 1
if kw.get('contract_file_name') and kw.get('contract_file') and kw.get('contract_code'): # BFM 内部下单 新增合同等内容补充
order_id.create_sale_documents(kw.get('contract_file_name'), kw.get('contract_file')) order_id.write_sale_documents(kw)
order_id.write({'contract_code': kw.get('contract_code'), 'contract_date': kw.get('contract_date')})
res['factory_order_no'] = order_id.name res['factory_order_no'] = order_id.name
order_id.confirm_to_supply_method() order_id.confirm_to_supply_method()
except Exception as e: except Exception as e:

View File

@@ -26,6 +26,7 @@ class ResProductMo(models.Model):
model_file = fields.Binary('模型文件') model_file = fields.Binary('模型文件')
categ_type = fields.Selection(string='产品的类别', related='categ_id.type', store=True) categ_type = fields.Selection(string='产品的类别', related='categ_id.type', store=True)
model_name = fields.Char('模型名称') model_name = fields.Char('模型名称')
blank_type = fields.Selection([('圆料', '圆料'), ('方料', '方料')], string='坯料分类')
model_long = fields.Float('模型长(mm)', digits=(16, 3)) model_long = fields.Float('模型长(mm)', digits=(16, 3))
model_width = fields.Float('模型宽(mm)', digits=(16, 3)) model_width = fields.Float('模型宽(mm)', digits=(16, 3))
model_height = fields.Float('模型高(mm)', digits=(16, 3)) model_height = fields.Float('模型高(mm)', digits=(16, 3))
@@ -895,6 +896,7 @@ class ResProductMo(models.Model):
product_name = self.generate_product_name(order_id, item, i) product_name = self.generate_product_name(order_id, item, i)
vals = { vals = {
'name': product_name, 'name': product_name,
'blank_type': item.get('blank_type'),
'model_long': self.format_float(item['model_long'] + embryo_redundancy_id.long), 'model_long': self.format_float(item['model_long'] + embryo_redundancy_id.long),
'model_width': self.format_float(item['model_width'] + embryo_redundancy_id.width), 'model_width': self.format_float(item['model_width'] + embryo_redundancy_id.width),
'model_height': self.format_float(item['model_height'] + embryo_redundancy_id.height), 'model_height': self.format_float(item['model_height'] + embryo_redundancy_id.height),

View File

@@ -193,6 +193,19 @@ class SaleOrder(models.Model):
'target': 'new', 'target': 'new',
'res_id': wizard.id, 'res_id': wizard.id,
} }
def write_sale_documents(self, kw):
"""BFM 内部下单 内容补充 """
val = {}
if kw.get('contract_file_name') and kw.get('contract_file'):
document_id = self.create_sale_documents(kw.get('contract_file_name'), kw.get('contract_file'))
val.update({'contract_document_id': document_id.id})
if kw.get('contract_code') or kw.get('contract_date'):
val.update({'contract_code': kw.get('contract_code'), 'contract_date': kw.get('contract_date')})
if kw.get('customer_name'):
val.update({'customer_name': kw.get('customer_name')})
self.write(val)
def create_sale_documents(self, contract_file_name, contract_file): def create_sale_documents(self, contract_file_name, contract_file):
# 创建ir.attachment记录 # 创建ir.attachment记录
attachment = self.env['ir.attachment'].sudo().create({ attachment = self.env['ir.attachment'].sudo().create({
@@ -214,9 +227,7 @@ class SaleOrder(models.Model):
'res_id': self.id, 'res_id': self.id,
}) })
self.write({ return document
'contract_document_id': document.id
})
class SaleOrderLine(models.Model): class SaleOrderLine(models.Model):
_inherit = 'sale.order.line' _inherit = 'sale.order.line'

View File

@@ -66,7 +66,7 @@
<attribute name="string">不合格</attribute> <attribute name="string">不合格</attribute>
</xpath> </xpath>
<xpath expr="//header//button[@name='do_fail'][2]" position="attributes"> <xpath expr="//header//button[@name='do_fail'][2]" position="attributes">
<attribute name="attrs">{'invisible': ['|',('quality_state', '!=', 'pass'),('work_state','in', ('done', 'rework'))]}</attribute> <attribute name="attrs">{'invisible': ['|','|',('quality_state', '!=', 'pass'),('work_state','in', ('done', 'rework')),'&amp;',('quality_state', '=', 'pass'), ('test_type', '=', '出厂检验报告')]}</attribute>
<attribute name="string">不合格</attribute> <attribute name="string">不合格</attribute>
</xpath> </xpath>

View File

@@ -63,6 +63,7 @@ class ReSaleOrder(models.Model):
model_display_version = fields.Char('模型展示版本', default="v1") model_display_version = fields.Char('模型展示版本', default="v1")
customer_name = fields.Char('终端客户')
contract_code = fields.Char('合同编号') contract_code = fields.Char('合同编号')
contract_date = fields.Date('合同日期') contract_date = fields.Date('合同日期')
contract_document_id = fields.Many2one('documents.document', string='合同文件') contract_document_id = fields.Many2one('documents.document', string='合同文件')
@@ -158,6 +159,7 @@ class ReSaleOrder(models.Model):
'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'],
'customer_delivery_date': item.get('customer_delivery_date'),
} }
return self.env['sale.order.line'].with_context(skip_procurement=True).create(vals) return self.env['sale.order.line'].with_context(skip_procurement=True).create(vals)
@@ -291,8 +293,8 @@ class ResaleOrderLine(models.Model):
manual_quotation = fields.Boolean('人工编程', default=False) manual_quotation = fields.Boolean('人工编程', default=False)
model_url = fields.Char('模型文件地址') model_url = fields.Char('模型文件地址')
model_id = fields.Char('模型ID') model_id = fields.Char('模型ID')
delivery_end_date = fields.Date('交货截止日期') delivery_end_date = fields.Date('交货截止日期')
customer_delivery_date = fields.Date('客户交期')
@api.depends('embryo_redundancy_id') @api.depends('embryo_redundancy_id')
def _compute_is_incoming_material(self): def _compute_is_incoming_material(self):

View File

@@ -90,6 +90,9 @@
<field name="partner_id" position="replace"> <field name="partner_id" position="replace">
<field name="partner_id" widget="res_partner_many2one" context="{'is_customer': True }" <field name="partner_id" widget="res_partner_many2one" context="{'is_customer': True }"
options='{"always_reload": True,"no_create": True}'/> options='{"always_reload": True,"no_create": True}'/>
<field name="customer_name" readonly="1"/>
<field name="contract_code" readonly="1"/>
<field name="contract_date" readonly="1"/>
</field> </field>
<field name="payment_term_id" position="attributes"> <field name="payment_term_id" position="attributes">
<attribute name="attrs">{'readonly': [('state', 'in', ['cancel','sale'])]}</attribute> <attribute name="attrs">{'readonly': [('state', 'in', ['cancel','sale'])]}</attribute>
@@ -124,6 +127,7 @@
<xpath expr="//field[@name='order_line']/tree/field[@name='name']" position="replace"> <xpath expr="//field[@name='order_line']/tree/field[@name='name']" position="replace">
<field name="name" widget="section_and_note_text" optional="show" <field name="name" widget="section_and_note_text" optional="show"
string="参数说明(长/宽/高/体积/精度/材质)"/> string="参数说明(长/宽/高/体积/精度/材质)"/>
<field name="customer_delivery_date" readonly="1"/>
<field name="manual_quotation" readonly="1"/> <field name="manual_quotation" readonly="1"/>
<field name="is_incoming_material" readonly="1"/> <field name="is_incoming_material" readonly="1"/>
</xpath> </xpath>

View File

@@ -818,6 +818,7 @@ class FunctionalToolAssembly(models.Model):
def _get_old_tool_material_lot(self, material_ids): def _get_old_tool_material_lot(self, material_ids):
""" 根据先进先出原则选择物料批次 """ """ 根据先进先出原则选择物料批次 """
material_ids = material_ids.filtered(lambda m: m.tracking != 'none')
location_id = self.env['stock.location'].search([('name', '=', '刀具房')]) location_id = self.env['stock.location'].search([('name', '=', '刀具房')])
stock_quant = self.env['stock.quant'].sudo().search( stock_quant = self.env['stock.quant'].sudo().search(
[('location_id', '=', location_id.id), ('product_id', 'in', material_ids.ids), ('quantity', '>', '0')], [('location_id', '=', location_id.id), ('product_id', 'in', material_ids.ids), ('quantity', '>', '0')],