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
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
],
|
||||
'web.assets_backend': [
|
||||
'sf_demand_plan/static/src/scss/style.css',
|
||||
'sf_demand_plan/static/src/js/print_demand.js',
|
||||
]
|
||||
},
|
||||
'license': 'LGPL-3',
|
||||
|
||||
@@ -272,18 +272,15 @@ class SfProductionDemandPlan(models.Model):
|
||||
else:
|
||||
record.actual_end_date = None
|
||||
|
||||
@api.depends('sale_order_id.mrp_production_ids.move_raw_ids.forecast_availability',
|
||||
'sale_order_id.mrp_production_ids.move_raw_ids.quantity_done')
|
||||
@api.depends('sale_order_id.mrp_production_ids.move_raw_ids.reserved_availability')
|
||||
def _compute_material_check(self):
|
||||
for record in self:
|
||||
if record.sale_order_id and record.sale_order_id.mrp_production_ids:
|
||||
manufacturing_orders = record.sale_order_id.mrp_production_ids.filtered(
|
||||
lambda mo: mo.product_id == record.product_id)
|
||||
if manufacturing_orders and manufacturing_orders.move_raw_ids:
|
||||
total_forecast_availability = sum(manufacturing_orders.mapped('move_raw_ids.forecast_availability'))
|
||||
total_quantity_done = sum(manufacturing_orders.mapped('move_raw_ids.quantity_done'))
|
||||
total_sum = total_forecast_availability + total_quantity_done
|
||||
if float_compare(total_sum, record.product_uom_qty,
|
||||
total_reserved_availability = sum(manufacturing_orders.mapped('move_raw_ids.reserved_availability'))
|
||||
if float_compare(total_reserved_availability, record.product_uom_qty,
|
||||
precision_rounding=record.product_id.uom_id.rounding) >= 0:
|
||||
record.material_check = '1' # 已齐套
|
||||
else:
|
||||
@@ -323,6 +320,7 @@ class SfProductionDemandPlan(models.Model):
|
||||
'name': _("打印"),
|
||||
'domain': [('demand_plan_id', 'in', self.ids)],
|
||||
'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',
|
||||
}
|
||||
|
||||
@@ -503,7 +501,10 @@ class SfProductionDemandPlan(models.Model):
|
||||
action = self.env["ir.actions.actions"]._for_xml_id("stock.action_picking_tree_all")
|
||||
picking_ids = None
|
||||
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')
|
||||
elif self.supply_method in ('purchase', 'outsourcing'):
|
||||
picking_ids = self.sale_order_id.picking_ids.filtered(
|
||||
|
||||
215
sf_demand_plan/static/src/js/print_demand.js
Normal file
215
sf_demand_plan/static/src/js/print_demand.js
Normal 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;
|
||||
});
|
||||
@@ -9,3 +9,58 @@
|
||||
.demand_plan_tree .o_list_table_ungrouped {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -30,8 +30,15 @@ class SfDemandPlanPrintWizard(models.TransientModel):
|
||||
workorder_id = fields.Many2one('mrp.workorder', string='工单')
|
||||
cnc_worksheet = fields.Binary('程序单')
|
||||
|
||||
def demand_plan_print(self):
|
||||
for record in self:
|
||||
@api.model
|
||||
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
|
||||
if pdf_data:
|
||||
try:
|
||||
@@ -46,9 +53,20 @@ class SfDemandPlanPrintWizard(models.TransientModel):
|
||||
elif record.type == '2':
|
||||
c_num += 1
|
||||
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:
|
||||
record.status = 'fail'
|
||||
_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):
|
||||
|
||||
@@ -4,14 +4,31 @@
|
||||
<field name="name">sf.demand.plan.print.wizard.tree</field>
|
||||
<field name="model">sf.demand.plan.print.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="打印">
|
||||
<tree string="打印" class="print_demand" js_class="print_demand" >
|
||||
<field name="model_id"/>
|
||||
<field name="filename_url"/>
|
||||
<field name="type"/>
|
||||
<field name="machining_drawings" widget="adaptive_viewer"/>
|
||||
<field name="cnc_worksheet" widget="pdf_viewer"/>
|
||||
<field name="machining_drawings" attrs="{'column_invisible': True }"/>
|
||||
<field name="cnc_worksheet" attrs="{'column_invisible': True }" />
|
||||
<field name="status"/>
|
||||
</tree>
|
||||
</field>
|
||||
</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>
|
||||
Reference in New Issue
Block a user