diff --git a/sf_demand_plan/__manifest__.py b/sf_demand_plan/__manifest__.py
index 932685e0..2a543f1a 100644
--- a/sf_demand_plan/__manifest__.py
+++ b/sf_demand_plan/__manifest__.py
@@ -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',
diff --git a/sf_demand_plan/models/sf_production_demand_plan.py b/sf_demand_plan/models/sf_production_demand_plan.py
index ef11adcc..c0121d58 100644
--- a/sf_demand_plan/models/sf_production_demand_plan.py
+++ b/sf_demand_plan/models/sf_production_demand_plan.py
@@ -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(
diff --git a/sf_demand_plan/static/src/js/print_demand.js b/sf_demand_plan/static/src/js/print_demand.js
new file mode 100644
index 00000000..6dacc7b3
--- /dev/null
+++ b/sf_demand_plan/static/src/js/print_demand.js
@@ -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(
+ `
+
![]()
+
+
`
+ );
+ self.$el.prepend(`
+
+
+
+
+ `);
+ }
+ });
+ },
+ 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;
+});
\ No newline at end of file
diff --git a/sf_demand_plan/static/src/scss/style.css b/sf_demand_plan/static/src/scss/style.css
index f5b687fb..358156b5 100644
--- a/sf_demand_plan/static/src/scss/style.css
+++ b/sf_demand_plan/static/src/scss/style.css
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/sf_demand_plan/wizard/sf_demand_plan_print_wizard.py b/sf_demand_plan/wizard/sf_demand_plan_print_wizard.py
index ddd154e6..25c7791a 100644
--- a/sf_demand_plan/wizard/sf_demand_plan_print_wizard.py
+++ b/sf_demand_plan/wizard/sf_demand_plan_print_wizard.py
@@ -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):
diff --git a/sf_demand_plan/wizard/sf_demand_plan_print_wizard_view.xml b/sf_demand_plan/wizard/sf_demand_plan_print_wizard_view.xml
index 311e3ae8..6927c283 100644
--- a/sf_demand_plan/wizard/sf_demand_plan_print_wizard_view.xml
+++ b/sf_demand_plan/wizard/sf_demand_plan_print_wizard_view.xml
@@ -4,14 +4,31 @@
sf.demand.plan.print.wizard.tree
sf.demand.plan.print.wizard
-
+
-
-
+
+
+
+
+ sf.demand.plan.print.wizard.search
+ sf.demand.plan.print.wizard
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file