Merge branch 'develop' into feature/sale_order_route_pick

This commit is contained in:
胡尧
2024-11-26 10:47:32 +08:00
12 changed files with 101 additions and 58 deletions

View File

@@ -1,5 +1,7 @@
import logging
import json
import traceback
from odoo import http
from odoo.http import request
from odoo.addons.sf_bf_connect.controllers.controllers import Sf_Bf_Connect
@@ -44,7 +46,8 @@ class JikimoSaleRoutePicking(Sf_Bf_Connect):
i += 1
res['factory_order_no'] = order_id.name
except Exception as e:
_logger.info('get_bfm_process_order_list error:%s' % e)
traceback_error = traceback.format_exc()
logging.error('get_bfm_process_order_list error: %s' % traceback_error)
res['status'] = -1
res['message'] = '工厂创建销售订单和产品失败,请联系管理员'
request.cr.rollback()

View File

@@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
import json
import logging
import traceback
from odoo import http
from odoo.http import request
@@ -123,7 +125,8 @@ class Sf_Bf_Connect(http.Controller):
res['factory_order_no'] = order_id.name
return json.JSONEncoder().encode(res)
except Exception as e:
logging.info('get_bfm_process_order_list error:%s' % e)
traceback_error = traceback.format_exc()
logging.error('get_bfm_process_order_list error: %s' % traceback_error)
res['status'] = -1
res['message'] = '工厂创建销售订单和产品失败,请联系管理员'
request.cr.rollback()

View File

@@ -278,7 +278,7 @@ class MrpProduction(models.Model):
@api.depends(
'move_raw_ids.state', 'move_raw_ids.quantity_done', 'move_finished_ids.state', 'tool_state',
'workorder_ids.state', 'product_qty', 'qty_producing', 'schedule_state', 'programming_state')
'workorder_ids.state', 'product_qty', 'qty_producing', 'schedule_state', 'programming_state', 'is_adjust')
def _compute_state(self):
for production in self:
if not production.state or not production.product_uom_id:
@@ -313,12 +313,17 @@ class MrpProduction(models.Model):
production.state == 'to_close' or production.state == 'progress') and production.schedule_state == '未排':
if not production.workorder_ids or production.is_adjust is True:
production.state = 'technology_to_confirmed'
else:
if production.is_adjust is True:
production.state = 'technology_to_confirmed'
else:
production.state = 'confirmed'
elif production.state == 'pending_cam' and production.schedule_state == '未排':
production.state = 'confirmed'
elif production.state == 'to_close' and production.schedule_state == '已排':
production.state = 'pending_cam'
elif production.state == 'confirmed' and production.is_adjust is True:
production.state = 'technology_to_confirmed'
if production.state == 'progress':
if all(wo_state not in ('progress', 'done', 'rework', 'scrap') for wo_state in
production.workorder_ids.mapped('state')):
@@ -383,9 +388,12 @@ class MrpProduction(models.Model):
def technology_confirm(self):
process_parameters = []
account_moves = []
parameters_not = []
special_design = self.technology_design_ids.filtered(
lambda a: a.routing_tag == 'special' and a.is_auto is False)
for special in special_design:
if special.route_id.routing_type == '表面工艺' and not special.process_parameters_id:
parameters_not.append(special.route_id.name)
if special.process_parameters_id:
product_production_process = self.env['product.template'].search(
[('server_product_process_parameters_id', '=', special.process_parameters_id.id)])
@@ -399,6 +407,8 @@ class MrpProduction(models.Model):
account_moves.append(purchase.name)
if account_moves:
raise UserError(_("请联系工厂生产经理对采购订单为%s生成的账单进行取消", ", ".join(account_moves)))
if parameters_not:
raise UserError(_("【工艺设计】-【工序】为%s未选择参数,请选择", ", ".join(parameters_not)))
if process_parameters:
raise UserError(_("【工艺设计】-【参数】为%s的在【产品】中不存在,请先创建", ", ".join(process_parameters)))
# 判断同一个加工面的标准工序的顺序是否依次排序
@@ -1126,6 +1136,14 @@ class MrpProduction(models.Model):
cloud_programming = None
if self.programming_state in ['已编程']:
cloud_programming = self._cron_get_programming_state()
result_ids = self.detection_result_ids.filtered(lambda dr: dr.handle_result == '待处理')
work_ids = []
if result_ids:
for result_id in result_ids:
work_ids.append(self.workorder_ids.filtered(
lambda wk: (wk.name == result_id.routing_type
and wk.processing_panel == result_id.processing_panel
and wk.state == 'done')).id)
return {
'name': _('返工'),
'type': 'ir.actions.act_window',
@@ -1134,7 +1152,7 @@ class MrpProduction(models.Model):
'target': 'new',
'context': {
'default_production_id': self.id,
'default_workorder_ids': self.workorder_ids.filtered(lambda wk: wk.state == 'done').ids,
'default_workorder_ids': work_ids,
'default_reprogramming_num': cloud_programming['reprogramming_num'],
'default_programming_state': cloud_programming['programming_state'],
'default_is_reprogramming': True if cloud_programming['programming_state'] in ['已下发'] else False
@@ -1288,6 +1306,7 @@ class MrpProduction(models.Model):
raise_user_error=not self.env.context.get('from_orderpoint'))
productions = self.env['mrp.production'].sudo().search(
[('origin', '=', self.origin)], order='id desc', limit=1)
productions.write({'programming_no': self.programming_no, 'is_remanufacture': True})
move = self.env['stock.move'].search([('origin', '=', productions.name)], order='id desc')
for mo in move:
domain = []
@@ -1314,7 +1333,6 @@ class MrpProduction(models.Model):
mo_move.write({'reference': sfp_move.reference, 'partner_id': sfp_move.partner_id.id,
'picking_id': sfp_move.picking_id.id, 'picking_type_id': sfp_move.picking_type_id.id,
'production_id': False})
productions.write({'programming_no': self.programming_no, 'is_remanufacture': True})
# productions.procurement_group_id.mrp_production_ids.move_dest_ids.write(
# {'group_id': self.env['procurement.group'].search([('name', '=', sale_order.name)])})
stock_picking_remanufacture = self.env['stock.picking'].search([('origin', '=', productions.name)])
@@ -1415,23 +1433,29 @@ class MrpProduction(models.Model):
vals['procurement_group_id'] = product_group_id[product_id.id]
return super(MrpProduction, self).create(vals_list)
@api.depends('procurement_group_id.stock_move_ids.created_purchase_line_id.order_id', 'procurement_group_id.stock_move_ids.move_orig_ids.purchase_line_id.order_id')
@api.depends('procurement_group_id.stock_move_ids.created_purchase_line_id.order_id',
'procurement_group_id.stock_move_ids.move_orig_ids.purchase_line_id.order_id')
def _compute_purchase_order_count(self):
for production in self:
# 找到来源的第一张制造订单的采购组
if production.product_id.product_tmpl_id.single_manufacturing == True:
first_production = self.env['mrp.production'].search([('origin', '=', production.origin), ('product_id', '=', production.product_id.id)], limit=1, order='id asc')
production.purchase_order_count = len(first_production.procurement_group_id.stock_move_ids.created_purchase_line_id.order_id |
first_production = self.env['mrp.production'].search(
[('origin', '=', production.origin), ('product_id', '=', production.product_id.id)], limit=1,
order='id asc')
production.purchase_order_count = len(
first_production.procurement_group_id.stock_move_ids.created_purchase_line_id.order_id |
first_production.procurement_group_id.stock_move_ids.move_orig_ids.purchase_line_id.order_id)
else:
production.purchase_order_count = len(production.procurement_group_id.stock_move_ids.created_purchase_line_id.order_id |
production.purchase_order_count = len(
production.procurement_group_id.stock_move_ids.created_purchase_line_id.order_id |
production.procurement_group_id.stock_move_ids.move_orig_ids.purchase_line_id.order_id)
@api.depends('procurement_group_id', 'procurement_group_id.stock_move_ids.group_id')
def _compute_picking_ids(self):
for order in self:
if order.product_id.product_tmpl_id.single_manufacturing == True:
first_order = self.env['mrp.production'].search([('origin', '=', order.origin), ('product_id', '=', order.product_id.id)], limit=1, order='id asc')
first_order = self.env['mrp.production'].search(
[('origin', '=', order.origin), ('product_id', '=', order.product_id.id)], limit=1, order='id asc')
order.picking_ids = self.env['stock.picking'].search([
('group_id', '=', first_order.procurement_group_id.id), ('group_id', '!=', False),
])

View File

@@ -281,7 +281,7 @@ class ResMrpWorkOrder(models.Model):
# if technology_design.is_auto is False:
# domain = [('origin', '=', order.production_id.name)]
# else:
domain = [('purchase_type', '=', 'consignment'),('origin', '=', ','.join(production_list))]
domain = [('purchase_type', '=', 'consignment'), ('origin', '=', ','.join(production_list))]
purchase = self.env['purchase.order'].search(domain)
if not purchase:
order.surface_technics_purchase_count = 0
@@ -1062,7 +1062,7 @@ class ResMrpWorkOrder(models.Model):
if workorder.production_id.workorder_ids.filtered(lambda wk: wk.sequence == 0):
continue
# ===== 对所有按序号排序的非[进行中、完成、返工、取消]状态的工单,除了第一条之外的工单状态都设置为[等待其他工单] =====
logging.info(workorder.state)
# logging.info(workorder.state)
work_ids = workorder.production_id.workorder_ids.filtered(
lambda wk: wk.state not in ['done', 'rework', 'cancel'])
if not work_ids:
@@ -1075,6 +1075,13 @@ class ResMrpWorkOrder(models.Model):
if workorder.state != 'pending':
workorder.state = 'pending'
continue
# ================= 如果制造订单制造类型为【人工线下加工】==========================
if (workorder.production_id.production_type == '人工线下加工'
and workorder.production_id.schedule_state == '已排'
and len(workorder.production_id.picking_ids.filtered(
lambda w: w.state not in ['done', 'cancel'])) == 0):
workorder.state = 'ready'
continue
# ================= 如果制造订单刀具状态为[无效刀、缺刀] 或者 制造订单状态为[返工]==========================
if (workorder.production_id.tool_state in ['1', '2'] or workorder.production_id.state == 'rework'
or workorder.production_id.schedule_state != '已排'
@@ -1096,7 +1103,7 @@ class ResMrpWorkOrder(models.Model):
# if purchase_order.picking_ids.filtered(lambda p: p.state in ['waiting', 'confirmed', 'assigned']):
# workorder.state = 'waiting'
# continue
if workorder.routing_type == '表面工艺':
if workorder.technology_design_id.routing_tag == 'special':
if workorder.is_subcontract is False:
workorder.state = 'ready'
else:
@@ -1195,6 +1202,7 @@ class ResMrpWorkOrder(models.Model):
raise UserError('制造订单【%s】缺少组件的序列号信息!' % self.production_id.name)
self.pro_code = self.production_id.move_raw_ids[0].move_line_ids[0].lot_id.name
# cnc校验
if self.production_id.production_type == '自动化产线加工':
cnc_workorder = self.search(
[('production_id', '=', self.production_id.id), ('routing_type', '=', 'CNC加工')],
limit=1, order='id asc')

View File

@@ -874,8 +874,8 @@ class ResProductMo(models.Model):
'height': item['model_height'],
'volume': item['model_long'] * item['model_width'] * item['model_height'],
'model_file': '' if not item['model_file'] else base64.b64decode(item['model_file']),
'model_name': attachment.name,
'upload_model_file': [(6, 0, [attachment.id])],
'model_name': attachment.name if attachment else None,
'upload_model_file': [(6, 0, [attachment.id])] if attachment else None,
'list_price': item['price'],
'materials_id': self.env['sf.production.materials'].search(
[('materials_no', '=', item['texture_code'])]).id,
@@ -924,6 +924,8 @@ class ResProductMo(models.Model):
return [(6, 0, process_parameters_ids)]
def attachment_create(self, name, data):
if not data:
return None
attachment = self.env['ir.attachment'].create({
'datas': base64.b64decode(data),
'type': 'binary',

View File

@@ -337,8 +337,8 @@ class StockRule(models.Model):
product_routing_workcenter = self.env[model].search(domain, order='sequence asc')
if production_item.production_type == '自动化产线加工':
for k in (production_item.product_id.model_processing_panel.split(',')):
i += 1
for route in product_routing_workcenter:
i += 1
technology_design_values.append(
self.env['sf.technology.design'].json_technology_design_str(k, route, i, False))
else:
@@ -480,6 +480,8 @@ class ProductionLot(models.Model):
[('company_id', '=', company.id), ('product_id', '=', product.id),
('name', 'ilike', product.name.split('[')[0])],
limit=1, order='name desc')
if not last_serial:
return "%s-%03d" % (product.name, 1)
return self.env['stock.lot'].generate_lot_names1(product.name, last_serial.name, 2)[1]
now = datetime.now().strftime("%Y%m%d")
if product.cutting_tool_model_id:
@@ -973,6 +975,13 @@ class ReStockMove(models.Model):
创建调拨单时,在此新增或修改调拨单的数据
"""
res = super(ReStockMove, self)._get_new_picking_values()
## 制造订单报废生成的新制造订单不走合并
production_remanufacture = None
if 'origin' in res:
if self.picking_type_id.name in ['生产发料', '内部调拨']:
production_remanufacture = self.env['mrp.production'].search(
[('name', '=', res['origin']), ('is_remanufacture', '=', True)])
if not production_remanufacture:
if self[0].origin and self.picking_type_id.name in ['生产发料', '内部调拨']:
production = self.env['mrp.production'].search([('name', '=', self[0].origin)], limit=1, order='id asc')
productions = self.env['mrp.production'].search(

View File

@@ -11,11 +11,11 @@ access_sf_model_type_group_sale_director,sf_model_type_group_sale_director,model
access_sf_model_type_group_purchase_director,sf_model_type_group_purchase_director,model_sf_model_type,sf_base.group_purchase_director,1,0,0,0
access_sf_model_type_group_plan_director,sf_model_type_group_plan_director,model_sf_model_type,sf_base.group_plan_director,1,0,0,0
access_sf_product_model_type_routing_sort_group_sf_mrp_user,sf_product_model_type_routing_sort,model_sf_product_model_type_routing_sort,sf_base.group_sf_mrp_user,1,0,0,0
access_sf_product_model_type_routing_sort_manager,sf_product_model_type_routing_sort,model_sf_product_model_type_routing_sort,sf_base.group_sf_mrp_manager,1,1,1,0
access_sf_product_model_type_routing_sort_manager,sf_product_model_type_routing_sort,model_sf_product_model_type_routing_sort,sf_base.group_sf_mrp_manager,1,1,1,1
access_sf_embryo_model_type_routing_sort_group_sf_mrp_user,sf_embryo_model_type_routing_sort,model_sf_embryo_model_type_routing_sort,sf_base.group_sf_mrp_user,1,0,0,0
access_sf_embryo_model_type_routing_sort_manager,sf_embryo_model_type_routing_sort,model_sf_embryo_model_type_routing_sort,sf_base.group_sf_mrp_manager,1,1,1,0
access_sf_embryo_model_type_routing_sort_manager,sf_embryo_model_type_routing_sort,model_sf_embryo_model_type_routing_sort,sf_base.group_sf_mrp_manager,1,1,1,1
access_sf_surface_technics_model_type_routing_sort,sf_surface_technics_model_type_routing_sort,model_sf_surface_technics_model_type_routing_sort,sf_base.group_sf_mrp_user,1,0,0,0
access_sf_surface_technics_model_type_routing_sort_manager,sf_surface_technics_model_type_routing_sort,model_sf_surface_technics_model_type_routing_sort,sf_base.group_sf_mrp_manager,1,1,1,0
access_sf_surface_technics_model_type_routing_sort_manager,sf_surface_technics_model_type_routing_sort,model_sf_surface_technics_model_type_routing_sort,sf_base.group_sf_mrp_manager,1,1,1,1
access_sf_production_line_group_sf_mrp_user,sf.production.line,model_sf_production_line,sf_base.group_sf_mrp_user,1,1,1,0
access_sf_production_line_manager,sf.production.line,model_sf_production_line,sf_base.group_sf_mrp_manager,1,1,1,0
access_maintenance_equipment_tool_group_sf_mrp_user,maintenance_equipment_tool,model_maintenance_equipment_tool,sf_base.group_sf_mrp_user,1,0,0,0
@@ -176,6 +176,6 @@ access_sf_production_technology_re_adjust_wizard_group_sf_mrp_manager,sf_product
access_sf_production_technology_re_adjust_wizard_group_production_engineer,sf_production_technology_re_adjust_wizard_group_production_engineer,model_sf_production_technology_re_adjust_wizard,sf_base.group_production_engineer,1,1,1,0
access_sf_manual_product_model_type_routing_sort_group_sf_mrp_user,sf_manual_product_model_type_routing_sort,model_sf_manual_product_model_type_routing_sort,sf_base.group_sf_mrp_user,1,0,0,0
access_sf_manual_product_model_type_routing_sort_manager,sf_manual_product_model_type_routing_sort,model_sf_manual_product_model_type_routing_sort,sf_base.group_sf_mrp_manager,1,1,1,0
access_sf_manual_product_model_type_routing_sort_manager,sf_manual_product_model_type_routing_sort,model_sf_manual_product_model_type_routing_sort,sf_base.group_sf_mrp_manager,1,1,1,1
access_sf_manual_product_model_type_routing_sort_group_plan_dispatch,sf_manual_product_model_type_routing_sort_group_plan_dispatch,model_sf_manual_product_model_type_routing_sort,sf_base.group_plan_dispatch,1,0,0,0
access_sf_detection_result_manager,sf_detection_result_manager,model_sf_detection_result,,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
11 access_sf_model_type_group_purchase_director sf_model_type_group_purchase_director model_sf_model_type sf_base.group_purchase_director 1 0 0 0
12 access_sf_model_type_group_plan_director sf_model_type_group_plan_director model_sf_model_type sf_base.group_plan_director 1 0 0 0
13 access_sf_product_model_type_routing_sort_group_sf_mrp_user sf_product_model_type_routing_sort model_sf_product_model_type_routing_sort sf_base.group_sf_mrp_user 1 0 0 0
14 access_sf_product_model_type_routing_sort_manager sf_product_model_type_routing_sort model_sf_product_model_type_routing_sort sf_base.group_sf_mrp_manager 1 1 1 0 1
15 access_sf_embryo_model_type_routing_sort_group_sf_mrp_user sf_embryo_model_type_routing_sort model_sf_embryo_model_type_routing_sort sf_base.group_sf_mrp_user 1 0 0 0
16 access_sf_embryo_model_type_routing_sort_manager sf_embryo_model_type_routing_sort model_sf_embryo_model_type_routing_sort sf_base.group_sf_mrp_manager 1 1 1 0 1
17 access_sf_surface_technics_model_type_routing_sort sf_surface_technics_model_type_routing_sort model_sf_surface_technics_model_type_routing_sort sf_base.group_sf_mrp_user 1 0 0 0
18 access_sf_surface_technics_model_type_routing_sort_manager sf_surface_technics_model_type_routing_sort model_sf_surface_technics_model_type_routing_sort sf_base.group_sf_mrp_manager 1 1 1 0 1
19 access_sf_production_line_group_sf_mrp_user sf.production.line model_sf_production_line sf_base.group_sf_mrp_user 1 1 1 0
20 access_sf_production_line_manager sf.production.line model_sf_production_line sf_base.group_sf_mrp_manager 1 1 1 0
21 access_maintenance_equipment_tool_group_sf_mrp_user maintenance_equipment_tool model_maintenance_equipment_tool sf_base.group_sf_mrp_user 1 0 0 0
176
177
178
179
180
181

View File

@@ -120,7 +120,8 @@
<!-- <field name="production_line_state" readonly="1"/>-->
<field name="part_name"/>
<field name="part_number" string="零件图号"/>
<field name="tool_state" attrs="{'invisible': [('production_type', 'not in', ['自动化产线加工'])]}"/>
<field name="tool_state"
attrs="{'invisible': [('production_type', 'not in', ['自动化产线加工'])]}"/>
<field name="tool_state_remark" string="备注" attrs="{'invisible': [('tool_state', '!=', '1')]}"/>
<field name="deadline_of_delivery" readonly="1"/>
<field name="tool_state_remark2" invisible="1"/>
@@ -365,7 +366,8 @@
<field name="sequence" widget="handle"/>
<field name="route_id" context="{'production_id': production_id}"
attrs="{'readonly': [('id', '!=', False)]}" options="{'no_create': True}"/>
<field name="process_parameters_id" attrs="{'readonly': [('id', '!=', False)]}"
<field name="process_parameters_id"
attrs="{'readonly': [('id', '!=', False),('routing_tag', '=', 'standard')]}"
string="参数" context="{'route_id':route_id}" options="{'no_create': True}"/>
<field name="panel" readonly="1"/>
<field name="routing_tag" readonly="1" widget="badge"
@@ -387,13 +389,16 @@
</page>
</xpath>
<xpath expr="//sheet/group/group/div[@class='d-flex flex-row align-items-start']/span[last()]" position="attributes">
<xpath expr="//sheet/group/group/div[@class='d-flex flex-row align-items-start']/span[last()]"
position="attributes">
<attribute name="invisible">True</attribute>
</xpath>
<xpath expr="//sheet/group/group/div[@class='d-flex flex-row align-items-start']/button[@name='action_product_forecast_report']" position="attributes">
<xpath expr="//sheet/group/group/div[@class='d-flex flex-row align-items-start']/button[@name='action_product_forecast_report']"
position="attributes">
<attribute name="invisible">True</attribute>
</xpath>
<xpath expr="//sheet/div[@class='oe_button_box']/button[@name='action_view_mrp_production_childs']/div/span[last()]" position="replace">
<xpath expr="//sheet/div[@class='oe_button_box']/button[@name='action_view_mrp_production_childs']/div/span[last()]"
position="replace">
<span class="o_stat_text">子MO</span>
</xpath>
</field>

View File

@@ -251,7 +251,7 @@
decoration-danger="tag_type == '重新加工'"/>
<field name="is_test_env" invisible="1"/>
<field name="rfid_code" force_save="1" readonly="1" cache="True"
attrs="{'invisible': [('rfid_code_old', '!=', False)]}" />
attrs="{'invisible': [('rfid_code_old', '!=', False)]}" widget="qrcode_widget"/>
<field name="rfid_code" string="RFID码(手动输入框)" force_save="1" readonly="0" cache="True"
attrs="{'invisible': ['|',('rfid_code_old', '!=', False), ('is_test_env', '=', False)]}"/>
<field name="rfid_code_old" readonly="1" attrs="{'invisible': [('rfid_code_old', '=', False)]}"/>

View File

@@ -14,7 +14,7 @@ class ProductionTechnologyReAdjustWizard(models.TransientModel):
def confirm(self):
if self.is_technology_re_adjust is True:
domain = [('origin', '=', self.origin), ('state', '=', 'technology_to_confirmed'),
domain = [('origin', '=', self.origin), ('state', '=', 'confirmed'),
('product_id', '=', self.production_id.product_id.id)]
else:
domain = [('id', '=', self.production_id.id)]

View File

@@ -51,18 +51,6 @@ class ReworkWizard(models.TransientModel):
self.workorder_id.button_finish()
else:
if self.workorder_ids:
# handle_result = self.production_id.detection_result_ids.filtered(
# lambda dr: dr.handle_result == '待处理')
# if handle_result:
# processing_panels_to_handle = set(handle_item.processing_panel for handle_item in handle_result)
# processing_panels_choice = set(dr_panel.name for dr_panel in self.processing_panel_id)
# # 使用集合的差集操作找出那些待处理结果中有但实际可用加工面中没有的加工面
# processing_panels_missing = processing_panels_to_handle - processing_panels_choice
# # 存在不一致的加工面
# if processing_panels_missing:
# processing_panels_str = ','.join(processing_panels_missing)
# raise UserError('您还有待处理的检测结果中为%s的加工面未选择' % processing_panels_str)
rework_workorder_ids = self.production_id.workorder_ids.filtered(
lambda ap: ap.id in self.workorder_ids.ids)
clamp_workorder_ids = None
@@ -87,8 +75,9 @@ class ReworkWizard(models.TransientModel):
(item.route_id.name == work.name and item.panel
and item.panel == work.processing_panel))
if route:
workorders_values.append(
self.env['mrp.workorder'].json_workorder_str(self.production_id, route[0]))
work_list = self.env['mrp.workorder'].json_workorder_str(self.production_id, route[0])
work_list[2].update({'tag_type': '重新加工'})
workorders_values.append(work_list)
# 创建新工单,并进行返工配置的相关操作
if workorders_values:
# 创建新工单、工序排序、完成检测结果单据

View File

@@ -131,7 +131,7 @@ class ReSaleOrder(models.Model):
product.materials_id.name),
'price_unit': product.list_price,
'product_uom_qty': item['number'],
'model_glb_file': base64.b64decode(item['model_file']),
'model_glb_file': base64.b64decode(item['model_file']) if item['model_file'] else None,
'remark': item.get('remark'),
'embryo_redundancy_id': item.get('embryo_redundancy_id'),
'is_incoming_material': True if item.get('embryo_redundancy_id') else False,