Compare commits

..

1 Commits

Author SHA1 Message Date
jinling.yang
609e65e36f Merge branch 'hotfix/修复工件上下产线' 2024-06-05 10:16:16 +08:00
55 changed files with 1504 additions and 2348 deletions

View File

@@ -522,8 +522,3 @@ div:has(.o_required_modifier) > label::before {
max-width: 100%; max-width: 100%;
overflow-x: auto; overflow-x: auto;
} }
// 设置表单页面label文本不换行
.o_form_view .o_group .o_wrap_label .o_form_label {
white-space: nowrap;
}

View File

@@ -27,7 +27,7 @@ class MrpWorkcenter(models.Model):
class MrpProductionWorkcenterLine(models.Model): class MrpProductionWorkcenterLine(models.Model):
_name = 'mrp.workorder' _name = 'mrp.workorder'
_inherit = ['mrp.workorder', 'barcodes.barcode_events_mixin', 'mail.thread', 'mail.activity.mixin'] _inherit = ['mrp.workorder', 'barcodes.barcode_events_mixin']
quality_point_ids = fields.Many2many('quality.point', compute='_compute_quality_point_ids', store=True) quality_point_ids = fields.Many2many('quality.point', compute='_compute_quality_point_ids', store=True)
quality_point_count = fields.Integer('Steps', compute='_compute_quality_point_count') quality_point_count = fields.Integer('Steps', compute='_compute_quality_point_count')
@@ -47,17 +47,14 @@ class MrpProductionWorkcenterLine(models.Model):
is_last_lot = fields.Boolean('Is Last lot', compute='_compute_is_last_lot') is_last_lot = fields.Boolean('Is Last lot', compute='_compute_is_last_lot')
is_first_started_wo = fields.Boolean('Is The first Work Order', compute='_compute_is_last_unfinished_wo') is_first_started_wo = fields.Boolean('Is The first Work Order', compute='_compute_is_last_unfinished_wo')
is_last_unfinished_wo = fields.Boolean('Is Last Work Order To Process', compute='_compute_is_last_unfinished_wo', is_last_unfinished_wo = fields.Boolean('Is Last Work Order To Process', compute='_compute_is_last_unfinished_wo', store=False)
store=False)
lot_id = fields.Many2one(related='current_quality_check_id.lot_id', readonly=False) lot_id = fields.Many2one(related='current_quality_check_id.lot_id', readonly=False)
move_id = fields.Many2one(related='current_quality_check_id.move_id', readonly=False) move_id = fields.Many2one(related='current_quality_check_id.move_id', readonly=False)
move_line_id = fields.Many2one(related='current_quality_check_id.move_line_id', readonly=False) move_line_id = fields.Many2one(related='current_quality_check_id.move_line_id', readonly=False)
move_line_ids = fields.One2many(related='move_id.move_line_ids') move_line_ids = fields.One2many(related='move_id.move_line_ids')
quality_state = fields.Selection(related='current_quality_check_id.quality_state', string="Quality State", quality_state = fields.Selection(related='current_quality_check_id.quality_state', string="Quality State", readonly=False)
readonly=False)
qty_done = fields.Float(related='current_quality_check_id.qty_done', readonly=False) qty_done = fields.Float(related='current_quality_check_id.qty_done', readonly=False)
test_type_id = fields.Many2one('quality.point.test_type', 'Test Type', test_type_id = fields.Many2one('quality.point.test_type', 'Test Type', related='current_quality_check_id.test_type_id')
related='current_quality_check_id.test_type_id')
test_type = fields.Char(related='test_type_id.technical_name') test_type = fields.Char(related='test_type_id.technical_name')
user_id = fields.Many2one(related='current_quality_check_id.user_id', readonly=False) user_id = fields.Many2one(related='current_quality_check_id.user_id', readonly=False)
worksheet_page = fields.Integer('Worksheet page') worksheet_page = fields.Integer('Worksheet page')
@@ -68,8 +65,7 @@ class MrpProductionWorkcenterLine(models.Model):
def _compute_quality_point_ids(self): def _compute_quality_point_ids(self):
for workorder in self: for workorder in self:
quality_points = workorder.operation_id.quality_point_ids quality_points = workorder.operation_id.quality_point_ids
quality_points = quality_points.filtered( quality_points = quality_points.filtered(lambda qp: not qp.product_ids or workorder.production_id.product_id in qp.product_ids)
lambda qp: not qp.product_ids or workorder.production_id.product_id in qp.product_ids)
workorder.quality_point_ids = quality_points workorder.quality_point_ids = quality_points
@api.depends('operation_id') @api.depends('operation_id')
@@ -95,8 +91,7 @@ class MrpProductionWorkcenterLine(models.Model):
@api.depends('check_ids') @api.depends('check_ids')
def _compute_finished_product_check_ids(self): def _compute_finished_product_check_ids(self):
for wo in self: for wo in self:
wo.finished_product_check_ids = wo.check_ids.filtered( wo.finished_product_check_ids = wo.check_ids.filtered(lambda c: c.finished_product_sequence == wo.qty_produced)
lambda c: c.finished_product_sequence == wo.qty_produced)
def write(self, values): def write(self, values):
res = super().write(values) res = super().write(values)
@@ -143,8 +138,7 @@ class MrpProductionWorkcenterLine(models.Model):
self.finished_lot_id = self.env['stock.lot'].create({ self.finished_lot_id = self.env['stock.lot'].create({
'product_id': self.product_id.id, 'product_id': self.product_id.id,
'company_id': self.company_id.id, 'company_id': self.company_id.id,
'name': self.env['stock.lot']._get_next_serial(self.company_id, self.product_id) or self.env[ 'name': self.env['stock.lot']._get_next_serial(self.company_id, self.product_id) or self.env['ir.sequence'].next_by_code('stock.lot.serial'),
'ir.sequence'].next_by_code('stock.lot.serial'),
}) })
def _create_subsequent_checks(self): def _create_subsequent_checks(self):
@@ -158,7 +152,7 @@ class MrpProductionWorkcenterLine(models.Model):
""" """
# Create another quality check if necessary # Create another quality check if necessary
next_check = self.current_quality_check_id.next_check_id next_check = self.current_quality_check_id.next_check_id
if next_check.component_id != self.current_quality_check_id.product_id or \ if next_check.component_id != self.current_quality_check_id.product_id or\
next_check.point_id != self.current_quality_check_id.point_id: next_check.point_id != self.current_quality_check_id.point_id:
# TODO: manage reservation here # TODO: manage reservation here
@@ -285,8 +279,7 @@ class MrpProductionWorkcenterLine(models.Model):
if self.current_quality_check_id: if self.current_quality_check_id:
team = self.current_quality_check_id.team_id team = self.current_quality_check_id.team_id
else: else:
team = self.env['quality.alert.team'].search( team = self.env['quality.alert.team'].search(['|', ('company_id', '=', self.company_id.id), ('company_id', '=', False)], limit=1)
['|', ('company_id', '=', self.company_id.id), ('company_id', '=', False)], limit=1)
return { return {
'type': 'ir.actions.act_window', 'type': 'ir.actions.act_window',
'res_model': 'quality.check', 'res_model': 'quality.check',
@@ -327,8 +320,7 @@ class MrpProductionWorkcenterLine(models.Model):
production = wo.production_id production = wo.production_id
move_raw_ids = wo.move_raw_ids.filtered(lambda m: m.state not in ('done', 'cancel')) move_raw_ids = wo.move_raw_ids.filtered(lambda m: m.state not in ('done', 'cancel'))
move_finished_ids = wo.move_finished_ids.filtered( move_finished_ids = wo.move_finished_ids.filtered(lambda m: m.state not in ('done', 'cancel') and m.product_id != wo.production_id.product_id)
lambda m: m.state not in ('done', 'cancel') and m.product_id != wo.production_id.product_id)
previous_check = self.env['quality.check'] previous_check = self.env['quality.check']
for point in wo.quality_point_ids: for point in wo.quality_point_ids:
# Check if we need a quality control for this point # Check if we need a quality control for this point
@@ -350,13 +342,11 @@ class MrpProductionWorkcenterLine(models.Model):
if point.test_type == 'register_byproducts': if point.test_type == 'register_byproducts':
moves = move_finished_ids.filtered(lambda m: m.product_id == point.component_id) moves = move_finished_ids.filtered(lambda m: m.product_id == point.component_id)
if not moves: if not moves:
moves = production.move_finished_ids.filtered( moves = production.move_finished_ids.filtered(lambda m: not m.operation_id and m.product_id == point.component_id)
lambda m: not m.operation_id and m.product_id == point.component_id)
elif point.test_type == 'register_consumed_materials': elif point.test_type == 'register_consumed_materials':
moves = move_raw_ids.filtered(lambda m: m.product_id == point.component_id) moves = move_raw_ids.filtered(lambda m: m.product_id == point.component_id)
if not moves: if not moves:
moves = production.move_raw_ids.filtered( moves = production.move_raw_ids.filtered(lambda m: not m.operation_id and m.product_id == point.component_id)
lambda m: not m.operation_id and m.product_id == point.component_id)
else: else:
check = self.env['quality.check'].create(values) check = self.env['quality.check'].create(values)
previous_check.next_check_id = check previous_check.next_check_id = check
@@ -373,10 +363,8 @@ class MrpProductionWorkcenterLine(models.Model):
processed_move |= moves processed_move |= moves
# Generate quality checks associated with unreferenced components # Generate quality checks associated with unreferenced components
moves_without_check = ((move_raw_ids | move_finished_ids) - processed_move).filtered(lambda move: ( moves_without_check = ((move_raw_ids | move_finished_ids) - processed_move).filtered(lambda move: (move.has_tracking != 'none' and not move.raw_material_production_id.use_auto_consume_components_lots) or move.operation_id)
move.has_tracking != 'none' and not move.raw_material_production_id.use_auto_consume_components_lots) or move.operation_id) quality_team_id = self.env['quality.alert.team'].search(['|', ('company_id', '=', wo.company_id.id), ('company_id', '=', False)], limit=1).id
quality_team_id = self.env['quality.alert.team'].search(
['|', ('company_id', '=', wo.company_id.id), ('company_id', '=', False)], limit=1).id
for move in moves_without_check: for move in moves_without_check:
values = { values = {
'production_id': production.id, 'production_id': production.id,
@@ -424,8 +412,7 @@ class MrpProductionWorkcenterLine(models.Model):
backorder = False backorder = False
# Trigger the backorder process if we produce less than expected # Trigger the backorder process if we produce less than expected
if float_compare(self.qty_producing, self.qty_remaining, if float_compare(self.qty_producing, self.qty_remaining, precision_rounding=self.product_uom_id.rounding) == -1 and self.is_first_started_wo:
precision_rounding=self.product_uom_id.rounding) == -1 and self.is_first_started_wo:
backorder = self.production_id._split_productions()[1:] backorder = self.production_id._split_productions()[1:]
for workorder in backorder.workorder_ids: for workorder in backorder.workorder_ids:
if workorder.product_tracking == 'serial': if workorder.product_tracking == 'serial':
@@ -436,8 +423,7 @@ class MrpProductionWorkcenterLine(models.Model):
else: else:
if self.operation_id: if self.operation_id:
backorder = (self.production_id.procurement_group_id.mrp_production_ids - self.production_id).filtered( backorder = (self.production_id.procurement_group_id.mrp_production_ids - self.production_id).filtered(
lambda p: p.workorder_ids.filtered(lambda wo: wo.operation_id == self.operation_id).state not in ( lambda p: p.workorder_ids.filtered(lambda wo: wo.operation_id == self.operation_id).state not in ('cancel', 'done')
'cancel', 'done')
)[:1] )[:1]
else: else:
index = list(self.production_id.workorder_ids).index(self) index = list(self.production_id.workorder_ids).index(self)
@@ -456,8 +442,7 @@ class MrpProductionWorkcenterLine(models.Model):
wo.current_quality_check_id._update_component_quantity() wo.current_quality_check_id._update_component_quantity()
if not self.env.context.get('no_start_next'): if not self.env.context.get('no_start_next'):
if self.operation_id: if self.operation_id:
return backorder.workorder_ids.filtered( return backorder.workorder_ids.filtered(lambda wo: wo.operation_id == self.operation_id).open_tablet_view()
lambda wo: wo.operation_id == self.operation_id).open_tablet_view()
else: else:
index = list(self.production_id.workorder_ids).index(self) index = list(self.production_id.workorder_ids).index(self)
return backorder.workorder_ids[index].open_tablet_view() return backorder.workorder_ids[index].open_tablet_view()
@@ -481,8 +466,7 @@ class MrpProductionWorkcenterLine(models.Model):
def open_tablet_view(self): def open_tablet_view(self):
self.ensure_one() self.ensure_one()
if not self.is_user_working and self.working_state != 'blocked' and self.state in ( if not self.is_user_working and self.working_state != 'blocked' and self.state in ('ready', 'waiting', 'progress', 'pending'):
'ready', 'waiting', 'progress', 'pending'):
self.button_start() self.button_start()
action = self.env["ir.actions.actions"]._for_xml_id("mrp_workorder.tablet_client_action") action = self.env["ir.actions.actions"]._for_xml_id("mrp_workorder.tablet_client_action")
action['target'] = 'fullscreen' action['target'] = 'fullscreen'
@@ -537,8 +521,7 @@ class MrpProductionWorkcenterLine(models.Model):
data = { data = {
'mrp.workorder': self.read(self._get_fields_for_tablet(), load=False)[0], 'mrp.workorder': self.read(self._get_fields_for_tablet(), load=False)[0],
'quality.check': self.check_ids._get_fields_for_tablet(sorted_check_list), 'quality.check': self.check_ids._get_fields_for_tablet(sorted_check_list),
'operation': self.operation_id.read(self.operation_id._get_fields_for_tablet())[ 'operation': self.operation_id.read(self.operation_id._get_fields_for_tablet())[0] if self.operation_id else {},
0] if self.operation_id else {},
'working_state': self.workcenter_id.working_state, 'working_state': self.workcenter_id.working_state,
'views': { 'views': {
'workorder': self.env.ref('mrp_workorder.mrp_workorder_view_form_tablet').id, 'workorder': self.env.ref('mrp_workorder.mrp_workorder_view_form_tablet').id,
@@ -570,8 +553,7 @@ class MrpProductionWorkcenterLine(models.Model):
return { return {
'duration': self.duration, 'duration': self.duration,
'position': bisect_left(last30op, self.duration), 'position': bisect_left(last30op, self.duration), # which position regarded other workorders ranked by duration
# which position regarded other workorders ranked by duration
'quality_score': score, 'quality_score': score,
'show_rainbow': show_rainbow, 'show_rainbow': show_rainbow,
} }

View File

@@ -27,13 +27,6 @@
</field> </field>
</page> </page>
</page> </page>
<xpath expr="//sheet" position="after">
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="activity_ids"/>
<field name="message_ids" options="{'post_refresh': 'recipients'}"/>
</div>
</xpath>
</field> </field>
</record> </record>

View File

@@ -331,7 +331,7 @@ class ToolInventory(models.Model):
work_material = fields.Selection([('', ''), ('', '')], string='加工材料') work_material = fields.Selection([('', ''), ('', '')], string='加工材料')
life_span = fields.Float('寿命(min)') life_span = fields.Float('寿命(min)')
tool_groups_id = fields.Many2one('sf.tool.groups', string='刀具组', required=True) tool_groups_id = fields.Many2one('sf.tool.groups', string='刀具组')
active = fields.Boolean('已归档', default=True) active = fields.Boolean('已归档', default=True)

View File

@@ -555,9 +555,9 @@
<field name="model">sf.tool.inventory</field> <field name="model">sf.tool.inventory</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="功能刀具清单" create="1" edit="1" delete="0" editable="bottom"> <tree string="功能刀具清单" create="1" edit="1" delete="0" editable="bottom">
<field name="name" attrs="{'readonly': [('id', '!=', False)]}"/> <field name="name"/>
<field name="functional_cutting_tool_model_id"/> <field name="functional_cutting_tool_model_id"/>
<field name="tool_groups_id" required="1" attrs="{'readonly': [('id', '!=', False)]}"/> <field name="tool_groups_id"/>
<field name="work_material"/> <field name="work_material"/>
<field name="life_span"/> <field name="life_span"/>
<field name="prefix" optional="hide"/> <field name="prefix" optional="hide"/>

View File

@@ -14,7 +14,7 @@ _logger = logging.getLogger(__name__)
class JdEclp(models.Model): class JdEclp(models.Model):
_inherit = 'stock.picking' _inherit = 'stock.picking'
senderNickName = fields.Char(string='寄件工厂简称', required=True, default='XT') senderNickName = fields.Char(string='寄件工厂简称', required=True, default='MW')
# receiverName = fields.Char(string='收件人姓名') # receiverName = fields.Char(string='收件人姓名')
# receiverMobile = fields.Char(string='收件人电话') # receiverMobile = fields.Char(string='收件人电话')
@@ -67,10 +67,9 @@ class JdEclp(models.Model):
""" """
判断是否为出库单 判断是否为出库单
""" """
for record in self: if self.name:
if record.name: is_check_out = self.name.split('/')
is_check_out = record.name.split('/') self.check_out = is_check_out[1]
record.check_out = is_check_out[1]
@api.depends('carrier_tracking_ref') @api.depends('carrier_tracking_ref')
def query_bill_pdf(self): def query_bill_pdf(self):

View File

@@ -10,7 +10,6 @@
<field name='categ_id' class="custom_required" attrs="{'readonly': [('id', '!=', False)]}"/> <field name='categ_id' class="custom_required" attrs="{'readonly': [('id', '!=', False)]}"/>
<field name='is_bfm' invisible="1"/> <field name='is_bfm' invisible="1"/>
<field name='categ_type' invisible="1"/> <field name='categ_type' invisible="1"/>
<field name='part_number' attrs="{'invisible': [('categ_type', '!=', '成品')]}"/>
<field name='manual_quotation' attrs="{'invisible':[('upload_model_file', '=', [])]}"/> <field name='manual_quotation' attrs="{'invisible':[('upload_model_file', '=', [])]}"/>
<field name="upload_model_file" <field name="upload_model_file"
widget="many2many_binary" widget="many2many_binary"
@@ -32,11 +31,9 @@
options="{'no_create': True}" options="{'no_create': True}"
attrs="{'invisible': [('categ_type', '!=', '刀具')],'required': [('categ_type', '=', '刀具')],'readonly': [('id', '!=', False)]}" attrs="{'invisible': [('categ_type', '!=', '刀具')],'required': [('categ_type', '=', '刀具')],'readonly': [('id', '!=', False)]}"
placeholder="请选择"/> placeholder="请选择"/>
<field name="brand_id" options="{'no_create': True}" placeholder="请选择"
attrs="{'invisible': [('categ_type', '!=', '刀具')],'required': [('categ_type', '=', '刀具')],'readonly': [('id', '!=', False)]}"/>
<field name="cutting_tool_model_id" placeholder="请选择" class="custom_required" <field name="cutting_tool_model_id" placeholder="请选择" class="custom_required"
options="{'no_create': True}" options="{'no_create': True}"
domain="[('cutting_tool_material_id','=',cutting_tool_material_id),('brand_id', '=', brand_id)]" domain="[('cutting_tool_material_id','=',cutting_tool_material_id)]"
context="{'default_cutting_tool_material_id': cutting_tool_material_id}" context="{'default_cutting_tool_material_id': cutting_tool_material_id}"
attrs="{'invisible': [('categ_type', '!=', '刀具')],'required': [('categ_type', '=', '刀具')],'readonly': [('id', '!=', False)]}"> attrs="{'invisible': [('categ_type', '!=', '刀具')],'required': [('categ_type', '=', '刀具')],'readonly': [('id', '!=', False)]}">
</field> </field>
@@ -50,10 +47,10 @@
<field name="fixture_material_id" <field name="fixture_material_id"
attrs="{'invisible': [('categ_type', '!=', '夹具')],'required': [('categ_type', '=', '夹具')]}" attrs="{'invisible': [('categ_type', '!=', '夹具')],'required': [('categ_type', '=', '夹具')]}"
placeholder="请选择" options="{'no_create': True}"/> placeholder="请选择" options="{'no_create': True}"/>
<field name="fixture_model_id" string="型号名称" placeholder="请选择" options="{'no_create': True}" <field name="fixture_model_id" string="型号" placeholder="请选择" options="{'no_create': True}"
attrs="{'invisible': [('categ_type', '!=', '夹具')],'required': [('categ_type', '=', '夹具')]}" attrs="{'invisible': [('categ_type', '!=', '夹具')],'required': [('categ_type', '=', '夹具')]}"
domain="[('fixture_material_id','=',fixture_material_id)]"/> domain="[('fixture_material_id','=',fixture_material_id)]"/>
<field name="specification_fixture_id" string="物料号" placeholder="请选择" <field name="specification_fixture_id" string="规格" placeholder="请选择"
options="{'no_create': True}" options="{'no_create': True}"
attrs="{'invisible': [('categ_type', '!=', '夹具')],'required': [('categ_type', '=', '夹具')]}" attrs="{'invisible': [('categ_type', '!=', '夹具')],'required': [('categ_type', '=', '夹具')]}"
domain="[('fixture_model_id','=',fixture_model_id)]"/> domain="[('fixture_model_id','=',fixture_model_id)]"/>
@@ -98,16 +95,6 @@
</group> </group>
</page> </page>
</xpath> </xpath>
<xpath expr="//field[@name='name']" position="attributes">
<attribute name="attrs">{'readonly': ['|',('id','!=',False),('categ_type', '=',
'刀具')], 'required': True}
</attribute>
</xpath>
<!-- <xpath expr="//field[@name='default_code']" position="attributes">-->
<!-- <attribute name="attrs">{'readonly': [('categ_type', '=', '刀具')], 'invisible':-->
<!-- [('product_variant_count', '>' , 1)]}-->
<!-- </attribute>-->
<!-- </xpath>-->
</field> </field>
</record> </record>
@@ -305,7 +292,7 @@
<field name="cutting_tool_blade_type" <field name="cutting_tool_blade_type"
attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')],'readonly': [('id', '!=', False)]}"/> attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')],'readonly': [('id', '!=', False)]}"/>
<field name="cutting_tool_coarse_medium_fine" string="粗/中/精" placeholder="请选择" <field name="cutting_tool_coarse_medium_fine" string="粗/中/精" placeholder="请选择"
attrs="{'invisible': [('cutting_tool_type', 'not in', ('整体式刀具','刀片'))],'readonly': [('id', '!=', False)]}"/> attrs="{'required': [('cutting_tool_type','=','整体式刀具')],'invisible': [('cutting_tool_type', 'not in', ('整体式刀具','刀片'))],'readonly': [('id', '!=', False)]}"/>
<!--整体式刀具--> <!--整体式刀具-->
<field name="cutting_tool_shank_diameter" string="柄部直径(mm)" class="diameter" <field name="cutting_tool_shank_diameter" string="柄部直径(mm)" class="diameter"
attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')],'readonly': [('id', '!=', False)]}"/> attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')],'readonly': [('id', '!=', False)]}"/>
@@ -468,8 +455,7 @@
<tree editable="bottom"> <tree editable="bottom">
<!-- <field name="cutting_speed"--> <!-- <field name="cutting_speed"-->
<!-- attrs="{'readonly': [('materials_type_id','!=',False)]}"/>--> <!-- attrs="{'readonly': [('materials_type_id','!=',False)]}"/>-->
<field name="materials_type_id" options="{'no_create': True}" <field name="materials_type_id" options="{'no_create': True}" placeholder="请选择"/>
placeholder="请选择"/>
<field name="blade_diameter"/> <field name="blade_diameter"/>
<field name="feed_per_tooth"/> <field name="feed_per_tooth"/>
</tree> </tree>

View File

@@ -25,9 +25,6 @@
<filter string="人工编程" name="manual_quotation" domain="[('manual_quotation', '=', True)]"/> <filter string="人工编程" name="manual_quotation" domain="[('manual_quotation', '=', True)]"/>
<filter string="自动编程" name="no_manual_quotation" domain="[('manual_quotation', '=', False)]"/> <filter string="自动编程" name="no_manual_quotation" domain="[('manual_quotation', '=', False)]"/>
</xpath> </xpath>
<xpath expr="//field[@name='production_id']" position="before">
<field name="product_tmpl_name"/>
</xpath>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -5,10 +5,10 @@
<field name="model">mrp.workorder</field> <field name="model">mrp.workorder</field>
<field name="inherit_id" ref="sf_manufacturing.view_mrp_production_workorder_tray_form_inherit_sf"/> <field name="inherit_id" ref="sf_manufacturing.view_mrp_production_workorder_tray_form_inherit_sf"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<!-- <xpath expr="//header" position="inside">--> <xpath expr="//header" position="inside">
<!-- <button string="程序下载" name="cnc_file_download" type="object" class="oe_highlight" attrs='{"invisible": ["|",--> <button string="程序下载" name="cnc_file_download" type="object" class="oe_highlight" attrs='{"invisible": ["|",
<!-- ("user_permissions","=",False),("routing_type","!=","CNC加工")]}'/>--> ("user_permissions","=",False),("routing_type","!=","CNC加工")]}'/>
<!-- </xpath>--> </xpath>
<xpath expr="//page//field[@name='cnc_ids']" position="before"> <xpath expr="//page//field[@name='cnc_ids']" position="before">
<group> <group>
<group> <group>
@@ -19,28 +19,21 @@
<div> <div>
<field name="button_compensation_state" attrs='{"invisible": ["|", <field name="button_compensation_state" attrs='{"invisible": ["|",
("state","!=","progress"),("user_permissions","=",False)]}'/> ("state","!=","progress"),("user_permissions","=",False)]}'/>
<!-- <span>&#32;</span>--> <button string="一键补偿" name="compensation" type="object" confirm="是否确认下发补偿"
<button name="button_send_program_again" type="object" string="重新下发NC程序" class="btn-primary" attrs='{"invisible": ["|",
class="btn-primary" ("state","!=","progress"),("user_permissions","=",False)]}'/>
confirm="是否确认重新下发NC程序" <span>&#32;</span>
groups="sf_base.group_sf_order_user,sf_base.group_sf_equipment_user" <button string="一键下发" name="up_all" type="object" style="text-align: right;" confirm="是否确认一键下发"
attrs="{'invisible': ['|', '|', '|',('routing_type','!=','装夹预调'),('state','in',['done', 'cancel', class="btn-primary" context="{'default_workorder_id': id}" attrs='{"invisible": ["|",
'progress']),('processing_drawing','=',False),('is_send_program_again','=',True)]}"/> ("state","!=","progress"),("user_permissions","=",False)]}'/>
<!-- <button string="一键补偿" name="compensation" type="object" confirm="是否确认下发补偿"--> <span>&#32;</span>
<!-- class="btn-primary" attrs='{"invisible": ["|",--> <button string="合并下发" id="action_up_select" name="%(sf_machine_connect.action_up_select)d"
<!-- ("state","!=","progress"),("user_permissions","=",False)]}'/>--> type="action" class="btn-primary" context="{'default_workorder_id': id}" attrs='{"invisible": ["|",
<!-- <span>&#32;</span>--> ("state","!=","progress"),("user_permissions","=",False)]}'/>
<!-- <button string="一键下发" name="up_all" type="object" style="text-align: right;" confirm="是否确认一键下发"--> <span>&#32;</span>
<!-- class="btn-primary" context="{'default_workorder_id': id}" attrs='{"invisible": ["|",--> <button string="一键合并下发" name="up_merge_all" type="object" style="text-align: right;" confirm="是否确认一键合并下发"
<!-- ("state","!=","progress"),("user_permissions","=",False)]}'/>--> class="btn-primary" context="{'default_workorder_id': id}" attrs='{"invisible": ["|",
<!-- <span>&#32;</span>--> ("state","!=","progress"),("user_permissions","=",False)]}'/>
<!-- <button string="合并下发" id="action_up_select" name="%(sf_machine_connect.action_up_select)d"-->
<!-- type="action" class="btn-primary" context="{'default_workorder_id': id}" attrs='{"invisible": ["|",-->
<!-- ("state","!=","progress"),("user_permissions","=",False)]}'/>-->
<!-- <span>&#32;</span>-->
<!-- <button string="一键合并下发" name="up_merge_all" type="object" style="text-align: right;" confirm="是否确认一键合并下发"-->
<!-- class="btn-primary" context="{'default_workorder_id': id}" attrs='{"invisible": ["|",-->
<!-- ("state","!=","progress"),("user_permissions","=",False)]}'/>-->
</div> </div>
</div> </div>
</group> </group>

View File

@@ -9,6 +9,7 @@
<tree> <tree>
<field name="sequence_number"/> <field name="sequence_number"/>
<field name="program_name"/> <field name="program_name"/>
<field name="cnc_id" string="文件"/>
<field name="functional_tool_type_id"/> <field name="functional_tool_type_id"/>
<field name="cutting_tool_name"/> <field name="cutting_tool_name"/>
<field name="cutting_tool_no"/> <field name="cutting_tool_no"/>

View File

@@ -8,7 +8,7 @@ from odoo.http import request
class Manufacturing_Connect(http.Controller): class Manufacturing_Connect(http.Controller):
@http.route('/AutoDeviceApi/GetWoInfo', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False, @http.route('/AutoDeviceApi/GetWoInfo', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
cors="*") cors="*")
def get_Work_Info(self, **kw): def get_Work_Info(self, **kw):
""" """
@@ -215,8 +215,6 @@ class Manufacturing_Connect(http.Controller):
if workorder.state != 'progress': if workorder.state != 'progress':
res = {'Succeed': False, 'ErrorCode': 202, 'Error': '该工单未开始'} res = {'Succeed': False, 'ErrorCode': 202, 'Error': '该工单未开始'}
return json.JSONEncoder().encode(res) return json.JSONEncoder().encode(res)
# workorder.write({'date_finished': datetime.now()})
if ret['IsComplete'] is True:
workorder.button_finish() workorder.button_finish()
# workorder.process_state = '待解除装夹' # workorder.process_state = '待解除装夹'
# workorder.sudo().production_id.process_state = '待解除装夹' # workorder.sudo().production_id.process_state = '待解除装夹'
@@ -460,7 +458,6 @@ class Manufacturing_Connect(http.Controller):
if f'RfidCode{i}' in ret: if f'RfidCode{i}' in ret:
rfid_code = ret[f'RfidCode{i}'] rfid_code = ret[f'RfidCode{i}']
logging.info('RfidCode:%s' % rfid_code) logging.info('RfidCode:%s' % rfid_code)
if rfid_code is not None:
domain = [ domain = [
('rfid_code', '=', rfid_code), ('rfid_code', '=', rfid_code),
('routing_type', '=', 'CNC加工') ('routing_type', '=', 'CNC加工')
@@ -472,8 +469,7 @@ class Manufacturing_Connect(http.Controller):
logging.info( logging.info(
'制造订单产线状态:%s' % order.production_id.production_line_state) '制造订单产线状态:%s' % order.production_id.production_line_state)
order.production_id.write({'production_line_state': '已上产线'}) order.production_id.write({'production_line_state': '已上产线'})
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search( workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search([
[
('rfid_code', '=', rfid_code), ('type', '=', '上产线'), ('rfid_code', '=', rfid_code), ('type', '=', '上产线'),
('production_id', '=', order.production_id.id)]) ('production_id', '=', order.production_id.id)])
if workpiece_delivery.status == '待下发': if workpiece_delivery.status == '待下发':
@@ -517,7 +513,6 @@ class Manufacturing_Connect(http.Controller):
if f'RfidCode{i}' in ret: if f'RfidCode{i}' in ret:
rfid_code = ret[f'RfidCode{i}'] rfid_code = ret[f'RfidCode{i}']
logging.info('RfidCode:%s' % rfid_code) logging.info('RfidCode:%s' % rfid_code)
if rfid_code is not None:
domain = [ domain = [
('rfid_code', '=', rfid_code), ('rfid_code', '=', rfid_code),
('routing_type', '=', 'CNC加工') ('routing_type', '=', 'CNC加工')
@@ -529,8 +524,7 @@ class Manufacturing_Connect(http.Controller):
logging.info( logging.info(
'制造订单产线状态:%s' % order.production_id.production_line_state) '制造订单产线状态:%s' % order.production_id.production_line_state)
order.production_id.write({'production_line_state': '已下产线'}) order.production_id.write({'production_line_state': '已下产线'})
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search( workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search([
[
('rfid_code', '=', rfid_code), ('type', '=', '下产线'), ('rfid_code', '=', rfid_code), ('type', '=', '下产线'),
('production_id', '=', order.production_id.id)]) ('production_id', '=', order.production_id.id)])
delivery_Arr.append(workpiece_delivery.id) delivery_Arr.append(workpiece_delivery.id)

View File

@@ -2,8 +2,7 @@
import requests import requests
import logging import logging
import time import time
from odoo import fields, models, api from odoo import fields, models
from odoo.exceptions import UserError
class AgvSetting(models.Model): class AgvSetting(models.Model):
@@ -60,17 +59,11 @@ class AgvTaskRoute(models.Model):
('F01', '搬运'), ], string='任务类型', default="F01") ('F01', '搬运'), ], string='任务类型', default="F01")
route_type = fields.Selection([ route_type = fields.Selection([
('上产线', '上产线'), ('下产线', '下产线'), ('运送空料架', '运送空料架')], string='类型') ('上产线', '上产线'), ('下产线', '下产线'), ('运送空料架', '运送空料架')], string='类型')
start_site_id = fields.Many2one('sf.agv.site', '起点接驳站') start_site_id = fields.Many2one('sf.agv.site', '起点接驳站位置编号')
end_site_id = fields.Many2one('sf.agv.site', '终点接驳站') end_site_id = fields.Many2one('sf.agv.site', '终点接驳站位置编号')
destination_production_line_id = fields.Many2one('sf.production.line', '目的生产线') destination_production_line_id = fields.Many2one('sf.production.line', '目的生产线')
active = fields.Boolean('有效', default=True) active = fields.Boolean('有效', default=True)
@api.constrains('end_site_id')
def _check_end_site_id(self):
if self.end_site_id:
if self.end_site_id == self.start_site_id:
raise UserError("您选择的终点接驳站与起点接驳站重复,请重新选择")
class Center_controlInterfaceLog(models.Model): class Center_controlInterfaceLog(models.Model):
_name = 'center_control.interface.log' _name = 'center_control.interface.log'

View File

@@ -53,13 +53,13 @@ class MrpProduction(models.Model):
active = fields.Boolean(string='已归档', default=True) active = fields.Boolean(string='已归档', default=True)
programming_no = fields.Char('编程单号') programming_no = fields.Char('编程单号')
work_state = fields.Char('业务状态') work_state = fields.Char('业务状态')
programming_state = fields.Char('编程状态', tracking=True) programming_state = fields.Char('编程状态')
glb_file = fields.Binary("glb模型文件") glb_file = fields.Binary("glb模型文件")
production_line_id = fields.Many2one('sf.production.line', string='生产线', tracking=True) production_line_id = fields.Many2one('sf.production.line', string='生产线')
plan_start_processing_time = fields.Datetime('计划开始加工时间') plan_start_processing_time = fields.Datetime('计划开始加工时间')
production_line_state = fields.Selection( production_line_state = fields.Selection(
[('待上产线', '待上产线'), ('已上产线', '已上产线'), ('已下产线', '已下产线')], [('待上产线', '待上产线'), ('已上产线', '已上产线'), ('已下产线', '已下产线')],
string='上/下产线', default='待上产线', tracking=True) string='上/下产线', default='待上产线')
# 工序状态 # 工序状态
# Todo 研究下用法 # Todo 研究下用法
process_state = fields.Selection([ process_state = fields.Selection([
@@ -77,7 +77,6 @@ class MrpProduction(models.Model):
part_drawing = fields.Binary('零件图纸') part_drawing = fields.Binary('零件图纸')
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True) manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
rework_production = fields.Many2one('mrp.production', string='返工的制造订单')
@api.depends( @api.depends(
'move_raw_ids.state', 'move_raw_ids.quantity_done', 'move_finished_ids.state', 'move_raw_ids.state', 'move_raw_ids.quantity_done', 'move_finished_ids.state',
@@ -155,28 +154,6 @@ class MrpProduction(models.Model):
for production in self: for production in self:
production.maintenance_count = len(production.request_ids) production.maintenance_count = len(production.request_ids)
# 制造订单报废:编程单更新
def updateCNC(self):
try:
res = {'production_no': self.name, 'programming_no': self.programming_no,
'order_no': self.origin}
logging.info('res=%s:' % res)
configsettings = self.env['res.config.settings'].get_values()
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
url = '/api/intelligent_programming/update_intelligent_programmings'
config_url = configsettings['sf_url'] + url
res['token'] = configsettings['token']
ret = requests.post(config_url, json={}, data=res, headers=config_header)
ret = ret.json()
logging.info('updateCNC-ret:%s' % ret)
if ret['status'] == 1:
self.write({'work_state': '已编程'})
else:
raise UserError(ret['message'])
except Exception as e:
logging.info('updateCNC error:%s' % e)
raise UserError("更新程单失败,请联系管理员")
# cnc程序获取 # cnc程序获取
def fetchCNC(self, production_names): def fetchCNC(self, production_names):
cnc = self.env['mrp.production'].search([('id', '=', self.id)]) cnc = self.env['mrp.production'].search([('id', '=', self.id)])
@@ -194,7 +171,6 @@ class MrpProduction(models.Model):
'production_no': production_names, 'production_no': production_names,
'machine_tool_code': '', 'machine_tool_code': '',
'product_name': cnc.product_id.name, 'product_name': cnc.product_id.name,
'remanufacture_type': '',
'model_code': cnc.product_id.model_code, 'model_code': cnc.product_id.model_code,
'material_code': self.env['sf.production.materials'].search( 'material_code': self.env['sf.production.materials'].search(
[('id', '=', cnc.product_id.materials_id.id)]).materials_no, [('id', '=', cnc.product_id.materials_id.id)]).materials_no,
@@ -292,7 +268,7 @@ class MrpProduction(models.Model):
# 则根据设备找到工作中心;否则采用前面描述的工作中心分配机制; # 则根据设备找到工作中心;否则采用前面描述的工作中心分配机制;
# 其他规则限制: 默认只分配给工作中心状态为非故障的工作中心; # 其他规则限制: 默认只分配给工作中心状态为非故障的工作中心;
def _create_workorder3(self, item): def _create_workorder3(self):
# 根据product_id对self进行分组 # 根据product_id对self进行分组
grouped_product_ids = {k: list(g) for k, g in groupby(self, key=lambda x: x.product_id.id)} grouped_product_ids = {k: list(g) for k, g in groupby(self, key=lambda x: x.product_id.id)}
# 初始化一个字典来存储每个product_id对应的生产订单名称列表 # 初始化一个字典来存储每个product_id对应的生产订单名称列表
@@ -328,6 +304,18 @@ class MrpProduction(models.Model):
'state': 'pending', 'state': 'pending',
}] }]
if production.product_id.categ_id.type == '成品': if production.product_id.categ_id.type == '成品':
if production.product_id.id in product_id_to_production_names:
# # 同一个产品多个制造订单对应一个编程单和模型库
# # 只调用一次fetchCNC并将所有生产订单的名称作为字符串传递
if not production.programming_no:
production_programming = self.search(
[('product_id.id', '=', production.product_id.id), ('origin', '=', production.origin)],
limit=1, order='id asc')
if not production_programming.programming_no:
production.fetchCNC(', '.join(product_id_to_production_names[production.product_id.id]))
else:
production.write({'programming_no': production_programming.programming_no,
'programming_state': '已编程' if production_programming.programming_state == '已编程' else '编程中'})
# # 根据加工面板的面数及对应的工序模板生成工单 # # 根据加工面板的面数及对应的工序模板生成工单
i = 0 i = 0
processing_panel_len = len(production.product_id.model_processing_panel.split(',')) processing_panel_len = len(production.product_id.model_processing_panel.split(','))
@@ -340,10 +328,10 @@ class MrpProduction(models.Model):
for route in product_routing_workcenter: for route in product_routing_workcenter:
if route.is_repeat is True: if route.is_repeat is True:
workorders_values.append( workorders_values.append(
self.env['mrp.workorder'].json_workorder_str(k, production, route, item)) self.env['mrp.workorder'].json_workorder_str(k, production, route))
# if i == processing_panel_len and route.routing_type == '解除装夹': if i == processing_panel_len and route.routing_type == '解除装夹':
# workorders_values.append( workorders_values.append(
# self.env['mrp.workorder'].json_workorder_str(k, production, route)) self.env['mrp.workorder'].json_workorder_str(k, production, route))
# 表面工艺工序 # 表面工艺工序
# 获取表面工艺id # 获取表面工艺id
if production.product_id.model_process_parameters_ids: if production.product_id.model_process_parameters_ids:
@@ -391,52 +379,12 @@ class MrpProduction(models.Model):
workorders_values.append( workorders_values.append(
self.env['mrp.workorder'].json_workorder_str('', production, route)) self.env['mrp.workorder'].json_workorder_str('', production, route))
production.workorder_ids = workorders_values production.workorder_ids = workorders_values
# for production_item in productions: if production_programming.programming_state == '已编程':
process_parameter_workorder = self.env['mrp.workorder'].search( logging.info("production_programming: %s" % production_programming.name)
[('surface_technics_parameters_id', '!=', False), ('production_id', '=', production.id), production.workorder_ids.filtered(lambda t: t.routing_type == 'CNC加工').write({
('is_subcontract', '=', True)]) 'cnc_ids': production_programming.workorder_ids.filtered(
if process_parameter_workorder: lambda
is_pick = False t1: t1.routing_type == 'CNC加工').cnc_ids})
consecutive_workorders = []
m = 0
sorted_workorders = sorted(process_parameter_workorder, key=lambda w: w.id)
for i in range(len(sorted_workorders) - 1):
if m == 0:
is_pick = False
if sorted_workorders[i].supplier_id.id == sorted_workorders[i + 1].supplier_id.id and \
sorted_workorders[i].is_subcontract == sorted_workorders[i + 1].is_subcontract and \
sorted_workorders[i].id == sorted_workorders[i + 1].id - 1:
if sorted_workorders[i] not in consecutive_workorders:
consecutive_workorders.append(sorted_workorders[i])
consecutive_workorders.append(sorted_workorders[i + 1])
m += 1
continue
else:
if m == len(consecutive_workorders) - 1 and m != 0:
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders,
production_item)
if sorted_workorders[i] in consecutive_workorders:
is_pick = True
consecutive_workorders = []
m = 0
# 当前面的连续工序生成对应的外协出入库单再生成当前工序的外协出入库单
if is_pick is False:
self.env['stock.picking'].create_outcontract_picking(sorted_workorders[i],
production_item)
if m == len(consecutive_workorders) - 1 and m != 0:
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders,
production_item)
if sorted_workorders[i] in consecutive_workorders:
is_pick = True
consecutive_workorders = []
m = 0
if m == len(consecutive_workorders) - 1 and m != 0:
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production_item)
if is_pick is False and m == 0:
if len(sorted_workorders) == 1:
self.env['stock.picking'].create_outcontract_picking(sorted_workorders, production_item)
else:
self.env['stock.picking'].create_outcontract_picking(sorted_workorders[i], production_item)
for workorder in production.workorder_ids: for workorder in production.workorder_ids:
workorder.duration_expected = workorder._get_duration_expected() workorder.duration_expected = workorder._get_duration_expected()
@@ -531,23 +479,15 @@ class MrpProduction(models.Model):
def _reset_work_order_sequence(self): def _reset_work_order_sequence(self):
for rec in self: for rec in self:
sequence_list = {} sequence_list = {}
# 产品模型类型
model_type_id = rec.product_id.product_model_type_id model_type_id = rec.product_id.product_model_type_id
# 产品加工面板
model_processing_panel = rec.product_id.model_processing_panel
if model_type_id: if model_type_id:
if model_processing_panel:
tmpl_num = 1 tmpl_num = 1
panel_list = model_processing_panel.split(',')
for panel in panel_list:
panel_sequence_list = {}
# 成品工序 # 成品工序
product_routing_tmpl_ids = model_type_id.product_routing_tmpl_ids product_routing_tmpl_ids = model_type_id.product_routing_tmpl_ids
if product_routing_tmpl_ids: if product_routing_tmpl_ids:
for tmpl_id in product_routing_tmpl_ids: for tmpl_id in product_routing_tmpl_ids:
panel_sequence_list.update({tmpl_id.route_workcenter_id.name: tmpl_num}) sequence_list.update({tmpl_id.route_workcenter_id.name: tmpl_num})
tmpl_num += 1 tmpl_num += 1
sequence_list.update({panel: panel_sequence_list})
# 表面工艺工序 # 表面工艺工序
# 模型类型的表面工艺工序模版 # 模型类型的表面工艺工序模版
surface_tmpl_ids = model_type_id.surface_technics_routing_tmpl_ids surface_tmpl_ids = model_type_id.surface_technics_routing_tmpl_ids
@@ -573,21 +513,12 @@ class MrpProduction(models.Model):
for tmpl_id in embryo_routing_tmpl_ids: for tmpl_id in embryo_routing_tmpl_ids:
sequence_list.update({tmpl_id.route_workcenter_id.name: tmpl_num}) sequence_list.update({tmpl_id.route_workcenter_id.name: tmpl_num})
tmpl_num += 1 tmpl_num += 1
else:
raise ValidationError('该产品【加工面板】为空!')
else: else:
raise ValidationError('该产品没有选择【模版类型】!') raise ValidationError('该产品没有选择【模版类型】!')
for work in rec.workorder_ids: for work in rec.workorder_ids:
if sequence_list.get(work.name): if sequence_list.get(work.name):
work.sequence = sequence_list[work.name] work.sequence = sequence_list[work.name]
elif sequence_list.get(work.processing_panel):
processing_panel = sequence_list.get(work.processing_panel)
if processing_panel.get(work.name):
work.sequence = processing_panel[work.name]
else:
raise ValidationError('工序【%s】在产品选择的模版类型中不存在!' % work.name)
else: else:
raise ValidationError('工序【%s】在产品选择的模版类型中不存在!' % work.name) raise ValidationError('工序【%s】在产品选择的模版类型中不存在!' % work.name)
# if work.name == '获取CNC加工程序': # if work.name == '获取CNC加工程序':
@@ -596,8 +527,8 @@ class MrpProduction(models.Model):
# work.button_finish() # work.button_finish()
# 创建工单并进行排序 # 创建工单并进行排序
def _create_workorder(self, item): def _create_workorder(self):
self._create_workorder3(item) self._create_workorder3()
self._reset_work_order_sequence() self._reset_work_order_sequence()
return True return True

View File

@@ -1,5 +1,5 @@
import re import re
import json
import logging import logging
import base64 import base64
import urllib.parse import urllib.parse
@@ -21,8 +21,6 @@ class ResMrpWorkOrder(models.Model):
_inherit = 'mrp.workorder' _inherit = 'mrp.workorder'
_order = 'sequence asc,create_date desc' _order = 'sequence asc,create_date desc'
product_tmpl_name = fields.Char('坯料产品名称', related='production_bom_id.bom_line_ids.product_id.name')
product_tmpl_id_length = fields.Float(related='production_id.product_tmpl_id.length', readonly=True, store=True, product_tmpl_id_length = fields.Float(related='production_id.product_tmpl_id.length', readonly=True, store=True,
string="坯料长度(mm)") string="坯料长度(mm)")
product_tmpl_id_width = fields.Float(related='production_id.product_tmpl_id.width', readonly=True, store=True, product_tmpl_id_width = fields.Float(related='production_id.product_tmpl_id.width', readonly=True, store=True,
@@ -104,7 +102,7 @@ class ResMrpWorkOrder(models.Model):
Z10_axis = fields.Float(default=0) Z10_axis = fields.Float(default=0)
X_deviation_angle = fields.Integer(string="X轴偏差度", default=0) X_deviation_angle = fields.Integer(string="X轴偏差度", default=0)
test_results = fields.Selection([("合格", "合格"), ("返工", "返工"), ("报废", "报废")], default='合格', test_results = fields.Selection([("合格", "合格"), ("返工", "返工"), ("报废", "报废")], default='合格',
string="检测结果", tracking=True) string="检测结果")
cnc_ids = fields.One2many("sf.cnc.processing", 'workorder_id', string="CNC加工程序") cnc_ids = fields.One2many("sf.cnc.processing", 'workorder_id', string="CNC加工程序")
cmm_ids = fields.One2many("sf.cmm.program", 'workorder_id', string="CMM程序") cmm_ids = fields.One2many("sf.cmm.program", 'workorder_id', string="CMM程序")
tray_code = fields.Char(string="托盘编码") tray_code = fields.Char(string="托盘编码")
@@ -135,7 +133,7 @@ class ResMrpWorkOrder(models.Model):
return action return action
supplier_id = fields.Many2one('res.partner', string='外协供应商') supplier_id = fields.Many2one('res.partner', string='外协供应商')
equipment_id = fields.Many2one('maintenance.equipment', string='加工设备', tracking=True) equipment_id = fields.Many2one('maintenance.equipment', string='加工设备')
is_ok = fields.Boolean(string='是否合格') is_ok = fields.Boolean(string='是否合格')
# 加工人 # 加工人
processing_user_id = fields.Many2one('res.users', string='加工人') processing_user_id = fields.Many2one('res.users', string='加工人')
@@ -197,17 +195,11 @@ class ResMrpWorkOrder(models.Model):
rfid_code_old = fields.Char('RFID码(已解除)') rfid_code_old = fields.Char('RFID码(已解除)')
production_line_id = fields.Many2one('sf.production.line', related='production_id.production_line_id', production_line_id = fields.Many2one('sf.production.line', related='production_id.production_line_id',
string='生产线', store=True, tracking=True) string='生产线', store=True)
production_line_state = fields.Selection(related='production_id.production_line_state', production_line_state = fields.Selection(related='production_id.production_line_state',
string='上/下产线', store=True, tracking=True) string='上/下产线', store=True)
detection_report = fields.Binary('检测报告', readonly=True) detection_report = fields.Binary('检测报告', readonly=True)
is_remanufacture = fields.Boolean(string='重新生成制造订单', default=False) is_remanufacture = fields.Boolean(string='是否重新生成制造订单', default=True)
is_fetchcnc = fields.Boolean(string='重新获取NC程序', default=False)
reason = fields.Selection(
[("programming", "编程"), ("clamping", "返工"), ("cutter", "刀具"), ("operate computer", "操机"),
("technology", "工艺"), ("customer redrawing", "客户改图"), ("other", "其他"), ], string="原因", tracking=True)
detailed_reason = fields.Text('详细原因')
is_send_program_again = fields.Boolean(string='是否重新下发NC程序', default=False)
@api.onchange('rfid_code') @api.onchange('rfid_code')
def _onchange(self): def _onchange(self):
@@ -474,7 +466,7 @@ class ResMrpWorkOrder(models.Model):
raise UserError(_("该工单暂未完成,无法进行工件配送")) raise UserError(_("该工单暂未完成,无法进行工件配送"))
# 拼接工单对象属性值 # 拼接工单对象属性值
def json_workorder_str(self, k, production, route, item): def json_workorder_str(self, k, production, route):
# 计算预计时长duration_expected # 计算预计时长duration_expected
if route.routing_type == '切割': if route.routing_type == '切割':
duration_expected = self.env['mrp.routing.workcenter'].sudo().search( duration_expected = self.env['mrp.routing.workcenter'].sudo().search(
@@ -507,7 +499,7 @@ class ResMrpWorkOrder(models.Model):
'processing_panel': k, 'processing_panel': k,
'quality_point_ids': route.route_workcenter_id.quality_point_ids, 'quality_point_ids': route.route_workcenter_id.quality_point_ids,
'routing_type': route.routing_type, 'routing_type': route.routing_type,
# 'work_state': '待发起', 'work_state': '待发起',
'workcenter_id': self.env['mrp.routing.workcenter'].get_workcenter(route.workcenter_ids.ids, 'workcenter_id': self.env['mrp.routing.workcenter'].get_workcenter(route.workcenter_ids.ids,
route.routing_type, route.routing_type,
production.product_id), production.product_id),
@@ -516,10 +508,6 @@ class ResMrpWorkOrder(models.Model):
'date_planned_finished': datetime.now() + timedelta(days=1), 'date_planned_finished': datetime.now() + timedelta(days=1),
'duration_expected': duration_expected, 'duration_expected': duration_expected,
'duration': 0, 'duration': 0,
'cnc_ids': False if route.routing_type != 'CNC加工' else self.env['sf.cnc.processing']._json_cnc_processing(
k, item),
'cmm_ids': False if route.routing_type != 'CNC加工' else self.env['sf.cmm.program']._json_cmm_program(k,
item),
'workpiece_delivery_ids': False if not route.routing_type == '装夹预调' else self._json_workpiece_delivery_list( 'workpiece_delivery_ids': False if not route.routing_type == '装夹预调' else self._json_workpiece_delivery_list(
production) production)
}] }]
@@ -684,7 +672,7 @@ class ResMrpWorkOrder(models.Model):
""" """
重新生成制造订单或者重新生成工单 重新生成制造订单或者重新生成工单
""" """
if self.test_results in ['返工', '报废']: if self.test_results == '报废':
values = self.env['mrp.production'].create_production1_values(self.production_id) values = self.env['mrp.production'].create_production1_values(self.production_id)
productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company( productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company(
self.production_id.company_id).create( self.production_id.company_id).create(
@@ -773,7 +761,6 @@ class ResMrpWorkOrder(models.Model):
sale_order = self.env['sale.order'].sudo().search([('name', '=', productions.origin)]) sale_order = self.env['sale.order'].sudo().search([('name', '=', productions.origin)])
if sale_order: if sale_order:
sale_order.mrp_production_ids |= productions
# sale_order.write({'schedule_status': 'to schedule'}) # sale_order.write({'schedule_status': 'to schedule'})
self.env['sf.production.plan'].sudo().with_company(self.production_id.company_id).create({ self.env['sf.production.plan'].sudo().with_company(self.production_id.company_id).create({
'name': productions.name, 'name': productions.name,
@@ -785,13 +772,13 @@ class ResMrpWorkOrder(models.Model):
'product_id': productions.product_id.id, 'product_id': productions.product_id.id,
'state': 'draft', 'state': 'draft',
}) })
# if self.test_results == '返工': if self.test_results == '返工':
# productions = self.production_id productions = self.production_id
# # self.env['stock.move'].sudo().create(productions._get_moves_raw_values()) # self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
# # self.env['stock.move'].sudo().create(productions._get_moves_finished_values()) # self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
# productions._create_workorder2(self.processing_panel) productions._create_workorder2(self.processing_panel)
# else: else:
# self.results = '合格' self.results = '合格'
def json_workorder_str1(self, k, production, route): def json_workorder_str1(self, k, production, route):
workorders_values_str = [0, '', { workorders_values_str = [0, '', {
@@ -816,28 +803,29 @@ class ResMrpWorkOrder(models.Model):
}] }]
return workorders_values_str return workorders_values_str
# @api.depends('production_availability', 'blocked_by_workorder_ids', 'blocked_by_workorder_ids.state') @api.depends('production_availability', 'blocked_by_workorder_ids', 'blocked_by_workorder_ids.state')
# def _compute_state(self): def _compute_state(self):
# super(ResMrpWorkOrder, self)._compute_state() super(ResMrpWorkOrder, self)._compute_state()
# for item in self: for item in self:
# print(item.name) scrap_workorder = self.env['mrp.workorder'].search(
# print(item.state) [('production_id', '=', item.production_id.id), ('routing_type', '=', 'CNC加工'),
# print(item.is_remanufacture) ('state', '=', 'done'), ('is_remanufacture', '=', True)])
# scrap_workorder = self.env['mrp.workorder'].search( print(item.name)
# [('production_id', '=', item.production_id.id), ('routing_type', '=', 'CNC加工'), print(item.state)
# ('state', '=', 'done'), ('test_results', 'in', ['返工', '报废'])]) if item.name == 'CNC加工(返工)' and item.state not in ['ready', 'progress', 'done']:
# print(scrap_workorder) item.state = 'ready'
# # if item.routing_type == 'CNC加工' and item.state in ['done'] and item.test_results in ['返工', '报废']: if item.routing_type == '解除装夹':
# if item.routing_type == '解除装夹': last_workorder = self.env['mrp.workorder'].search(
# if scrap_workorder and item.state not in ['cancel']: [('production_id', '=', item.production_id.id), ('name', '=', 'CNC加工(返工)'),
# item.state = 'cancel' ('state', '!=', 'done')])
# elif item.routing_type == '表面工艺': if item.state != 'pending':
# if scrap_workorder: if last_workorder:
# stock_move = self.env['stock.move'].search( item.state = 'pending'
# [('origin', '=', item.production_id.name)]) if scrap_workorder:
# stock_move.write({'state': 'cancel'}) item.state = 'cancel'
# item.picking_ids.write({'state': 'cancel'}) elif item.routing_type == '表面工艺':
# item.state = 'cancel' if scrap_workorder:
item.state = 'cancel'
# 重写工单开始按钮方法 # 重写工单开始按钮方法
def button_start(self): def button_start(self):
@@ -856,12 +844,12 @@ class ResMrpWorkOrder(models.Model):
limit=1, order='id asc') limit=1, order='id asc')
if not cnc_workorder.cnc_ids: if not cnc_workorder.cnc_ids:
raise UserError(_('该制造订单还未下发CNC程序请稍后再试')) raise UserError(_('该制造订单还未下发CNC程序请稍后再试'))
# else: else:
# for item in cnc_workorder.cnc_ids: for item in cnc_workorder.cnc_ids:
# functional_cutting_tool = self.env['sf.functional.cutting.tool.entity'].search( functional_cutting_tool = self.env['sf.functional.cutting.tool.entity'].search(
# [('tool_name_id.name', '=', item.cutting_tool_name)]) [('tool_name_id.name', '=', item.cutting_tool_name)])
# if not functional_cutting_tool: if not functional_cutting_tool:
# raise UserError(_('该制造订单的CNC程序为%s没有对应的功能刀具' % item.cutting_tool_name)) raise UserError(_('该制造订单的CNC程序为%s没有对应的功能刀具' % item.cutting_tool_name))
if self.routing_type == '解除装夹': if self.routing_type == '解除装夹':
''' '''
记录开始时间 记录开始时间
@@ -994,7 +982,6 @@ class ResMrpWorkOrder(models.Model):
raise UserError( raise UserError(
'请先在产品中配置表面工艺为%s相关的外协服务产品' % item.surface_technics_parameters_id.name) '请先在产品中配置表面工艺为%s相关的外协服务产品' % item.surface_technics_parameters_id.name)
tem_date_planned_finished = record.date_planned_finished tem_date_planned_finished = record.date_planned_finished
tem_date_finished = record.date_finished
logging.info('routing_type:%s' % record.routing_type) logging.info('routing_type:%s' % record.routing_type)
super().button_finish() super().button_finish()
logging.info('date_planned_finished:%s' % record.date_planned_finished) logging.info('date_planned_finished:%s' % record.date_planned_finished)
@@ -1003,28 +990,16 @@ class ResMrpWorkOrder(models.Model):
record.write({ record.write({
'date_planned_finished': tem_date_planned_finished # 保持原值 'date_planned_finished': tem_date_planned_finished # 保持原值
}) })
# if record.routing_type == 'CNC加工': if record.routing_type == 'CNC加工' and record.test_results in ['返工', '报废']:
# record.write({ record.recreateManufacturingOrWorkerOrder()
# 'date_finished': tem_date_finished # 保持原值
# })
# if record.routing_type == 'CNC加工' and record.test_results in ['返工', '报废']:
# record.production_id.action_cancel()
# record.production_id.workorder_ids.write({'rfid_code': False, 'rfid_code_old': record.rfid_code})
# if record.is_remanufacture is True:
# record.recreateManufacturingOrWorkerOrder()
is_production_id = True is_production_id = True
for workorder in record.production_id.workorder_ids: for workorder in record.production_id.workorder_ids:
if workorder.state != 'done': if workorder.state != 'done':
is_production_id = False is_production_id = False
if record.routing_type == '解除装夹':
for workorder in record.production_id.workorder_ids:
if workorder.processing_panel == record.processing_panel:
rfid_code = workorder.rfid_code
workorder.write({'rfid_code_old': rfid_code,
'rfid_code': ''})
workorder.rfid_code_old = rfid_code
workorder.rfid_code = ''
if is_production_id is True and record.routing_type in ['解除装夹', '表面工艺']: if is_production_id is True and record.routing_type in ['解除装夹', '表面工艺']:
for workorder in record.production_id.workorder_ids:
workorder.rfid_code_old = workorder.rfid_code
workorder.rfid_code = None
for move_raw_id in record.production_id.move_raw_ids: for move_raw_id in record.production_id.move_raw_ids:
move_raw_id.quantity_done = move_raw_id.product_uom_qty move_raw_id.quantity_done = move_raw_id.product_uom_qty
record.process_state = '已完工' record.process_state = '已完工'
@@ -1078,33 +1053,6 @@ class ResMrpWorkOrder(models.Model):
workorder.detection_report = base64.b64encode(open(report_file_path, 'rb').read()) workorder.detection_report = base64.b64encode(open(report_file_path, 'rb').read())
return True return True
# 重新下发nc程序
def button_send_program_again(self):
try:
res = {'programming_no': self.production_id.programming_no}
configsettings = self.env['res.config.settings'].get_values()
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
url = '/api/intelligent_programming/reset_state_again'
config_url = configsettings['sf_url'] + url
r = requests.post(config_url, json=res, data=None, headers=config_header)
r = r.json()
result = json.loads(r['result'])
if result['status'] == 1:
productions = self.env['mrp.production'].search(
[('programming_no', '=', self.production_id.programming_no), ('programming_state', '=', '已编程')])
if productions:
workorder = productions.workorder_ids.filtered(
lambda ap: ap.routing_type in ['装夹预调', 'CNC加工'] and ap.state not in ['done', 'cancel',
'progress'])
if workorder:
workorder.write({'is_send_program_again': True})
productions.write({'work_state': '编程中', 'programming_state': '编程中'})
else:
raise UserError(result['message'])
except Exception as e:
logging.info('button_send_program_again error:%s' % e)
raise UserError("重新下发nc程序失败,请联系管理员")
class CNCprocessing(models.Model): class CNCprocessing(models.Model):
_name = 'sf.cnc.processing' _name = 'sf.cnc.processing'
@@ -1130,7 +1078,6 @@ class CNCprocessing(models.Model):
production_id = fields.Many2one('mrp.production', string="制造订单") production_id = fields.Many2one('mrp.production', string="制造订单")
button_state = fields.Boolean(string='是否已经下发') button_state = fields.Boolean(string='是否已经下发')
program_path = fields.Char('程序文件路径') program_path = fields.Char('程序文件路径')
program_create_date = fields.Datetime('程序创建日期')
# mrs下发编程单创建CNC加工 # mrs下发编程单创建CNC加工
def cnc_processing_create(self, cnc_workorder, ret, program_path, program_path_tmp): def cnc_processing_create(self, cnc_workorder, ret, program_path, program_path_tmp):
@@ -1163,37 +1110,34 @@ class CNCprocessing(models.Model):
cnc_workorder.write({'programming_state': '已编程', 'work_state': '已编程'}) cnc_workorder.write({'programming_state': '已编程', 'work_state': '已编程'})
return cnc_processing return cnc_processing
def _json_cnc_processing(self, panel, ret): def _json_cnc_processing(self, obj):
cnc_processing = [] cnc_processing_str = (0, 0, {
for item in ret['programming_list']: 'sequence_number': obj['sequence_number'],
if item['processing_panel'] == panel and item['ftp_path'].find('.dmi') == -1: 'program_name': obj['program_name'],
cnc_processing.append((0, 0, { 'cutting_tool_name': obj['cutting_tool_name'],
'sequence_number': item['sequence_number'], 'cutting_tool_no': obj['cutting_tool_no'],
'program_name': item['program_name'], 'processing_type': obj['processing_type'],
'cutting_tool_name': item['cutting_tool_name'], 'margin_x_y': obj['margin_x_y'],
'cutting_tool_no': item['cutting_tool_no'], 'margin_z': obj['margin_z'],
'processing_type': item['processing_type'], 'depth_of_processing_z': obj['depth_of_processing_z'],
'margin_x_y': item['margin_x_y'], 'cutting_tool_extension_length': obj['cutting_tool_extension_length'],
'margin_z': item['margin_z'], 'cutting_tool_handle_type': obj['cutting_tool_handle_type'],
'depth_of_processing_z': item['depth_of_processing_z'], 'estimated_processing_time': obj['estimated_processing_time'],
'cutting_tool_extension_length': item['cutting_tool_extension_length'], 'program_path': obj['program_path'],
'cutting_tool_handle_type': item['cutting_tool_handle_type'], 'cnc_id': obj['cnc_id'].id,
'estimated_processing_time': item['estimated_processing_time'], 'remark': obj['remark']
'program_path': item['ftp_path'], })
'program_create_date': datetime.strptime(item['program_create_date'], '%Y-%m-%d %H:%M:%S'), return cnc_processing_str
'remark': item['remark']
}))
return cnc_processing
# 根据程序名和加工面匹配到ftp里对应的Nc程序名,可优化为根据cnc_processing.program_path进行匹配 # 根据程序名和加工面匹配到ftp里对应的Nc程序名,可优化为根据cnc_processing.program_path进行匹配
def get_cnc_processing_file(self, serverdir, cnc_processing, program_path): def get_cnc_processing_file(self, serverdir, cnc_processing, program_path):
logging.info('serverdir:%s' % serverdir) logging.info('serverdir:%s' % serverdir)
logging.info('cnc_processing:%s' % cnc_processing)
for root, dirs, files in os.walk(serverdir): for root, dirs, files in os.walk(serverdir):
for f in files: for f in files:
logging.info('splitext(f):%s' % os.path.splitext(f)[1])
if os.path.splitext(f)[1] == ".pdf": if os.path.splitext(f)[1] == ".pdf":
full_path = os.path.join(serverdir, root, f) full_path = os.path.join(serverdir, root, f)
if full_path is not False:
if not cnc_processing.workorder_id.cnc_worksheet:
cnc_processing.workorder_id.cnc_worksheet = base64.b64encode( cnc_processing.workorder_id.cnc_worksheet = base64.b64encode(
open(full_path, 'rb').read()) open(full_path, 'rb').read())
else: else:
@@ -1213,14 +1157,14 @@ class CNCprocessing(models.Model):
}) })
return attachment return attachment
# 将FTP的多面的程序单文件下载到临时目录 # 将FTP的nc文件下载到临时目录
def download_file_tmp(self, production_no, processing_panel): def download_file_tmp(self, production_no, processing_panel):
remotepath = os.path.join('/NC', production_no, 'return', processing_panel) remotepath = os.path.join('/NC', production_no, 'return', processing_panel)
serverdir = os.path.join('/tmp', production_no, 'return', processing_panel) serverdir = os.path.join('/tmp', production_no, 'return', processing_panel)
ftp_resconfig = self.env['res.config.settings'].get_values() ftp_resconfig = self.env['res.config.settings'].get_values()
ftp = FtpController(str(ftp_resconfig['ftp_host']), int(ftp_resconfig['ftp_port']), ftp_resconfig['ftp_user'], ftp = FtpController(str(ftp_resconfig['ftp_host']), int(ftp_resconfig['ftp_port']), ftp_resconfig['ftp_user'],
ftp_resconfig['ftp_password']) ftp_resconfig['ftp_password'])
download_state = ftp.download_program_file(remotepath, serverdir) download_state = ftp.download_file_tree(remotepath, serverdir)
logging.info('download_state:%s' % download_state) logging.info('download_state:%s' % download_state)
return download_state return download_state
@@ -1297,12 +1241,11 @@ class SfWorkOrderBarcodes(models.Model):
workorder.write(val) workorder.write(val)
self.write(val) self.write(val)
workorder_rfid = self.env['mrp.workorder'].search( workorder_rfid = self.env['mrp.workorder'].search(
[('production_id', '=', workorder.production_id.id), [('production_id', '=', workorder.production_id.id)])
('processing_panel', '=', workorder.processing_panel)])
if workorder_rfid: if workorder_rfid:
for item in workorder_rfid: for item in workorder_rfid:
item.write({'rfid_code': barcode}) item.write({'rfid_code': barcode})
logging.info("Rfid[%s]绑定成功!!!" % barcode) logging.info("Rfid绑定成功")
else: else:
raise UserError('该Rfid【%s】绑定的是【%s】, 不是托盘!!!' % (barcode, lot.product_id.name)) raise UserError('该Rfid【%s】绑定的是【%s】, 不是托盘!!!' % (barcode, lot.product_id.name))
self.process_state = '待检测' self.process_state = '待检测'
@@ -1362,18 +1305,17 @@ class SfWorkOrderBarcodes(models.Model):
class WorkPieceDelivery(models.Model): class WorkPieceDelivery(models.Model):
_name = "sf.workpiece.delivery" _name = "sf.workpiece.delivery"
_inherit = ['mail.thread', 'mail.activity.mixin']
_description = '工件配送' _description = '工件配送'
name = fields.Char('单据编') name = fields.Char('单据编')
workorder_id = fields.Many2one('mrp.workorder', string='工单', readonly=True) workorder_id = fields.Many2one('mrp.workorder', string='工单', readonly=True)
workorder_state = fields.Selection(related='workorder_id.state', string='工单状态') workorder_state = fields.Selection(related='workorder_id.state', string='工单状态')
rfid_code = fields.Char(related='workorder_id.rfid_code', string='rfid码', store=True) rfid_code = fields.Char(related='workorder_id.rfid_code', string='rfid码', store=True)
production_id = fields.Many2one('mrp.production', string='制造订单号', readonly=True) production_id = fields.Many2one('mrp.production', string='制造订单号', readonly=True)
production_line_id = fields.Many2one('sf.production.line', string='目的生产线', tracking=True) production_line_id = fields.Many2one('sf.production.line', string='目的生产线')
plan_start_processing_time = fields.Datetime('计划开始加工时间', readonly=True) plan_start_processing_time = fields.Datetime('计划开始加工时间', readonly=True)
route_id = fields.Many2one('sf.agv.task.route', '任务路线', tracking=True) route_id = fields.Many2one('sf.agv.task.route', '任务路线')
feeder_station_start_id = fields.Many2one('sf.agv.site', '起点接驳站') feeder_station_start_id = fields.Many2one('sf.agv.site', '起点接驳站')
feeder_station_destination_id = fields.Many2one('sf.agv.site', '目的接驳站') feeder_station_destination_id = fields.Many2one('sf.agv.site', '目的接驳站')
task_delivery_time = fields.Datetime('任务下发时间') task_delivery_time = fields.Datetime('任务下发时间')
@@ -1382,41 +1324,26 @@ class WorkPieceDelivery(models.Model):
[('上产线', '上产线'), ('下产线', '下产线'), ('运送空料架', '运送空料架')], string='类型') [('上产线', '上产线'), ('下产线', '下产线'), ('运送空料架', '运送空料架')], string='类型')
delivery_duration = fields.Float('配送时长', compute='_compute_delivery_duration') delivery_duration = fields.Float('配送时长', compute='_compute_delivery_duration')
status = fields.Selection( status = fields.Selection(
[('待下发', '待下发'), ('待配送', '待配送'), ('已配送', '已配送')], string='状态', default='待下发', [('待下发', '待下发'), ('待配送', '待配送'), ('已配送', '已配送')], string='状态', default='待下发')
tracking=True) is_cnc_program_down = fields.Boolean('程序是否下发', default=False)
is_cnc_program_down = fields.Boolean('程序是否下发', default=False, tracking=True)
is_manual_work = fields.Boolean('人工操作', default=False) is_manual_work = fields.Boolean('人工操作', default=False)
active = fields.Boolean(string="有效", default=True) active = fields.Boolean(string="有效", default=True)
@api.model @api.model
def create(self, vals): def create(self, vals):
if vals['route_id'] and vals.get('type') is None:
vals['type'] = '运送空料架'
else:
if vals.get('name', '/') == '/' or vals.get('name', '/') is False: if vals.get('name', '/') == '/' or vals.get('name', '/') is False:
vals['name'] = self.env['ir.sequence'].next_by_code('sf.workpiece.delivery') or '/' vals['name'] = self.env['ir.sequence'].next_by_code('sf.workpiece.delivery') or '/'
else:
vals['type'] = '运送空料架'
obj = super(WorkPieceDelivery, self).create(vals) obj = super(WorkPieceDelivery, self).create(vals)
if obj.type == '运送空料架':
if obj.name is False:
obj.name = "运送空料架路线:%s-%s" % (
obj.feeder_station_start_id.name, obj.feeder_station_destination_id.name)
return obj return obj
@api.constrains('route_id') @api.constrains('name')
def _check_route_id(self): def _check_name(self):
if self.type == '运送空料架': if self.type == '运送空料架':
if self.route_id and self.name is False: wd = self.sudo().search([('name', '=', self.name), ('id', '!=', self.id)])
route = self.sudo().search( if wd:
[('route_id', '=', self.route_id.id), ('id', '!=', self.id), ('name', 'ilike', '运送空料架路线')]) raise UserError("该名称已存在")
if route:
raise UserError("该任务路线已存在,请重新选择")
# @api.constrains('name')
# def _check_name(self):
# if self.type == '运送空料架':
# wd = self.sudo().search([('name', '=', self.name), ('id', '!=', self.id)])
# if wd:
# raise UserError("该名称已存在")
def action_delivery_history(self): def action_delivery_history(self):
return { return {
@@ -1625,22 +1552,80 @@ class CMMprogram(models.Model):
_name = 'sf.cmm.program' _name = 'sf.cmm.program'
_description = "CMM程序" _description = "CMM程序"
cmm_id = fields.Many2one('ir.attachment')
sequence_number = fields.Integer('序号') sequence_number = fields.Integer('序号')
program_name = fields.Char('程序名') program_name = fields.Char('程序名')
cutting_tool_name = fields.Char('刀具名称')
cutting_tool_no = fields.Char('刀号')
processing_type = fields.Char('加工类型')
margin_x_y = fields.Char('余量_X/Y')
margin_z = fields.Char('余量_Z')
depth_of_processing_z = fields.Char('加工深度(Z)')
cutting_tool_extension_length = fields.Char('刀具伸出长度')
cutting_tool_handle_type = fields.Char('刀柄型号')
estimated_processing_time = fields.Char('预计加工时间')
remark = fields.Text('备注') remark = fields.Text('备注')
workorder_id = fields.Many2one('mrp.workorder', string="工单") workorder_id = fields.Many2one('mrp.workorder', string="工单")
production_id = fields.Many2one('mrp.production', string="制造订单") production_id = fields.Many2one('mrp.production', string="制造订单")
program_path = fields.Char('程序文件路径') program_path = fields.Char('程序文件路径')
program_create_date = fields.Datetime('程序创建日期')
def _json_cmm_program(self, panel, ret): def cmm_program_create(self, ret, program_path, program_path_tmp):
cmm_program = [] cmm_program = None
for item in ret['programming_list']: for obj in ret['programming_list']:
if item['processing_panel'] == panel and item['ftp_path'].find('.dmi') != -1: workorder = self.env['mrp.workorder'].search(
cmm_program.append((0, 0, { [('production_id.name', '=', ret['production_order_no'].split(',')[0]),
'sequence_number': 1, ('processing_panel', '=', obj['processing_panel']),
'program_name': item['program_name'], ('routing_type', '=', 'CNC加工')])
'program_path': item['ftp_path'], if obj['program_name'] in program_path:
'program_create_date': datetime.strptime(item['program_create_date'], '%Y-%m-%d %H:%M:%S'), logging.info('obj:%s' % obj['program_name'])
})) cmm_program = self.sudo().create({
'workorder_id': workorder.id,
'sequence_number': obj['sequence_number'],
'program_name': obj['program_name'],
'cutting_tool_name': obj['cutting_tool_name'],
'cutting_tool_no': obj['cutting_tool_no'],
'processing_type': obj['processing_type'],
'margin_x_y': obj['margin_x_y'],
'margin_z': obj['margin_z'],
'depth_of_processing_z': obj['depth_of_processing_z'],
'cutting_tool_extension_length': obj['cutting_tool_extension_length'],
'cutting_tool_handle_type': obj['cutting_tool_handle_type'],
'estimated_processing_time': obj['estimated_processing_time'],
'remark': obj['remark'],
'program_path': program_path.replace('/tmp', '')
})
cmm_program.get_cmm_program_file(program_path_tmp, cmm_program, program_path)
return cmm_program return cmm_program
# 根据程序名和加工面匹配到ftp里对应的cmm程序名
def get_cmm_program_file(self, serverdir, cmm_program, program_path):
logging.info('cmm-serverdir:%s' % serverdir)
for root, dirs, files in os.walk(serverdir):
for f in files:
if f in program_path:
cmm_program_file_path = os.path.join(serverdir, root, f)
self.write_file_cmm(cmm_program_file_path, cmm_program)
# 创建附件(nc文件)
def attachment_create(self, name, data):
attachment = self.env['ir.attachment'].create({
'datas': base64.b64encode(data),
'type': 'binary',
'public': True,
'description': '程序文件',
'name': name
})
return attachment
# 将cmm文件存到attach的datas里
def write_file_cmm(self, cmm_file_path, cnc):
cmm_file_name = cmm_file_path.split('/')
logging.info('cmm_file_name:%s' % cmm_file_name[-1])
if os.path.exists(cmm_file_path):
with open(cmm_file_path, 'rb') as file:
data_bytes = file.read()
attachment = self.attachment_create(cnc.program_name + cmm_file_name[-1], data_bytes)
cnc.write({'cmm_id': attachment.id})
file.close()
else:
return False

View File

@@ -50,8 +50,8 @@ class ResProductMo(models.Model):
cutting_tool_material_id = fields.Many2one('sf.cutting.tool.material', string='刀具物料') cutting_tool_material_id = fields.Many2one('sf.cutting.tool.material', string='刀具物料')
cutting_tool_type = fields.Char(string="刀具物料类型", related='cutting_tool_material_id.name', store=True) cutting_tool_type = fields.Char(string="刀具物料类型", related='cutting_tool_material_id.name', store=True)
cutting_tool_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='型号名称') cutting_tool_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='型号')
specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='物料号') specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='规格')
cutting_tool_type_id = fields.Many2one('sf.cutting.tool.type', string='类型', cutting_tool_type_id = fields.Many2one('sf.cutting.tool.type', string='类型',
domain="[('cutting_tool_material_id.name', '=', cutting_tool_type)]") domain="[('cutting_tool_material_id.name', '=', cutting_tool_type)]")
@@ -104,15 +104,6 @@ class ResProductMo(models.Model):
compaction_way_id = fields.Many2one('maintenance.equipment.image', compaction_way_id = fields.Many2one('maintenance.equipment.image',
'压紧方式', domain=[('type', '=', '压紧方式')]) '压紧方式', domain=[('type', '=', '压紧方式')])
name = fields.Char('产品名称', compute='_compute_tool_name', store=True, required=False)
@api.depends('cutting_tool_model_id', 'specification_id')
def _compute_tool_name(self):
for item in self:
if item.cutting_tool_model_id and item.specification_id:
name = '%s%s' % (item.cutting_tool_model_id.name, item.specification_id.name)
item.name = name
@api.onchange('cutting_tool_model_id') @api.onchange('cutting_tool_model_id')
def _onchange_cutting_tool_model_id(self): def _onchange_cutting_tool_model_id(self):
for item in self: for item in self:
@@ -539,7 +530,6 @@ class ResProductMo(models.Model):
# bfm下单 # bfm下单
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True) manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
part_number = fields.Char(string='零件图号', readonly=True)
@api.constrains('tool_length') @api.constrains('tool_length')
def _check_tool_length_size(self): def _check_tool_length_size(self):
@@ -636,7 +626,6 @@ class ResProductMo(models.Model):
'model_remark': item['remark'], 'model_remark': item['remark'],
'default_code': '%s-%s' % (order_number, i), 'default_code': '%s-%s' % (order_number, i),
'manual_quotation': item['manual_quotation'] or False, 'manual_quotation': item['manual_quotation'] or False,
'part_number': item.get('part_number') or '',
'active': True, 'active': True,
} }
copy_product_id.sudo().write(vals) copy_product_id.sudo().write(vals)
@@ -732,10 +721,6 @@ class ResProductMo(models.Model):
logging.info('create-model_file:%s' % len(vals['model_file'])) logging.info('create-model_file:%s' % len(vals['model_file']))
self._sanitize_vals(vals) self._sanitize_vals(vals)
templates = super(ResProductMo, self).create(vals_list) templates = super(ResProductMo, self).create(vals_list)
# 产品名称唯一性校验
for item in templates:
if len(self.search([('name', '=', item.name)])) > 1:
raise ValidationError('产品名称【%s】已存在' % item.name)
if "create_product_product" not in self._context: if "create_product_product" not in self._context:
templates._create_variant_ids() templates._create_variant_ids()

View File

@@ -1,10 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import base64 import base64
import qrcode import qrcode
from itertools import groupby
from collections import defaultdict, namedtuple from collections import defaultdict, namedtuple
import logging import logging
import io
import json import json
from re import split as regex_split from re import split as regex_split
from re import findall as regex_findall from re import findall as regex_findall
@@ -206,37 +204,61 @@ class StockRule(models.Model):
# self.env['stock.move'].sudo().create(productions._get_moves_raw_values()) # self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
self.env['stock.move'].sudo().create(productions._get_moves_finished_values()) self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
'''
创建工单
'''
productions._create_workorder()
productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \ productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \
( (
p.move_dest_ids.procure_method != 'make_to_order' and not p.move_dest_ids.procure_method != 'make_to_order' and not
p.move_raw_ids and not p.workorder_ids)).action_confirm() p.move_raw_ids and not p.workorder_ids)).action_confirm()
'''
创建工单
'''
# productions._create_workorder()
#
grouped_product_ids = {k: list(g) for k, g in groupby(productions, key=lambda x: x.product_id.id)}
# 初始化一个字典来存储每个product_id对应的生产订单名称列表
product_id_to_production_names = {}
# 对于每个product_id获取其所有生产订单的名称
for product_id, productions in grouped_product_ids.items():
# 为同一个product_id创建一个生产订单名称列表
product_id_to_production_names[product_id] = [production.name for production in productions]
for production_item in productions: for production_item in productions:
if production_item.product_id.id in product_id_to_production_names: process_parameter_workorder = self.env['mrp.workorder'].search(
# # 同一个产品多个制造订单对应一个编程单和模型库 [('surface_technics_parameters_id', '!=', False), ('production_id', '=', production_item.id),
# # 只调用一次fetchCNC并将所有生产订单的名称作为字符串传递 ('is_subcontract', '=', True)])
if not production_item.programming_no: if process_parameter_workorder:
production_programming = self.env['mrp.production'].search( is_pick = False
[('product_id.id', '=', production_item.product_id.id), consecutive_workorders = []
('origin', '=', production_item.origin)], m = 0
limit=1, order='id asc') sorted_workorders = sorted(process_parameter_workorder, key=lambda w: w.id)
if not production_programming.programming_no: for i in range(len(sorted_workorders) - 1):
production_item.fetchCNC( if m == 0:
', '.join(product_id_to_production_names[production_item.product_id.id])) is_pick = False
if sorted_workorders[i].supplier_id.id == sorted_workorders[i + 1].supplier_id.id and \
sorted_workorders[i].is_subcontract == sorted_workorders[i + 1].is_subcontract and \
sorted_workorders[i].id == sorted_workorders[i + 1].id - 1:
if sorted_workorders[i] not in consecutive_workorders:
consecutive_workorders.append(sorted_workorders[i])
consecutive_workorders.append(sorted_workorders[i + 1])
m += 1
continue
else: else:
production_item.write({'programming_no': production_programming.programming_no, if m == len(consecutive_workorders) - 1 and m != 0:
'programming_state': '编程中'}) self.env['stock.picking'].create_outcontract_picking(consecutive_workorders,
production_item)
if sorted_workorders[i] in consecutive_workorders:
is_pick = True
consecutive_workorders = []
m = 0
# 当前面的连续工序生成对应的外协出入库单再生成当前工序的外协出入库单
if is_pick is False:
self.env['stock.picking'].create_outcontract_picking(sorted_workorders[i],
production_item)
if m == len(consecutive_workorders) - 1 and m != 0:
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders,
production_item)
if sorted_workorders[i] in consecutive_workorders:
is_pick = True
consecutive_workorders = []
m = 0
if m == len(consecutive_workorders) - 1 and m != 0:
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production_item)
if is_pick is False and m == 0:
if len(sorted_workorders) == 1:
self.env['stock.picking'].create_outcontract_picking(sorted_workorders, production_item)
else:
self.env['stock.picking'].create_outcontract_picking(sorted_workorders[i], production_item)
for production in productions: for production in productions:
''' '''
@@ -609,8 +631,8 @@ class ReStockMove(models.Model):
'reserved_uom_qty': 1.0, 'reserved_uom_qty': 1.0,
'lot_id': purchase.picking_ids.move_line_ids.lot_id.id, 'lot_id': purchase.picking_ids.move_line_ids.lot_id.id,
'company_id': self.company_id.id, 'company_id': self.company_id.id,
# 'workorder_id': '' if not sorted_workorders else sorted_workorders.id, 'workorder_id': '' if not sorted_workorders else sorted_workorders.id,
# 'production_id': '' if not sorted_workorders else sorted_workorders.production_id.id, 'production_id': '' if not sorted_workorders else sorted_workorders.production_id.id,
'state': 'assigned', 'state': 'assigned',
} }
@@ -646,14 +668,12 @@ class ReStockMove(models.Model):
else: else:
view = self.env.ref('stock.view_stock_move_nosuggest_operations') view = self.env.ref('stock.view_stock_move_nosuggest_operations')
if self.state == "assigned": if self.product_id.tracking == "serial" and self.state == "assigned":
if self.product_id.tracking == "serial": print(self.origin)
if self.product_id.categ_id.name == '刀具': if self.product_id.categ_id.name == '刀具':
self.next_serial = self._get_tool_next_serial(self.company_id, self.product_id, self.origin) self.next_serial = self._get_tool_next_serial(self.company_id, self.product_id, self.origin)
else: else:
self.next_serial = self.env['stock.lot']._get_next_serial(self.company_id, self.product_id) self.next_serial = self.env['stock.lot']._get_next_serial(self.company_id, self.product_id)
elif self.product_id.tracking == "lot":
self._put_tool_lot(self.company_id, self.product_id, self.origin)
return { return {
'name': _('Detailed Operations'), 'name': _('Detailed Operations'),
@@ -678,58 +698,6 @@ class ReStockMove(models.Model):
), ),
} }
def put_move_line(self):
"""
确认订单时,自动分配序列号
"""
if self.product_id.tracking == "serial":
if self.product_id.categ_id.name == '刀具':
self.next_serial = self._get_tool_next_serial(self.company_id, self.product_id, self.origin)
else:
self.next_serial = self.env['stock.lot']._get_next_serial(self.company_id, self.product_id)
self._generate_serial_numbers()
for item in self.move_line_nosuggest_ids:
if item.lot_name:
lot_name = item.lot_name
if item.product_id.categ_id.name == '坯料':
lot_name = lot_name.split('[', 1)[0]
item.lot_qr_code = self.compute_lot_qr_code(lot_name)
def _put_tool_lot(self, company, product, origin):
if product.tracking == "lot" and self.product_id.categ_id.name == '刀具':
if not self.move_line_nosuggest_ids:
lot_code = '%s-%s-%s' % ('%s-T-DJWL-%s' % (
product.cutting_tool_model_id.code.split('-')[0], product.cutting_tool_material_id.code),
datetime.now().strftime("%Y%m%d"), origin)
move_line_ids = self.env['stock.move.line'].sudo().search([('lot_name', 'like', lot_code)], limit=1,
order='id desc')
if not move_line_ids:
lot_code = '%s-001' % lot_code
else:
lot_code = '%s-%03d' % (lot_code, int(move_line_ids.lot_name[-3:]) + 1)
lot_names = self.env['stock.lot'].generate_lot_names(lot_code, 1)
move_lines_commands = self._generate_serial_move_line_commands_tool_lot(lot_names)
self.write({'move_line_nosuggest_ids': move_lines_commands})
for item in self.move_line_nosuggest_ids:
if item.lot_name:
item.lot_qr_code = self.compute_lot_qr_code(item.lot_name)
def compute_lot_qr_code(self, lot_name):
qr = qrcode.QRCode(
version=1,
error_correction=qrcode.constants.ERROR_CORRECT_L,
box_size=10,
border=4,
)
qr.add_data(lot_name)
qr.make(fit=True)
img = qr.make_image(fill_color="black", back_color="white")
buffer = io.BytesIO()
img.save(buffer, format="PNG")
binary_data = buffer.getvalue()
data = base64.b64encode(binary_data).decode() # 确保返回的是字符串形式的数据
return data
def _get_tool_next_serial(self, company, product, origin): def _get_tool_next_serial(self, company, product, origin):
"""Return the next serial number to be attributed to the product.""" """Return the next serial number to be attributed to the product."""
if product.tracking == "serial": if product.tracking == "serial":
@@ -743,67 +711,6 @@ class ReStockMove(models.Model):
else: else:
return "%s-T-%s-%s-%03d" % (split_codes[0], origin, product.specification_id.name, 1) return "%s-T-%s-%s-%03d" % (split_codes[0], origin, product.specification_id.name, 1)
def _generate_serial_move_line_commands_tool_lot(self, lot_names, origin_move_line=None):
"""Return a list of commands to update the move lines (write on
existing ones or create new ones).
Called when user want to create and assign multiple serial numbers in
one time (using the button/wizard or copy-paste a list in the field).
:param lot_names: A list containing all serial number to assign.
:type lot_names: list
:param origin_move_line: A move line to duplicate the value from, default to None
:type origin_move_line: record of :class:`stock.move.line`
:return: A list of commands to create/update :class:`stock.move.line`
:rtype: list
"""
self.ensure_one()
# Select the right move lines depending of the picking type configuration.
move_lines = self.env['stock.move.line']
if self.picking_type_id.show_reserved:
move_lines = self.move_line_ids.filtered(lambda ml: not ml.lot_id and not ml.lot_name)
else:
move_lines = self.move_line_nosuggest_ids.filtered(lambda ml: not ml.lot_id and not ml.lot_name)
loc_dest = origin_move_line and origin_move_line.location_dest_id
move_line_vals = {
'picking_id': self.picking_id.id,
'location_id': self.location_id.id,
'product_id': self.product_id.id,
'product_uom_id': self.product_id.uom_id.id,
'qty_done': self.product_uom_qty,
}
if origin_move_line:
# `owner_id` and `package_id` are taken only in the case we create
# new move lines from an existing move line. Also, updates the
# `qty_done` because it could be usefull for products tracked by lot.
move_line_vals.update({
'owner_id': origin_move_line.owner_id.id,
'package_id': origin_move_line.package_id.id,
'qty_done': origin_move_line.qty_done or 1,
})
move_lines_commands = []
qty_by_location = defaultdict(float)
for lot_name in lot_names:
# We write the lot name on an existing move line (if we have still one)...
if move_lines:
move_lines_commands.append((1, move_lines[0].id, {
'lot_name': lot_name,
'qty_done': 1,
}))
qty_by_location[move_lines[0].location_dest_id.id] += 1
move_lines = move_lines[1:]
# ... or create a new move line with the serial name.
else:
loc = loc_dest or self.location_dest_id._get_putaway_strategy(self.product_id, quantity=1,
packaging=self.product_packaging_id,
additional_qty=qty_by_location)
move_line_cmd = dict(move_line_vals, lot_name=lot_name, location_dest_id=loc.id)
move_lines_commands.append((0, 0, move_line_cmd))
qty_by_location[loc.id] += 1
return move_lines_commands
class ReStockQuant(models.Model): class ReStockQuant(models.Model):
_inherit = 'stock.quant' _inherit = 'stock.quant'

View File

@@ -1,9 +1,8 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_sf_cnc_processing_group_sf_mrp_user,sf_cnc_processing,model_sf_cnc_processing,sf_base.group_sf_mrp_user,1,0,0,0 access_sf_cnc_processing_group_sf_mrp_user,sf_cnc_processing,model_sf_cnc_processing,sf_base.group_sf_mrp_user,1,0,0,0
access_sf_cnc_processing_manager,sf_cnc_processing,model_sf_cnc_processing,sf_base.group_sf_mrp_manager,1,1,1,0 access_sf_cnc_processing_manager,sf_cnc_processing,model_sf_cnc_processing,sf_base.group_sf_mrp_manager,1,1,1,0
access_sf_cmm_program_group_sf_mrp_user,sf_cmm_program_group_sf_mrp_user,model_sf_cmm_program,sf_base.group_sf_mrp_user,1,0,0,0 access_sf_cmm_program_group_sf_mrp_user_group_sf_mrp_user,sf_cmm_program_group_sf_mrp_user,model_sf_cmm_program,sf_base.group_sf_mrp_user,1,0,0,0
access_sf_cmm_program_group_sf_mrp_manager,sf_cmm_program_group_sf_mrp_manager,model_sf_cmm_program,sf_base.group_sf_mrp_manager,1,0,0,0 access_sf_cmm_program_group_sf_mrp_manager,sf_cmm_program_group_sf_mrp_manager,model_sf_cmm_program,sf_base.group_sf_mrp_manager,1,0,0,0
access_sf_cmm_program_admin,sf_cmm_program_admin,model_sf_cmm_program,base.group_system,1,1,1,1
access_sf_model_type_group_sf_mrp_user,sf_model_type,model_sf_model_type,sf_base.group_sf_mrp_user,1,0,0,0 access_sf_model_type_group_sf_mrp_user,sf_model_type,model_sf_model_type,sf_base.group_sf_mrp_user,1,0,0,0
access_sf_model_type_admin,sf_model_type_admin,model_sf_model_type,base.group_system,1,1,1,0 access_sf_model_type_admin,sf_model_type_admin,model_sf_model_type,base.group_system,1,1,1,0
access_sf_model_type_manager,sf_model_type,model_sf_model_type,sf_base.group_sf_mrp_manager,1,1,1,0 access_sf_model_type_manager,sf_model_type,model_sf_model_type,sf_base.group_sf_mrp_manager,1,1,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_sf_cnc_processing_group_sf_mrp_user sf_cnc_processing model_sf_cnc_processing sf_base.group_sf_mrp_user 1 0 0 0
3 access_sf_cnc_processing_manager sf_cnc_processing model_sf_cnc_processing sf_base.group_sf_mrp_manager 1 1 1 0
4 access_sf_cmm_program_group_sf_mrp_user access_sf_cmm_program_group_sf_mrp_user_group_sf_mrp_user sf_cmm_program_group_sf_mrp_user model_sf_cmm_program sf_base.group_sf_mrp_user 1 0 0 0
5 access_sf_cmm_program_group_sf_mrp_manager sf_cmm_program_group_sf_mrp_manager model_sf_cmm_program sf_base.group_sf_mrp_manager 1 0 0 0
access_sf_cmm_program_admin sf_cmm_program_admin model_sf_cmm_program base.group_system 1 1 1 1
6 access_sf_model_type_group_sf_mrp_user sf_model_type model_sf_model_type sf_base.group_sf_mrp_user 1 0 0 0
7 access_sf_model_type_admin sf_model_type_admin model_sf_model_type base.group_system 1 1 1 0
8 access_sf_model_type_manager sf_model_type model_sf_model_type sf_base.group_sf_mrp_manager 1 1 1 0

View File

@@ -7,9 +7,9 @@
<field name="model">sf.agv.site</field> <field name="model">sf.agv.site</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree editable="bottom"> <tree editable="bottom">
<field name="name" required="1" attrs="{'readonly': [('id', '!=', False)]}"/> <field name="name" required="1"/>
<field name="owning_region" required="1" attrs="{'readonly': [('id', '!=', False)]}"/> <field name="owning_region" required="1"/>
<field name="state" required="1" attrs="{'readonly': [('id', '!=', False)]}"/> <field name="state" required="1"/>
<field name="divide_the_work" required="1"/> <field name="divide_the_work" required="1"/>
</tree> </tree>
</field> </field>
@@ -34,14 +34,12 @@
<field name="model">sf.agv.task.route</field> <field name="model">sf.agv.task.route</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree editable="bottom"> <tree editable="bottom">
<field name="name" required="1" attrs="{'readonly': [('id', '!=', False)]}"/> <field name="name" required="1"/>
<field name="type" readonly="1" string="任务类型"/> <field name="type" readonly="1" string="任务类型"/>
<field name="route_type" string="类型" required="1" attrs="{'readonly': [('id', '!=', False)]}"/> <field name="route_type" string="类型" required="1"/>
<field name="start_site_id" required="1" options="{'no_create': True}" string="起点接驳站" <field name="start_site_id" required="1" options="{'no_create': True}" string="起点接驳站"/>
attrs="{'readonly': [('id', '!=', False)]}"/>
<field name="end_site_id" required="1" options="{'no_create': True}" string="终点接驳站"/> <field name="end_site_id" required="1" options="{'no_create': True}" string="终点接驳站"/>
<field name="destination_production_line_id" required="1" options="{'no_create': True}" <field name="destination_production_line_id" required="1" options="{'no_create': True}"/>
attrs="{'readonly': [('id', '!=', False)]}"/>
</tree> </tree>
</field> </field>
</record> </record>
@@ -75,8 +73,7 @@
<field name="model">center_control.interface.log</field> <field name="model">center_control.interface.log</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="Logs"> <search string="Logs">
<field name="name" filter_domain="[('name','ilike', self)]"/> <field name="name"/>
<field name="content" filter_domain="[('content','ilike', self)]"/>
<group expand="0" string="分组"> <group expand="0" string="分组">
<field name="interface_call_date"/> <field name="interface_call_date"/>
</group> </group>

View File

@@ -62,17 +62,16 @@
<field name="inherit_id" ref="mrp.mrp_production_form_view"/> <field name="inherit_id" ref="mrp.mrp_production_form_view"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='state']" position="attributes"> <xpath expr="//field[@name='state']" position="attributes">
<!-- <attribute name="statusbar_visible">draft,confirmed,progress,pending_processing,completed,done --> <!-- <attribute name="statusbar_visible">draft,confirmed,progress,pending_processing,completed,done -->
<!-- </attribute> --> <!-- </attribute> -->
<attribute name="statusbar_visible"> <attribute name="statusbar_visible">progress,pending_cam,pending_processing,pending_era_cam,completed,done
progress,pending_cam,pending_processing,pending_era_cam,completed,done
</attribute> </attribute>
</xpath> </xpath>
<xpath expr="//sheet//group//group[2]//label" position="before"> <xpath expr="//sheet//group//group[2]//label" position="before">
<!-- <field name="process_state"/> --> <!-- <field name="process_state"/> -->
<field name="state"/> <field name="state"/>
<!-- <field name="process_state"/> --> <!-- <field name="process_state"/> -->
</xpath> </xpath>
<xpath expr="//sheet//group//group//div[3]" position="after"> <xpath expr="//sheet//group//group//div[3]" position="after">
@@ -88,7 +87,7 @@
<xpath expr="//field[@name='user_id']" position="after"> <xpath expr="//field[@name='user_id']" position="after">
<field name="production_line_id" readonly="1"/> <field name="production_line_id" readonly="1"/>
<field name="production_line_state" readonly="1"/> <field name="production_line_state" readonly="1"/>
<field name="part_number" string="成品的零件图号"/> <field name="part_number"/>
<field name="part_drawing"/> <field name="part_drawing"/>
</xpath> </xpath>
<xpath expr="//header//button[@name='action_cancel']" position="replace"> <xpath expr="//header//button[@name='action_cancel']" position="replace">
@@ -282,7 +281,7 @@
<field name="routing_type" invisible="True"/> <field name="routing_type" invisible="True"/>
<button name="button_start" type="object" string="开始" class="btn-success" <button name="button_start" type="object" string="开始" class="btn-success"
attrs="{'invisible': ['|', '|', '|','|', ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel')), ('is_user_working', '!=', False), ('routing_type', '=', 'CNC加工')]}" attrs="{'invisible': ['|', '|', '|','|', ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel')), ('is_user_working', '!=', False), ('routing_type', '=', 'CNC加工')]}"
groups="sf_base.group_sf_mrp_user" confirm="是否确认开始?"/> groups="sf_base.group_sf_mrp_user"/>
</xpath> </xpath>
<xpath expr="//tree//button[@name='button_pending']" position="replace"> <xpath expr="//tree//button[@name='button_pending']" position="replace">
<button name="button_pending" type="object" string="Pause" class="btn-warning" <button name="button_pending" type="object" string="Pause" class="btn-warning"
@@ -292,8 +291,7 @@
<xpath expr="//tree//button[@name='button_finish']" position="replace"> <xpath expr="//tree//button[@name='button_finish']" position="replace">
<button name="button_finish" type="object" string="Done" class="btn-success" <button name="button_finish" type="object" string="Done" class="btn-success"
attrs="{'invisible': ['|', '|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False), ('routing_type', '=', 'CNC加工')]}" attrs="{'invisible': ['|', '|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False), ('routing_type', '=', 'CNC加工')]}"
groups="sf_base.group_sf_mrp_user" groups="sf_base.group_sf_mrp_user"/>
confirm="是否确认完成?"/>
</xpath> </xpath>
<xpath expr="//tree//button[@name='%(mrp.act_mrp_block_workcenter_wo)d']" position="replace"> <xpath expr="//tree//button[@name='%(mrp.act_mrp_block_workcenter_wo)d']" position="replace">
<button name="%(mrp.act_mrp_block_workcenter_wo)d" type="action" string="Block" <button name="%(mrp.act_mrp_block_workcenter_wo)d" type="action" string="Block"
@@ -311,10 +309,10 @@
<button name="action_open_wizard" type="object" icon="fa-external-link" class="oe_edit_only" <button name="action_open_wizard" type="object" icon="fa-external-link" class="oe_edit_only"
title="Open Work Order" title="Open Work Order"
context="{'default_workcenter_id': workcenter_id}" groups="sf_base.group_sf_mrp_user"/> context="{'default_workcenter_id': workcenter_id}" groups="sf_base.group_sf_mrp_user"/>
<!-- ======= --> <!-- ======= -->
<!-- <button name="button_start" type="object" string="开始" class="btn-success" --> <!-- <button name="button_start" type="object" string="开始" class="btn-success" -->
<!-- attrs="{'invisible': ['|', '|', '|', ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel')), ('is_user_working', '!=', False)]}" --> <!-- attrs="{'invisible': ['|', '|', '|', ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel')), ('is_user_working', '!=', False)]}" -->
<!-- groups="sf_base.group_sf_mrp_user"/> --> <!-- groups="sf_base.group_sf_mrp_user"/> -->
</xpath> </xpath>
<xpath expr="//tree//button[@name='button_pending']" position="replace"> <xpath expr="//tree//button[@name='button_pending']" position="replace">
<button name="button_pending" type="object" string="暂停" class="btn-warning" <button name="button_pending" type="object" string="暂停" class="btn-warning"
@@ -324,7 +322,7 @@
<xpath expr="//tree//button[@name='button_finish']" position="replace"> <xpath expr="//tree//button[@name='button_finish']" position="replace">
<button name="button_finish" type="object" string="完成" class="btn-success" <button name="button_finish" type="object" string="完成" class="btn-success"
attrs="{'invisible': ['|', '|','|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False), ('routing_type', '=', 'CNC加工')]}" attrs="{'invisible': ['|', '|','|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False), ('routing_type', '=', 'CNC加工')]}"
groups="sf_base.group_sf_mrp_user" confirm="是否确认完成?"/> groups="sf_base.group_sf_mrp_user"/>
</xpath> </xpath>
<xpath expr="//tree//button[@name='%(mrp.act_mrp_block_workcenter_wo)d']" position="replace"> <xpath expr="//tree//button[@name='%(mrp.act_mrp_block_workcenter_wo)d']" position="replace">
<button name="%(mrp.act_mrp_block_workcenter_wo)d" type="action" string="阻塞" <button name="%(mrp.act_mrp_block_workcenter_wo)d" type="action" string="阻塞"

View File

@@ -11,7 +11,7 @@
<field name="name" decoration-success="is_subcontract" decoration-bf="is_subcontract"/> <field name="name" decoration-success="is_subcontract" decoration-bf="is_subcontract"/>
</field> </field>
<field name="name" position="before"> <field name="name" position="before">
<field name="sequence" optional="hide"/> <field name="sequence"/>
<field name='user_permissions' invisible="1"/> <field name='user_permissions' invisible="1"/>
</field> </field>
<field name="name" position="after"> <field name="name" position="after">
@@ -19,13 +19,6 @@
</field> </field>
<field name="state" position="after"> <field name="state" position="after">
<field name="work_state" optional="hide"/> <field name="work_state" optional="hide"/>
<field name="product_tmpl_name" invisible="1"/>
</field>
<field name="duration" position="replace">
<field name="duration" optional="hide"/>
</field>
<field name="workcenter_id" position="replace">
<field name="workcenter_id" optional="hide"/>
</field> </field>
<field name="product_id" position="after"> <field name="product_id" position="after">
<field name="equipment_id" optional="hide"/> <field name="equipment_id" optional="hide"/>
@@ -37,7 +30,7 @@
<field name="date_planned_start" string="计划开始日期" optional="show"/> <field name="date_planned_start" string="计划开始日期" optional="show"/>
</xpath> </xpath>
<xpath expr="//field[@name='date_planned_finished']" position="replace"> <xpath expr="//field[@name='date_planned_finished']" position="replace">
<field name="date_planned_finished" string="计划结束日期" optional="hide"/> <field name="date_planned_finished" string="计划结束日期" optional="show"/>
</xpath> </xpath>
<xpath expr="//button[@name='button_start']" position="attributes"> <xpath expr="//button[@name='button_start']" position="attributes">
<attribute name="attrs">{'invisible': ['|', '|', '|','|','|', ('production_state','in', ('draft', <attribute name="attrs">{'invisible': ['|', '|', '|','|','|', ('production_state','in', ('draft',
@@ -124,7 +117,6 @@
<field name='user_permissions' invisible="1"/> <field name='user_permissions' invisible="1"/>
<field name='name' invisible="1"/> <field name='name' invisible="1"/>
<field name='is_delivery' invisible="1"/> <field name='is_delivery' invisible="1"/>
<field name='is_send_program_again' invisible="1"/>
<!-- 工单form页面的开始停工按钮等 --> <!-- 工单form页面的开始停工按钮等 -->
<!-- <button name="button_start" type="object" string="开始" class="btn-success" --> <!-- <button name="button_start" type="object" string="开始" class="btn-success" -->
<!-- attrs="{'invisible': ['|', '|', ('production_state', 'not in', ('pending_processing', 'pending_cam', 'pending_era_cam')), ('state','!=','ready'), ('routing_type', 'not in', ('装夹预调', 'CNC加工', '解除装夹'))]}" --> <!-- attrs="{'invisible': ['|', '|', ('production_state', 'not in', ('pending_processing', 'pending_cam', 'pending_era_cam')), ('state','!=','ready'), ('routing_type', 'not in', ('装夹预调', 'CNC加工', '解除装夹'))]}" -->
@@ -159,12 +151,7 @@
<!-- groups="sf_base.group_sf_mrp_user" --> <!-- groups="sf_base.group_sf_mrp_user" -->
<!-- attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '!=', 'blocked'),('state','=','done')]}"/> --> <!-- attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '!=', 'blocked'),('state','=','done')]}"/> -->
<button name="button_workpiece_delivery" type="object" string="工件配送" class="btn-primary" <button name="button_workpiece_delivery" type="object" string="工件配送" class="btn-primary"
attrs="{'invisible': ['|','|',('routing_type','!=','装夹预调'),('is_delivery','=',True),('state','!=','done')]}"/> attrs="{'invisible': ['|',('routing_type','!=','装夹预调'),('is_delivery','=',True)]}"/>
<button name="button_send_program_again" type="object" string="重新下发NC程序" class="btn-primary"
confirm="是否确认重新下发NC程序"
groups="sf_base.group_sf_order_user,sf_base.group_sf_equipment_user"
attrs="{'invisible': ['|', '|', '|',('routing_type','!=','装夹预调'),('state','in',['done', 'cancel',
'progress']),('cnc_worksheet','=',False),('is_send_program_again','=',True)]}"/>
</xpath> </xpath>
<xpath expr="//page[1]" position="before"> <xpath expr="//page[1]" position="before">
<page string="开料要求" attrs='{"invisible": [("routing_type","!=","切割")]}'> <page string="开料要求" attrs='{"invisible": [("routing_type","!=","切割")]}'>
@@ -216,17 +203,17 @@
<field name="processing_panel" readonly="1" <field name="processing_panel" readonly="1"
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/> attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
<field name="equipment_id" <field name="equipment_id"
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割","装夹预调"))]}'/> attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
<field name="production_line_id" <field name="production_line_id"
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/> attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
<field name="production_line_state" <field name="production_line_state"
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割","装夹预调"))]}'/> attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
<!-- <field name="functional_fixture_id" --> <field name="functional_fixture_id"
<!-- attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/> --> attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
<!-- <field name="functional_fixture_code" force_save="1" --> <field name="functional_fixture_code" force_save="1"
<!-- attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/> --> attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
<!-- <field name="functional_fixture_type_id" --> <field name="functional_fixture_type_id"
<!-- attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/> --> attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
<field name="rfid_code" force_save="1" readonly="1" cache="True" <field name="rfid_code" force_save="1" readonly="1" cache="True"
attrs="{'invisible': [('rfid_code_old', '!=', False)]}"/> attrs="{'invisible': [('rfid_code_old', '!=', False)]}"/>
<field name="rfid_code_old" readonly="1" attrs="{'invisible': [('rfid_code_old', '=', False)]}"/> <field name="rfid_code_old" readonly="1" attrs="{'invisible': [('rfid_code_old', '=', False)]}"/>
@@ -294,26 +281,20 @@
<!-- </group>--> <!-- </group>-->
<group string="托盘"> <group string="托盘">
<field name="tray_serial_number" readonly="1" string="序列号"/> <field name="tray_serial_number" readonly="1" string="序列号"/>
</group>
</group>
<group>
<group>
<field name="tray_product_id" readonly="1" string="名称"/> <field name="tray_product_id" readonly="1" string="名称"/>
<field name="tray_brand_id" readonly="1" string="品牌"/> <field name="tray_brand_id" readonly="1" string="品牌"/>
</group>
<group>
<field name="tray_type_id" readonly="1" string="类型"/> <field name="tray_type_id" readonly="1" string="类型"/>
<field name="tray_model_id" readonly="1" string="型号"/> <field name="tray_model_id" readonly="1" string="型号"/>
</group> </group>
</group> </group>
<group string="加工图纸">
<!-- 隐藏加工图纸字段名 -->
<field name="processing_drawing" widget="pdf_viewer" string="" readonly="1"/>
</group>
<group string="预调程序信息"> <group string="预调程序信息">
<field name="preset_program_information" colspan="2" nolabel="1" <field name="preset_program_information" colspan="2" nolabel="1"
placeholder="如有预调程序信息请在此处输入....."/> placeholder="如有预调程序信息请在此处输入....."/>
</group> </group>
<group string="加工图纸">
<!-- 隐藏加工图纸字段名 -->
<field name="processing_drawing" widget="pdf_viewer" string=""/>
</group>
</page> </page>
<page string="前置三元检测定位参数" attrs='{"invisible": [("routing_type","!=","装夹预调")]}'> <page string="前置三元检测定位参数" attrs='{"invisible": [("routing_type","!=","装夹预调")]}'>
@@ -496,13 +477,8 @@
<page string="后置三元检测" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'> <page string="后置三元检测" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
<group> <group>
<field name="test_results" attrs='{"invisible":[("results","!=",False)]}'/> <field name="test_results" attrs='{"invisible":[("results","!=",False)]}'/>
<!-- <field name="is_remanufacture" attrs='{"invisible":[("test_results","!=","报废")]}'/>--> <field name="is_remanufacture" attrs='{"invisible":[("test_results","!=","报废")]}'/>
<!-- <field name="is_fetchcnc"--> <field name="results" readonly="1" attrs='{"invisible":[("results","!=","合格")]}'/>
<!-- attrs='{"invisible":["|",("test_results","=","合格"),("is_remanufacture","=",False)]}'/>-->
<!-- <field name="reason"-->
<!-- attrs='{"required":[("test_results","!=","合格")],"invisible":[("test_results","=","合格")]}'/>-->
<!-- <field name="detailed_reason" attrs='{"invisible":[("test_results","=","合格")]}'/>-->
<!-- <field name="results" readonly="1" attrs='{"invisible":[("results","!=","合格")]}'/>-->
<field name="detection_report" attrs='{"invisible":[("results","!=",False)]}' <field name="detection_report" attrs='{"invisible":[("results","!=",False)]}'
widget="pdf_viewer"/> widget="pdf_viewer"/>
</group> </group>
@@ -515,11 +491,11 @@
</xpath> </xpath>
<xpath expr="//page[1]" position="before"> <xpath expr="//page[1]" position="before">
<page string="CNC程序" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'> <page string="CNC程序" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
<field name="cnc_ids" widget="one2many" string="工作程序" default_order="sequence_number,id" <field name="cnc_ids" widget="one2many" string="工作程序" default_order="sequence_number,id">
readonly="1"> <tree decoration-success="button_state" decoration-bf="button_state">
<tree>
<field name="sequence_number"/> <field name="sequence_number"/>
<field name="program_name"/> <field name="program_name"/>
<field name="cnc_id" string="文件"/>
<field name="cutting_tool_name"/> <field name="cutting_tool_name"/>
<field name="cutting_tool_no"/> <field name="cutting_tool_no"/>
<field name="processing_type"/> <field name="processing_type"/>
@@ -529,10 +505,8 @@
<field name="cutting_tool_extension_length"/> <field name="cutting_tool_extension_length"/>
<field name="cutting_tool_handle_type"/> <field name="cutting_tool_handle_type"/>
<field name="estimated_processing_time"/> <field name="estimated_processing_time"/>
<field name="program_path"/>
<field name="program_create_date"/>
<field name="remark"/> <field name="remark"/>
<!-- <field name="button_state" invisible="1"/>--> <field name="button_state" invisible="1"/>
</tree> </tree>
</field> </field>
<group> <group>
@@ -540,12 +514,20 @@
</group> </group>
</page> </page>
<page string="CMM程序" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'> <page string="CMM程序" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
<field name="cmm_ids" widget="one2many" string="CMM程序" readonly="1"> <field name="cmm_ids" widget="one2many" string="CMM程序">
<tree> <tree>
<field name="sequence_number"/> <field name="sequence_number"/>
<field name="program_name"/> <field name="program_name"/>
<field name="program_path"/> <field name="cmm_id" string="文件"/>
<field name="program_create_date"/> <field name="cutting_tool_name"/>
<field name="cutting_tool_no"/>
<field name="processing_type"/>
<field name="margin_x_y"/>
<field name="margin_z"/>
<field name="depth_of_processing_z"/>
<field name="cutting_tool_extension_length"/>
<field name="cutting_tool_handle_type"/>
<field name="estimated_processing_time"/>
<field name="remark"/> <field name="remark"/>
</tree> </tree>
</field> </field>
@@ -575,9 +557,9 @@
</div> </div>
</xpath> </xpath>
<xpath expr="//form//sheet//group//group//div[3]" position="after"> <xpath expr="//form//sheet//group//group//div[3]" position="after">
<field name="is_ok" attrs='{"invisible": [("routing_type","=","装夹预调")]}'/> <field name="is_ok"/>
<field name="processing_user_id" attrs='{"invisible": [("routing_type","=","装夹预调")]}'/> <field name="processing_user_id"/>
<field name="inspection_user_id" attrs='{"invisible": [("routing_type","=","装夹预调")]}'/> <field name="inspection_user_id"/>
<field name="save_name" widget="CopyClipboardChar" <field name="save_name" widget="CopyClipboardChar"
attrs="{'invisible':[('routing_type','!=','装夹预调')]}"/> attrs="{'invisible':[('routing_type','!=','装夹预调')]}"/>
<label for="material_length" string="物料尺寸"/> <label for="material_length" string="物料尺寸"/>
@@ -591,25 +573,11 @@
<label for="material_height" string="高"/> <label for="material_height" string="高"/>
<field name="material_height" class="o_address_zip"/> <field name="material_height" class="o_address_zip"/>
</div> </div>
<field name="part_number" string="成品的零件图号"/> <field name="part_number"/>
<field name="rfid_code" force_save="1" readonly="1" cache="True"
attrs="{'invisible': [('rfid_code_old', '!=', False)]}"/>
<field name="rfid_code_old" readonly="1" attrs="{'invisible': [('rfid_code_old', '=', False)]}"/>
</xpath> </xpath>
</field> </field>
</record> </record>
<record id="workcenter_form_workorder_search" model="ir.ui.view">
<field name="name">custom.workorder.search</field>
<field name="model">mrp.workorder</field>
<field name="inherit_id" ref="mrp.view_mrp_production_work_order_search"/>
<field name="arch" type="xml">
<field name="product_id" position="after">
<field name="part_number" string="成品零件图号"/>
</field>
</field>
</record>
<record id="mrp_workorder_action_schedule" model="ir.actions.act_window"> <record id="mrp_workorder_action_schedule" model="ir.actions.act_window">
<field name="name">工单</field> <field name="name">工单</field>
<field name="type">ir.actions.act_window</field> <field name="type">ir.actions.act_window</field>
@@ -636,7 +604,7 @@
<field name="name">工件配送</field> <field name="name">工件配送</field>
<field name="model">sf.workpiece.delivery</field> <field name="model">sf.workpiece.delivery</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="工件配送" class="center" create="0" delete="0"> <tree string="工件配送" editable="bottom" class="center" create="0" delete="0">
<header> <header>
<button name="button_delivery" type="object" string="配送" class="oe_highlight"/> <button name="button_delivery" type="object" string="配送" class="oe_highlight"/>
</header> </header>
@@ -644,7 +612,6 @@
decoration-success="status == '已配送'" decoration-success="status == '已配送'"
decoration-warning="status == '待下发'" decoration-warning="status == '待下发'"
decoration-danger="status == '待配送'"/> decoration-danger="status == '待配送'"/>
<field name="name"/>
<field name="production_id"/> <field name="production_id"/>
<field name="type" readonly="1"/> <field name="type" readonly="1"/>
<field name="production_line_id" options="{'no_create': True}" readonly="1"/> <field name="production_line_id" options="{'no_create': True}" readonly="1"/>
@@ -661,58 +628,13 @@
</field> </field>
</record> </record>
<record id="sf_workpiece_delivery_form" model="ir.ui.view">
<field name="name">工件配送</field>
<field name="model">sf.workpiece.delivery</field>
<field name="arch" type="xml">
<form string="工件配送" create="0" delete="0">
<header>
<field name="status" widget="statusbar"/>
<button name="button_delivery" type="object" string="配送" class="oe_highlight"
attrs="{'invisible': [('status', '!=', '待下发')]}"/>
</header>
<sheet>
<div class="oe_title">
<h1>
<field name="name" readonly="1"/>
</h1>
</div>
<group>
<group string="基本信息">
<field name="production_id"/>
<field name="type" readonly="1"/>
<field name="production_line_id" options="{'no_create': True}" readonly="1"/>
<field name="is_cnc_program_down" readonly="1"/>
<!-- <field name="rfid_code"/>-->
</group>
<group string="配送信息">
<field name="route_id" options="{'no_create': True}"
domain="[('route_type','in',['上产线','下产线'])]"/>
<field name="feeder_station_start_id" readonly="1" force_save="1"/>
<field name="feeder_station_destination_id" readonly="1" force_save="1"/>
<field name="task_delivery_time" readonly="1"/>
<field name="task_completion_time" readonly="1"/>
<field name="delivery_duration" widget="float_time"/>
</group>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="activity_ids"/>
<field name="message_ids" options="{'post_refresh': 'recipients'}"/>
</div>
</form>
</field>
</record>
<record id="sf_workpiece_delivery_search" model="ir.ui.view"> <record id="sf_workpiece_delivery_search" model="ir.ui.view">
<field name="name">工件配送</field> <field name="name">工件配送</field>
<field name="model">sf.workpiece.delivery</field> <field name="model">sf.workpiece.delivery</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="工件配送"> <search string="工件配送">
<filter name="filter_to_be_issued" string="待下发" domain="[('status', 'in', ['待下发'])]"/> <filter string="上产线" name="on_up" domain="[('type', '=', '上产线')]"/>
<filter name="filter_waiting_delivery" string="待配送" domain="[('status', 'in', ['待配送'])]"/> <filter string="下产线" name="on_down" domain="[('type', '=', '下产线' )]"/>
<filter name="filter_delivered" string="已配送" domain="[('status', 'in', ['已配送'])]"/>
<field name="rfid_code"/> <field name="rfid_code"/>
<field name="production_id"/> <field name="production_id"/>
<field name="feeder_station_start_id"/> <field name="feeder_station_start_id"/>
@@ -734,10 +656,8 @@
<field name="name">工件配送</field> <field name="name">工件配送</field>
<field name="res_model">sf.workpiece.delivery</field> <field name="res_model">sf.workpiece.delivery</field>
<field name="search_view_id" ref="sf_workpiece_delivery_search"/> <field name="search_view_id" ref="sf_workpiece_delivery_search"/>
<field name="context">{'search_default_filter_to_be_issued': 1, <field name="context">{'search_default_on_up':1}</field>
'search_default_filter_waiting_delivery': 1} <field name="view_mode">tree,search</field>
</field>
<field name="view_mode">tree,form</field>
<field name="domain"> <field name="domain">
[('type','in',['上产线','下产线']),('workorder_state','=','done'),('is_manual_work','=',false)] [('type','in',['上产线','下产线']),('workorder_state','=','done'),('is_manual_work','=',false)]
</field> </field>
@@ -750,39 +670,23 @@
<field name="model">sf.workpiece.delivery</field> <field name="model">sf.workpiece.delivery</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="工件配送" editable="bottom" class="center" delete="0" create="1"> <tree string="工件配送" editable="bottom" class="center" delete="0" create="1">
<!-- <header>--> <header>
<!-- <button name="button_delivery" type="object" string="配送" class="oe_highlight"/>--> <button name="button_delivery" type="object" string="配送" class="oe_highlight"/>
<!-- </header>--> </header>
<!-- <field name="name" string="路线名称" attrs="{'readonly': [('id', '!=', False)]}"--> <field name="name" string="路线名称" attrs="{'readonly': [('id', '!=', False)]}"
<!-- placeholder="例如:运送空料架路线:G01-A01" required="1" force_save="1"/>--> placeholder="例如:运送空料架路线:G01-A01" required="1" force_save="1"/>
<field name="route_id" options="{'no_create': True}" required="1" <field name="route_id" options="{'no_create': True}" required="1"
attrs="{'readonly': [('id', '!=', False)]}" domain="[('route_type', '=', '运送空料架')]" attrs="{'readonly': [('id', '!=', False)]}" domain="[('route_type', '=', '运送空料架')]"
force_save="1"/> force_save="1"/>
<field name="feeder_station_start_id" readonly="1" force_save="1"/> <field name="feeder_station_start_id" readonly="1" force_save="1"/>
<!-- <field name="type" readonly="1"/>--> <!-- <field name="type" readonly="1"/>-->
<field name="feeder_station_destination_id" readonly="1" force_save="1"/> <field name="feeder_station_destination_id" readonly="1" force_save="1"/>
<button name="button_delivery" type="object" string="配送" class="oe_highlight"/>
<button name="action_delivery_history" type="object" class="btn btn-link text-info" icon="fa-history" <button name="action_delivery_history" type="object" class="btn btn-link text-info" icon="fa-history"
string="历史"/> string="历史"/>
</tree> </tree>
</field> </field>
</record> </record>
<!-- <record id="sf_workpiece_delivery_empty_racks_kanban" model="ir.ui.view">-->
<!-- <field name="name">sf.workpiece.delivery.view.kanban</field>-->
<!-- <field name="model">sf.workpiece.delivery</field>-->
<!-- <field name="arch" type="xml">-->
<!-- <kanban>-->
<!-- <field name="route_id"/>-->
<!-- <field name="feeder_station_start_id"/>-->
<!-- <field name="feeder_station_destination_id"/>-->
<!--&lt;!&ndash; <button name="button_delivery" type="object" string="配送" class="oe_highlight"/>&ndash;&gt;-->
<!--&lt;!&ndash; <button name="action_delivery_history" type="object" class="btn btn-link text-info" icon="fa-history"&ndash;&gt;-->
<!--&lt;!&ndash; string="历史"/>&ndash;&gt;-->
<!-- </kanban>-->
<!-- </field>-->
<!-- </record>-->
<record id="sf_workpiece_delivery_empty_racks_tree" model="ir.ui.view"> <record id="sf_workpiece_delivery_empty_racks_tree" model="ir.ui.view">
<field name="name">空料架配送</field> <field name="name">空料架配送</field>
<field name="model">sf.workpiece.delivery</field> <field name="model">sf.workpiece.delivery</field>
@@ -805,7 +709,6 @@
<field name="model">sf.workpiece.delivery</field> <field name="model">sf.workpiece.delivery</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="运送空料架"> <search string="运送空料架">
<filter name="filter_active" string="已归档" domain="[('active', '=', False)]"/>
<field name="route_id"/> <field name="route_id"/>
<field name="feeder_station_start_id"/> <field name="feeder_station_start_id"/>
<field name="feeder_station_destination_id"/> <field name="feeder_station_destination_id"/>

View File

@@ -41,8 +41,8 @@
<field name="model">stock.lot</field> <field name="model">stock.lot</field>
<field name="inherit_id" ref="stock.view_production_lot_tree"/> <field name="inherit_id" ref="stock.view_production_lot_tree"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='name']" position="after"> <xpath expr="//field[@name='create_date']" position="after">
<field name="rfid"/> <field name="rfid" invisible="1"/>
</xpath> </xpath>
</field> </field>
</record> </record>

View File

@@ -24,18 +24,20 @@ class Sf_Mrs_Connect(http.Controller):
ret = json.loads(datas) ret = json.loads(datas)
ret = json.loads(ret['result']) ret = json.loads(ret['result'])
logging.info('下发编程单:%s' % ret) logging.info('下发编程单:%s' % ret)
productions = request.env['mrp.production'].with_user( # 查询状态为进行中且类型为获取CNC加工程序的工单
cnc_production = request.env['mrp.production'].with_user(
request.env.ref("base.user_admin")).search([('name', '=', ret['production_order_no'].split(',')[0])])
cnc_program = request.env['mrp.production'].with_user(
request.env.ref("base.user_admin")).search( request.env.ref("base.user_admin")).search(
[('programming_no', '=', ret['programming_no'])]) [('programming_no', '=', cnc_production.programming_no), ('id', '!=', cnc_production.id)])
if productions: # cnc_program = request.env['mrp.production'].with_user(
# request.env.ref("base.user_admin")).search([('programming_no', '=', cnc_production.programming_no)])
logging.info('制造订单号:%s' % cnc_production.name)
if cnc_production:
# if ret['glb_file']:
# cnc_production.glb_file = base64.b64encode(ret['glb_file'])
# 拉取所有加工面的程序文件 # 拉取所有加工面的程序文件
for r in ret['processing_panel'].split(','): for r in ret['processing_panel']:
program_path_tmp_r = os.path.join('/tmp', ret['folder_name'], 'return', r)
files_r = os.listdir(program_path_tmp_r)
if files_r:
for file_name in files_r:
file_path = os.path.join(program_path_tmp_r, file_name)
os.remove(file_path)
download_state = request.env['sf.cnc.processing'].with_user( download_state = request.env['sf.cnc.processing'].with_user(
request.env.ref("base.user_admin")).download_file_tmp( request.env.ref("base.user_admin")).download_file_tmp(
ret['folder_name'], r) ret['folder_name'], r)
@@ -43,48 +45,38 @@ class Sf_Mrs_Connect(http.Controller):
res['status'] = -2 res['status'] = -2
res['message'] = '制造订单号为%s的CNC程序文件从FTP拉取失败' % (cnc_production.name) res['message'] = '制造订单号为%s的CNC程序文件从FTP拉取失败' % (cnc_production.name)
return json.JSONEncoder().encode(res) return json.JSONEncoder().encode(res)
for production in productions: logging.info('创建cnc工单')
if not production.workorder_ids: program_path_tmp = os.path.join('/tmp', ret['folder_name'], 'return', r)
production.product_id.model_processing_panel = ret['processing_panel'] # program_path_tmp = "C://Users//43484//Desktop//机企猫工作文档//其他//model_analysis"
production._create_workorder(ret) files = os.listdir(program_path_tmp)
else: cnc_processing_arr = []
for panel in ret['processing_panel'].split(','): for f in files:
# 查询状态为进行中且工序类型为CNC加工的工单 program_path = os.path.join(program_path_tmp, f)
cnc_workorder = production.workorder_ids.filtered( logging.info('cnc程序路径 :%s' % program_path)
lambda ac: ac.routing_type == 'CNC加工' and ac.state not in ['progress', 'done', if f.endswith(".doc"):
'cancel'] and ac.processing_panel == panel) # 插入cmm程序数据
if cnc_workorder: cmm_program = request.env['sf.cmm.program'].with_user(
if cnc_workorder.cnc_ids: request.env.ref("base.user_admin")).cmm_program_create(ret, program_path, program_path_tmp)
cnc_workorder.cmm_ids.sudo().unlink() cnc_processing = request.env['sf.cnc.processing'].with_user(
cnc_workorder.cnc_ids.sudo().unlink() request.env.ref("base.user_admin")).cnc_processing_create(cnc_production, ret, program_path,
request.env['sf.cam.work.order.program.knife.plan'].sudo().unlink_cam_plan( program_path_tmp)
production) logging.info('cnc_processing111:%s' % cnc_processing)
# program_path_tmp_panel = os.path.join('C://Users//43484//Desktop//fsdownload//test', if cnc_processing:
# panel) cnc_processing_arr.append(cnc_processing._json_cnc_processing(cnc_processing))
program_path_tmp_panel = os.path.join('/tmp', ret['folder_name'], 'return', panel) if (cnc_program and cnc_processing_arr) or (not cnc_program and cnc_processing_arr):
logging.info('program_path_tmp_panel:%s' % program_path_tmp_panel) logging.info('cnc_processing_arr:%s' % cnc_processing_arr)
files_panel = os.listdir(program_path_tmp_panel) if cnc_program and cnc_processing_arr:
if files_panel: cnc_program.write({'programming_state': '已编程', 'work_state': '已编程'})
for file in files_panel: cnc_program.workorder_ids.filtered(lambda b1: b1.routing_type == '装夹预调').write(
file_extension = os.path.splitext(file)[1] {'processing_drawing': cnc_production.workorder_ids.filtered(
logging.info('file_extension:%s' % file_extension) lambda b1: b1.routing_type == 'CNC加工').cnc_worksheet})
if file_extension.lower() == '.pdf': cnc_program.workorder_ids.filtered(lambda b: b.routing_type == 'CNC加工').write(
panel_file_path = os.path.join(program_path_tmp_panel, file) {'cnc_ids': cnc_processing_arr, 'cnc_worksheet': cnc_production.workorder_ids.filtered(
logging.info('panel_file_path:%s' % panel_file_path) lambda b: b.routing_type == 'CNC加工').cnc_worksheet})
cnc_workorder.write( cnc_program |= cnc_production
{'is_send_program_again': False, if not cnc_program and cnc_processing_arr:
'cnc_ids': cnc_workorder.cnc_ids.sudo()._json_cnc_processing(panel, ret), cnc_program = cnc_production
'cmm_ids': cnc_workorder.cmm_ids.sudo()._json_cmm_program(panel, ret), cnc_program_ids = [item.id for item in cnc_program]
'cnc_worksheet': base64.b64encode(open(panel_file_path, 'rb').read())})
pre_workorder = production.workorder_ids.filtered(
lambda ap: ap.routing_type == '装夹预调' and ap.state not in ['done',
'cancel'] and ap.processing_panel == panel)
if pre_workorder:
pre_workorder.write(
{'is_send_program_again': False,
'processing_drawing': base64.b64encode(open(panel_file_path, 'rb').read())})
productions.write({'programming_state': '已编程', 'work_state': '已编程'})
cnc_program_ids = [item.id for item in productions]
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search( workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search(
[('production_id', 'in', cnc_program_ids)]) [('production_id', 'in', cnc_program_ids)])
if workpiece_delivery: if workpiece_delivery:

View File

@@ -46,8 +46,6 @@ class FtpController():
os.makedirs(serverdir) os.makedirs(serverdir)
try: try:
logging.info("进入FTP目录 ") logging.info("进入FTP目录 ")
self.ftp.pwd()
logging.info('当前目录:%s' % self.ftp.pwd())
logging.info('目录:%s' % target_dir) logging.info('目录:%s' % target_dir)
target_dir1 = target_dir.split('/') target_dir1 = target_dir.split('/')
logging.info('目录1:%s' % target_dir1[1]) logging.info('目录1:%s' % target_dir1[1])

View File

@@ -26,7 +26,6 @@ class ResConfigSettings(models.TransientModel):
ftp_port = fields.Char(string='FTP端口') ftp_port = fields.Char(string='FTP端口')
ftp_user = fields.Char(string='FTP用户') ftp_user = fields.Char(string='FTP用户')
ftp_password = fields.Char(string='FTP密码') ftp_password = fields.Char(string='FTP密码')
enable_tool_presetter = fields.Boolean('是否启用刀具预调仪', default=True)
def sf_all_sync(self): def sf_all_sync(self):
try: try:
@@ -109,7 +108,6 @@ class ResConfigSettings(models.TransientModel):
ftp_port = config.get_param('ftp_port', default='') ftp_port = config.get_param('ftp_port', default='')
ftp_user = config.get_param('ftp_user', default='') ftp_user = config.get_param('ftp_user', default='')
ftp_password = config.get_param('ftp_password', default='') ftp_password = config.get_param('ftp_password', default='')
enable_tool_presetter = config.get_param('enable_tool_presetter', default='')
values.update( values.update(
token=token, token=token,
@@ -123,8 +121,7 @@ class ResConfigSettings(models.TransientModel):
ftp_host=ftp_host, ftp_host=ftp_host,
ftp_port=ftp_port, ftp_port=ftp_port,
ftp_user=ftp_user, ftp_user=ftp_user,
ftp_password=ftp_password, ftp_password=ftp_password
enable_tool_presetter=enable_tool_presetter
) )
return values return values
@@ -143,4 +140,3 @@ class ResConfigSettings(models.TransientModel):
ir_config.set_param("ftp_port", self.ftp_port or "") ir_config.set_param("ftp_port", self.ftp_port or "")
ir_config.set_param("ftp_user", self.ftp_user or "") ir_config.set_param("ftp_user", self.ftp_user or "")
ir_config.set_param("ftp_password", self.ftp_password or "") ir_config.set_param("ftp_password", self.ftp_password or "")
ir_config.set_param("enable_tool_presetter", self.enable_tool_presetter or False)

View File

@@ -114,21 +114,6 @@
</div> </div>
</div> </div>
</div> </div>
<div>
<h2>刀具预调仪配置</h2>
<div class="row mt16 o_settings_container">
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane">
<field name="enable_tool_presetter"/>
</div>
<div class="o_setting_right_pane">
<div class="text-muted">
<label for="enable_tool_presetter" string="是否启用刀具预调仪"/>
</div>
</div>
</div>
</div>
</div>
</xpath> </xpath>
</field> </field>
</record> </record>

View File

@@ -19,7 +19,7 @@ class sf_production_plan(models.Model):
('done', '已排程'), ('done', '已排程'),
('processing', '加工中'), ('processing', '加工中'),
('finished', '已完成') ('finished', '已完成')
], string='状态', tracking=True) ], string='工单状态', tracking=True)
state_order = fields.Integer(compute='_compute_state_order', store=True) state_order = fields.Integer(compute='_compute_state_order', store=True)
@@ -36,7 +36,7 @@ class sf_production_plan(models.Model):
_order = 'state_order asc, write_date desc' _order = 'state_order asc, write_date desc'
name = fields.Char(string='制造订单') name = fields.Char(string='工单编号')
active = fields.Boolean(string='已归档', default=True) active = fields.Boolean(string='已归档', default=True)
# selected = fields.Boolean(default=False) # selected = fields.Boolean(default=False)
# order_number = fields.Char(string='订单号') # order_number = fields.Char(string='订单号')
@@ -52,7 +52,7 @@ class sf_production_plan(models.Model):
schedule_setting = fields.Selection([ schedule_setting = fields.Selection([
('reverse', '倒排'), ('positive', '顺排')], string='排程设置', default='reverse') ('reverse', '倒排'), ('positive', '顺排')], string='排程设置', default='reverse')
product_id = fields.Many2one('product.product', '关联产品') product_id = fields.Many2one('product.product', '关联产品')
origin = fields.Char(string='销售订单') origin = fields.Char(string='订单')
# # 加工时长 # # 加工时长
# process_time = fields.Float(string='加工时长', digits=(16, 2)) # process_time = fields.Float(string='加工时长', digits=(16, 2))
# 实际加工时长、实际开始时间、实际结束时间 # 实际加工时长、实际开始时间、实际结束时间
@@ -200,7 +200,6 @@ class sf_production_plan(models.Model):
raise ValidationError("未选择生产线") raise ValidationError("未选择生产线")
else: else:
workorder_id_list = record.production_id.workorder_ids.ids workorder_id_list = record.production_id.workorder_ids.ids
if record.production_id:
if record.production_id.workorder_ids: if record.production_id.workorder_ids:
for item in record.production_id.workorder_ids: for item in record.production_id.workorder_ids:
if item.name == 'CNC加工': if item.name == 'CNC加工':
@@ -232,12 +231,12 @@ class sf_production_plan(models.Model):
# record.production_id.date_planned_start = record.date_planned_start # record.production_id.date_planned_start = record.date_planned_start
# record.production_id.date_planned_finished = record.date_planned_finished # record.production_id.date_planned_finished = record.date_planned_finished
record.sudo().production_id.production_line_id = record.production_line_id.id record.sudo().production_id.production_line_id = record.production_line_id.id
if record.production_id.workorder_ids:
record.sudo().production_id.workorder_ids.filtered( record.sudo().production_id.workorder_ids.filtered(
lambda b: b.routing_type == "装夹预调").workpiece_delivery_ids.write( lambda b: b.routing_type == "装夹预调").workpiece_delivery_ids.write(
{'production_line_id': record.production_line_id.id, {'production_line_id': record.production_line_id.id,
'plan_start_processing_time': record.date_planned_start}) 'plan_start_processing_time': record.date_planned_start})
else:
raise ValidationError("未找到工单")
# record.date_planned_finished = record.date_planned_start + timedelta(days=3) # record.date_planned_finished = record.date_planned_start + timedelta(days=3)
# record.state = 'done' # record.state = 'done'
return { return {

View File

@@ -17,18 +17,18 @@
decoration-danger="state == 'finished'"/> decoration-danger="state == 'finished'"/>
<field name="name"/> <field name="name"/>
<field name="origin"/> <field name="origin"/>
<field name="order_deadline" widget="date"/> <field name="order_deadline"/>
<field name="product_qty"/> <field name="product_qty"/>
<field name="production_line_id"/> <field name="production_line_id"/>
<field name="date_planned_start"/> <field name="date_planned_start"/>
<field name="date_planned_finished"/> <field name="date_planned_finished"/>
<field name="actual_start_time" optional='hide'/> <field name="actual_start_time"/>
<field name="actual_end_time" optional='hide'/> <field name="actual_end_time"/>
<field name="actual_process_time" optional='hide'/> <field name="actual_process_time"/>
<field name="schedule_setting" optional='hide'/> <field name="schedule_setting"/>
<!-- <button name="do_production_schedule" class="btn schedule_done" string="生产排程" type="object" --> <button name="do_production_schedule" class="btn schedule_done" string="生产排程" type="object"
<!-- attrs="{'invisible': ['|', ('state', '!=', 'draft'), ('actual_start_time', '!=', False)]}" --> attrs="{'invisible': ['|', ('state', '!=', 'draft'), ('actual_start_time', '!=', False)]}"
<!-- groups="sf_base.group_plan_dispatch"/> --> groups="sf_base.group_plan_dispatch"/>
<button name="cancel_production_schedule" class="btn schedule_cancel" string="取消排程" type="object" <button name="cancel_production_schedule" class="btn schedule_cancel" string="取消排程" type="object"
attrs="{'invisible': ['|', ('state', '!=', 'done'), ('actual_start_time', '!=', False)]}" attrs="{'invisible': ['|', ('state', '!=', 'done'), ('actual_start_time', '!=', False)]}"
groups="sf_base.group_plan_dispatch"/> groups="sf_base.group_plan_dispatch"/>
@@ -68,7 +68,7 @@
<field name="product_id"/> <field name="product_id"/>
<field name="origin"/> <field name="origin"/>
<field name="product_qty"/> <field name="product_qty"/>
<field name="order_deadline" widget="date"/> <field name="order_deadline"/>
<!-- <field name="process_time"/> --> <!-- <field name="process_time"/> -->
<field name="schedule_setting"/> <field name="schedule_setting"/>
<field name="production_line_id" domain="[('name', 'ilike', 'CNC')]"/> <field name="production_line_id" domain="[('name', 'ilike', 'CNC')]"/>
@@ -135,13 +135,12 @@
<!-- <field name="delivery_quantity"/> --> <!-- <field name="delivery_quantity"/> -->
<!-- <field name="delivery_date"/> --> <!-- <field name="delivery_date"/> -->
<!-- </group> --> <!-- </group> -->
</group>
</sheet>
<div class="oe_chatter"> <div class="oe_chatter">
<field name="message_follower_ids"/> <field name="message_follower_ids"/>
<field name="message_ids"/> <field name="message_ids"/>
</div> </div>
</group>
</sheet>
</form> </form>
</field> </field>
</record> </record>
@@ -152,27 +151,16 @@
<field name="model">sf.production.plan</field> <field name="model">sf.production.plan</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="订单计划"> <search string="订单计划">
<!-- Your other filters go here --> <!-- Your other filters go here -->
<!-- <filter name="archived" string="已归档" domain="[('active','=',False)]"/> --> <filter name="archived" string="已归档" domain="[('active','=',False)]"/>
<!-- <filter name="not archived" string="未归档" domain="[('active','=',True)]"/> --> <filter name="not archived" string="未归档" domain="[('active','=',True)]"/>
<field name="name"/> <field name="name"/>
<field name="product_qty"/> <field name="product_qty"/>
<field name="date_planned_start"/>
<field name="date_planned_finished"/>
<field name="state"/> <field name="state"/>
<filter string="待排程" name="draft" domain="[('state','=','draft')]"/> <searchpanel class="account_root">
<filter string="已排程" name="done" domain="[('state','=','done')]"/> <field name="state" icon="fa-filter"/>
<filter string="加工中" name="processing" domain="[('state','=','processing')]"/>
<filter string="已完成" name="finished" domain="[('state','=','finished')]"/>
<group expand="0" string="Group By">
<filter name="group_by_state" string="状态" domain="[]" context="{'group_by': 'state'}"/>
</group>
<group expand="0" string="Group By">
<filter name="group_by_production_line_id" string="生产线" domain="[]" context="{'group_by': 'production_line_id'}"/>
</group>
<searchpanel>
<!-- <field name="state" icon="fa-filter"/> -->
<field name="production_line_id" select="multi" string="生产线" icon="fa-building" enable_counters="1"/>
<field name="state" select="multi" string="状态" icon="fa-building" enable_counters="1"/>
</searchpanel> </searchpanel>
</search> </search>
</field> </field>
@@ -199,41 +187,30 @@
<field name="date_planned_start"/> <field name="date_planned_start"/>
<field name="date_planned_finished"/> <field name="date_planned_finished"/>
<field name="state"/> <field name="state"/>
<field name="origin"/>
<field name="order_deadline"/>
<field name="product_id"/>
<templates> <templates>
<div t-name="gantt-popover" class="container-fluid"> <div t-name="gantt-popover" class="container-fluid">
<div class="row g-0"> <div class="row g-0">
<div class="col"> <div class="col">
<ul class="ps-1 mb-0 list-unstyled"> <ul class="ps-1 mb-0 list-unstyled">
<li> <li>
<strong>销售订单号:</strong> <strong>开始时间:</strong>
<t t-out="origin"/> <t t-out="userTimezoneStartDate.format('L LTS')"/>
</li> </li>
<li> <li>
<strong>制造订单号:</strong> <strong>结束时间:</strong>
<t t-out="userTimezoneStopDate.format('L LTS')"/>
</li>
<li>
<strong>名称:</strong>
<t t-out="name"/> <t t-out="name"/>
</li> </li>
<li>
<strong>订单交期:</strong>
<t t-out="order_deadline"/>
</li>
<li>
<strong>产品名称:</strong>
<t t-out="product_id"/>
</li>
<li> <li>
<strong>数量:</strong> <strong>数量:</strong>
<t t-out="product_qty"/> <t t-out="product_qty"/>
</li> </li>
<li> <li>
<strong>计划开始时间:</strong> <strong>状态:</strong>
<t t-out="userTimezoneStartDate.format('L LTS')"/> <t t-out="state"/>
</li>
<li>
<strong>计划结束时间:</strong>
<t t-out="userTimezoneStopDate.format('L LTS')"/>
</li> </li>
</ul> </ul>
</div> </div>
@@ -268,7 +245,6 @@
<field name="type">ir.actions.act_window</field> <field name="type">ir.actions.act_window</field>
<field name="res_model">sf.production.plan</field> <field name="res_model">sf.production.plan</field>
<field name="view_mode">tree,gantt,form</field> <field name="view_mode">tree,gantt,form</field>
<field name="context">{'search_default_group_by_state': 1, 'search_default_draft': 1, 'display_complete': True}</field>
</record> </record>
<menuitem <menuitem

View File

@@ -19,7 +19,6 @@ from . import parser_and_calculate_work_time as pc
class QuickEasyOrder(models.Model): class QuickEasyOrder(models.Model):
_name = 'quick.easy.order' _name = 'quick.easy.order'
_inherit = ['mail.thread', 'mail.activity.mixin']
_description = '简易下单' _description = '简易下单'
_order = 'id desc' _order = 'id desc'
@@ -36,14 +35,13 @@ class QuickEasyOrder(models.Model):
('0.03', '±0.03mm'), ('0.03', '±0.03mm'),
('0.02', '±0.02mm'), ('0.02', '±0.02mm'),
('0.01', '±0.01mm')], string='加工精度', default='0.10') ('0.01', '±0.01mm')], string='加工精度', default='0.10')
material_id = fields.Many2one('sf.production.materials', '材料', tracking=True) material_id = fields.Many2one('sf.production.materials', '材料')
material_model_id = fields.Many2one('sf.materials.model', '型号', tracking=True) material_model_id = fields.Many2one('sf.materials.model', '型号')
# process_id = fields.Many2one('sf.production.process', string='表面工艺') # process_id = fields.Many2one('sf.production.process', string='表面工艺')
parameter_ids = fields.Many2many('sf.production.process.parameter', 'process_item_order_rel', string='可选参数', parameter_ids = fields.Many2many('sf.production.process.parameter', 'process_item_order_rel', string='可选参数')
tracking=True) quantity = fields.Integer('数量', default=1)
quantity = fields.Integer('数量', default=1, tracking=True) unit_price = fields.Float('单价')
unit_price = fields.Float('', tracking=True) price = fields.Float('')
price = fields.Float('总价', tracking=True)
model_file = fields.Binary('glb模型文件') model_file = fields.Binary('glb模型文件')
upload_model_file = fields.Many2many('ir.attachment', 'upload_qf_model_file_attachment_ref', string='上传模型文件') upload_model_file = fields.Many2many('ir.attachment', 'upload_qf_model_file_attachment_ref', string='上传模型文件')
delivery_time = fields.Date('交货日期') delivery_time = fields.Date('交货日期')
@@ -51,10 +49,10 @@ class QuickEasyOrder(models.Model):
state = fields.Selection([('草稿', '草稿'), ('待派单', '待派单'), state = fields.Selection([('草稿', '草稿'), ('待派单', '待派单'),
('待接单', '待接单'), ('加工中', '加工中'), ('待接单', '待接单'), ('加工中', '加工中'),
('物流中', '物流中'), ('已交付', '已交付')], string='订单状态', default='草稿', ('物流中', '物流中'), ('已交付', '已交付')], string='订单状态', default='草稿',
readonly=True, tracking=True) readonly=True)
model_color_state = fields.Selection([ model_color_state = fields.Selection([
('success', '成功'), ('success', '成功'),
('fail', '失败')], string='模型上色状态', tracking=True) ('fail', '失败')], string='模型上色状态')
processing_time = fields.Integer('加工时长(min)') processing_time = fields.Integer('加工时长(min)')
sale_order_id = fields.Many2one('sale.order', '销售订单号') sale_order_id = fields.Many2one('sale.order', '销售订单号')
@@ -96,7 +94,8 @@ class QuickEasyOrder(models.Model):
obj.state = '待接单' obj.state = '待接单'
return obj return obj
def model_analyze(self, model_attachment):
def model_analyze(self,model_attachment):
""" """
step模型解析上传模型时转为web可显示的格式 step模型解析上传模型时转为web可显示的格式
:return: :return:

View File

@@ -16,7 +16,6 @@ from odoo.exceptions import ValidationError, UserError
class QuickEasyOrder(models.Model): class QuickEasyOrder(models.Model):
_name = 'quick.easy.order' _name = 'quick.easy.order'
_inherit = ['mail.thread', 'mail.activity.mixin']
_description = '简易下单' _description = '简易下单'
_order = 'id desc' _order = 'id desc'
@@ -33,15 +32,13 @@ class QuickEasyOrder(models.Model):
('0.03', '±0.03mm'), ('0.03', '±0.03mm'),
('0.02', '±0.02mm'), ('0.02', '±0.02mm'),
('0.01', '±0.01mm')], string='加工精度', default='0.10') ('0.01', '±0.01mm')], string='加工精度', default='0.10')
material_id = fields.Many2one('sf.production.materials', '材料', tracking=True) material_id = fields.Many2one('sf.production.materials', '材料')
material_model_id = fields.Many2one('sf.materials.model', '型号', domain="[('materials_id', '=', material_id)]", material_model_id = fields.Many2one('sf.materials.model', '型号', domain="[('materials_id', '=', material_id)]")
tracking=True)
# process_id = fields.Many2one('sf.production.process', string='表面工艺') # process_id = fields.Many2one('sf.production.process', string='表面工艺')
parameter_ids = fields.Many2many('sf.production.process.parameter', 'process_item_order_rel', string='可选参数', parameter_ids = fields.Many2many('sf.production.process.parameter', 'process_item_order_rel', string='可选参数')
tracking=True) quantity = fields.Integer('数量', default=1)
quantity = fields.Integer('数量', default=1, tracking=True) unit_price = fields.Float('单价')
unit_price = fields.Float('', tracking=True) price = fields.Float('')
price = fields.Float('总价', tracking=True)
model_file = fields.Binary('glb模型文件') model_file = fields.Binary('glb模型文件')
upload_model_file = fields.Many2many('ir.attachment', 'upload_qf_model_file_attachment_ref', string='上传模型文件') upload_model_file = fields.Many2many('ir.attachment', 'upload_qf_model_file_attachment_ref', string='上传模型文件')
delivery_time = fields.Date('交货日期') delivery_time = fields.Date('交货日期')
@@ -49,10 +46,10 @@ class QuickEasyOrder(models.Model):
state = fields.Selection([('草稿', '草稿'), ('待派单', '待派单'), state = fields.Selection([('草稿', '草稿'), ('待派单', '待派单'),
('待接单', '待接单'), ('加工中', '加工中'), ('待接单', '待接单'), ('加工中', '加工中'),
('物流中', '物流中'), ('已交付', '已交付')], string='订单状态', default='草稿', ('物流中', '物流中'), ('已交付', '已交付')], string='订单状态', default='草稿',
readonly=True, tracking=True) readonly=True)
model_color_state = fields.Selection([ model_color_state = fields.Selection([
('success', '成功'), ('success', '成功'),
('fail', '失败')], string='模型上色状态', tracking=True) ('fail', '失败')], string='模型上色状态')
processing_time = fields.Integer('加工时长(min)') processing_time = fields.Integer('加工时长(min)')
sale_order_id = fields.Many2one('sale.order', '销售订单号') sale_order_id = fields.Many2one('sale.order', '销售订单号')

View File

@@ -215,17 +215,6 @@ class RePurchaseOrder(models.Model):
if len(product_id) != len(line): if len(product_id) != len(line):
raise ValidationError('%s】已存在,请勿重复添加' % product[-1].name) raise ValidationError('%s】已存在,请勿重复添加' % product[-1].name)
def button_confirm(self):
result = super(RePurchaseOrder, self).button_confirm()
for item in self:
# 确认订单时,自动分配序列号
if item.picking_ids:
for picking_id in item.picking_ids:
if picking_id.move_ids:
for move_id in picking_id.move_ids:
move_id.put_move_line()
return result
class ResPartnerToSale(models.Model): class ResPartnerToSale(models.Model):
_inherit = 'res.partner' _inherit = 'res.partner'
@@ -244,12 +233,12 @@ class ResPartnerToSale(models.Model):
if obj: if obj:
raise UserError('该税ID已存在,请重新输入') raise UserError('该税ID已存在,请重新输入')
# @api.constrains('email') @api.constrains('email')
# def _check_email(self): def _check_email(self):
# if self.customer_rank > 0: if self.customer_rank > 0:
# obj = self.sudo().search([('email', '=', self.email), ('id', '!=', self.id), ('active', '=', True)]) obj = self.sudo().search([('email', '=', self.email), ('id', '!=', self.id), ('active', '=', True)])
# if obj: if obj:
# raise UserError('该邮箱已存在,请重新输入') raise UserError('该邮箱已存在,请重新输入')
@api.model @api.model
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None): def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):

View File

@@ -84,11 +84,6 @@
</group> </group>
</group> </group>
</sheet> </sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="activity_ids"/>
<field name="message_ids" options="{'post_refresh': 'recipients'}"/>
</div>
</form> </form>
</field> </field>
</record> </record>

View File

@@ -24,18 +24,18 @@
<attribute name="required">1</attribute> <attribute name="required">1</attribute>
<attribute name="attrs">{'readonly': [('id','!=', False)]}</attribute> <attribute name="attrs">{'readonly': [('id','!=', False)]}</attribute>
</field> </field>
<!-- <field name="email" position="replace">--> <field name="email" position="replace">
<!-- <field name="email"--> <field name="email"
<!-- attrs="{'readonly': [('id','!=', False)]}"/>--> attrs="{'readonly': [('id','!=', False)]}"/>
<!-- </field>--> </field>
<!-- <field name="mobile" position="attributes">--> <field name="mobile" position="attributes">
<!-- <attribute name="attrs">{'required': [('phone', '=', False)],'readonly': [('id','!=', False)]}--> <attribute name="attrs">{'required': [('phone', '=', False)],'readonly': [('id','!=', False)]}
<!-- </attribute>--> </attribute>
<!-- </field>--> </field>
<!-- <field name="phone" position="attributes">--> <field name="phone" position="attributes">
<!-- <attribute name="attrs">{'required': [('mobile', '=', False)],'readonly': [('id','!=', False)]}--> <attribute name="attrs">{'required': [('mobile', '=', False)],'readonly': [('id','!=', False)]}
<!-- </attribute>--> </attribute>
<!-- </field>--> </field>
<field name="street" position="attributes"> <field name="street" position="attributes">
<attribute name="attrs">{'readonly': [('id','!=', False)]} <attribute name="attrs">{'readonly': [('id','!=', False)]}
</attribute> </attribute>
@@ -56,10 +56,10 @@
<field name="user_id" widget="many2one_avatar_user" context="{'is_sale': True }" <field name="user_id" widget="many2one_avatar_user" context="{'is_sale': True }"
attrs="{'required' : [('customer_rank','>', 0)]}"/> attrs="{'required' : [('customer_rank','>', 0)]}"/>
</xpath> </xpath>
<!-- <field name="category_id" position="attributes">--> <field name="category_id" position="attributes">
<!-- <attribute name="required">1</attribute>--> <attribute name="required">1</attribute>
<!-- <attribute name="attrs">{'readonly': [('id','!=', False)]}</attribute>--> <attribute name="attrs">{'readonly': [('id','!=', False)]}</attribute>
<!-- </field>--> </field>
<field name="company_registry" position="attributes"> <field name="company_registry" position="attributes">
<attribute name="attrs">{'readonly': [('id','!=', False)]}</attribute> <attribute name="attrs">{'readonly': [('id','!=', False)]}</attribute>
</field> </field>
@@ -101,7 +101,7 @@
<field name="property_supplier_payment_term_id" position="before"> <field name="property_supplier_payment_term_id" position="before">
<field name="purchase_user_id" context="{'supplier_rank': supplier_rank }" <field name="purchase_user_id" context="{'supplier_rank': supplier_rank }"
widget="many2one_avatar_user" widget="many2one_avatar_user"
attrs="{'required' : [('supplier_rank','>', 0)]}"/> attrs="{'required' : [('supplier_rank','>', 0)],'readonly': [('customer_rank','>', 0)]}"/>
</field> </field>
<xpath expr="//field[@name='property_account_position_id']" position="attributes"> <xpath expr="//field[@name='property_account_position_id']" position="attributes">
<attribute name="attrs">{'readonly': [('id','!=', False)]}</attribute> <attribute name="attrs">{'readonly': [('id','!=', False)]}</attribute>
@@ -195,10 +195,10 @@
<attribute name="attrs">{'invisible': [('customer_rank','=', 0)]} <attribute name="attrs">{'invisible': [('customer_rank','=', 0)]}
</attribute> </attribute>
</field> </field>
<!-- <field name="user_id" position="before">--> <field name="user_id" position="before">
<!-- <field name="purchase_user_id" widget="many2one_avatar_user"--> <field name="purchase_user_id" widget="many2one_avatar_user"
<!-- attrs="{'invisible' : [('supplier_rank','=', 0)]}"/>--> attrs="{'invisible' : [('supplier_rank','=', 0)]}"/>
<!-- </field>--> </field>
</field> </field>
</record> </record>
</data> </data>

View File

@@ -1,6 +1,54 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<odoo> <odoo>
<data> <data>
<record id="sale_order_view_search_inherit_sf" model="ir.ui.view">
<field name="name">sale.order.search.inherit.sf</field>
<field name="model">sale.order</field>
<field name="mode">primary</field>
<field name="inherit_id" ref="sale.view_sales_order_filter"/>
<field name="arch" type="xml">
<filter name="my_sale_orders_filter" position="replace">
<field name="campaign_id"/>
<separator/>
<filter string="报价" name="draft" domain="[('state','in',('draft', 'sent'))]"/>
<filter string="销售订单" name="sales" domain="[('state','in',('sale','done'))]"/>
<separator/>
<filter string="创建日期" name="filter_create_date" date="create_date"/>
</filter>
</field>
</record>
<record id="action_quotations_with_onboarding_inherit_sf" model="ir.actions.act_window">
<field name="name">报价</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">sale.order</field>
<field name="view_id" ref="sale.view_quotation_tree_with_onboarding"/>
<field name="view_mode">tree,kanban,form,calendar,pivot,graph,activity</field>
<field name="search_view_id" ref="sale_order_view_search_inherit_sf"/>
<field name="context">{'search_default_my_quotation': 1}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create a new quotation, the first step of a new sale!
</p>
<p>
Once the quotation is confirmed by the customer, it becomes a sales order.
<br/>
You will be able to create an invoice and collect the payment.
</p>
</field>
</record>
<!-- <menuitem id="menu_sale_quotations">-->
<!-- <field name="active" eval="False"/>-->
<!-- </menuitem>-->
<menuitem id="menu_sale_quotations_inherit_sf"
action="action_quotations_with_onboarding_inherit_sf"
groups="sales_team.group_sale_salesman,sf_base.group_sale_salemanager,sf_base.group_sale_director"
parent="sale.sale_order_menu"
sequence="11"/>
<record model="ir.ui.view" id="view_sale_order_form_inherit_sf"> <record model="ir.ui.view" id="view_sale_order_form_inherit_sf">
<field name="name">sale.order.form.inherit.sf</field> <field name="name">sale.order.form.inherit.sf</field>
<field name="model">sale.order</field> <field name="model">sale.order</field>

View File

@@ -22,7 +22,6 @@
'views/tool_material_search.xml', 'views/tool_material_search.xml',
'views/fixture_material_search_views.xml', 'views/fixture_material_search_views.xml',
'views/menu_view.xml', 'views/menu_view.xml',
'views/stock.xml',
'data/tool_data.xml', 'data/tool_data.xml',
], ],
'demo': [ 'demo': [

View File

@@ -8,35 +8,6 @@ from odoo.http import request
class Manufacturing_Connect(http.Controller): class Manufacturing_Connect(http.Controller):
@http.route('/AutoDeviceApi/ToolGroup', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
cors="*")
def get_functional_tool_groups_Info(self, **kw):
"""
刀具组接口
:param kw:
:return:
"""
logging.info('get_functional_tool_groups_Info:%s' % kw)
try:
datas = request.httprequest.data
ret = json.loads(datas)
# ret = json.loads(ret['result'])
logging.info('DeviceId:%s' % ret)
functional_tools = request.env['sf.tool.inventory'].sudo().search([])
res = {'Succeed': True, 'Datas': []}
if functional_tools:
for item in functional_tools:
res['Datas'].append({
'GroupName': item.tool_groups_id.name,
'ToolId': item.functional_cutting_tool_model_id.name,
'ToolName': item.name
})
except Exception as e:
res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
logging.info('get_functional_tool_groups_Info error:%s' % e)
return json.JSONEncoder().encode(res)
@http.route('/AutoDeviceApi/ToolInventory', type='json', auth='none', methods=['GET', 'POST'], csrf=False, @http.route('/AutoDeviceApi/ToolInventory', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
cors="*") cors="*")
def get_functional_tool_inventory_Info(self, **kw): def get_functional_tool_inventory_Info(self, **kw):
@@ -109,7 +80,6 @@ class Manufacturing_Connect(http.Controller):
res = {'Succeed': True, 'Datas': []} res = {'Succeed': True, 'Datas': []}
try: try:
datas = request.httprequest.data datas = request.httprequest.data
logging.info('datas: %s' % datas)
ret = str(datas, 'utf-8') ret = str(datas, 'utf-8')
data_lists = ret.split(",") data_lists = ret.split(",")
data_list = [data.replace('+', '') for data in data_lists] data_list = [data.replace('+', '') for data in data_lists]
@@ -121,7 +91,7 @@ class Manufacturing_Connect(http.Controller):
{'Succeed': False, 'ErrorCode': 201, 'code': data_list[0], 'Error': '没有找到正在组装的组装单!'}) {'Succeed': False, 'ErrorCode': 201, 'code': data_list[0], 'Error': '没有找到正在组装的组装单!'})
tool_assembly.write({ tool_assembly.write({
'after_assembly_tool_loading_length': float(data_list[1] or "0"), # 高度(总长度) 'after_assembly_tool_loading_length': float(data_list[1] or "0"), # 高度(总长度)
'after_assembly_functional_tool_diameter': float(data_list[2] or "0") * 2, # 直径 'after_assembly_functional_tool_diameter': float(data_list[2] or "0"), # 直径
'after_assembly_knife_tip_r_angle': float(data_list[3] or "0") # R角 'after_assembly_knife_tip_r_angle': float(data_list[3] or "0") # R角
}) })
except Exception as e: except Exception as e:

View File

@@ -7,5 +7,4 @@ from . import functional_tool_enroll
from . import fixture_material_search from . import fixture_material_search
from . import fixture_enroll from . import fixture_enroll
from . import temporary_data_processing_methods from . import temporary_data_processing_methods
from . import stock

View File

@@ -181,7 +181,6 @@ class MachineTableToolChangingApply(models.Model):
class CAMWorkOrderProgramKnifePlan(models.Model): class CAMWorkOrderProgramKnifePlan(models.Model):
_name = 'sf.cam.work.order.program.knife.plan' _name = 'sf.cam.work.order.program.knife.plan'
_inherit = ['mail.thread']
_description = 'CAM工单程序用刀计划' _description = 'CAM工单程序用刀计划'
name = fields.Char('工单任务编号') name = fields.Char('工单任务编号')
@@ -229,7 +228,7 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
estimated_processing_time = fields.Char('预计加工时间') estimated_processing_time = fields.Char('预计加工时间')
plan_execute_status = fields.Selection([('0', '待下发'), ('1', '执行中'), ('2', '已完成')], plan_execute_status = fields.Selection([('0', '待下发'), ('1', '执行中'), ('2', '已完成')],
string='计划执行状态', default='0', readonly=False, tracking=True) string='计划执行状态', default='0', readonly=False)
sf_functional_tool_assembly_id = fields.Many2one('sf.functional.tool.assembly', '功能刀具组装', readonly=True) sf_functional_tool_assembly_id = fields.Many2one('sf.functional.tool.assembly', '功能刀具组装', readonly=True)
@@ -283,8 +282,7 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
'loading_task_source': '0', 'loading_task_source': '0',
'applicant': self.env.user.name, 'applicant': self.env.user.name,
'use_tool_time': fields.Datetime.now() + timedelta( 'use_tool_time': self.need_knife_time,
hours=4) if not self.need_knife_time else self.need_knife_time,
'reason_for_applying': '工单用刀', 'reason_for_applying': '工单用刀',
'sf_cam_work_order_program_knife_plan_id': self.id 'sf_cam_work_order_program_knife_plan_id': self.id
@@ -313,11 +311,10 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
'applicant': None, 'applicant': None,
'sf_functional_tool_assembly_id': None}) 'sf_functional_tool_assembly_id': None})
def create_cam_work_plan(self, cnc_processing_ids): def create_cam_work_plan(self, cnc_processing):
""" """
根据传入的工单信息查询是否有需要的功能刀具如果没有则生成CAM工单程序用刀计划 根据传入的工单信息查询是否有需要的功能刀具如果没有则生成CAM工单程序用刀计划
""" """
for cnc_processing in cnc_processing_ids:
status = False status = False
if cnc_processing.cutting_tool_name: if cnc_processing.cutting_tool_name:
functional_tools = self.env['sf.real.time.distribution.of.functional.tools'].sudo().search( functional_tools = self.env['sf.real.time.distribution.of.functional.tools'].sudo().search(
@@ -350,21 +347,9 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
else: else:
logging.info('功能刀具【%s】满足CNC用刀需求' % cnc_processing.cutting_tool_name) logging.info('功能刀具【%s】满足CNC用刀需求' % cnc_processing.cutting_tool_name)
def unlink_cam_plan(self, production):
for item in production:
cam_plan_ids = self.env['sf.cam.work.order.program.knife.plan'].search([('name', '=', item.name)])
for cam_plan_id in cam_plan_ids:
assembly_id = cam_plan_id.sf_functional_tool_assembly_id
if assembly_id.assemble_status in ('0', '待组装') and not assembly_id.start_preset_bool:
logging.info('%s删除成功!!!' % assembly_id)
assembly_id.sudo().unlink()
logging.info('unlink_cam_plan成功')
cam_plan_ids.sudo().unlink()
class FunctionalToolAssembly(models.Model): class FunctionalToolAssembly(models.Model):
_name = 'sf.functional.tool.assembly' _name = 'sf.functional.tool.assembly'
_inherit = ['mail.thread']
_description = '功能刀具组装' _description = '功能刀具组装'
_order = 'assemble_status, use_tool_time asc' _order = 'assemble_status, use_tool_time asc'
@@ -399,7 +384,7 @@ class FunctionalToolAssembly(models.Model):
applicant = fields.Char(string='申请人', readonly=True) applicant = fields.Char(string='申请人', readonly=True)
apply_time = fields.Datetime(string='申请时间', default=fields.Datetime.now(), readonly=True) apply_time = fields.Datetime(string='申请时间', default=fields.Datetime.now(), readonly=True)
assemble_status = fields.Selection([('0', '待组装'), ('1', '已组装')], string='组装状态', default='0', assemble_status = fields.Selection([('0', '待组装'), ('1', '已组装')], string='组装状态', default='0',
tracking=True, readonly=True) readonly=True)
cutter_spacing_code_id = fields.Many2one('maintenance.equipment.tool', string='刀位号', readonly=True) cutter_spacing_code_id = fields.Many2one('maintenance.equipment.tool', string='刀位号', readonly=True)
whether_standard_knife = fields.Boolean(string='是否标准刀', default=True, readonly=True) whether_standard_knife = fields.Boolean(string='是否标准刀', default=True, readonly=True)
reason_for_applying = fields.Char(string='申请原因', readonly=True) reason_for_applying = fields.Char(string='申请原因', readonly=True)
@@ -416,9 +401,8 @@ class FunctionalToolAssembly(models.Model):
return categories.browse(functional_tool_type_ids) return categories.browse(functional_tool_type_ids)
# 刀具物料信息 # 刀具物料信息
# ==============整体式刀具型号============= # ==============整体式刀具型号============
integral_freight_barcode_id = fields.Many2one('sf.shelf.location', string='整体式刀具货位') integral_freight_barcode = fields.Char('整体式刀具货位')
integral_lot_id = fields.Many2one('stock.lot', string='整体式刀具批次')
integral_product_id = fields.Many2one('product.product', string='整体式刀具名称', integral_product_id = fields.Many2one('product.product', string='整体式刀具名称',
compute='_compute_integral_product_id', store=True) compute='_compute_integral_product_id', store=True)
cutting_tool_integral_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='整体式刀具型号', cutting_tool_integral_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='整体式刀具型号',
@@ -428,15 +412,19 @@ class FunctionalToolAssembly(models.Model):
sf_tool_brand_id_1 = fields.Many2one('sf.machine.brand', string='整体式刀具品牌', sf_tool_brand_id_1 = fields.Many2one('sf.machine.brand', string='整体式刀具品牌',
related='integral_product_id.brand_id') related='integral_product_id.brand_id')
@api.depends('integral_lot_id') @api.depends('integral_freight_barcode')
def _compute_integral_product_id(self): def _compute_integral_product_id(self):
for item in self: for item in self:
if item.integral_lot_id: if item.integral_freight_barcode:
item.integral_product_id = item.integral_lot_id.product_id.id location = self.env['sf.shelf.location'].sudo().search(
[('barcode', '=', item.integral_freight_barcode)])
if location:
item.integral_product_id = location.product_id.id
else:
item.integral_product_id = False
# =================刀片型号============= # =================刀片型号=============
blade_freight_barcode_id = fields.Many2one('sf.shelf.location', string='刀片货位') blade_freight_barcode = fields.Char('刀片货位')
blade_lot_id = fields.Many2one('stock.lot', string='刀片批次')
blade_product_id = fields.Many2one('product.product', string='刀片名称', compute='_compute_blade_product_id', blade_product_id = fields.Many2one('product.product', string='刀片名称', compute='_compute_blade_product_id',
store=True) store=True)
cutting_tool_blade_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀片型号', cutting_tool_blade_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀片型号',
@@ -445,15 +433,18 @@ class FunctionalToolAssembly(models.Model):
related='blade_product_id.specification_id') related='blade_product_id.specification_id')
sf_tool_brand_id_2 = fields.Many2one('sf.machine.brand', '刀片品牌', related='blade_product_id.brand_id') sf_tool_brand_id_2 = fields.Many2one('sf.machine.brand', '刀片品牌', related='blade_product_id.brand_id')
@api.depends('blade_lot_id') @api.depends('blade_freight_barcode')
def _compute_blade_product_id(self): def _compute_blade_product_id(self):
for item in self: for item in self:
if item.blade_lot_id: if item.blade_freight_barcode:
item.blade_product_id = item.blade_lot_id.product_id.id location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', item.blade_freight_barcode)])
if location:
item.blade_product_id = location.product_id.id
else:
item.blade_product_id = False
# ==============刀杆型号================ # ==============刀杆型号================
bar_freight_barcode_id = fields.Many2one('sf.shelf.location', string='刀杆货位') bar_freight_barcode = fields.Char('刀杆货位')
bar_lot_id = fields.Many2one('stock.lot', string='刀杆批次')
bar_product_id = fields.Many2one('product.product', string='刀杆名称', compute='_compute_bar_product_id', bar_product_id = fields.Many2one('product.product', string='刀杆名称', compute='_compute_bar_product_id',
store=True) store=True)
cutting_tool_cutterbar_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀杆型号', cutting_tool_cutterbar_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀杆型号',
@@ -462,15 +453,18 @@ class FunctionalToolAssembly(models.Model):
related='bar_product_id.specification_id') related='bar_product_id.specification_id')
sf_tool_brand_id_3 = fields.Many2one('sf.machine.brand', '刀杆品牌', related='bar_product_id.brand_id') sf_tool_brand_id_3 = fields.Many2one('sf.machine.brand', '刀杆品牌', related='bar_product_id.brand_id')
@api.depends('bar_lot_id') @api.depends('bar_freight_barcode')
def _compute_bar_product_id(self): def _compute_bar_product_id(self):
for item in self: for item in self:
if item.bar_lot_id: if item.bar_freight_barcode:
item.bar_product_id = item.bar_lot_id.product_id.id location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', item.bar_freight_barcode)])
if location:
item.bar_product_id = location.product_id.id
else:
item.bar_product_id = False
# =============刀盘型号================ # =============刀盘型号================
pad_freight_barcode_id = fields.Many2one('sf.shelf.location', string='刀盘货位') pad_freight_barcode = fields.Char('刀盘货位')
pad_lot_id = fields.Many2one('stock.lot', string='刀盘批次')
pad_product_id = fields.Many2one('product.product', string='刀盘名称', compute='_compute_pad_product_id', pad_product_id = fields.Many2one('product.product', string='刀盘名称', compute='_compute_pad_product_id',
store=True) store=True)
cutting_tool_cutterpad_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀盘型号', cutting_tool_cutterpad_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀盘型号',
@@ -479,11 +473,15 @@ class FunctionalToolAssembly(models.Model):
related='pad_product_id.specification_id') related='pad_product_id.specification_id')
sf_tool_brand_id_4 = fields.Many2one('sf.machine.brand', '刀盘品牌', related='pad_product_id.brand_id') sf_tool_brand_id_4 = fields.Many2one('sf.machine.brand', '刀盘品牌', related='pad_product_id.brand_id')
@api.depends('pad_lot_id') @api.depends('pad_freight_barcode')
def _compute_pad_product_id(self): def _compute_pad_product_id(self):
for item in self: for item in self:
if item.pad_lot_id: if item.pad_freight_barcode:
item.pad_product_id = item.pad_lot_id.product_id.id location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', item.pad_freight_barcode)])
if location:
item.pad_product_id = location.product_id.id
else:
item.pad_product_id = False
# ==============刀柄型号============== # ==============刀柄型号==============
handle_freight_rfid = fields.Char('刀柄Rfid', compute='_compute_handle_product_id', store=True) handle_freight_rfid = fields.Char('刀柄Rfid', compute='_compute_handle_product_id', store=True)
@@ -507,8 +505,7 @@ class FunctionalToolAssembly(models.Model):
item.handle_freight_rfid = False item.handle_freight_rfid = False
# ==============夹头型号============== # ==============夹头型号==============
chuck_freight_barcode_id = fields.Many2one('sf.shelf.location', string='夹头货位') chuck_freight_barcode = fields.Char('夹头货位')
chuck_lot_id = fields.Many2one('stock.lot', string='夹头批次')
chuck_product_id = fields.Many2one('product.product', string='夹头名称', compute='_compute_chuck_product_id', chuck_product_id = fields.Many2one('product.product', string='夹头名称', compute='_compute_chuck_product_id',
store=True) store=True)
cutting_tool_cutterhead_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='夹头型号', cutting_tool_cutterhead_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='夹头型号',
@@ -517,18 +514,17 @@ class FunctionalToolAssembly(models.Model):
related='chuck_product_id.specification_id') related='chuck_product_id.specification_id')
sf_tool_brand_id_6 = fields.Many2one('sf.machine.brand', '夹头品牌', related='chuck_product_id.brand_id') sf_tool_brand_id_6 = fields.Many2one('sf.machine.brand', '夹头品牌', related='chuck_product_id.brand_id')
@api.depends('chuck_lot_id') @api.depends('chuck_freight_barcode')
def _compute_chuck_product_id(self): def _compute_chuck_product_id(self):
for item in self: for item in self:
if item.chuck_lot_id: if item.chuck_freight_barcode:
item.chuck_product_id = item.chuck_lot_id.product_id.id location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', item.chuck_freight_barcode)])
if location:
item.chuck_product_id = location.product_id.id
else:
item.chuck_product_id = False
# ==================待删除字段================== # ==================待删除字段==================
integral_freight_barcode = fields.Char('整体式刀具货位')
blade_freight_barcode = fields.Char('刀片货位')
bar_freight_barcode = fields.Char('刀杆货位')
pad_freight_barcode = fields.Char('刀盘货位')
chuck_freight_barcode = fields.Char('夹头货位')
blade_name = fields.Char('') blade_name = fields.Char('')
integral_name = fields.Char('') integral_name = fields.Char('')
blade_code_id = fields.Many2one('stock.lot', '刀片序列号') blade_code_id = fields.Many2one('stock.lot', '刀片序列号')
@@ -547,8 +543,7 @@ class FunctionalToolAssembly(models.Model):
after_assembly_functional_tool_name = fields.Char(string='组装后功能刀具名称', readonly=True) after_assembly_functional_tool_name = fields.Char(string='组装后功能刀具名称', readonly=True)
after_assembly_functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', after_assembly_functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model',
string='组装后功能刀具类型', readonly=True) string='组装后功能刀具类型', readonly=True)
after_assembly_functional_tool_diameter = fields.Float(string='组装后功能刀具直径(mm)', readonly=True, after_assembly_functional_tool_diameter = fields.Float(string='组装后功能刀具直径(mm)', readonly=True, digits=(10, 3))
digits=(10, 3))
after_assembly_knife_tip_r_angle = fields.Float(string='组装后刀尖R角(mm)', readonly=True, digits=(10, 3)) after_assembly_knife_tip_r_angle = fields.Float(string='组装后刀尖R角(mm)', readonly=True, digits=(10, 3))
after_assembly_new_former = fields.Selection([('0', ''), ('1', '')], string='组装后新/旧', readonly=True) after_assembly_new_former = fields.Selection([('0', ''), ('1', '')], string='组装后新/旧', readonly=True)
cut_time = fields.Integer(string='已切削时间(min)', readonly=True) cut_time = fields.Integer(string='已切削时间(min)', readonly=True)
@@ -562,7 +557,7 @@ class FunctionalToolAssembly(models.Model):
after_assembly_alarm_value = fields.Integer(string='组装后报警值(min)', readonly=True) after_assembly_alarm_value = fields.Integer(string='组装后报警值(min)', readonly=True)
after_assembly_used_value = fields.Integer(string='组装后已使用值(min)', readonly=True) after_assembly_used_value = fields.Integer(string='组装后已使用值(min)', readonly=True)
after_assembly_tool_loading_length = fields.Float(string='组装后总长度(mm)', readonly=True, digits=(10, 3)) after_assembly_tool_loading_length = fields.Float(string='组装后总长度(mm)', readonly=True, digits=(10, 3))
after_assembly_handle_length = fields.Float(string='组装后刀柄长度(mm)', readonly=True, digits=(10, 3)) after_assembly_handle_length = fields.Float(string='组装后刀柄长度(mm)',readonly=True, digits=(10, 3))
after_assembly_functional_tool_length = fields.Float(string='组装后伸出长(mm)', readonly=True, digits=(10, 3)) after_assembly_functional_tool_length = fields.Float(string='组装后伸出长(mm)', readonly=True, digits=(10, 3))
after_assembly_effective_length = fields.Float(string='组装后有效长(mm)', readonly=True) after_assembly_effective_length = fields.Float(string='组装后有效长(mm)', readonly=True)
L_D_number = fields.Float(string='L/D值(mm)', readonly=True) L_D_number = fields.Float(string='L/D值(mm)', readonly=True)
@@ -581,15 +576,6 @@ class FunctionalToolAssembly(models.Model):
active = fields.Boolean(string='已归档', default=True) active = fields.Boolean(string='已归档', default=True)
def action_open_reference1(self):
self.ensure_one()
return {
'res_model': self._name,
'type': 'ir.actions.act_window',
'views': [[False, "form"]],
'res_id': self.id,
}
def put_start_preset(self): def put_start_preset(self):
self.search([('start_preset_bool', '=', True)]).write({'start_preset_bool': False}) self.search([('start_preset_bool', '=', True)]).write({'start_preset_bool': False})
self.write({ self.write({
@@ -680,7 +666,7 @@ class FunctionalToolAssembly(models.Model):
class FunctionalToolDismantle(models.Model): class FunctionalToolDismantle(models.Model):
_name = 'sf.functional.tool.dismantle' _name = 'sf.functional.tool.dismantle'
_inherit = ["barcodes.barcode_events_mixin", 'mail.thread'] _inherit = ["barcodes.barcode_events_mixin"]
_description = '功能刀具拆解' _description = '功能刀具拆解'
def on_barcode_scanned(self, barcode): def on_barcode_scanned(self, barcode):
@@ -741,26 +727,9 @@ class FunctionalToolDismantle(models.Model):
raise ValidationError('该功能刀具因为%s拆解,无需录入库位' % self.dismantle_cause) raise ValidationError('该功能刀具因为%s拆解,无需录入库位' % self.dismantle_cause)
name = fields.Char('名称', related='functional_tool_id.name') name = fields.Char('名称', related='functional_tool_id.name')
code = fields.Char('拆解单号', default=lambda self: self._get_code(), readonly=True)
def _get_code(self):
"""
自动生成拆解单编码
"""
new_time = str(fields.Date.today())
datetime = new_time[2:4] + new_time[5:7] + new_time[-2:]
functional_tool_dismantle = self.env['sf.functional.tool.dismantle'].sudo().search(
[('code', 'ilike', datetime)], limit=1, order="id desc")
if not functional_tool_dismantle:
num = "%03d" % 1
else:
m = int(functional_tool_dismantle.code[-3:]) + 1
num = "%03d" % m
return 'GNDJ-CJD-%s-%s' % (datetime, num)
functional_tool_id = fields.Many2one('sf.functional.cutting.tool.entity', '功能刀具', required=True, functional_tool_id = fields.Many2one('sf.functional.cutting.tool.entity', '功能刀具', required=True,
domain=[('functional_tool_status', '!=', '已拆除'), domain=[('functional_tool_status', '!=', '已拆除')])
('current_location', '=', '刀具房')])
tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', store=True, tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', store=True,
compute='_compute_functional_tool_num') compute='_compute_functional_tool_num')
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', compute='_compute_functional_tool_num', store=True) tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', compute='_compute_functional_tool_num', store=True)
@@ -771,7 +740,7 @@ class FunctionalToolDismantle(models.Model):
dismantle_cause = fields.Selection( dismantle_cause = fields.Selection(
[('寿命到期报废', '寿命到期报废'), ('崩刀报废', '崩刀报废'), ('更换为其他刀具', '更换为其他刀具'), [('寿命到期报废', '寿命到期报废'), ('崩刀报废', '崩刀报废'), ('更换为其他刀具', '更换为其他刀具'),
('刀具需磨削', '刀具需磨削')], string='拆解原因', required=True, tracking=True) ('刀具需磨削', '刀具需磨削')], string='拆解原因', required=True)
dismantle_data = fields.Datetime('拆解日期', readonly=True) dismantle_data = fields.Datetime('拆解日期', readonly=True)
dismantle_person = fields.Char('拆解人', readonly=True) dismantle_person = fields.Char('拆解人', readonly=True)
image = fields.Binary('图片', readonly=True) image = fields.Binary('图片', readonly=True)
@@ -779,7 +748,7 @@ class FunctionalToolDismantle(models.Model):
scrap_id = fields.Char('报废单号', readonly=True) scrap_id = fields.Char('报废单号', readonly=True)
grinding_id = fields.Char('磨削单号', readonly=True) grinding_id = fields.Char('磨削单号', readonly=True)
state = fields.Selection([('待拆解', '待拆解'), ('已拆解', '已拆解')], default='待拆解', tracking=True) state = fields.Selection([('待拆解', '待拆解'), ('已拆解', '已拆解')], default='待拆解')
active = fields.Boolean('有效', default=True) active = fields.Boolean('有效', default=True)
# 刀柄 # 刀柄
@@ -789,9 +758,7 @@ class FunctionalToolDismantle(models.Model):
related='handle_product_id.cutting_tool_model_id') related='handle_product_id.cutting_tool_model_id')
handle_brand_id = fields.Many2one('sf.machine.brand', string='刀柄品牌', related='handle_product_id.brand_id') handle_brand_id = fields.Many2one('sf.machine.brand', string='刀柄品牌', related='handle_product_id.brand_id')
handle_rfid = fields.Char(string='刀柄Rfid', compute='_compute_functional_tool_num', store=True) handle_rfid = fields.Char(string='刀柄Rfid', compute='_compute_functional_tool_num', store=True)
handle_lot_id = fields.Many2one('stock.lot', string='刀柄序列号', compute='_compute_functional_tool_num', scrap_boolean = fields.Boolean(string='刀柄是否报废', default=False)
store=True)
scrap_boolean = fields.Boolean(string='刀柄是否报废', default=False, tracking=True)
# 整体式 # 整体式
integral_product_id = fields.Many2one('product.product', string='整体式刀具', integral_product_id = fields.Many2one('product.product', string='整体式刀具',
@@ -800,8 +767,6 @@ class FunctionalToolDismantle(models.Model):
related='integral_product_id.cutting_tool_model_id') related='integral_product_id.cutting_tool_model_id')
integral_brand_id = fields.Many2one('sf.machine.brand', string='整体式刀具品牌', integral_brand_id = fields.Many2one('sf.machine.brand', string='整体式刀具品牌',
related='integral_product_id.brand_id') related='integral_product_id.brand_id')
integral_lot_id = fields.Many2one('stock.lot', string='整体式刀具批次', compute='_compute_functional_tool_num',
store=True)
integral_freight_id = fields.Many2one('sf.shelf.location', '整体式刀具目标货位', integral_freight_id = fields.Many2one('sf.shelf.location', '整体式刀具目标货位',
domain="[('product_id', 'in', (integral_product_id, False))]") domain="[('product_id', 'in', (integral_product_id, False))]")
@@ -811,7 +776,6 @@ class FunctionalToolDismantle(models.Model):
blade_type_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀片型号', blade_type_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀片型号',
related='blade_product_id.cutting_tool_model_id') related='blade_product_id.cutting_tool_model_id')
blade_brand_id = fields.Many2one('sf.machine.brand', string='刀片品牌', related='blade_product_id.brand_id') blade_brand_id = fields.Many2one('sf.machine.brand', string='刀片品牌', related='blade_product_id.brand_id')
blade_lot_id = fields.Many2one('stock.lot', string='刀片批次', compute='_compute_functional_tool_num', store=True)
blade_freight_id = fields.Many2one('sf.shelf.location', '刀片目标货位', blade_freight_id = fields.Many2one('sf.shelf.location', '刀片目标货位',
domain="[('product_id', 'in', (blade_product_id, False))]") domain="[('product_id', 'in', (blade_product_id, False))]")
@@ -821,7 +785,6 @@ class FunctionalToolDismantle(models.Model):
bar_type_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀杆型号', bar_type_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀杆型号',
related='bar_product_id.cutting_tool_model_id') related='bar_product_id.cutting_tool_model_id')
bar_brand_id = fields.Many2one('sf.machine.brand', string='刀杆品牌', related='bar_product_id.brand_id') bar_brand_id = fields.Many2one('sf.machine.brand', string='刀杆品牌', related='bar_product_id.brand_id')
bar_lot_id = fields.Many2one('stock.lot', string='刀杆批次', compute='_compute_functional_tool_num', store=True)
bar_freight_id = fields.Many2one('sf.shelf.location', '刀杆目标货位', bar_freight_id = fields.Many2one('sf.shelf.location', '刀杆目标货位',
domain="[('product_id', 'in', (bar_product_id, False))]") domain="[('product_id', 'in', (bar_product_id, False))]")
@@ -831,7 +794,6 @@ class FunctionalToolDismantle(models.Model):
pad_type_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀盘型号', pad_type_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀盘型号',
related='pad_product_id.cutting_tool_model_id') related='pad_product_id.cutting_tool_model_id')
pad_brand_id = fields.Many2one('sf.machine.brand', string='刀盘品牌', related='pad_product_id.brand_id') pad_brand_id = fields.Many2one('sf.machine.brand', string='刀盘品牌', related='pad_product_id.brand_id')
pad_lot_id = fields.Many2one('stock.lot', string='刀盘批次', compute='_compute_functional_tool_num', store=True)
pad_freight_id = fields.Many2one('sf.shelf.location', '刀盘目标货位', pad_freight_id = fields.Many2one('sf.shelf.location', '刀盘目标货位',
domain="[('product_id', 'in', (pad_product_id, False))]") domain="[('product_id', 'in', (pad_product_id, False))]")
@@ -841,7 +803,6 @@ class FunctionalToolDismantle(models.Model):
chuck_type_id = fields.Many2one('sf.cutting_tool.standard.library', string='夹头型号', chuck_type_id = fields.Many2one('sf.cutting_tool.standard.library', string='夹头型号',
related='chuck_product_id.cutting_tool_model_id') related='chuck_product_id.cutting_tool_model_id')
chuck_brand_id = fields.Many2one('sf.machine.brand', string='夹头品牌', related='chuck_product_id.brand_id') chuck_brand_id = fields.Many2one('sf.machine.brand', string='夹头品牌', related='chuck_product_id.brand_id')
chuck_lot_id = fields.Many2one('stock.lot', string='夹头批次', compute='_compute_functional_tool_num', store=True)
chuck_freight_id = fields.Many2one('sf.shelf.location', '夹头目标货位', chuck_freight_id = fields.Many2one('sf.shelf.location', '夹头目标货位',
domain="[('product_id', 'in', (chuck_product_id, False))]") domain="[('product_id', 'in', (chuck_product_id, False))]")
@@ -865,20 +826,12 @@ class FunctionalToolDismantle(models.Model):
item.rfid = item.functional_tool_id.rfid item.rfid = item.functional_tool_id.rfid
item.handle_rfid = item.functional_tool_id.rfid item.handle_rfid = item.functional_tool_id.rfid
# 产品
item.handle_product_id = item.functional_tool_id.functional_tool_name_id.handle_product_id.id item.handle_product_id = item.functional_tool_id.functional_tool_name_id.handle_product_id.id
item.integral_product_id = item.functional_tool_id.functional_tool_name_id.integral_product_id.id item.integral_product_id = item.functional_tool_id.functional_tool_name_id.integral_product_id.id
item.blade_product_id = item.functional_tool_id.functional_tool_name_id.blade_product_id.id item.blade_product_id = item.functional_tool_id.functional_tool_name_id.blade_product_id.id
item.bar_product_id = item.functional_tool_id.functional_tool_name_id.bar_product_id.id item.bar_product_id = item.functional_tool_id.functional_tool_name_id.bar_product_id.id
item.pad_product_id = item.functional_tool_id.functional_tool_name_id.pad_product_id.id item.pad_product_id = item.functional_tool_id.functional_tool_name_id.pad_product_id.id
item.chuck_product_id = item.functional_tool_id.functional_tool_name_id.chuck_product_id.id item.chuck_product_id = item.functional_tool_id.functional_tool_name_id.chuck_product_id.id
# 批次/序列号
item.handle_lot_id = item.functional_tool_id.functional_tool_name_id.handle_code_id.id
item.integral_lot_id = item.functional_tool_id.functional_tool_name_id.integral_lot_id.id
item.blade_lot_id = item.functional_tool_id.functional_tool_name_id.blade_lot_id.id
item.bar_lot_id = item.functional_tool_id.functional_tool_name_id.bar_lot_id.id
item.pad_lot_id = item.functional_tool_id.functional_tool_name_id.pad_lot_id.id
item.chuck_lot_id = item.functional_tool_id.functional_tool_name_id.chuck_lot_id.id
else: else:
item.tool_groups_id = False item.tool_groups_id = False
item.tool_type_id = False item.tool_type_id = False
@@ -894,49 +847,14 @@ class FunctionalToolDismantle(models.Model):
item.pad_product_id = False item.pad_product_id = False
item.chuck_product_id = False item.chuck_product_id = False
item.handle_lot_id = False
item.integral_lot_id = False
item.blade_lot_id = False
item.bar_lot_id = False
item.pad_lot_id = False
item.chuck_lot_id = False
def location_duplicate_check(self):
"""
目标货位去重校验
"""
if self.blade_freight_id:
if self.bar_freight_id:
if self.blade_freight_id == self.bar_freight_id:
raise ValidationError('【刀片】和【刀杆】的目标货位重复,请重新选择!')
elif self.pad_freight_id:
if self.blade_freight_id == self.pad_freight_id:
raise ValidationError('【刀片】和【刀盘】的目标货位重复,请重新选择!')
if self.chuck_freight_id:
if self.chuck_freight_id == self.integral_freight_id:
raise ValidationError('【夹头】和【整体式刀具】的目标货位重复,请重新选择!')
if self.chuck_freight_id == self.blade_freight_id:
raise ValidationError('【夹头】和【刀片】的目标货位重复,请重新选择!')
if self.chuck_freight_id == self.bar_freight_id:
raise ValidationError('【夹头】和【刀杆】的目标货位重复,请重新选择!')
if self.chuck_freight_id == self.pad_freight_id:
raise ValidationError('【夹头】和【刀盘】的目标货位重复,请重新选择!')
def confirmation_disassembly(self): def confirmation_disassembly(self):
logging.info('%s刀具确认开始拆解' % self.dismantle_cause) logging.info('%s刀具确认开始拆解' % self.dismantle_cause)
code = self.code
if self.functional_tool_id.functional_tool_status == '已拆除': if self.functional_tool_id.functional_tool_status == '已拆除':
raise ValidationError('Rfid为【%s】的功能刀具已经拆解,请勿重复操作!' % self.functional_tool_id.rfid_dismantle) raise ValidationError('Rfid为【%s】的功能刀具已经拆解,请勿重复操作!' % self.functional_tool_id.rfid_dismantle)
# 对拆解的功能刀具进行校验,只有在刀具房的功能刀具才能拆解
if self.functional_tool_id.tool_room_num == 0:
raise ValidationError('Rfid为【%s】的功能刀具当前位置为【%s】,不能进行拆解!' % (
self.rfid, self.functional_tool_id.current_location))
# 目标重复校验
self.location_duplicate_check()
location = self.env['stock.location'].search([('name', '=', '刀具组装位置')]) location = self.env['stock.location'].search([('name', '=', '刀具组装位置')])
location_dest = self.env['stock.location'].search([('name', '=', '刀具房')]) location_dest = self.env['stock.location'].search([('name', '=', '刀具房')])
# =================刀柄是否[报废]拆解======= # =================刀柄是否[报废]拆解=======
location_dest_scrap_ids = self.env['stock.location'].search([('name', 'in', ('Scrap', '报废'))]) location_dest_scrap = self.env['stock.location'].search([('name', '=', 'Scrap')])
if self.handle_rfid: if self.handle_rfid:
lot = self.env['stock.lot'].sudo().search([('rfid', '=', self.handle_rfid)]) lot = self.env['stock.lot'].sudo().search([('rfid', '=', self.handle_rfid)])
if not lot: if not lot:
@@ -944,65 +862,53 @@ class FunctionalToolDismantle(models.Model):
functional_tool_assembly = self.functional_tool_id.functional_tool_name_id functional_tool_assembly = self.functional_tool_id.functional_tool_name_id
if self.scrap_boolean: if self.scrap_boolean:
# 刀柄报废 入库到Scrap # 刀柄报废 入库到Scrap
lot.create_stock_quant(location, location_dest_scrap_ids[-1], functional_tool_assembly.id, code, lot.create_stock_quant(location, location_dest_scrap, functional_tool_assembly.id, '功能刀具拆解',
functional_tool_assembly, functional_tool_assembly.tool_groups_id) functional_tool_assembly, functional_tool_assembly.tool_groups_id)
lot.tool_material_status = '报废'
else: else:
# 刀柄不报废 入库到刀具房 # 刀柄不报废 入库到刀具房
lot.create_stock_quant(location, location_dest, functional_tool_assembly.id, code, lot.create_stock_quant(location, location_dest, functional_tool_assembly.id, '功能刀具拆解',
functional_tool_assembly, functional_tool_assembly.tool_groups_id) functional_tool_assembly, functional_tool_assembly.tool_groups_id)
lot.tool_material_status = '可用'
# ==============功能刀具[报废]拆解================ # ==============功能刀具[报废]拆解================
if self.dismantle_cause in ['寿命到期报废', '崩刀报废']: if self.dismantle_cause in ['寿命到期报废', '崩刀报废']:
# 除刀柄外物料报废 入库到Scrap # 除刀柄外物料报废 入库到Scrap
if self.integral_product_id: if self.integral_product_id:
self.integral_product_id.dismantle_stock_moves(False, self.integral_lot_id, location, self.integral_product_id.dismantle_stock_moves(False, location, location_dest_scrap)
location_dest_scrap_ids[-1], code)
elif self.blade_product_id: elif self.blade_product_id:
self.blade_product_id.dismantle_stock_moves(False, self.blade_lot_id, location, self.blade_product_id.dismantle_stock_moves(False, location, location_dest_scrap)
location_dest_scrap_ids[-1], code)
if self.bar_product_id: if self.bar_product_id:
self.bar_product_id.dismantle_stock_moves(False, self.bar_lot_id, location, self.bar_product_id.dismantle_stock_moves(False, location, location_dest_scrap)
location_dest_scrap_ids[-1], code)
elif self.pad_product_id: elif self.pad_product_id:
self.pad_product_id.dismantle_stock_moves(False, self.pad_lot_id, location, self.pad_product_id.dismantle_stock_moves(False, location, location_dest_scrap)
location_dest_scrap_ids[-1], code)
if self.chuck_product_id: if self.chuck_product_id:
self.chuck_product_id.dismantle_stock_moves(False, self.chuck_lot_id, location, self.chuck_product_id.dismantle_stock_moves(False, location, location_dest_scrap)
location_dest_scrap_ids[-1], code)
# ===========功能刀具[磨削]拆解============== # ===========功能刀具[磨削]拆解==============
# elif self.dismantle_cause in ['刀具需磨削']: elif self.dismantle_cause in ['刀具需磨削']:
# location_dest = self.env['stock.location'].search([('name', '=', '磨削房')]) location_dest = self.env['stock.location'].search([('name', '=', '磨削房')])
# # 除刀柄外物料拆解 入库到具体库位 # 除刀柄外物料拆解 入库到具体库位
# if self.integral_product_id: if self.integral_product_id:
# self.integral_product_id.dismantle_stock_moves(False, location, location_dest) self.integral_product_id.dismantle_stock_moves(False, location, location_dest)
# elif self.blade_product_id: elif self.blade_product_id:
# self.blade_product_id.dismantle_stock_moves(False, location, location_dest) self.blade_product_id.dismantle_stock_moves(False, location, location_dest)
# if self.bar_product_id: if self.bar_product_id:
# self.bar_product_id.dismantle_stock_moves(False, location, location_dest) self.bar_product_id.dismantle_stock_moves(False, location, location_dest)
# elif self.pad_product_id: elif self.pad_product_id:
# self.pad_product_id.dismantle_stock_moves(False, location, location_dest) self.pad_product_id.dismantle_stock_moves(False, location, location_dest)
# if self.chuck_product_id: if self.chuck_product_id:
# self.chuck_product_id.dismantle_stock_moves(False, location, location_dest) self.chuck_product_id.dismantle_stock_moves(False, location, location_dest)
# ==============功能刀具[更换,磨削]拆解============== # ==============功能刀具[更换]拆解==============
elif self.dismantle_cause in ['更换为其他刀具', '刀具需磨削']: elif self.dismantle_cause in ['更换为其他刀具']:
# 除刀柄外物料拆解 入库到具体 # 除刀柄外物料拆解 入库到具体
if self.integral_freight_id: if self.integral_freight_id:
self.integral_product_id.dismantle_stock_moves(self.integral_freight_id, self.integral_lot_id, location, self.integral_product_id.dismantle_stock_moves(self.integral_freight_id.barcode, location,
location_dest, code) location_dest)
elif self.blade_freight_id: elif self.blade_freight_id:
self.blade_product_id.dismantle_stock_moves(self.blade_freight_id, self.blade_lot_id, location, self.blade_product_id.dismantle_stock_moves(self.blade_freight_id.barcode, location, location_dest)
location_dest, code)
if self.bar_freight_id: if self.bar_freight_id:
self.bar_product_id.dismantle_stock_moves(self.bar_freight_id, self.bar_lot_id, location, self.bar_product_id.dismantle_stock_moves(self.bar_freight_id.barcode, location, location_dest)
location_dest, code)
elif self.pad_freight_id: elif self.pad_freight_id:
self.pad_product_id.dismantle_stock_moves(self.pad_freight_id, self.pad_lot_id, location, self.pad_product_id.dismantle_stock_moves(self.pad_freight_id.barcode, location, location_dest)
location_dest, code)
if self.chuck_freight_id: if self.chuck_freight_id:
self.chuck_product_id.dismantle_stock_moves(self.chuck_freight_id, self.chuck_lot_id, location, self.chuck_product_id.dismantle_stock_moves(self.chuck_freight_id.barcode, location, location_dest)
location_dest, code)
# ===============删除功能刀具的Rfid字段的值 赋值给Rfid(已拆解)字段===== # ===============删除功能刀具的Rfid字段的值 赋值给Rfid(已拆解)字段=====
self.functional_tool_id.write({ self.functional_tool_id.write({
'rfid_dismantle': self.functional_tool_id.rfid, 'rfid_dismantle': self.functional_tool_id.rfid,
@@ -1023,22 +929,26 @@ class FunctionalToolDismantle(models.Model):
class ProductProduct(models.Model): class ProductProduct(models.Model):
_inherit = 'product.product' _inherit = 'product.product'
def dismantle_stock_moves(self, shelf_location_id, lot_id, location_id, location_dest_id, code): def dismantle_stock_moves(self, shelf_location_barcode, location_id, location_dest_id):
# 创建功能刀具拆解单产品库存移动记录 # 创建功能刀具拆解单产品库存移动记录
stock_move_id = self.env['stock.move'].sudo().create({ stock_move_id = self.env['stock.move'].sudo().create({
'name': code, 'name': '功能刀具拆解',
'product_id': self.id, 'product_id': self.id,
'location_id': location_id.id, 'location_id': location_id.id,
'location_dest_id': location_dest_id.id, 'location_dest_id': location_dest_id.id,
'product_uom_qty': 1.00, 'product_uom_qty': 1.00,
'state': 'done' 'state': 'done'
}) })
if shelf_location_barcode:
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', shelf_location_barcode)])
location.product_num = location.product_num + 1
else:
location = self.env['sf.shelf.location']
# 创建移动历史记录 # 创建移动历史记录
stock_move_line_id = self.env['stock.move.line'].sudo().create({ stock_move_line_id = self.env['stock.move.line'].sudo().create({
'product_id': self.id, 'product_id': self.id,
'lot_id': lot_id.id,
'move_id': stock_move_id.id, 'move_id': stock_move_id.id,
'destination_location_id': shelf_location_id.id if shelf_location_id else False, 'current_location_id': location.id,
'install_tool_time': fields.Datetime.now(), 'install_tool_time': fields.Datetime.now(),
'qty_done': 1.0, 'qty_done': 1.0,
'state': 'done', 'state': 'done',

View File

@@ -14,15 +14,14 @@ class FunctionalCuttingToolEntity(models.Model):
functional_tool_name_id = fields.Many2one('sf.functional.tool.assembly', string='功能刀具组装单', readonly=True) functional_tool_name_id = fields.Many2one('sf.functional.tool.assembly', string='功能刀具组装单', readonly=True)
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', related='functional_tool_name_id.tool_groups_id', tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', related='functional_tool_name_id.tool_groups_id')
store=True)
code = fields.Char('编码') code = fields.Char('编码')
rfid = fields.Char('Rfid', readonly=True) rfid = fields.Char('Rfid', readonly=True)
rfid_dismantle = fields.Char('Rfid(已拆解)', readonly=True) rfid_dismantle = fields.Char('Rfid(已拆解)', readonly=True)
name = fields.Char('名称') name = fields.Char('名称')
tool_name_id = fields.Many2one('sf.tool.inventory', '功能刀具名称') tool_name_id = fields.Many2one('sf.tool.inventory', '功能刀具名称')
sf_cutting_tool_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀具型号') sf_cutting_tool_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀具型号')
barcode_id = fields.Many2one('stock.lot', string='序列号', readonly=True) barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号', readonly=True)
sf_cutting_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', sf_cutting_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型',
group_expand='_read_group_mrs_cutting_tool_type_id', compute_sudo=True) group_expand='_read_group_mrs_cutting_tool_type_id', compute_sudo=True)
@@ -31,61 +30,56 @@ class FunctionalCuttingToolEntity(models.Model):
coarse_middle_thin = fields.Selection([("1", ""), ('2', ''), ('3', '')], string='粗/中/精', readonly=True) coarse_middle_thin = fields.Selection([("1", ""), ('2', ''), ('3', '')], string='粗/中/精', readonly=True)
new_former = fields.Selection([('0', ''), ('1', '')], string='新/旧', readonly=True) new_former = fields.Selection([('0', ''), ('1', '')], string='新/旧', readonly=True)
tool_loading_length = fields.Float(string='总长度(mm)', readonly=True, digits=(10, 3)) tool_loading_length = fields.Float(string='总长度(mm)', readonly=True, digits=(10, 3))
handle_length = fields.Float(string='刀柄长度(mm)', readonly=True, digits=(10, 3)) handle_length = fields.Float(string='刀柄长度(mm)',readonly=True, digits=(10, 3))
functional_tool_length = fields.Float(string='伸出长(mm)', readonly=True, digits=(10, 3)) functional_tool_length = fields.Float(string='伸出长(mm)', readonly=True, digits=(10, 3))
effective_length = fields.Float(string='有效长(mm)', readonly=True) effective_length = fields.Float(string='有效长(mm)', readonly=True)
tool_room_num = fields.Integer(string='刀具房数量', compute='_compute_num', store=True) tool_room_num = fields.Integer(string='刀具房数量', readonly=True)
line_edge_knife_library_num = fields.Integer(string='线边刀库数量', compute='_compute_num', store=True) line_edge_knife_library_num = fields.Integer(string='线边刀库数量', readonly=True)
machine_knife_library_num = fields.Integer(string='机内刀库数量', compute='_compute_num', store=True) machine_knife_library_num = fields.Integer(string='机内刀库数量', readonly=True)
max_lifetime_value = fields.Integer(string='最大寿命值(min)', readonly=True) max_lifetime_value = fields.Integer(string='最大寿命值(min)', readonly=True)
alarm_value = fields.Integer(string='报警值(min)', readonly=True) alarm_value = fields.Integer(string='报警值(min)', readonly=True)
used_value = fields.Integer(string='已使用值(min)', readonly=True) used_value = fields.Integer(string='已使用值(min)', readonly=True)
functional_tool_status = fields.Selection([('正常', '正常'), ('报警', '报警'), ('已拆除', '已拆除')], functional_tool_status = fields.Selection([('正常', '正常'), ('报警', '报警'), ('已拆除', '已拆除')],
string='状态', store=True, default='正常') string='状态', store=True, default='正常')
current_location_id = fields.Many2one('stock.location', string='当前位置', compute='_compute_current_location_id', current_location_id = fields.Many2one('stock.location', string='当前位置', readonly=True)
store=True)
current_shelf_location_id = fields.Many2one('sf.shelf.location', string='当前货位', readonly=True)
current_location = fields.Selection( current_location = fields.Selection(
[('组装后', '组装后'), ('刀具房', '刀具房'), ('线边刀库', '线边刀库'), ('机内刀库', '机内刀库')], [('组装后', '组装后'), ('刀具房', '刀具房'), ('线边刀库', '线边刀库'), ('机内刀库', '机内刀库')],
string='位置', compute='_compute_current_location_id', store=True) string='位置', compute='_compute_current_location_id', store=True)
image = fields.Binary('图片', readonly=True) image = fields.Binary('图片', readonly=True)
active = fields.Boolean(string='已归档', default=True)
safe_inventory_id = fields.Many2one('sf.real.time.distribution.of.functional.tools', safe_inventory_id = fields.Many2one('sf.real.time.distribution.of.functional.tools',
string='功能刀具安全库存', readonly=True) string='功能刀具安全库存', readonly=True)
@api.depends('barcode_id.quant_ids', 'functional_tool_status', 'current_shelf_location_id') @api.depends('barcode_id.quant_ids', 'functional_tool_status')
def _compute_current_location_id(self): def _compute_current_location_id(self):
for record in self: for record in self:
if record.functional_tool_status == '已拆除':
record.current_location_id = False
record.current_location = False
else:
if record.barcode_id.quant_ids: if record.barcode_id.quant_ids:
for quant_id in record.barcode_id.quant_ids: for quant_id in record.barcode_id.quant_ids:
if quant_id.inventory_quantity_auto_apply > 0: if quant_id.inventory_quantity_auto_apply > 0:
record.current_location_id = quant_id.location_id record.current_location_id = quant_id.location_id
if quant_id.location_id.name == '制造前': if quant_id.location_id.name == '制造前':
if not record.current_shelf_location_id:
record.current_location = '机内刀库' record.current_location = '机内刀库'
else: else:
record.current_location = '线边刀库' record.current_location = quant_id.location_id.name
else: if record.current_location_id:
record.current_location = '刀具房' record.sudo().get_location_num()
else: else:
record.current_location_id = False record.current_location_id = False
record.current_location = False record.current_location = False
if record.functional_tool_status == '已拆除':
record.current_location_id = False
record.current_location = False
record.tool_room_num = 0
record.line_edge_knife_library_num = 0
record.machine_knife_library_num = 0
@api.depends('current_location', 'functional_tool_status') def get_location_num(self):
def _compute_num(self):
""" """
计算库存位置数量 计算库存位置数量
""" """
for obj in self: for obj in self:
if obj.functional_tool_status == '已拆除':
obj.tool_room_num = 0
obj.line_edge_knife_library_num = 0
obj.machine_knife_library_num = 0
else:
if obj.current_location_id: if obj.current_location_id:
obj.tool_room_num = 0 obj.tool_room_num = 0
obj.line_edge_knife_library_num = 0 obj.line_edge_knife_library_num = 0
@@ -97,70 +91,6 @@ class FunctionalCuttingToolEntity(models.Model):
elif "机内刀库" in obj.current_location: elif "机内刀库" in obj.current_location:
obj.machine_knife_library_num = 1 obj.machine_knife_library_num = 1
def tool_in_out_stock_location(self, location_id):
tool_room_id = self.env['stock.location'].search([('name', '=', '刀具房')])
pre_manufacturing_id = self.env['stock.location'].search([('name', '=', '制造前')])
for item in self:
# 中控反馈该位置有刀
if item:
# 系统该位置有刀
if location_id.product_sn_id:
# 中控反馈和系统中,该位置是同一把刀
if item.barcode_id == location_id.product_sn_id:
return True
# 中控反馈和系统中,该位置不是同一把刀
else:
# 原刀从线边出库
item.tool_in_out_stock_location_1(location_id, tool_room_id)
# 新刀入库到线边
item.create_stock_move(pre_manufacturing_id, location_id)
item.current_shelf_location_id = location_id.id
# 中控反馈该位置没有刀
else:
# 系统该位置有刀
if location_id.product_sn_id:
item.tool_in_out_stock_location_1(location_id, tool_room_id)
def tool_in_out_stock_location_1(self, location_id, tool_room_id):
tool = self.env['sf.functional.cutting.tool.entity'].search(
[('barcode_id', '=', location_id.product_sn_id.id)])
if tool.current_location == '线边刀库':
tool.create_stock_move(tool_room_id, False)
# 修改功能刀具的当前位置
tool.current_shelf_location_id = False
def create_stock_move(self, location_dest_id, destination_location_id):
# 创建库存移动记录
stock_move_id = self.env['stock.move'].sudo().create({
'name': '/',
'product_id': self.barcode_id.product_id.id,
'location_id': self.current_location_id.id,
'location_dest_id': location_dest_id.id,
'product_uom_qty': 1.00,
'state': 'done'
})
# 创建移动历史记录
stock_move_line_id = self.env['stock.move.line'].sudo().create({
'product_id': self.barcode_id.product_id.id,
'lot_id': self.barcode_id.id,
'move_id': stock_move_id.id,
'current_location_id': False if not self.current_shelf_location_id else self.current_shelf_location_id.id,
'destination_location_id': False if not destination_location_id else destination_location_id.id,
'qty_done': 1.0,
'state': 'done',
'functional_tool_type_id': self.sf_cutting_tool_type_id.id,
'diameter': self.functional_tool_diameter,
'knife_tip_r_angle': self.knife_tip_r_angle,
'code': self.code,
'rfid': self.rfid,
'functional_tool_name': self.name,
'tool_groups_id': self.tool_groups_id.id
})
return stock_move_id, stock_move_line_id
@api.model @api.model
def _read_group_mrs_cutting_tool_type_id(self, categories, domain, order): def _read_group_mrs_cutting_tool_type_id(self, categories, domain, order):
mrs_cutting_tool_type_ids = categories._search([], order=order, access_rights_uid=SUPERUSER_ID) mrs_cutting_tool_type_ids = categories._search([], order=order, access_rights_uid=SUPERUSER_ID)
@@ -262,14 +192,12 @@ class FunctionalCuttingToolEntity(models.Model):
机床当前刀库实时信息接口,功能刀具出库 机床当前刀库实时信息接口,功能刀具出库
""" """
# 获取位置对象 # 获取位置对象
location_inventory_id = self.current_location_id
stock_location_id = self.env['stock.location'].search([('name', '=', '制造前')]) stock_location_id = self.env['stock.location'].search([('name', '=', '制造前')])
# 创建功能刀具该批次/序列号 库存移动和移动历史 # 创建功能刀具该批次/序列号 库存移动和移动历史
self.create_stock_move(stock_location_id, False) self.barcode_id.create_stock_quant(location_inventory_id, stock_location_id,
self.current_location_id = stock_location_id.id self.functional_tool_name_id.id, '机床装刀', self.functional_tool_name_id,
self.current_shelf_location_id = False self.functional_tool_name_id.tool_groups_id)
# self.barcode_id.create_stock_quant(location_inventory_id, stock_location_id,
# self.functional_tool_name_id.id, '机床装刀', self.functional_tool_name_id,
# self.functional_tool_name_id.tool_groups_id)
# ==========刀具组接口========== # ==========刀具组接口==========
# def _register_functional_tool_groups(self, obj): # def _register_functional_tool_groups(self, obj):
@@ -377,7 +305,7 @@ class StockMoveLine(models.Model):
functional_tool_name = fields.Char('刀具名称') functional_tool_name = fields.Char('刀具名称')
diameter = fields.Float(string='刀具直径(mm)') diameter = fields.Float(string='刀具直径(mm)')
knife_tip_r_angle = fields.Float(string='刀尖R角(mm)') knife_tip_r_angle = fields.Float(string='刀尖R角(mm)')
install_tool_time = fields.Datetime("刀具组装时间") install_tool_time = fields.Datetime("刀具组装时间", default=fields.Datetime.now())
code = fields.Char('编码') code = fields.Char('编码')
rfid = fields.Char('Rfid') rfid = fields.Char('Rfid')
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组') tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组')
@@ -387,26 +315,9 @@ class StockMoveLine(models.Model):
names = categories._search([], order=order, access_rights_uid=SUPERUSER_ID) names = categories._search([], order=order, access_rights_uid=SUPERUSER_ID)
return categories.browse(names) return categories.browse(names)
def action_open_reference1(self):
self.ensure_one()
if self.functional_tool_name_id:
action = self.functional_tool_name_id.action_open_reference1()
return action
elif self.move_id:
action = self.move_id.action_open_reference()
if action['res_model'] != 'stock.move':
return action
return {
'res_model': self._name,
'type': 'ir.actions.act_window',
'views': [[False, "form"]],
'res_id': self.id,
}
class RealTimeDistributionOfFunctionalTools(models.Model): class RealTimeDistributionOfFunctionalTools(models.Model):
_name = 'sf.real.time.distribution.of.functional.tools' _name = 'sf.real.time.distribution.of.functional.tools'
_inherit = ['mail.thread']
_description = '功能刀具安全库存' _description = '功能刀具安全库存'
name = fields.Char('名称', readonly=True, compute='_compute_name', store=True) name = fields.Char('名称', readonly=True, compute='_compute_name', store=True)
@@ -416,15 +327,15 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
group_expand='_read_mrs_cutting_tool_type_ids', store=True) group_expand='_read_mrs_cutting_tool_type_ids', store=True)
diameter = fields.Float(string='刀具直径(mm)', readonly=False) diameter = fields.Float(string='刀具直径(mm)', readonly=False)
knife_tip_r_angle = fields.Float(string='刀尖R角(mm)', readonly=False) knife_tip_r_angle = fields.Float(string='刀尖R角(mm)', readonly=False)
tool_stock_num = fields.Integer(string='刀具房数量', compute='_compute_stock_num', store=True) tool_stock_num = fields.Integer(string='刀具房数量')
side_shelf_num = fields.Integer(string='线边刀库数量', compute='_compute_stock_num', store=True) side_shelf_num = fields.Integer(string='线边刀库数量')
on_tool_stock_num = fields.Integer(string='机内刀库数量', compute='_compute_stock_num', store=True) on_tool_stock_num = fields.Integer(string='机内刀库数量')
tool_stock_total = fields.Integer(string='当前库存量', compute='_compute_tool_stock_total', store=True) tool_stock_total = fields.Integer(string='当前库存量', readonly=True)
min_stock_num = fields.Integer('最低库存量', tracking=True) min_stock_num = fields.Integer('最低库存量')
max_stock_num = fields.Integer('最高库存量', tracking=True) max_stock_num = fields.Integer('最高库存量')
batch_replenishment_num = fields.Integer('批次补货量', readonly=True, compute='_compute_batch_replenishment_num', batch_replenishment_num = fields.Integer('批次补货量', readonly=True, compute='_compute_batch_replenishment_num',
store=True) store=True)
unit = fields.Char('单位', default="") unit = fields.Char('单位')
image = fields.Binary('图片', readonly=False) image = fields.Binary('图片', readonly=False)
coarse_middle_thin = fields.Selection([("1", ""), ('2', ''), ('3', '')], string='粗/中/精', readonly=False) coarse_middle_thin = fields.Selection([("1", ""), ('2', ''), ('3', '')], string='粗/中/精', readonly=False)
@@ -492,6 +403,10 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
def _compute_batch_replenishment_num(self): def _compute_batch_replenishment_num(self):
for tool in self: for tool in self:
if tool: if tool:
# 计算刀具房数量、线边刀库数量、机内刀库数量
tool.sudo().get_stock_num(tool)
# 计算当前库存量
tool.sudo().tool_stock_total = tool.tool_stock_num + tool.side_shelf_num + tool.on_tool_stock_num
# 如果当前库存量小于最低库存量,计算批次补货量 # 如果当前库存量小于最低库存量,计算批次补货量
tool.sudo().open_batch_replenishment_num(tool) tool.sudo().open_batch_replenishment_num(tool)
@@ -510,38 +425,6 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
else: else:
tool.sudo().batch_replenishment_num = 0 tool.sudo().batch_replenishment_num = 0
@api.depends('sf_functional_tool_entity_ids', 'sf_functional_tool_entity_ids.tool_room_num',
'sf_functional_tool_entity_ids.line_edge_knife_library_num',
'sf_functional_tool_entity_ids.machine_knife_library_num')
def _compute_stock_num(self):
"""
计算刀具房数量、线边刀库数量、机内刀库数量
"""
for tool in self:
if tool:
tool.tool_stock_num = 0
tool.side_shelf_num = 0
tool.on_tool_stock_num = 0
if tool.sf_functional_tool_entity_ids:
for cutting_tool in tool.sf_functional_tool_entity_ids:
if cutting_tool.tool_room_num > 0:
tool.tool_stock_num += 1
elif cutting_tool.line_edge_knife_library_num > 0:
tool.side_shelf_num += 1
elif cutting_tool.machine_knife_library_num > 0:
tool.on_tool_stock_num += 1
else:
tool.tool_stock_num = 0
tool.side_shelf_num = 0
tool.on_tool_stock_num = 0
@api.depends('tool_stock_num', 'side_shelf_num', 'on_tool_stock_num')
def _compute_tool_stock_total(self):
for tool in self:
if tool:
# 计算当前库存量
tool.tool_stock_total = tool.tool_stock_num + tool.side_shelf_num + tool.on_tool_stock_num
def create_functional_tool_assembly(self, tool): def create_functional_tool_assembly(self, tool):
""" """
创建功能刀具组装单 创建功能刀具组装单
@@ -562,6 +445,27 @@ class RealTimeDistributionOfFunctionalTools(models.Model):
}) })
tool.sudo().sf_functional_tool_assembly_ids = [(4, functional_tool_assembly.id)] tool.sudo().sf_functional_tool_assembly_ids = [(4, functional_tool_assembly.id)]
def get_stock_num(self, tool):
"""
计算刀具房数量、线边刀库数量、机内刀库数量
"""
if tool:
tool.tool_stock_num = 0
tool.side_shelf_num = 0
tool.on_tool_stock_num = 0
if tool.sf_functional_tool_entity_ids:
for cutting_tool in tool.sf_functional_tool_entity_ids:
if cutting_tool.tool_room_num > 0:
tool.tool_stock_num += 1
elif cutting_tool.line_edge_knife_library_num > 0:
tool.side_shelf_num += 1
elif cutting_tool.machine_knife_library_num > 0:
tool.on_tool_stock_num += 1
else:
tool.tool_stock_num = 0
tool.side_shelf_num = 0
tool.on_tool_stock_num = 0
def create_or_edit_safety_stock(self, vals, sf_functional_tool_entity_ids): def create_or_edit_safety_stock(self, vals, sf_functional_tool_entity_ids):
""" """
根据传入的信息新增或者更新功能刀具安全库存的信息 根据传入的信息新增或者更新功能刀具安全库存的信息

View File

@@ -80,7 +80,7 @@ class StockLot(models.Model):
headers = Common.get_headers(self, token, sf_secret_key) headers = Common.get_headers(self, token, sf_secret_key)
str_url = sf_sync_config['sf_url'] + "/api/tool_material_stock/create" str_url = sf_sync_config['sf_url'] + "/api/tool_material_stock/create"
product_ids = self.env['product.product'].sudo().search([('categ_type', '=', '刀具')]).ids product_ids = self.env['product.product'].sudo().search([('categ_type', '=', '刀具')]).ids
objs_all = self.env['stock.lot'].search([('product_id', 'in', product_ids)]) objs_all = self.env['stock.lot'].search([('rfid', '!=', False), ('product_id', 'in', product_ids)])
self._get_sync_stock_lot(objs_all, str_url, token, headers) self._get_sync_stock_lot(objs_all, str_url, token, headers)
def _get_sync_stock_lot(self, objs_all, str_url, token, headers): def _get_sync_stock_lot(self, objs_all, str_url, token, headers):
@@ -90,7 +90,6 @@ class StockLot(models.Model):
for item in objs_all: for item in objs_all:
val = { val = {
'name': item.name, 'name': item.name,
'qty': item.product_qty,
'tool_material_status': item.tool_material_status, 'tool_material_status': item.tool_material_status,
'location': [] if not item.quant_ids else item.quant_ids[-1].location_id.name, 'location': [] if not item.quant_ids else item.quant_ids[-1].location_id.name,
'tool_material_search_id': item.tool_material_search_id.id, 'tool_material_search_id': item.tool_material_search_id.id,
@@ -163,6 +162,14 @@ class ToolMaterial(models.Model):
except Exception as e: except Exception as e:
logging.info("刀具物料同步失败:%s" % e) logging.info("刀具物料同步失败:%s" % e)
# @api.model_create_multi
# def create(self, vals_list):
# records = super(ToolMaterial, self).create(vals_list)
# for record in records:
# if record:
# record.enroll_tool_material()
# return records
class FunctionalCuttingToolEntity(models.Model): class FunctionalCuttingToolEntity(models.Model):
_inherit = 'sf.functional.cutting.tool.entity' _inherit = 'sf.functional.cutting.tool.entity'
@@ -234,7 +241,8 @@ class FunctionalCuttingToolEntity(models.Model):
'blade_tip_characteristics_name': item.blade_tip_characteristics_id.name, 'blade_tip_characteristics_name': item.blade_tip_characteristics_id.name,
'handle_type_name': item.handle_type_id.name, 'handle_type_name': item.handle_type_id.name,
'cutting_direction_names': get_cutting_direction_names(item), 'cutting_direction_names': get_cutting_direction_names(item),
'suitable_coolant_names': get_suitable_coolant_names(item) 'suitable_coolant_names': get_suitable_coolant_names(item),
'active': item.active,
} }
functional_tool_list.append(val) functional_tool_list.append(val)
kw = json.dumps(functional_tool_list, ensure_ascii=False) kw = json.dumps(functional_tool_list, ensure_ascii=False)
@@ -248,206 +256,250 @@ class FunctionalCuttingToolEntity(models.Model):
except Exception as e: except Exception as e:
logging.info("功能刀具同步失败:%s" % e) logging.info("功能刀具同步失败:%s" % e)
# @api.model_create_multi
# def create(self, vals_list):
# records = super(FunctionalCuttingToolEntity, self).create(vals_list)
# for record in records:
# if record:
# record.enroll_functional_tool_entity()
# return records
class FunctionalToolWarning(models.Model): # def write(self, vals):
_inherit = 'sf.functional.tool.warning' # res = super().write(vals)
_description = '功能刀具预警注册' # if vals.get('current_location'):
# self.enroll_functional_tool_entity()
# return res
crea_url = "/api/functional_tool_warning/create" #
# class FunctionalToolWarning(models.Model):
# 注册同步功能刀具预警 # _inherit = 'sf.functional.tool.warning'
def enroll_functional_tool_warning(self): # _description = '功能刀具预警注册'
logging.info('调用功能刀具预警注册接口: enroll_functional_tool_warning()') #
sf_sync_config = self.env['res.config.settings'].get_values() # crea_url = "/api/functional_tool_warning/create"
token = sf_sync_config['token'] #
sf_secret_key = sf_sync_config['sf_secret_key'] # # 注册同步功能刀具预警
headers = Common.get_headers(self, token, sf_secret_key) # def enroll_functional_tool_warning(self):
str_url = sf_sync_config['sf_url'] + self.crea_url # logging.info('调用功能刀具预警注册接口: enroll_functional_tool_warning()')
objs_all = self.env['sf.functional.tool.warning'].search([('id', '=', self.id)]) # sf_sync_config = self.env['res.config.settings'].get_values()
self.get_sync_functional_tool_warning(objs_all, str_url, token, headers) # token = sf_sync_config['token']
# sf_secret_key = sf_sync_config['sf_secret_key']
def sync_enroll_functional_tool_warning_all(self): # headers = Common.get_headers(self, token, sf_secret_key)
logging.info('调用功能刀具预警注册接口: sync_enroll_functional_tool_warning_all()') # str_url = sf_sync_config['sf_url'] + self.crea_url
sf_sync_config = self.env['res.config.settings'].get_values() # objs_all = self.env['sf.functional.tool.warning'].search([('id', '=', self.id)])
token = sf_sync_config['token'] # self.get_sync_functional_tool_warning(objs_all, str_url, token, headers)
sf_secret_key = sf_sync_config['sf_secret_key'] #
headers = Common.get_headers(self, token, sf_secret_key) # def sync_enroll_functional_tool_warning_all(self):
str_url = sf_sync_config['sf_url'] + self.crea_url # logging.info('调用功能刀具预警注册接口: sync_enroll_functional_tool_warning_all()')
objs_all = self.env['sf.functional.tool.warning'].search([]) # sf_sync_config = self.env['res.config.settings'].get_values()
self.get_sync_functional_tool_warning(objs_all, str_url, token, headers) # token = sf_sync_config['token']
# sf_secret_key = sf_sync_config['sf_secret_key']
def get_sync_functional_tool_warning(self, objs_all, str_url, token, headers): # headers = Common.get_headers(self, token, sf_secret_key)
tool_warning_list = [] # str_url = sf_sync_config['sf_url'] + self.crea_url
try: # objs_all = self.env['sf.functional.tool.warning'].search([])
if objs_all: # self.get_sync_functional_tool_warning(objs_all, str_url, token, headers)
for item in objs_all: #
val = { # def get_sync_functional_tool_warning(self, objs_all, str_url, token, headers):
'id': item.id, # tool_warning_list = []
'name': item.name, # try:
'code': item.code, # if objs_all:
'rfid': item.rfid, # for item in objs_all:
'tool_groups_name': item.tool_groups_id.name, # val = {
'production_line': item.production_line_id.name, # 'id': item.id,
'machine_tool_id': item.maintenance_equipment_id.code, # 'name': item.name,
'machine_tool_code': item.machine_tool_code, # 'code': item.code,
'cutter_spacing_code': item.cutter_spacing_code_id.code, # 'rfid': item.rfid,
'functional_tool_name': item.name, # 'tool_groups_name': item.tool_groups_id.name,
'barcode': item.barcode_id.name, # 'production_line': item.production_line_id.name,
'mrs_cutting_tool_type_code': item.mrs_cutting_tool_type_id.code, # 'machine_tool_id': item.maintenance_equipment_id.code,
'diameter': item.diameter, # 'machine_tool_code': item.machine_tool_code,
'knife_tip_r_angle': item.knife_tip_r_angle, # 'cutter_spacing_code': item.cutter_spacing_code_id.code,
'install_tool_time': item.install_tool_time.strftime('%Y-%m-%d %H:%M:%S'), # 'functional_tool_name': item.name,
'on_board_time': item.on_board_time.strftime('%Y-%m-%d %H:%M:%S'), # 'barcode': item.barcode_id.name,
'max_lifetime_value': item.max_lifetime_value, # 'mrs_cutting_tool_type_code': item.mrs_cutting_tool_type_id.code,
'alarm_value': item.alarm_value, # 'diameter': item.diameter,
'used_value': item.used_value, # 'knife_tip_r_angle': item.knife_tip_r_angle,
'functional_tool_status': item.functional_tool_status, # 'install_tool_time': item.install_tool_time.strftime('%Y-%m-%d %H:%M:%S'),
'alarm_time': item.alarm_time.strftime('%Y-%m-%d %H:%M:%S'), # 'on_board_time': item.on_board_time.strftime('%Y-%m-%d %H:%M:%S'),
'dispose_user': item.dispose_user, # 'max_lifetime_value': item.max_lifetime_value,
'dispose_time': item.dispose_time, # 'alarm_value': item.alarm_value,
'dispose_func': item.dispose_func, # 'used_value': item.used_value,
} # 'functional_tool_status': item.functional_tool_status,
tool_warning_list.append(val) # 'alarm_time': item.alarm_time.strftime('%Y-%m-%d %H:%M:%S'),
kw = json.dumps(tool_warning_list, ensure_ascii=False) # 'dispose_user': item.dispose_user,
r = requests.post(str_url, json={}, data={'kw': kw, 'token': token}, headers=headers) # 'dispose_time': item.dispose_time,
ret = r.json() # 'dispose_func': item.dispose_func,
if ret.get('code') == 200: # }
return "功能刀具预警注册成功" # tool_warning_list.append(val)
else: # kw = json.dumps(tool_warning_list, ensure_ascii=False)
logging.info('没有注册功能刀具预警信息') # r = requests.post(str_url, json={}, data={'kw': kw, 'token': token}, headers=headers)
except Exception as e: # ret = r.json()
logging.info("捕获错误信息:%s" % e) # if ret.get('code') == 200:
# return "功能刀具预警注册成功"
# else:
class StockMoveLine(models.Model): # logging.info('没有注册功能刀具预警信息')
_inherit = 'stock.move.line' # except Exception as e:
_description = '功能刀具出入库记录注册' # logging.info("捕获错误信息:%s" % e)
#
crea_url = "/api/functional_tool_move/create" # @api.model_create_multi
# def create(self, vals_list):
# 注册同步功能刀具出入库记录 # records = super(FunctionalToolWarning, self).create(vals_list)
def enroll_functional_tool_move(self): # for record in records:
logging.info('调用功能刀具出入库记录注册接口: enroll_functional_tool_move()') # if record:
sf_sync_config = self.env['res.config.settings'].get_values() # record.enroll_functional_tool_warning()
token = sf_sync_config['token'] # return records
sf_secret_key = sf_sync_config['sf_secret_key'] #
headers = Common.get_headers(self, token, sf_secret_key) #
str_url = sf_sync_config['sf_url'] + self.crea_url # class StockMoveLine(models.Model):
objs_all = self.env['stock.move.line'].search([('id', '=', self.id), ('functional_tool_name_id', '!=', False)]) # _inherit = 'stock.move.line'
self.get_sync_stock_move_line(objs_all, str_url, token, headers) # _description = '功能刀具出入库记录注册'
#
def sync_enroll_functional_tool_move_all(self): # crea_url = "/api/functional_tool_move/create"
logging.info('调用功能刀具出入库记录注册接口: sync_enroll_functional_tool_move_all()') #
sf_sync_config = self.env['res.config.settings'].get_values() # # 注册同步功能刀具出入库记录
token = sf_sync_config['token'] # def enroll_functional_tool_move(self):
sf_secret_key = sf_sync_config['sf_secret_key'] # logging.info('调用功能刀具出入库记录注册接口: enroll_functional_tool_move()')
headers = Common.get_headers(self, token, sf_secret_key) # sf_sync_config = self.env['res.config.settings'].get_values()
str_url = sf_sync_config['sf_url'] + self.crea_url # token = sf_sync_config['token']
objs_all = self.env['stock.move.line'].search([('functional_tool_name_id', '!=', False)]) # sf_secret_key = sf_sync_config['sf_secret_key']
self.get_sync_stock_move_line(objs_all, str_url, token, headers) # headers = Common.get_headers(self, token, sf_secret_key)
# str_url = sf_sync_config['sf_url'] + self.crea_url
def get_sync_stock_move_line(self, objs_all, str_url, token, headers): # objs_all = self.env['stock.move.line'].search([('id', '=', self.id), ('functional_tool_name_id', '!=', False)])
tool_stock_list = [] # self.get_sync_stock_move_line(objs_all, str_url, token, headers)
try: #
if objs_all: # def sync_enroll_functional_tool_move_all(self):
for item in objs_all: # logging.info('调用功能刀具出入库记录注册接口: sync_enroll_functional_tool_move_all()')
val = { # sf_sync_config = self.env['res.config.settings'].get_values()
'id': item.id, # token = sf_sync_config['token']
'name': item.functional_tool_name, # sf_secret_key = sf_sync_config['sf_secret_key']
'code': item.code, # headers = Common.get_headers(self, token, sf_secret_key)
'rfid': item.rfid, # str_url = sf_sync_config['sf_url'] + self.crea_url
'tool_groups_name': item.tool_groups_id.name, # objs_all = self.env['stock.move.line'].search([('functional_tool_name_id', '!=', False)])
'reference': item.reference, # self.get_sync_stock_move_line(objs_all, str_url, token, headers)
'barcode': item.lot_id.name, #
'functional_tool_type_code': item.functional_tool_type_id.code, # def get_sync_stock_move_line(self, objs_all, str_url, token, headers):
'diameter': item.diameter, # tool_stock_list = []
'knife_tip_r_angle': item.knife_tip_r_angle, # try:
'install_tool_time': item.install_tool_time.strftime('%Y-%m-%d %H:%M:%S'), # if objs_all:
'location_id': item.location_id.name, # for item in objs_all:
'location_dest_name': item.location_dest_id.name, # val = {
'date': item.date.strftime('%Y-%m-%d %H:%M:%S'), # 'id': item.id,
'qty_done': item.qty_done, # 'name': item.functional_tool_name,
} # 'code': item.code,
tool_stock_list.append(val) # 'rfid': item.rfid,
kw = json.dumps(tool_stock_list, ensure_ascii=False) # 'tool_groups_name': item.tool_groups_id.name,
r = requests.post(str_url, json={}, data={'kw': kw, 'token': token}, headers=headers) # 'reference': item.reference,
ret = r.json() # 'barcode': item.lot_id.name,
if ret.get('code') == 200: # 'functional_tool_type_code': item.functional_tool_type_id.code,
return "功能刀具出入库记录注册成功" # 'diameter': item.diameter,
else: # 'knife_tip_r_angle': item.knife_tip_r_angle,
logging.info('没有注册功能刀具出入库记录信息') # 'install_tool_time': item.install_tool_time.strftime('%Y-%m-%d %H:%M:%S'),
except Exception as e: # 'location_id': item.location_id.name,
logging.info("捕获错误信息:%s" % e) # 'location_dest_name': item.location_dest_id.name,
# 'date': item.date.strftime('%Y-%m-%d %H:%M:%S'),
# 'qty_done': item.qty_done,
class RealTimeDistributionFunctionalTools(models.Model): # }
_inherit = 'sf.real.time.distribution.of.functional.tools' # tool_stock_list.append(val)
_description = '功能刀具安全库存注册' # kw = json.dumps(tool_stock_list, ensure_ascii=False)
# r = requests.post(str_url, json={}, data={'kw': kw, 'token': token}, headers=headers)
crea_url = "/api/functional_tool_distribution/create" # ret = r.json()
# if ret.get('code') == 200:
# 注册同步功能刀具预警 # return "功能刀具出入库记录注册成功"
def enroll_functional_tool_real_time_distribution(self): # else:
logging.info('调用功能刀具安全库存注册接口: enroll_functional_tool_real_time_distribution()') # logging.info('没有注册功能刀具出入库记录信息')
sf_sync_config = self.env['res.config.settings'].get_values() # except Exception as e:
token = sf_sync_config['token'] # logging.info("捕获错误信息:%s" % e)
sf_secret_key = sf_sync_config['sf_secret_key'] #
headers = Common.get_headers(self, token, sf_secret_key) # @api.model_create_multi
str_url = sf_sync_config['sf_url'] + self.crea_url # def create(self, vals_list):
objs_all = self.env['sf.real.time.distribution.of.functional.tools'].search([('id', '=', self.id)]) # records = super(StockMoveLine, self).create(vals_list)
self.get_sync_real_time_distribution_functional_tools(objs_all, str_url, token, headers) # for record in records:
# if record.functional_tool_name_id:
def sync_enroll_functional_tool_real_time_distribution_all(self): # record.enroll_functional_tool_move()
logging.info('调用功能刀具安全库存注册接口: sync_enroll_functional_tool_real_time_distribution_all()') # return records
sf_sync_config = self.env['res.config.settings'].get_values() #
token = sf_sync_config['token'] #
sf_secret_key = sf_sync_config['sf_secret_key'] # class RealTimeDistributionFunctionalTools(models.Model):
headers = Common.get_headers(self, token, sf_secret_key) # _inherit = 'sf.real.time.distribution.of.functional.tools'
str_url = sf_sync_config['sf_url'] + self.crea_url # _description = '功能刀具安全库存注册'
objs_all = self.env['sf.real.time.distribution.of.functional.tools'].search([]) #
self.get_sync_real_time_distribution_functional_tools(objs_all, str_url, token, headers) # crea_url = "/api/functional_tool_distribution/create"
#
def get_sync_real_time_distribution_functional_tools(self, objs_all, str_url, token, headers): # # 注册同步功能刀具预警
tool_distribution_list = [] # def enroll_functional_tool_real_time_distribution(self):
try: # logging.info('调用功能刀具安全库存注册接口: enroll_functional_tool_real_time_distribution()')
if objs_all: # sf_sync_config = self.env['res.config.settings'].get_values()
for item in objs_all: # token = sf_sync_config['token']
functional_tool_codes = [] # sf_secret_key = sf_sync_config['sf_secret_key']
for obj in item.sf_functional_tool_entity_ids: # headers = Common.get_headers(self, token, sf_secret_key)
functional_tool_codes.append(obj.code) # str_url = sf_sync_config['sf_url'] + self.crea_url
val = { # objs_all = self.env['sf.real.time.distribution.of.functional.tools'].search([('id', '=', self.id)])
'id': item.id, # self.get_sync_real_time_distribution_functional_tools(objs_all, str_url, token, headers)
'name': item.name, #
'tool_groups_name': item.tool_groups_id.name, # def sync_enroll_functional_tool_real_time_distribution_all(self):
'cutting_tool_type_code': item.sf_cutting_tool_type_id.code, # logging.info('调用功能刀具安全库存注册接口: sync_enroll_functional_tool_real_time_distribution_all()')
'diameter': item.diameter, # sf_sync_config = self.env['res.config.settings'].get_values()
'knife_tip_r_angle': item.knife_tip_r_angle, # token = sf_sync_config['token']
'tool_stock_num': item.tool_stock_num, # sf_secret_key = sf_sync_config['sf_secret_key']
'side_shelf_num': item.side_shelf_num, # headers = Common.get_headers(self, token, sf_secret_key)
'on_tool_stock_num': item.on_tool_stock_num, # str_url = sf_sync_config['sf_url'] + self.crea_url
'tool_stock_total': item.tool_stock_total, # objs_all = self.env['sf.real.time.distribution.of.functional.tools'].search([])
'min_stock_num': item.min_stock_num, # self.get_sync_real_time_distribution_functional_tools(objs_all, str_url, token, headers)
'max_stock_num': item.max_stock_num, #
'batch_replenishment_num': item.batch_replenishment_num, # def get_sync_real_time_distribution_functional_tools(self, objs_all, str_url, token, headers):
'unit': item.unit, # tool_distribution_list = []
'image': '' if not item.image else base64.b64encode(item.image).decode('utf-8'), # try:
'functional_tool_codes': str(functional_tool_codes), # if objs_all:
'coarse_middle_thin': item.coarse_middle_thin, # for item in objs_all:
'whether_standard_knife': item.whether_standard_knife, # functional_tool_codes = []
'suitable_machining_method_names': get_suitable_machining_method_names(item), # for obj in item.sf_functional_tool_entity_ids:
'blade_tip_characteristics_name': item.blade_tip_characteristics_id.name, # functional_tool_codes.append(obj.code)
'handle_type_name': item.handle_type_id.name, # val = {
'cutting_direction_names': get_cutting_direction_names(item), # 'id': item.id,
'suitable_coolant_names': get_suitable_coolant_names(item), # 'name': item.name,
'active': item.active # 'tool_groups_name': item.tool_groups_id.name,
} # 'cutting_tool_type_code': item.sf_cutting_tool_type_id.code,
tool_distribution_list.append(val) # 'diameter': item.diameter,
kw = json.dumps(tool_distribution_list, ensure_ascii=False) # 'knife_tip_r_angle': item.knife_tip_r_angle,
r = requests.post(str_url, json={}, data={'kw': kw, 'token': token}, headers=headers) # 'tool_stock_num': item.tool_stock_num,
ret = r.json() # 'side_shelf_num': item.side_shelf_num,
if ret.get('code') == 200: # 'on_tool_stock_num': item.on_tool_stock_num,
return "功能刀具出入库记录注册成功" # 'tool_stock_total': item.tool_stock_total,
else: # 'min_stock_num': item.min_stock_num,
logging.info('没有注册功能刀具出入库记录信息') # 'max_stock_num': item.max_stock_num,
except Exception as e: # 'batch_replenishment_num': item.batch_replenishment_num,
logging.info("捕获错误信息:%s" % e) # 'unit': item.unit,
# 'image': '' if not item.image else base64.b64encode(item.image).decode('utf-8'),
# 'functional_tool_codes': str(functional_tool_codes),
# 'coarse_middle_thin': item.coarse_middle_thin,
# 'whether_standard_knife': item.whether_standard_knife,
# 'suitable_machining_method_names': get_suitable_machining_method_names(item),
# 'blade_tip_characteristics_name': item.blade_tip_characteristics_id.name,
# 'handle_type_name': item.handle_type_id.name,
# 'cutting_direction_names': get_cutting_direction_names(item),
# 'suitable_coolant_names': get_suitable_coolant_names(item),
# 'active': item.active
# }
# tool_distribution_list.append(val)
# kw = json.dumps(tool_distribution_list, ensure_ascii=False)
# r = requests.post(str_url, json={}, data={'kw': kw, 'token': token}, headers=headers)
# ret = r.json()
# if ret.get('code') == 200:
# return "功能刀具出入库记录注册成功"
# else:
# logging.info('没有注册功能刀具出入库记录信息')
# except Exception as e:
# logging.info("捕获错误信息:%s" % e)
#
# @api.model_create_multi
# def create(self, vals_list):
# records = super(RealTimeDistributionFunctionalTools, self).create(vals_list)
# for record in records:
# if record:
# record.enroll_functional_tool_real_time_distribution()
# return records
#
# def write(self, vals):
# res = super().write(vals)
# if vals.get('sf_functional_tool_entity_ids') or vals.get('min_stock_num') or vals.get('max_stock_num'):
# self.enroll_functional_tool_real_time_distribution()
# return res

View File

@@ -44,7 +44,6 @@ class SfMaintenanceEquipment(models.Model):
# ==========机床当前刀库实时信息接口========== # ==========机床当前刀库实时信息接口==========
def register_equipment_tool(self): def register_equipment_tool(self):
try:
config = self.env['res.config.settings'].get_values() config = self.env['res.config.settings'].get_values()
# token = sf_sync_config['token'Ba F2CF5DCC-1A00-4234-9E95-65603F70CC8A] # token = sf_sync_config['token'Ba F2CF5DCC-1A00-4234-9E95-65603F70CC8A]
headers = {'Authorization': config['center_control_Authorization']} headers = {'Authorization': config['center_control_Authorization']}
@@ -59,18 +58,9 @@ class SfMaintenanceEquipment(models.Model):
return "机床当前刀库实时信息指令发送成功" return "机床当前刀库实时信息指令发送成功"
else: else:
raise ValidationError("机床当前刀库实时信息指令发送失败") raise ValidationError("机床当前刀库实时信息指令发送失败")
except Exception as e:
logging.info("register_equipment_tool()捕获错误信息:%s" % e)
def write_maintenance_equipment_tool(self, datas): def write_maintenance_equipment_tool(self, datas):
try:
if datas: if datas:
# 清除设备机床刀位的刀具信息
for obj in self.product_template_ids:
obj.write({
'functional_tool_name_id': False,
'tool_install_time': None
})
for data in datas: for data in datas:
maintenance_equipment_id = self.search([('name', '=', data['DeviceId'])]) maintenance_equipment_id = self.search([('name', '=', data['DeviceId'])])
if maintenance_equipment_id: if maintenance_equipment_id:
@@ -80,8 +70,6 @@ class SfMaintenanceEquipment(models.Model):
functional_tool_id = self.env['sf.functional.cutting.tool.entity'].sudo().search( functional_tool_id = self.env['sf.functional.cutting.tool.entity'].sudo().search(
[('rfid', '=', data['RfidCode'])]) [('rfid', '=', data['RfidCode'])])
if functional_tool_id: if functional_tool_id:
if len(functional_tool_id) > 1:
functional_tool_id = functional_tool_id[-1]
# 查询该功能刀具是否已经装在机床内其他位置,如果是就删除 # 查询该功能刀具是否已经装在机床内其他位置,如果是就删除
equipment_tools = self.env['maintenance.equipment.tool'].sudo().search( equipment_tools = self.env['maintenance.equipment.tool'].sudo().search(
[('functional_tool_name_id', '=', functional_tool_id.id), ('code', '!=', tool_id)]) [('functional_tool_name_id', '=', functional_tool_id.id), ('code', '!=', tool_id)])
@@ -103,8 +91,8 @@ class SfMaintenanceEquipment(models.Model):
'functional_tool_name_id': functional_tool_id.id, 'functional_tool_name_id': functional_tool_id.id,
'tool_install_time': time 'tool_install_time': time
}) })
if functional_tool_id.current_location != '机内刀库': if functional_tool_id.current_location_id.name != '制造前':
# 对功能刀具进行移动到生产线 # 对功能刀具进行出库到生产线
functional_tool_id.tool_inventory_displacement_out() functional_tool_id.tool_inventory_displacement_out()
functional_tool_id.write({ functional_tool_id.write({
'max_lifetime_value': data['MaxLife'], 'max_lifetime_value': data['MaxLife'],
@@ -112,11 +100,9 @@ class SfMaintenanceEquipment(models.Model):
'functional_tool_status': tool_install_time.get(data['State']) 'functional_tool_status': tool_install_time.get(data['State'])
}) })
else: else:
logging.info('获取的【%s】设备不存在!!!' % data['DeviceId']) raise ValidationError('获取的【%s】设备不存在!!!' % data['DeviceId'])
else: else:
logging.info('没有获取到【%s】设备的刀具库信息!!!' % self.name) raise ValidationError('没有获取到刀具库信息!!!')
except Exception as e:
logging.info("write_maintenance_equipment_tool()捕获错误信息:%s" % e)
class StockLot(models.Model): class StockLot(models.Model):
@@ -142,6 +128,12 @@ class StockLot(models.Model):
record.tool_material_status = '报废' record.tool_material_status = '报废'
else: else:
record.tool_material_status = '未入库' record.tool_material_status = '未入库'
# if record.tool_material_search_id:
# # 注册刀具物料状态到cloud平台
# record.enroll_tool_material_stock()
# elif record.fixture_material_search_id:
# # 注册夹具物料状态到cloud平台
# record.enroll_fixture_material_stock()
@api.model @api.model
def name_search(self, name='', args=None, operator='ilike', limit=100): def name_search(self, name='', args=None, operator='ilike', limit=100):

View File

@@ -1,23 +0,0 @@
from odoo import api, fields, models, _
class ShelfLocation(models.Model):
_inherit = 'sf.shelf.location'
tool_rfid = fields.Char('Rfid', compute='_compute_tool', store=True)
tool_name_id = fields.Many2one('sf.functional.cutting.tool.entity', string='功能刀具名称', compute='_compute_tool',
store=True)
@api.depends('product_id')
def _compute_tool(self):
for item in self:
if item.product_id:
if item.product_id.categ_id.name == '功能刀具':
tool_id = self.env['sf.functional.cutting.tool.entity'].sudo().search(
[('barcode_id', '=', item.product_sn_id.id)])
if tool_id:
item.tool_rfid = tool_id.rfid
item.tool_name_id = tool_id.id
continue
item.tool_rfid = ''
item.tool_name_id = False

View File

@@ -45,8 +45,8 @@ class ToolMaterial(models.Model):
record.have_been_used_num = have_been_used_num record.have_been_used_num = have_been_used_num
record.scrap_num = scrap_num record.scrap_num = scrap_num
record.number = usable_num + have_been_used_num + scrap_num record.number = usable_num + have_been_used_num + scrap_num
# 更新数据到cloud的动态数据
# record.enroll_tool_material()
@api.model @api.model
def _read_group_cutting_tool_material_id(self, categories, domain, order): def _read_group_cutting_tool_material_id(self, categories, domain, order):

View File

@@ -6,7 +6,7 @@
<field name="name">sf.functional.cutting.tool.entity.list.tree</field> <field name="name">sf.functional.cutting.tool.entity.list.tree</field>
<field name="model">sf.functional.cutting.tool.entity</field> <field name="model">sf.functional.cutting.tool.entity</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="功能刀具" create="0" edit="0" delete="0"> <tree string="功能刀具列表" create="0" edit="0" delete="0">
<field name="barcode_id" invisible="1"/> <field name="barcode_id" invisible="1"/>
<field name="rfid"/> <field name="rfid"/>
<field name="tool_name_id"/> <field name="tool_name_id"/>
@@ -19,16 +19,15 @@
<field name="tool_loading_length" optional="hide"/> <field name="tool_loading_length" optional="hide"/>
<field name="functional_tool_length" optional="hide"/> <field name="functional_tool_length" optional="hide"/>
<field name="effective_length" optional="hide"/> <field name="effective_length" optional="hide"/>
<field name="tool_room_num" optional="hide"/> <field name="tool_room_num"/>
<field name="line_edge_knife_library_num" optional="hide"/> <field name="line_edge_knife_library_num"/>
<field name="machine_knife_library_num" optional="hide"/> <field name="machine_knife_library_num"/>
<field name="max_lifetime_value"/> <field name="max_lifetime_value"/>
<field name="alarm_value"/> <field name="alarm_value"/>
<field name="used_value"/> <field name="used_value"/>
<field name="functional_tool_status"/> <field name="functional_tool_status"/>
<field name="current_location" string="当前位置"/>
<field name="current_location_id" invisible="1"/> <field name="current_location_id" optional="hide"/>
<field name="current_location" optional="hide"/> <field name="current_location" optional="hide"/>
<field name="sf_cutting_tool_type_id" invisible="True"/> <field name="sf_cutting_tool_type_id" invisible="True"/>
</tree> </tree>
@@ -47,8 +46,8 @@
</header> </header>
<sheet> <sheet>
<div class="oe_button_box" name="button_box"> <div class="oe_button_box" name="button_box">
<!-- <button name="button_safe_inventory_id" string="更新功能刀具关联的安全库存记录"--> <!-- <button name="button_safe_inventory_id" string="更新功能刀具关联的安全库存记录"-->
<!-- type="object" class="btn-primary"/>--> <!-- type="object" class="btn-primary"/>-->
<button class="oe_stat_button" groups="sf_base.group_sf_mrp_user" <button class="oe_stat_button" groups="sf_base.group_sf_mrp_user"
name="open_functional_tool_warning" name="open_functional_tool_warning"
icon="fa-list-ul" icon="fa-list-ul"
@@ -87,7 +86,7 @@
</div> </div>
<group> <group>
<group> <group>
<field name="barcode_id" invisible="0"/> <field name="barcode_id" invisible="1"/>
<field name="rfid" readonly="1" <field name="rfid" readonly="1"
attrs="{'invisible': [('functional_tool_status', '=', '已拆除')]}"/> attrs="{'invisible': [('functional_tool_status', '=', '已拆除')]}"/>
<field name="rfid_dismantle" readonly="1" <field name="rfid_dismantle" readonly="1"
@@ -116,7 +115,7 @@
options="{'no_create': True, 'no_quick_create': True}"/> options="{'no_create': True, 'no_quick_create': True}"/>
<field name="cutting_tool_cutterhead_model_id" <field name="cutting_tool_cutterhead_model_id"
options="{'no_create': True, 'no_quick_create': True}"/> options="{'no_create': True, 'no_quick_create': True}"/>
<field name="safe_inventory_id" invisible="1"/> <field name="safe_inventory_id" readonly="0"/>
</group> </group>
<group> <group>
<field name="image" nolabel="1" widget="image"/> <field name="image" nolabel="1" widget="image"/>
@@ -174,10 +173,7 @@
<field name="cut_time" attrs="{'invisible': [('new_former','=','0')]}"/> <field name="cut_time" attrs="{'invisible': [('new_former','=','0')]}"/>
<field name="cut_length" attrs="{'invisible': [('new_former','=','0')]}"/> <field name="cut_length" attrs="{'invisible': [('new_former','=','0')]}"/>
<field name="cut_number" attrs="{'invisible': [('new_former','=','0')]}"/> <field name="cut_number" attrs="{'invisible': [('new_former','=','0')]}"/>
<field name="current_location_id" string="当前位置"/>
<field name="current_location" string="当前位置"/> <field name="current_location" string="当前位置"/>
<field name="current_shelf_location_id" string="当前货位"
attrs="{'invisible': [('current_shelf_location_id', '=', False)]}"/>
</group> </group>
</group> </group>
</page> </page>
@@ -193,34 +189,19 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<search> <search>
<field name="rfid"/> <field name="rfid"/>
<field name="barcode_id"/>
<field name="tool_name_id"/> <field name="tool_name_id"/>
<field name="functional_tool_diameter"/> <field name="functional_tool_diameter"/>
<field name="knife_tip_r_angle"/> <field name="knife_tip_r_angle"/>
<filter string="刀具房" name="tool_room" domain="[('current_location', '=', '刀具房')]"/>
<filter string="线边刀库" name="storage_area" domain="[('current_location', '=', '线边刀库')]"/>
<filter string="机内刀库" name="machine_knife_library"
domain="[('current_location', '=', '机内刀库')]"/>
<separator/>
<filter string="正常" name="normal" domain="[('functional_tool_status', '=', '正常')]"/>
<filter string="报警" name="alarm" domain="[('functional_tool_status', '=', '报警')]"/>
<separator/>
<filter string="未拆除" name="no_state_removed" <filter string="未拆除" name="no_state_removed"
domain="[('functional_tool_status', '!=', '已拆除')]"/> domain="[('functional_tool_status', '!=', '已拆除')]"/>
<filter string="已拆除" name="state_removed" domain="[('functional_tool_status', '=', '已拆除')]"/> <filter string="已拆除" name="state_removed" domain="[('functional_tool_status', '=', '已拆除')]"/>
<separator/>
<filter string="已归档" name="inactive" domain="[('active', '=', False)]"/>
<searchpanel> <searchpanel>
<field name="sf_cutting_tool_type_id" icon="fa-building" enable_counters="1"/>
<field name="current_location" icon="fa-building" enable_counters="1"/> <field name="current_location" icon="fa-building" enable_counters="1"/>
<field name="functional_tool_status" icon="fa-building" enable_counters="1"/> <field name="functional_tool_status" icon="fa-building" enable_counters="1"/>
<field name="sf_cutting_tool_type_id" icon="fa-building" enable_counters="1"/>
</searchpanel> </searchpanel>
<group expand="0">
<filter string="功能刀具名称" name="tool_name" domain="[]"
context="{'group_by': 'tool_name_id'}"/>
<filter string="刀具组" name="tool_groups" domain="[]"
context="{'group_by': 'tool_groups_id'}"/>
<filter string="当前位置" name="current_location" domain="[]"
context="{'group_by': 'current_location'}"/>
</group>
</search> </search>
</field> </field>
</record> </record>
@@ -316,10 +297,11 @@
<tree> <tree>
<field name="name" invisible="1"/> <field name="name" invisible="1"/>
<field name="functional_name_id"/> <field name="functional_name_id"/>
<field name="sf_cutting_tool_type_id" invisible="True"/>
<field name="tool_groups_id"/> <field name="tool_groups_id"/>
<field name="diameter"/> <field name="diameter"/>
<field name="knife_tip_r_angle"/> <field name="knife_tip_r_angle"/>
<field name="coarse_middle_thin" optional="hide"/> <field name="coarse_middle_thin"/>
<field name="tool_stock_num"/> <field name="tool_stock_num"/>
<field name="side_shelf_num"/> <field name="side_shelf_num"/>
<field name="on_tool_stock_num"/> <field name="on_tool_stock_num"/>
@@ -328,8 +310,6 @@
<field name="max_stock_num"/> <field name="max_stock_num"/>
<field name="batch_replenishment_num"/> <field name="batch_replenishment_num"/>
<field name="unit"/> <field name="unit"/>
<field name="sf_cutting_tool_type_id" invisible="True"/>
</tree> </tree>
</field> </field>
</record> </record>
@@ -431,10 +411,6 @@
</page> </page>
</notebook> </notebook>
</sheet> </sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="message_ids"/>
</div>
</form> </form>
</field> </field>
</record> </record>
@@ -445,20 +421,21 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<search> <search>
<field name="name"/> <field name="name"/>
<field name="tool_groups_id"/> <field name="sf_cutting_tool_type_id" invisible="True"/>
<field name="sf_cutting_tool_type_id"/>
<field name="diameter"/> <field name="diameter"/>
<field name="knife_tip_r_angle"/> <field name="knife_tip_r_angle"/>
<filter string="需补货" name="batch_replenishment" domain="[('batch_replenishment_num', '>', 0)]"/> <field name="tool_stock_num"/>
<separator/> <field name="side_shelf_num"/>
<field name="on_tool_stock_num"/>
<field name="tool_stock_total"/>
<field name="min_stock_num"/>
<field name="max_stock_num"/>
<field name="batch_replenishment_num"/>
<field name="unit"/>
<filter string="已归档" name="inactive" domain="[('active', '=', False)]"/> <filter string="已归档" name="inactive" domain="[('active', '=', False)]"/>
<searchpanel> <searchpanel>
<field name="sf_cutting_tool_type_id" enable_counters="1" icon="fa-building"/> <field name="sf_cutting_tool_type_id" enable_counters="1" icon="fa-building"/>
</searchpanel> </searchpanel>
<group expand="0">
<filter string="刀具组" name="tool_groups" domain="[]"
context="{'group_by': 'tool_groups_id'}"/>
</group>
</search> </search>
</field> </field>
</record> </record>
@@ -477,8 +454,7 @@
<field name="name">功能刀具出入库记录</field> <field name="name">功能刀具出入库记录</field>
<field name="model">stock.move.line</field> <field name="model">stock.move.line</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="功能刀具出入库记录" create="0" edit="0" delete="0" default_order="id desc" <tree string="功能刀具出入库记录" create="0" edit="0" delete="0">
action="action_open_reference1" type="object">
<field name="reference" string="单据号"/> <field name="reference" string="单据号"/>
<field name="lot_id" invisible="1"/> <field name="lot_id" invisible="1"/>
<field name="rfid"/> <field name="rfid"/>
@@ -488,9 +464,7 @@
<field name="knife_tip_r_angle"/> <field name="knife_tip_r_angle"/>
<field name="install_tool_time"/> <field name="install_tool_time"/>
<field name="location_id"/> <field name="location_id"/>
<field name="current_location_id"/>
<field name="location_dest_id"/> <field name="location_dest_id"/>
<field name="destination_location_id"/>
<field name="date"/> <field name="date"/>
<field name="qty_done" string="数量"/> <field name="qty_done" string="数量"/>
<field name="functional_tool_type_id" invisible="True"/> <field name="functional_tool_type_id" invisible="True"/>
@@ -505,20 +479,21 @@
<field name="model">stock.move.line</field> <field name="model">stock.move.line</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search> <search>
<field name="reference"/>
<field name="lot_id"/>
<field name="rfid"/> <field name="rfid"/>
<field name="functional_tool_name"/> <field name="functional_tool_name"/>
<field name="diameter"/> <field name="diameter"/>
<field name="knife_tip_r_angle"/> <field name="knife_tip_r_angle"/>
<field name="reference"/> <field name="install_tool_time"/>
<field name="lot_id"/> <field name="location_id"/>
<field name="location_dest_id"/>
<field name="date"/>
<field name="qty_done"/>
<field name="functional_tool_type_id" invisible="True"/>
<searchpanel> <searchpanel>
<field name="functional_tool_type_id" enable_counters="1" icon="fa-building"/> <field name="functional_tool_type_id" enable_counters="1" icon="fa-building"/>
</searchpanel> </searchpanel>
<group expand="0">
<filter string="功能刀具名称" name="functional_tool_name" domain="[]"
context="{'group_by': 'functional_tool_name'}"/>
<filter string="日期" name="date" domain="[]" context="{'group_by': 'date'}"/>
</group>
</search> </search>
</field> </field>
</record> </record>
@@ -532,7 +507,7 @@
ref="sf_tool_management.sf_inbound_and_outbound_records_of_functional_tools_view_tree"/> ref="sf_tool_management.sf_inbound_and_outbound_records_of_functional_tools_view_tree"/>
<field name="search_view_id" <field name="search_view_id"
ref="sf_tool_management.sf_inbound_and_outbound_records_of_functional_tools_view_search"/> ref="sf_tool_management.sf_inbound_and_outbound_records_of_functional_tools_view_search"/>
<field name="domain">[('rfid', '!=', ''),('functional_tool_name', '!=', '')]</field> <field name="domain">[('functional_tool_name_id', '!=', False)]</field>
</record> </record>
</data> </data>

View File

@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="view_shelf_location_tool" model="ir.ui.view">
<field name="name">sf.shelf.location.form.tool</field>
<field name="model">sf.shelf.location</field>
<field name="inherit_id" ref="sf_warehouse.view_shelf_location_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='product_id']" position="after">
<field name="tool_rfid" attrs="{'invisible': [('tool_name_id', '=', False)]}"/>
<field name="tool_name_id" attrs="{'invisible': [('tool_name_id', '=', False)]}"/>
</xpath>
</field>
</record>
</odoo>

View File

@@ -376,10 +376,6 @@
</page> </page>
</notebook> </notebook>
</sheet> </sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="message_ids"/>
</div>
</form> </form>
</field> </field>
</record> </record>
@@ -434,17 +430,17 @@
<field name="code" optional="hide"/> <field name="code" optional="hide"/>
<field name="functional_tool_name"/> <field name="functional_tool_name"/>
<field name="tool_groups_id"/> <field name="tool_groups_id"/>
<field name="functional_tool_diameter" string="刀具直径(mm)"/> <field name="functional_tool_diameter" string="刀具直径"/>
<field name="knife_tip_r_angle"/> <field name="knife_tip_r_angle"/>
<field name="coarse_middle_thin" optional="hide"/> <field name="coarse_middle_thin" optional="hide"/>
<field name="new_former" optional="hide"/> <field name="new_former" optional="hide"/>
<field name="tool_loading_length" optional="hide"/> <field name="tool_loading_length" optional="hide"/>
<field name="functional_tool_length" optional="hide"/> <field name="functional_tool_length" optional="hide"/>
<field name="effective_length" invisible="1"/> <field name="effective_length" optional="hide"/>
<field name="loading_task_source" string="任务来源"/> <field name="loading_task_source" string="任务来源"/>
<field name="use_tool_time"/> <field name="use_tool_time"/>
<field name="production_line_name_id" optional="hide"/> <field name="production_line_name_id"/>
<field name="machine_tool_name_id" optional="hide"/> <field name="machine_tool_name_id"/>
<field name="applicant"/> <field name="applicant"/>
<field name="apply_time"/> <field name="apply_time"/>
<field name="assemble_status" optional="hide"/> <field name="assemble_status" optional="hide"/>
@@ -468,8 +464,8 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<form create="0" delete="0" edit="0"> <form create="0" delete="0" edit="0">
<header> <header>
<!-- <button string="修改编码" name="put_assembly_order_code" type="object"--> <!-- <button string="修改编码" name="put_assembly_order_code" type="object"-->
<!-- class="btn-primary" confirm="是否确认修改编码"/>--> <!-- class="btn-primary" confirm="是否确认修改编码"/>-->
<button string="组装" name="put_start_preset" type="object" <button string="组装" name="put_start_preset" type="object"
attrs="{'invisible': [('assemble_status', '!=', '0')]}" attrs="{'invisible': [('assemble_status', '!=', '0')]}"
class="btn-primary"/> class="btn-primary"/>
@@ -532,10 +528,8 @@
<field name="after_assembly_max_lifetime_value" <field name="after_assembly_max_lifetime_value"
string="最大寿命值(min)"/> string="最大寿命值(min)"/>
<field name="after_assembly_alarm_value" string="报警值(min)"/> <field name="after_assembly_alarm_value" string="报警值(min)"/>
<field name="after_assembly_used_value" string="已使用值(min)" <field name="after_assembly_used_value" string="已使用值(min)" invisible="1"/>
invisible="1"/> <field name="after_assembly_effective_length" string="有效长(mm)" invisible="1"/>
<field name="after_assembly_effective_length" string="有效长(mm)"
invisible="1"/>
<field name="L_D_number" invisible="1"/> <field name="L_D_number" invisible="1"/>
<field name="hiding_length" invisible="1"/> <field name="hiding_length" invisible="1"/>
</group> </group>
@@ -557,14 +551,13 @@
<field name="sf_tool_brand_id_5" string="品牌"/> <field name="sf_tool_brand_id_5" string="品牌"/>
</group> </group>
</group> </group>
<group col="1" attrs="{'invisible': [('chuck_freight_barcode_id', '=', False)]}"> <group col="1" attrs="{'invisible': [('chuck_freight_barcode', '=', False)]}">
<div> <div>
<separator string="夹头:" style="font-size: 13px;"/> <separator string="夹头:" style="font-size: 13px;"/>
</div> </div>
<group> <group>
<group> <group>
<field name="chuck_freight_barcode_id" string="货位"/> <field name="chuck_freight_barcode" string="货位"/>
<field name="chuck_lot_id" string="批次"/>
<field name="chuck_product_id" string="名称"/> <field name="chuck_product_id" string="名称"/>
<field name="cutting_tool_cutterhead_model_id" string="型号"/> <field name="cutting_tool_cutterhead_model_id" string="型号"/>
<field name="chuck_specification_id" string="规格"/> <field name="chuck_specification_id" string="规格"/>
@@ -576,27 +569,24 @@
<group> <group>
<group col="1"> <group col="1">
<group col="1" <group col="1"
attrs="{'invisible': [('integral_freight_barcode_id', '=', False)]}"> attrs="{'invisible': [('integral_freight_barcode', '=', False)]}">
<div> <div>
<separator string="整体式刀具:" style="font-size: 13px;"/> <separator string="整体式刀具:" style="font-size: 13px;"/>
</div> </div>
<group> <group>
<field name="integral_freight_barcode_id" string="货位"/> <field name="integral_freight_barcode" string="货位"/>
<field name="integral_lot_id" string="批次"/>
<field name="integral_product_id" string="名称"/> <field name="integral_product_id" string="名称"/>
<field name="cutting_tool_integral_model_id" string="型号"/> <field name="cutting_tool_integral_model_id" string="型号"/>
<field name="integral_specification_id" string="规格"/> <field name="integral_specification_id" string="规格"/>
<field name="sf_tool_brand_id_1" string="品牌"/> <field name="sf_tool_brand_id_1" string="品牌"/>
</group> </group>
</group> </group>
<group col="1" <group col="1" attrs="{'invisible': [('blade_freight_barcode', '=', False)]}">
attrs="{'invisible': [('blade_freight_barcode_id', '=', False)]}">
<div> <div>
<separator string="刀片:" style="font-size: 13px;"/> <separator string="刀片:" style="font-size: 13px;"/>
</div> </div>
<group> <group>
<field name="blade_freight_barcode_id" string="货位"/> <field name="blade_freight_barcode" string="货位"/>
<field name="blade_lot_id" string="批次"/>
<field name="blade_product_id" string="名称"/> <field name="blade_product_id" string="名称"/>
<field name="cutting_tool_blade_model_id" string="型号"/> <field name="cutting_tool_blade_model_id" string="型号"/>
<field name="blade_specification_id" string="规格"/> <field name="blade_specification_id" string="规格"/>
@@ -605,14 +595,13 @@
</group> </group>
</group> </group>
<group col="1"> <group col="1">
<group col="1" attrs="{'invisible': [('bar_freight_barcode_id', '=', False)]}"> <group col="1" attrs="{'invisible': [('bar_freight_barcode', '=', False)]}">
<div> <div>
<separator string="刀杆:" style="font-size: 13px;"/> <separator string="刀杆:" style="font-size: 13px;"/>
</div> </div>
<group> <group>
<group> <group>
<field name="bar_freight_barcode_id" string="货位"/> <field name="bar_freight_barcode" string="货位"/>
<field name="bar_lot_id" string="批次"/>
<field name="bar_product_id" string="名称"/> <field name="bar_product_id" string="名称"/>
<field name="cutting_tool_cutterbar_model_id" string="型号"/> <field name="cutting_tool_cutterbar_model_id" string="型号"/>
<field name="bar_specification_id" string="规格"/> <field name="bar_specification_id" string="规格"/>
@@ -620,14 +609,13 @@
</group> </group>
</group> </group>
</group> </group>
<group col="1" attrs="{'invisible': [('pad_freight_barcode_id', '=', False)]}"> <group col="1" attrs="{'invisible': [('pad_freight_barcode', '=', False)]}">
<div> <div>
<separator string="刀盘:" style="font-size: 13px;"/> <separator string="刀盘:" style="font-size: 13px;"/>
</div> </div>
<group> <group>
<group> <group>
<field name="pad_freight_barcode_id" string="货位"/> <field name="pad_freight_barcode" string="货位"/>
<field name="pad_lot_id" string="批次"/>
<field name="pad_product_id" string="名称"/> <field name="pad_product_id" string="名称"/>
<field name="cutting_tool_cutterpad_model_id" string="型号"/> <field name="cutting_tool_cutterpad_model_id" string="型号"/>
<field name="pad_specification_id" string="规格"/> <field name="pad_specification_id" string="规格"/>
@@ -680,10 +668,6 @@
</page> </page>
</notebook> </notebook>
</sheet> </sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="message_ids"/>
</div>
</form> </form>
</field> </field>
</record> </record>
@@ -693,29 +677,30 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<search> <search>
<field name="assembly_order_code"/> <field name="assembly_order_code"/>
<field name="code" string="功能刀具编码"/> <field name="barcode_id" optional="hide"/>
<field name="barcode_id"/>
<field name="functional_tool_name"/> <field name="functional_tool_name"/>
<field name="functional_tool_type_id"/> <field name="functional_tool_diameter"/>
<field name="tool_groups_id"/> <field name="knife_tip_r_angle"/>
<field name="coarse_middle_thin"/>
<field name="new_former"/>
<field name="tool_loading_length"/>
<field name="functional_tool_length"/>
<field name="effective_length"/>
<field name="loading_task_source" string="任务来源"/> <field name="loading_task_source" string="任务来源"/>
<field name="use_tool_time"/>
<field name="production_line_name_id"/> <field name="production_line_name_id"/>
<field name="machine_tool_name_id"/> <field name="machine_tool_name_id"/>
<field name="applicant"/> <field name="applicant"/>
<field name="apply_time"/>
<field name="functional_tool_type_id"/>
<filter name="no_assemble_status" string="未组装" domain="[('assemble_status', '=', '0')]"/> <filter name="no_assemble_status" string="未组装" domain="[('assemble_status', '=', '0')]"/>
<filter name="yes_assemble_status" string="已组装" domain="[('assemble_status', '=', '1')]"/> <filter name="yes_assemble_status" string="已组装" domain="[('assemble_status', '=', '1')]"/>
<separator/> <separator/>
<filter string="已归档" name="inactive" domain="[('active', '=', False)]"/> <filter string="已归档" name="inactive" domain="[('active', '=', False)]"/>
<searchpanel> <searchpanel>
<field name="functional_tool_type_id" enable_counters="1" icon="fa-filter"/> <field name="functional_tool_type_id" enable_counters="1" icon="fa-filter"/>
<!-- <field name="assemble_status" enable_counters="1" icon="fa-filter"/>-->
</searchpanel> </searchpanel>
<group expand="0" string="Group By...">
<filter string="功能刀具名称" name="name" domain="[]" context="{'group_by': 'functional_tool_name'}"/>
<filter string="刀具组" name="tool_groups" domain="[]" context="{'group_by': 'tool_groups_id'}"/>
<filter string="任务来源" name="loading_task_source" domain="[]" context="{'group_by': 'loading_task_source'}"/>
<filter string="用刀时间" name="use_tool_time" domain="[]" context="{'group_by': 'use_tool_time'}"/>
</group>
</search> </search>
</field> </field>
</record> </record>
@@ -737,7 +722,6 @@
<field name="model">sf.functional.tool.dismantle</field> <field name="model">sf.functional.tool.dismantle</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree create="1"> <tree create="1">
<field name="code"/>
<field name="rfid"/> <field name="rfid"/>
<field name="functional_tool_id"/> <field name="functional_tool_id"/>
<field name="tool_type_id" invisible="1"/> <field name="tool_type_id" invisible="1"/>
@@ -765,14 +749,13 @@
<sheet> <sheet>
<div class="oe_title"> <div class="oe_title">
<h1> <h1>
<field name="code"/> <field name="functional_tool_id" placeholder="请选择将要拆解的功能刀具"
options="{'no_create': True}" attrs="{'readonly': [('state', '=', '已拆解')]}"/>
</h1> </h1>
</div> </div>
<field name="_barcode_scanned" widget="barcode_handler"/> <field name="_barcode_scanned" widget="barcode_handler"/>
<group> <group>
<group> <group>
<field name="functional_tool_id" placeholder="请选择将要拆解的功能刀具"
options="{'no_create': True}" attrs="{'readonly': [('state', '=', '已拆解')]}"/>
<field name="rfid" attrs="{'invisible': [('state', '=', '已拆解')]}"/> <field name="rfid" attrs="{'invisible': [('state', '=', '已拆解')]}"/>
<field name="rfid_dismantle" attrs="{'invisible': [('state', '!=', '已拆解')]}"/> <field name="rfid_dismantle" attrs="{'invisible': [('state', '!=', '已拆解')]}"/>
<field name="tool_type_id"/> <field name="tool_type_id"/>
@@ -803,98 +786,91 @@
<group> <group>
<group string="刀柄" attrs="{'invisible': [('handle_product_id', '=', False)]}"> <group string="刀柄" attrs="{'invisible': [('handle_product_id', '=', False)]}">
<group> <group>
<field name="scrap_boolean" string="是否报废"
attrs="{'invisible': [('dismantle_cause', 'not in', ['寿命到期报废','崩刀报废'])], 'readonly': [('state', '=', '已拆解')]}"/>
<field name="handle_rfid" string="Rfid"/>
<field name="handle_lot_id" string="序列号"/>
<field name="handle_product_id" string="名称"/> <field name="handle_product_id" string="名称"/>
<field name="handle_type_id" string="型号"/> <field name="handle_type_id" string="型号"/>
<field name="handle_brand_id" string="品牌"/> <field name="handle_brand_id" string="品牌"/>
</group> </group>
<group>
<field name="handle_rfid" string="Rfid"/>
<field name="scrap_boolean" string="是否报废"
attrs="{'invisible': [('dismantle_cause', 'not in', ['寿命到期报废','崩刀报废'])], 'readonly': [('state', '=', '已拆解')]}"/>
</group>
</group> </group>
<group string="夹头" <group string="夹头"
attrs="{'invisible': [('chuck_product_id', '=', False)]}"> attrs="{'invisible': [('chuck_product_id', '=', False)]}">
<group> <group>
<field name="chuck_freight_id" string="目标货位" placeholder="请选择"
options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具', '刀具需磨削'])], 'readonly': [('state', '=', '已拆解')],
'required': [('chuck_lot_id', '!=', False),('dismantle_cause', 'in', ['更换为其他刀具', '刀具需磨削'])]}"/>
<field name="chuck_lot_id" string="批次"/>
<field name="chuck_product_id" string="名称"/> <field name="chuck_product_id" string="名称"/>
<field name="chuck_type_id" string="型号"/> <field name="chuck_type_id" string="型号"/>
<field name="chuck_brand_id" string="品牌"/> <field name="chuck_brand_id" string="品牌"/>
</group> </group>
<group>
<field name="chuck_freight_id" string="目标货位"
options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])], 'readonly': [('state', '=', '已拆解')],
'required': [('chuck_product_id', '!=', False),('dismantle_cause', 'in', ['更换为其他刀具'])]}"/>
</group>
</group> </group>
</group> </group>
<group attrs="{'invisible': [('integral_product_id', '=', False)]}"> <group attrs="{'invisible': [('integral_product_id', '=', False)]}">
<group string="整体式刀具"> <group string="整体式刀具">
<group> <group>
<field name="integral_freight_id" string="目标货位" placeholder="请选择"
options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具', '刀具需磨削'])], 'readonly': [('state', '=', '已拆解')],
'required': [('integral_lot_id', '!=', False),('dismantle_cause', 'in', ['更换为其他刀具', '刀具需磨削'])]}"/>
<field name="integral_lot_id" string="批次"/>
<field name="integral_product_id" string="名称"/> <field name="integral_product_id" string="名称"/>
<field name="integral_type_id" string="型号"/> <field name="integral_type_id" string="型号"/>
<field name="integral_brand_id" string="品牌"/> <field name="integral_brand_id" string="品牌"/>
</group> </group>
<group>
<field name="integral_freight_id" string="目标货位"
options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])], 'readonly': [('state', '=', '已拆解')],
'required': [('integral_product_id', '!=', False),('dismantle_cause', 'in', ['更换为其他刀具'])]}"/>
</group>
</group> </group>
</group> </group>
<group> <group>
<group string="刀片" attrs="{'invisible': [('blade_product_id', '=', False)]}"> <group string="刀片" attrs="{'invisible': [('blade_product_id', '=', False)]}">
<group> <group>
<field name="blade_freight_id" string="目标货位" placeholder="请选择"
options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具', '刀具需磨削'])], 'readonly': [('state', '=', '已拆解')],
'required': [('blade_lot_id', '!=', False),('dismantle_cause', 'in', ['更换为其他刀具', '刀具需磨削'])]}"/>
<field name="blade_lot_id" string="批次"/>
<field name="blade_product_id" string="名称"/> <field name="blade_product_id" string="名称"/>
<field name="blade_type_id" string="型号"/> <field name="blade_type_id" string="型号"/>
<field name="blade_brand_id" string="品牌"/> <field name="blade_brand_id" string="品牌"/>
</group> </group>
<group>
<field name="blade_freight_id" string="目标货位"
options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])], 'readonly': [('state', '=', '已拆解')],
'required': [('blade_product_id', '!=', False),('dismantle_cause', 'in', ['更换为其他刀具'])]}"/>
</group>
</group> </group>
<group string="刀杆" attrs="{'invisible': [('bar_product_id', '=', False)]}"> <group string="刀杆" attrs="{'invisible': [('bar_product_id', '=', False)]}">
<group> <group>
<field name="bar_freight_id" string="目标货位" placeholder="请选择"
options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具', '刀具需磨削'])], 'readonly': [('state', '=', '已拆解')],
'required': [('bar_lot_id', '!=', False),('dismantle_cause', 'in', ['更换为其他刀具', '刀具需磨削'])]}"/>
<field name="bar_lot_id" string="批次"/>
<field name="bar_product_id" string="名称"/> <field name="bar_product_id" string="名称"/>
<field name="bar_type_id" string="型号"/> <field name="bar_type_id" string="型号"/>
<field name="bar_brand_id" string="品牌"/> <field name="bar_brand_id" string="品牌"/>
</group> </group>
<group>
<field name="bar_freight_id" string="目标货位"
options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])], 'readonly': [('state', '=', '已拆解')],
'required': [('bar_product_id', '!=', False),('dismantle_cause', 'in', ['更换为其他刀具'])]}"/>
</group>
</group> </group>
<group string="刀盘" attrs="{'invisible': [('pad_product_id', '=', False)]}"> <group string="刀盘" attrs="{'invisible': [('pad_product_id', '=', False)]}">
<group> <group>
<field name="pad_freight_id" string="目标货位" placeholder="请选择"
options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具', '刀具需磨削'])], 'readonly': [('state', '=', '已拆解')],
'required': [('pad_lot_id', '!=', False), ('dismantle_cause', 'in', ['更换为其他刀具', '刀具需磨削'])]}"/>
<field name="pad_lot_id" string="批次"/>
<field name="pad_product_id" string="名称"/> <field name="pad_product_id" string="名称"/>
<field name="pad_type_id" string="型号"/> <field name="pad_type_id" string="型号"/>
<field name="pad_brand_id" string="品牌"/> <field name="pad_brand_id" string="品牌"/>
</group> </group>
</group>
</group>
</page>
<page string="其他">
<group> <group>
<group> <field name="pad_freight_id" string="目标货位"
<field name="dismantle_person"/> options="{'no_create': True,'no_create_edit':True}"
attrs="{'invisible': [('dismantle_cause', 'not in', ['更换为其他刀具'])], 'readonly': [('state', '=', '已拆解')],
'required': [('pad_product_id', '!=', False), ('dismantle_cause', 'in', ['更换为其他刀具'])]}"/>
</group> </group>
<group>
<field name="dismantle_data"/>
</group> </group>
</group> </group>
</page> </page>
</notebook> </notebook>
</sheet> </sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="message_ids"/>
</div>
</form> </form>
</field> </field>
</record> </record>
@@ -904,7 +880,6 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<search> <search>
<field name="functional_tool_id"/> <field name="functional_tool_id"/>
<field name="code" string="拆解单编码"/>
<filter name="no_dismantle_state" string="未拆解" domain="[('state','!=','已拆解')]"/> <filter name="no_dismantle_state" string="未拆解" domain="[('state','!=','已拆解')]"/>
<filter name="dismantle_state" string="已拆解" domain="[('state','=','已拆解')]"/> <filter name="dismantle_state" string="已拆解" domain="[('state','=','已拆解')]"/>
<separator/> <separator/>

View File

@@ -62,7 +62,6 @@
<tree> <tree>
<field name="name"/> <field name="name"/>
<field name="rfid"/> <field name="rfid"/>
<field name="product_qty"/>
<field name="tool_material_status"/> <field name="tool_material_status"/>
<!-- <button name="enroll_tool_material_stock" string="序列号注册" type="object" class="btn-primary"/>--> <!-- <button name="enroll_tool_material_stock" string="序列号注册" type="object" class="btn-primary"/>-->
</tree> </tree>

View File

@@ -233,10 +233,7 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
# 功能刀具组装信息 # 功能刀具组装信息
# ===============整体式刀具型号================= # ===============整体式刀具型号=================
integral_freight_barcode_id = fields.Many2one('sf.shelf.location', string='整体式刀具货位', integral_freight_barcode = fields.Char('整体式刀具货位')
domain="[('product_id.cutting_tool_material_id.name', '=', '整体式刀具'),('product_num', '>', 0)]")
integral_freight_lot_id = fields.Many2one('sf.shelf.location.lot', string='整体式刀具批次',
domain="[('shelf_location_id', '=', integral_freight_barcode_id)]")
integral_product_id = fields.Many2one('product.product', string='整体式刀具名称', integral_product_id = fields.Many2one('product.product', string='整体式刀具名称',
compute='_compute_integral_product_id', store=True) compute='_compute_integral_product_id', store=True)
cutting_tool_integral_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='整体式刀具型号', cutting_tool_integral_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='整体式刀具型号',
@@ -246,23 +243,28 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
sf_tool_brand_id_1 = fields.Many2one('sf.machine.brand', string='整体式刀具品牌', sf_tool_brand_id_1 = fields.Many2one('sf.machine.brand', string='整体式刀具品牌',
related='integral_product_id.brand_id') related='integral_product_id.brand_id')
@api.onchange('integral_freight_barcode_id') @api.depends('integral_freight_barcode')
def _onchange_integral_freight_barcode_id(self):
for item in self:
item.integral_freight_lot_id = False
@api.depends('integral_freight_lot_id')
def _compute_integral_product_id(self): def _compute_integral_product_id(self):
if self.integral_freight_lot_id: if self.integral_freight_barcode:
self.integral_product_id = self.integral_freight_lot_id.lot_id.product_id.id location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.integral_freight_barcode)])
if location:
if not location.product_id:
raise ValidationError('编码为【%s】的货位为空货位!' % location.barcode)
else: else:
self.integral_product_id = False material_name_id = location.product_id.cutting_tool_material_id
if material_name_id and material_name_id.name == '整体式刀具':
if location.product_num == 0:
raise ValidationError('编码为【%s】的货位的产品库存数量为0,请重新选择!' % location.barcode)
self.integral_product_id = location.product_id.id
else:
raise ValidationError(
'编码为【%s】的货位存放的产品为【%s】,不是整体式刀具,请重新选择!' % (
location.barcode, location.product_id.name))
else:
raise ValidationError('编码为【%s】的货位不存在!' % self.integral_freight_barcode)
# ===============刀片型号==================== # ===============刀片型号====================
blade_freight_barcode_id = fields.Many2one('sf.shelf.location', string='刀片货位', blade_freight_barcode = fields.Char('刀片货位')
domain="[('product_id.cutting_tool_material_id.name', '=', '刀片'),('product_num', '>', 0)]")
blade_freight_lot_id = fields.Many2one('sf.shelf.location.lot', string='刀片批次',
domain="[('shelf_location_id', '=', blade_freight_barcode_id)]")
blade_product_id = fields.Many2one('product.product', string='刀片名称', compute='_compute_blade_product_id', blade_product_id = fields.Many2one('product.product', string='刀片名称', compute='_compute_blade_product_id',
store=True) store=True)
cutting_tool_blade_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀片型号', cutting_tool_blade_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀片型号',
@@ -271,23 +273,28 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
related='blade_product_id.specification_id') related='blade_product_id.specification_id')
sf_tool_brand_id_2 = fields.Many2one('sf.machine.brand', '刀片品牌', related='blade_product_id.brand_id') sf_tool_brand_id_2 = fields.Many2one('sf.machine.brand', '刀片品牌', related='blade_product_id.brand_id')
@api.onchange('blade_freight_barcode_id') @api.depends('blade_freight_barcode')
def _onchange_blade_freight_barcode_id(self):
for item in self:
item.blade_freight_lot_id = False
@api.depends('blade_freight_lot_id')
def _compute_blade_product_id(self): def _compute_blade_product_id(self):
if self.blade_freight_lot_id: if self.blade_freight_barcode:
self.blade_product_id = self.blade_freight_lot_id.lot_id.product_id.id location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.blade_freight_barcode)])
if location:
if not location.product_id:
raise ValidationError('编码为【%s】的货位为空货位!' % location.barcode)
else: else:
self.blade_product_id = False material_name_id = location.product_id.cutting_tool_material_id
if material_name_id and material_name_id.name == '刀片':
if location.product_num == 0:
raise ValidationError('编码为【%s】的货位的产品库存数量为0,请重新选择!' % location.barcode)
self.blade_product_id = location.product_id.id
else:
raise ValidationError(
'编码为【%s】的货位存放的产品为【%s】,不是刀片,请重新选择!' % (
location.barcode, location.product_id.name))
else:
raise ValidationError('编码为【%s】的货位不存在!' % self.blade_freight_barcode)
# ====================刀杆型号================== # ====================刀杆型号==================
bar_freight_barcode_id = fields.Many2one('sf.shelf.location', string='刀杆货位', bar_freight_barcode = fields.Char('刀杆货位')
domain="[('product_id.cutting_tool_material_id.name', '=', '刀杆'),('product_num', '>', 0)]")
bar_freight_lot_id = fields.Many2one('sf.shelf.location.lot', string='刀杆批次',
domain="[('shelf_location_id', '=', bar_freight_barcode_id)]")
bar_product_id = fields.Many2one('product.product', string='刀杆名称', compute='_compute_bar_product_id', bar_product_id = fields.Many2one('product.product', string='刀杆名称', compute='_compute_bar_product_id',
store=True) store=True)
cutting_tool_cutterbar_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀杆型号', cutting_tool_cutterbar_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀杆型号',
@@ -296,23 +303,28 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
related='bar_product_id.specification_id') related='bar_product_id.specification_id')
sf_tool_brand_id_3 = fields.Many2one('sf.machine.brand', '刀杆品牌', related='bar_product_id.brand_id') sf_tool_brand_id_3 = fields.Many2one('sf.machine.brand', '刀杆品牌', related='bar_product_id.brand_id')
@api.onchange('bar_freight_barcode_id') @api.depends('bar_freight_barcode')
def _onchange_bar_freight_barcode_id(self):
for item in self:
item.bar_freight_lot_id = False
@api.depends('bar_freight_lot_id')
def _compute_bar_product_id(self): def _compute_bar_product_id(self):
if self.bar_freight_lot_id: if self.bar_freight_barcode:
self.bar_product_id = self.bar_freight_lot_id.lot_id.product_id.id location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.bar_freight_barcode)])
if location:
if not location.product_id:
raise ValidationError('编码为【%s】的货位为空货位!' % location.barcode)
else: else:
self.bar_product_id = False material_name_id = location.product_id.cutting_tool_material_id
if material_name_id and material_name_id.name == '刀杆':
if location.product_num == 0:
raise ValidationError('编码为【%s】的货位的产品库存数量为0,请重新选择!' % location.barcode)
self.bar_product_id = location.product_id.id
else:
raise ValidationError(
'编码为【%s】的货位存放的产品为【%s】,不是刀杆,请重新选择!' % (
location.barcode, location.product_id.name))
else:
raise ValidationError('编码为【%s】的货位不存在!' % self.bar_freight_barcode)
# ===============刀盘型号=================== # ===============刀盘型号===================
pad_freight_barcode_id = fields.Many2one('sf.shelf.location', string='刀盘货位', pad_freight_barcode = fields.Char('刀盘货位')
domain="[('product_id.cutting_tool_material_id.name', '=', '刀盘'),('product_num', '>', 0)]")
pad_freight_lot_id = fields.Many2one('sf.shelf.location.lot', string='刀盘批次',
domain="[('shelf_location_id', '=', pad_freight_barcode_id)]")
pad_product_id = fields.Many2one('product.product', string='刀盘名称', compute='_compute_pad_product_id', pad_product_id = fields.Many2one('product.product', string='刀盘名称', compute='_compute_pad_product_id',
store=True) store=True)
cutting_tool_cutterpad_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀盘型号', cutting_tool_cutterpad_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀盘型号',
@@ -321,17 +333,25 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
related='pad_product_id.specification_id') related='pad_product_id.specification_id')
sf_tool_brand_id_4 = fields.Many2one('sf.machine.brand', '刀盘品牌', related='pad_product_id.brand_id') sf_tool_brand_id_4 = fields.Many2one('sf.machine.brand', '刀盘品牌', related='pad_product_id.brand_id')
@api.onchange('pad_freight_barcode_id') @api.depends('pad_freight_barcode')
def _onchange_pad_freight_barcode_id(self):
for item in self:
item.pad_freight_lot_id = False
@api.depends('pad_freight_lot_id')
def _compute_pad_product_id(self): def _compute_pad_product_id(self):
if self.pad_freight_lot_id: if self.pad_freight_barcode:
self.pad_product_id = self.pad_freight_lot_id.lot_id.product_id.id location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.pad_freight_barcode)])
if location:
if not location.product_id:
raise ValidationError('编码为【%s】的货位为空货位!' % location.barcode)
else: else:
self.pad_product_id = False material_name_id = location.product_id.cutting_tool_material_id
if material_name_id and material_name_id.name == '刀盘':
if location.product_num == 0:
raise ValidationError('编码为【%s】的货位的产品库存数量为0,请重新选择!' % location.barcode)
self.pad_product_id = location.product_id.id
else:
raise ValidationError(
'编码为【%s】的货位存放的产品为【%s】,不是刀盘,请重新选择!' % (
location.barcode, location.product_id.name))
else:
raise ValidationError('编码为【%s】的货位不存在!' % self.pad_freight_barcode)
# ================刀柄型号=============== # ================刀柄型号===============
handle_freight_rfid = fields.Char('刀柄Rfid', compute='_compute_rfid') handle_freight_rfid = fields.Char('刀柄Rfid', compute='_compute_rfid')
@@ -354,10 +374,7 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
self.pad_product_id = False self.pad_product_id = False
# =================夹头型号============== # =================夹头型号==============
chuck_freight_barcode_id = fields.Many2one('sf.shelf.location', string='夹头货位', chuck_freight_barcode = fields.Char('夹头货位')
domain="[('product_id.cutting_tool_material_id.name', '=', '夹头'),('product_num', '>', 0)]")
chuck_freight_lot_id = fields.Many2one('sf.shelf.location.lot', string='夹头批次',
domain="[('shelf_location_id', '=', chuck_freight_barcode_id)]")
chuck_product_id = fields.Many2one('product.product', string='夹头名称', compute='_compute_chuck_product_id', chuck_product_id = fields.Many2one('product.product', string='夹头名称', compute='_compute_chuck_product_id',
store=True) store=True)
cutting_tool_cutterhead_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='夹头型号', cutting_tool_cutterhead_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='夹头型号',
@@ -366,17 +383,25 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
related='chuck_product_id.specification_id') related='chuck_product_id.specification_id')
sf_tool_brand_id_6 = fields.Many2one('sf.machine.brand', '夹头品牌', related='chuck_product_id.brand_id') sf_tool_brand_id_6 = fields.Many2one('sf.machine.brand', '夹头品牌', related='chuck_product_id.brand_id')
@api.onchange('chuck_freight_barcode_id') @api.depends('chuck_freight_barcode')
def _onchange_chuck_freight_barcode_id(self):
for item in self:
item.chuck_freight_lot_id = False
@api.depends('chuck_freight_lot_id')
def _compute_chuck_product_id(self): def _compute_chuck_product_id(self):
if self.chuck_freight_lot_id: if self.chuck_freight_barcode:
self.chuck_product_id = self.chuck_freight_lot_id.lot_id.product_id.id location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.chuck_freight_barcode)])
if location:
if not location.product_id:
raise ValidationError('编码为【%s】的货位为空货位!' % location.barcode)
else: else:
self.chuck_product_id = False material_name_id = location.product_id.cutting_tool_material_id
if material_name_id and material_name_id.name == '夹头':
if location.product_num == 0:
raise ValidationError('编码为【%s】的货位的产品库存数量为0,请重新选择!' % location.barcode)
self.chuck_product_id = location.product_id.id
else:
raise ValidationError(
'编码为【%s】的货位存放的产品为【%s】,不是夹头,请重新选择!' % (
location.barcode, location.product_id.name))
else:
raise ValidationError('编码为【%s】的货位不存在!' % self.chuck_freight_barcode)
# ======================================== # ========================================
def on_barcode_scanned(self, barcode): def on_barcode_scanned(self, barcode):
@@ -398,23 +423,23 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
if location: if location:
material_name = location.product_id.cutting_tool_material_id.name material_name = location.product_id.cutting_tool_material_id.name
if material_name == '夹头': if material_name == '夹头':
record.chuck_freight_barcode_id = location.id record.chuck_freight_barcode = barcode
elif material_name == '整体式刀具': elif material_name == '整体式刀具':
record.integral_freight_barcode_id = location.id record.integral_freight_barcode = barcode
record.blade_freight_barcode_id = False record.blade_freight_barcode = ''
record.bar_freight_barcode_id = False record.bar_freight_barcode = ''
record.pad_freight_barcode_id = False record.pad_freight_barcode = ''
elif material_name == '刀片': elif material_name == '刀片':
record.blade_freight_barcode_id = location.id record.blade_freight_barcode = barcode
record.integral_freight_barcode_id = False record.integral_freight_barcode = ''
elif material_name == '刀杆': elif material_name == '刀杆':
record.bar_freight_barcode_id = location.id record.bar_freight_barcode = barcode
record.integral_freight_barcode_id = False record.integral_freight_barcode = ''
record.pad_freight_barcode_id = False record.pad_freight_barcode = ''
elif material_name == '刀盘': elif material_name == '刀盘':
record.pad_freight_barcode_id = location.id record.pad_freight_barcode = barcode
record.integral_freight_barcode_id = False record.integral_freight_barcode = ''
record.bar_freight_barcode_id = False record.bar_freight_barcode = ''
else: else:
raise ValidationError('扫描的刀具物料不存在,请重新扫描!') raise ValidationError('扫描的刀具物料不存在,请重新扫描!')
else: else:
@@ -465,15 +490,6 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
compute='_compute_after_assembly_max_lifetime_value') compute='_compute_after_assembly_max_lifetime_value')
obtain_measurement_status = fields.Boolean('是否获取测量值', default=False) obtain_measurement_status = fields.Boolean('是否获取测量值', default=False)
enable_tool_presetter = fields.Boolean('是否启用刀具预调仪', default=lambda self: self.get_enable_tool_presetter())
def get_enable_tool_presetter(self):
"""
获取是否启用刀具预调仪数据
"""
sf_sync_config = self.env['res.config.settings'].get_values()
enable_tool_presetter = sf_sync_config['enable_tool_presetter']
return enable_tool_presetter
@api.depends('after_assembly_tool_loading_length', 'after_assembly_handle_length') @api.depends('after_assembly_tool_loading_length', 'after_assembly_handle_length')
def _compute_after_assembly_functional_tool_length(self): def _compute_after_assembly_functional_tool_length(self):
@@ -537,21 +553,32 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
# functional_tool_cutting_type = fields.Char(string='功能刀具切削类型', readonly=False) # functional_tool_cutting_type = fields.Char(string='功能刀具切削类型', readonly=False)
# res_partner_id = fields.Many2one('res.partner', '智能工厂', domain="[('is_factory', '=', True)]") # res_partner_id = fields.Many2one('res.partner', '智能工厂', domain="[('is_factory', '=', True)]")
@api.depends('after_assembly_functional_tool_type_id', 'cutting_tool_cutterhandle_model_id', @api.depends('after_assembly_functional_tool_type_id', 'integral_specification_id', 'bar_specification_id',
'after_assembly_functional_tool_diameter', 'after_assembly_tool_loading_length', 'pad_specification_id', 'handle_specification_id', 'after_assembly_tool_loading_length')
'after_assembly_knife_tip_r_angle', 'after_assembly_functional_tool_length',
'after_assembly_handle_length')
def _compute_code(self): def _compute_code(self):
for obj in self: for obj in self:
if obj.cutting_tool_cutterhandle_model_id: str_1 = 'GNDJ-%s' % obj.after_assembly_functional_tool_type_id.code
code = obj.cutting_tool_cutterhandle_model_id.code.split('-', 1)[0] str_2 = ''
str_1 = '%s-GNDJ-%s-D%sL%sR%sB%sH%s' % ( if obj.handle_specification_id:
code, obj.after_assembly_functional_tool_type_id.code, obj.after_assembly_functional_tool_diameter, if obj.integral_specification_id:
obj.after_assembly_tool_loading_length, obj.after_assembly_knife_tip_r_angle, str_2 = '%s-D%sL%sB%sH%s-' % (
round(obj.after_assembly_functional_tool_length, 3), obj.after_assembly_handle_length) str_1, obj.integral_specification_id.blade_diameter, obj.after_assembly_tool_loading_length,
obj.code = '%s-%s' % (str_1, self._get_code(str_1)) obj.integral_specification_id.blade_length, obj.handle_specification_id.total_length)
elif obj.bar_specification_id:
str_2 = '%s-D%sL%sB%sH%s-' % (
str_1, obj.bar_specification_id.cutter_arbor_diameter, obj.after_assembly_tool_loading_length,
obj.bar_specification_id.blade_length, obj.handle_specification_id.total_length)
elif obj.pad_specification_id:
str_2 = '%s-D%sL%sB%sH%s-' % (
str_1, obj.pad_specification_id.cutter_head_diameter, obj.after_assembly_tool_loading_length,
obj.pad_specification_id.cut_depth_max, obj.handle_specification_id.total_length,
)
else: else:
obj.code = '' obj.code = str_2
return True
obj.code = str_2 + str(self._get_code(str_2))
else:
obj.code = str_2
def _get_code(self, str_2): def _get_code(self, str_2):
functional_tool_assembly = self.env['sf.functional.cutting.tool.entity'].sudo().search( functional_tool_assembly = self.env['sf.functional.cutting.tool.entity'].sudo().search(
@@ -574,7 +601,7 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
else: else:
obj.after_assembly_functional_tool_name = '' obj.after_assembly_functional_tool_name = ''
@api.onchange('integral_freight_barcode_id') @api.onchange('integral_freight_barcode')
def _onchange_after_assembly_functional_tool_diameter(self): def _onchange_after_assembly_functional_tool_diameter(self):
for obj in self: for obj in self:
if obj.integral_product_id: if obj.integral_product_id:
@@ -582,7 +609,7 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
else: else:
obj.after_assembly_functional_tool_diameter = 0 obj.after_assembly_functional_tool_diameter = 0
@api.onchange('blade_freight_barcode_id') @api.onchange('blade_freight_barcode')
def _onchange_after_assembly_knife_tip_r_angle(self): def _onchange_after_assembly_knife_tip_r_angle(self):
for obj in self: for obj in self:
if obj.blade_product_id: if obj.blade_product_id:
@@ -617,32 +644,25 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
# 创建组装入库单 # 创建组装入库单
# 创建功能刀具批次/序列号记录 # 创建功能刀具批次/序列号记录
stock_lot = product_id.create_assemble_warehouse_receipt(self.id, functional_tool_assembly, self) stock_lot = product_id.create_assemble_warehouse_receipt(self.id, functional_tool_assembly, self)
# 封装功能刀具数据,用于更新组装单信息
desc_1 = self.get_desc_1(stock_lot)
# 封装功能刀具数据,用于创建功能刀具记录
desc_2 = self.get_desc_2(stock_lot, functional_tool_assembly)
# 创建刀具组装入库单 # 创建刀具组装入库单
self.env['stock.picking'].create_stocking_picking(stock_lot, functional_tool_assembly, self) self.env['stock.picking'].create_stocking_picking(stock_lot, functional_tool_assembly, self)
# 刀具物料出库 # 刀具物料出库
if self.handle_code_id: if self.handle_code_id:
product_id.tool_material_stock_moves(self.handle_code_id, self.assembly_order_code) product_id.tool_material_stock_moves(self.handle_code_id, self.assembly_order_code)
if self.integral_product_id: if self.integral_product_id:
self.integral_product_id.material_stock_moves(self.integral_freight_barcode_id, self.integral_product_id.material_stock_moves(self.integral_freight_barcode, self.assembly_order_code)
self.integral_freight_lot_id, self.assembly_order_code)
if self.blade_product_id: if self.blade_product_id:
self.blade_product_id.material_stock_moves(self.blade_freight_barcode_id, self.blade_product_id.material_stock_moves(self.blade_freight_barcode, self.assembly_order_code)
self.blade_freight_lot_id, self.assembly_order_code)
if self.bar_product_id: if self.bar_product_id:
self.bar_product_id.material_stock_moves(self.bar_freight_barcode_id, self.bar_product_id.material_stock_moves(self.bar_freight_barcode, self.assembly_order_code)
self.bar_freight_lot_id, self.assembly_order_code)
if self.pad_product_id: if self.pad_product_id:
self.pad_product_id.material_stock_moves(self.pad_freight_barcode_id, self.pad_product_id.material_stock_moves(self.pad_freight_barcode, self.assembly_order_code)
self.pad_freight_lot_id, self.assembly_order_code)
if self.chuck_product_id: if self.chuck_product_id:
self.chuck_product_id.material_stock_moves(self.chuck_freight_barcode_id, self.chuck_product_id.material_stock_moves(self.chuck_freight_barcode, self.assembly_order_code)
self.chuck_freight_lot_id, self.assembly_order_code)
# ============================创建功能刀具列表、安全库存记录=============================== # ============================创建功能刀具列表、安全库存记录===============================
# 封装功能刀具数据
desc_2 = self.get_desc_2(stock_lot, functional_tool_assembly)
# 创建功能刀具列表记录 # 创建功能刀具列表记录
record_1 = self.env['sf.functional.cutting.tool.entity'].create(desc_2) record_1 = self.env['sf.functional.cutting.tool.entity'].create(desc_2)
# 创建安全库存信息 # 创建安全库存信息
@@ -651,6 +671,8 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
}, record_1) }, record_1)
# =====================修改功能刀具组装单、机床换刀申请、CAM工单程序用刀计划的状态============== # =====================修改功能刀具组装单、机床换刀申请、CAM工单程序用刀计划的状态==============
# 封装功能刀具数据
desc_1 = self.get_desc_1(stock_lot)
# 修改功能刀具组装单信息 # 修改功能刀具组装单信息
functional_tool_assembly.write(desc_1) functional_tool_assembly.write(desc_1)
if functional_tool_assembly.sf_machine_table_tool_changing_apply_id: if functional_tool_assembly.sf_machine_table_tool_changing_apply_id:
@@ -707,17 +729,12 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
'code': self.code, 'code': self.code,
'rfid': self.rfid, 'rfid': self.rfid,
'tool_groups_id': self.after_tool_groups_id.id, 'tool_groups_id': self.after_tool_groups_id.id,
'integral_freight_barcode': self.integral_freight_barcode,
'blade_freight_barcode': self.blade_freight_barcode,
'bar_freight_barcode': self.bar_freight_barcode,
'pad_freight_barcode': self.pad_freight_barcode,
'handle_code_id': self.handle_code_id.id, 'handle_code_id': self.handle_code_id.id,
'integral_freight_barcode_id': self.integral_freight_barcode_id.id, 'chuck_freight_barcode': self.chuck_freight_barcode,
'integral_lot_id': self.integral_freight_lot_id.lot_id.id,
'blade_freight_barcode_id': self.blade_freight_barcode_id.id,
'blade_lot_id': self.blade_freight_lot_id.lot_id.id,
'bar_freight_barcode_id': self.bar_freight_barcode_id.id,
'bar_lot_id': self.bar_freight_lot_id.lot_id.id,
'pad_freight_barcode_id': self.pad_freight_barcode_id.id,
'pad_lot_id': self.pad_freight_lot_id.lot_id.id,
'chuck_freight_barcode_id': self.chuck_freight_barcode_id.id,
'chuck_lot_id': self.chuck_freight_lot_id.lot_id.id,
'after_assembly_functional_tool_name': self.after_assembly_functional_tool_name, 'after_assembly_functional_tool_name': self.after_assembly_functional_tool_name,
'after_assembly_functional_tool_type_id': self.after_assembly_functional_tool_type_id.id, 'after_assembly_functional_tool_type_id': self.after_assembly_functional_tool_type_id.id,
@@ -798,7 +815,6 @@ class StockPicking(models.Model):
'picking_type_id': picking_type_id.id, 'picking_type_id': picking_type_id.id,
'location_id': picking_type_id.default_location_src_id.id, 'location_id': picking_type_id.default_location_src_id.id,
'location_dest_id': picking_type_id.default_location_dest_id.id, 'location_dest_id': picking_type_id.default_location_dest_id.id,
'origin': obj.assembly_order_code
}) })
# 创建作业详情对象记录,并绑定到刀具组装入库单 # 创建作业详情对象记录,并绑定到刀具组装入库单
self.env['stock.move.line'].create({ self.env['stock.move.line'].create({
@@ -849,34 +865,38 @@ class ProductProduct(models.Model):
logging.info('没有搜索到功能刀具产品:%s' % product_id) logging.info('没有搜索到功能刀具产品:%s' % product_id)
raise ValidationError('没有找到按唯一序列号追溯的功能刀具产品信息!') raise ValidationError('没有找到按唯一序列号追溯的功能刀具产品信息!')
stock_lot = self.env['stock.lot'].create({ stock_lot = self.env['stock.lot'].create({
'name': self.get_stock_lot_name(obj), 'name': self.get_stock_lot_name(tool_assembly_order_id),
'product_id': product_id[0].id, 'product_id': product_id[0].id,
'company_id': self.env.company.id 'company_id': self.env.company.id
}) })
# 获取位置对象 # 获取位置对象
location_inventory_ids = self.env['stock.location'].search([('name', 'in', ('Production', '生产'))]) location_inventory_id = self.env['stock.location'].search([('name', '=', 'Production')])
stock_location_id = self.env['stock.location'].search([('name', '=', '组装后')]) stock_location_id = self.env['stock.location'].search([('name', '=', '组装后')])
# 创建功能刀具该批次/序列号 库存移动和移动历史 # 创建功能刀具该批次/序列号 库存移动和移动历史
stock_lot.create_stock_quant(location_inventory_ids[-1], stock_location_id, functional_tool_assembly.id, stock_lot.create_stock_quant(location_inventory_id, stock_location_id, functional_tool_assembly.id,
obj.assembly_order_code, obj, obj.after_tool_groups_id) obj.assembly_order_code, obj, obj.after_tool_groups_id)
return stock_lot return stock_lot
def get_stock_lot_name(self, obj): def get_stock_lot_name(self, tool_assembly_order_id):
""" """
生成功能刀具序列号 生成功能刀具序列号
""" """
company = obj.cutting_tool_cutterhandle_model_id.code.split('-', 1)[0] tool_assembly_order = self.env['sf.functional.tool.assembly.order'].search(
[('id', '=', tool_assembly_order_id)])
code = 'JKM-T-' + str(tool_assembly_order.after_assembly_functional_tool_type_id.code) + '-' + str(
tool_assembly_order.after_assembly_functional_tool_diameter) + '-'
new_time = datetime.strptime(str(fields.Date.today()), "%Y-%m-%d").strftime("%Y%m%d") new_time = datetime.strptime(str(fields.Date.today()), "%Y-%m-%d").strftime("%Y%m%d")
code = '%s-GNDJ-%s-%s' % (company, obj.after_assembly_functional_tool_type_id.code, new_time) code += str(new_time) + '-'
stock_lot_id = self.env['stock.lot'].sudo().search( stock_lot_id = self.env['stock.lot'].sudo().search(
[('name', 'like', code)], limit=1, order="id desc") [('name', 'like', new_time), ('product_id.categ_type', '=', '功能刀具'),
('product_id.tracking', '=', 'serial')], limit=1, order="id desc")
if not stock_lot_id: if not stock_lot_id:
num = "%03d" % 1 num = "%03d" % 1
else: else:
m = int(stock_lot_id.name[-3:]) + 1 m = int(stock_lot_id.name[-3:]) + 1
num = "%03d" % m num = "%03d" % m
return '%s-%s' % (code, num) return code + str(num)
def tool_material_stock_moves(self, tool_material, assembly_order_code): def tool_material_stock_moves(self, tool_material, assembly_order_code):
""" """
@@ -889,7 +909,7 @@ class ProductProduct(models.Model):
tool_material.create_stock_quant(location_inventory_id, stock_location_id, None, assembly_order_code, False, tool_material.create_stock_quant(location_inventory_id, stock_location_id, None, assembly_order_code, False,
False) False)
def material_stock_moves(self, shelf_location_barcode_id, lot_id, assembly_order_code): def material_stock_moves(self, shelf_location_barcode, assembly_order_code):
# 创建库存移动记录 # 创建库存移动记录
stock_move_id = self.env['stock.move'].sudo().create({ stock_move_id = self.env['stock.move'].sudo().create({
'name': assembly_order_code, 'name': assembly_order_code,
@@ -900,16 +920,21 @@ class ProductProduct(models.Model):
'state': 'done' 'state': 'done'
}) })
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', shelf_location_barcode)])
# 创建移动历史记录 # 创建移动历史记录
stock_move_line_id = self.env['stock.move.line'].sudo().create({ stock_move_line_id = self.env['stock.move.line'].sudo().create({
'product_id': self.id, 'product_id': self.id,
'move_id': stock_move_id.id, 'move_id': stock_move_id.id,
'lot_id': lot_id.lot_id.id, 'current_location_id': location.id,
'current_location_id': shelf_location_barcode_id.id,
'install_tool_time': fields.Datetime.now(), 'install_tool_time': fields.Datetime.now(),
'qty_done': 1.0, 'qty_done': 1.0,
'state': 'done', 'state': 'done',
}) })
if location.product_num > 0:
location.product_num = location.product_num - 1
else:
raise ValidationError(
'%s】货位的【%s】产品库存数量为零,请采购入库后再重新组装!' % (location.barcode, location.product_id.name))
return stock_move_id, stock_move_line_id return stock_move_id, stock_move_line_id

View File

@@ -229,18 +229,13 @@
</group> </group>
</group> </group>
<group col="1" <group col="1"
attrs="{'invisible': ['|','|',('blade_freight_barcode_id', '!=', False),('bar_freight_barcode_id', '!=', False),('pad_freight_barcode_id', '!=', False)]}"> attrs="{'invisible': ['|','|',('blade_freight_barcode', '!=', False),('bar_freight_barcode', '!=', False),('pad_freight_barcode', '!=', False)]}">
<div> <div>
<separator string="整体式刀具:" style="font-size: 13px;"/> <separator string="整体式刀具:" style="font-size: 13px;"/>
</div> </div>
<group> <group>
<group> <group>
<field name="integral_freight_barcode_id" options="{'no_create': True}" <field name="integral_freight_barcode" string="货位"/>
placeholder="请选择" string="货位"/>
</group>
<group>
<field name="integral_freight_lot_id" options="{'no_create': True}"
placeholder="请选择" string="批次"/>
</group> </group>
</group> </group>
<group col="2"> <group col="2">
@@ -254,18 +249,13 @@
</group> </group>
</group> </group>
</group> </group>
<group col="1" attrs="{'invisible': [('integral_freight_barcode_id', '!=', False)]}"> <group col="1" attrs="{'invisible': [('integral_freight_barcode', '!=', False)]}">
<div> <div>
<separator string="刀片:" style="font-size: 13px;"/> <separator string="刀片:" style="font-size: 13px;"/>
</div> </div>
<group> <group>
<group> <group>
<field name="blade_freight_barcode_id" options="{'no_create': True}" <field name="blade_freight_barcode" string="货位"/>
placeholder="请选择" string="货位"/>
</group>
<group>
<field name="blade_freight_lot_id" options="{'no_create': True}"
placeholder="请选择" string="批次"/>
</group> </group>
</group> </group>
<group col="2"> <group col="2">
@@ -280,18 +270,13 @@
</group> </group>
</group> </group>
<group col="1" <group col="1"
attrs="{'invisible': ['|',('integral_freight_barcode_id', '!=', False),('pad_freight_barcode_id', '!=', False)]}"> attrs="{'invisible': ['|',('integral_freight_barcode', '!=', False),('pad_freight_barcode', '!=', False)]}">
<div> <div>
<separator string="刀杆:" style="font-size: 13px;"/> <separator string="刀杆:" style="font-size: 13px;"/>
</div> </div>
<group> <group>
<group> <group>
<field name="bar_freight_barcode_id" options="{'no_create': True}" <field name="bar_freight_barcode" string="货位"/>
placeholder="请选择" string="货位"/>
</group>
<group>
<field name="bar_freight_lot_id" options="{'no_create': True}" placeholder="请选择"
string="批次"/>
</group> </group>
</group> </group>
<group col="2"> <group col="2">
@@ -306,18 +291,13 @@
</group> </group>
</group> </group>
<group col="1" <group col="1"
attrs="{'invisible': ['|',('integral_freight_barcode_id', '!=', False),('bar_freight_barcode_id', '!=', False)]}"> attrs="{'invisible': ['|',('integral_freight_barcode', '!=', False),('bar_freight_barcode', '!=', False)]}">
<div> <div>
<separator string="刀盘:" style="font-size: 13px;"/> <separator string="刀盘:" style="font-size: 13px;"/>
</div> </div>
<group> <group>
<group> <group>
<field name="pad_freight_barcode_id" options="{'no_create': True}" <field name="pad_freight_barcode" string="货位"/>
placeholder="请选择" string="货位"/>
</group>
<group>
<field name="pad_freight_lot_id" options="{'no_create': True}" placeholder="请选择"
string="批次"/>
</group> </group>
</group> </group>
<group col="2"> <group col="2">
@@ -337,12 +317,7 @@
</div> </div>
<group> <group>
<group> <group>
<field name="chuck_freight_barcode_id" options="{'no_create': True}" <field name="chuck_freight_barcode" string="货位"/>
placeholder="请选择" string="货位"/>
</group>
<group>
<field name="chuck_freight_lot_id" options="{'no_create': True}"
placeholder="请选择" string="批次"/>
</group> </group>
</group> </group>
<group col="2"> <group col="2">
@@ -368,14 +343,12 @@
<group> <group>
<field name="obtain_measurement_status" invisible="1"/> <field name="obtain_measurement_status" invisible="1"/>
<button name="get_tool_preset_parameter" string="获取测量值" type="object" <button name="get_tool_preset_parameter" string="获取测量值" type="object"
attrs="{'invisible': [('enable_tool_presetter', '=', False)]}"
class="btn-primary"/> class="btn-primary"/>
</group> </group>
</group> </group>
<group> <group>
<group> <group>
<field name="after_name_id" string="功能刀具名称" placeholder="请选择功能刀具名称" <field name="after_name_id" string="功能刀具名称" placeholder="请选择功能刀具名称" readonly="1"
readonly="1"
options="{'no_create': True, 'no_quick_create': True}"/> options="{'no_create': True, 'no_quick_create': True}"/>
<field name="after_assembly_functional_tool_name" string="功能刀具名称" <field name="after_assembly_functional_tool_name" string="功能刀具名称"
invisible="1"/> invisible="1"/>
@@ -394,16 +367,12 @@
attrs="{'invisible': [('after_assembly_new_former','=','0')]}"/> attrs="{'invisible': [('after_assembly_new_former','=','0')]}"/>
</group> </group>
<group> <group>
<field name="enable_tool_presetter" invisible="1"/>
<field name="after_assembly_functional_tool_diameter" string="刀具直径(mm)" <field name="after_assembly_functional_tool_diameter" string="刀具直径(mm)"
attrs="{'readonly': [('enable_tool_presetter', '=', True)]}" class="custom_required" readonly="1"/>
class="custom_required"/>
<field name="after_assembly_knife_tip_r_angle" string="刀尖R角(mm)" <field name="after_assembly_knife_tip_r_angle" string="刀尖R角(mm)"
attrs="{'readonly': [('enable_tool_presetter', '=', True)]}" class="custom_required" readonly="1"/>
class="custom_required"/>
<field name="after_assembly_tool_loading_length" string="总长度(mm)" <field name="after_assembly_tool_loading_length" string="总长度(mm)"
attrs="{'readonly': [('enable_tool_presetter', '=', True)]}" class="custom_required" readonly="1"/>
class="custom_required"/>
<field name="after_assembly_handle_length" string="刀柄长度(mm)" <field name="after_assembly_handle_length" string="刀柄长度(mm)"
class="custom_required"/> class="custom_required"/>
<field name="after_assembly_functional_tool_length" string="伸出长(mm)" <field name="after_assembly_functional_tool_length" string="伸出长(mm)"
@@ -423,7 +392,7 @@
</sheet> </sheet>
<footer> <footer>
<button string="确定" name="functional_tool_assembly" type="object" class="btn-primary" <button string="确定" name="functional_tool_assembly" type="object" class="btn-primary"
attrs="{'invisible': [('obtain_measurement_status', '=', False),('enable_tool_presetter', '=', True)]}" attrs="{'invisible': [('obtain_measurement_status', '=', False)]}"
confirm="是否确认申请组装"/> confirm="是否确认申请组装"/>
<button string="取消" class="btn-secondary" special="cancel"/> <button string="取消" class="btn-secondary" special="cancel"/>
</footer> </footer>

View File

@@ -452,9 +452,8 @@ class ShelfLocation(models.Model):
# product_id = fields.Many2one('product.template', string='产品') # product_id = fields.Many2one('product.template', string='产品')
product_id = fields.Many2one('product.product', string='产品', compute='_compute_product_id', store=True) product_id = fields.Many2one('product.product', string='产品', compute='_compute_product_id', store=True)
product_sn_id = fields.Many2one('stock.lot', string='产品序列号') product_sn_id = fields.Many2one('stock.lot', string='产品序列号')
product_sn_ids = fields.One2many('sf.shelf.location.lot', 'shelf_location_id', string='产品批次号')
# 产品数量 # 产品数量
product_num = fields.Integer('数量', compute='_compute_number', store=True) product_num = fields.Integer('数量')
@api.depends('product_num') @api.depends('product_num')
def _compute_product_num(self): def _compute_product_num(self):
@@ -464,15 +463,6 @@ class ShelfLocation(models.Model):
elif record.product_num == 0: elif record.product_num == 0:
record.location_status = '空闲' record.location_status = '空闲'
@api.depends('product_sn_ids.qty')
def _compute_number(self):
for item in self:
if item.product_sn_ids:
qty = 0
for product_sn_id in item.product_sn_ids:
qty += product_sn_id.qty
item.product_num = qty
# 修改货位状态为禁用 # 修改货位状态为禁用
def action_location_status_disable(self): def action_location_status_disable(self):
self.location_status = '禁用' self.location_status = '禁用'
@@ -481,7 +471,7 @@ class ShelfLocation(models.Model):
def action_location_status_enable(self): def action_location_status_enable(self):
self.location_status = '空闲' self.location_status = '空闲'
@api.depends('product_sn_id', 'product_sn_ids') @api.depends('product_sn_id')
def _compute_product_id(self): def _compute_product_id(self):
""" """
根据产品序列号,获取产品 根据产品序列号,获取产品
@@ -494,8 +484,7 @@ class ShelfLocation(models.Model):
record.sudo().product_num = 1 record.sudo().product_num = 1
except Exception as e: except Exception as e:
print('eeeeeee占用', e) print('eeeeeee占用', e)
elif record.product_sn_ids:
return True
else: else:
try: try:
record.sudo().product_id = False record.sudo().product_id = False
@@ -536,24 +525,7 @@ class ShelfLocation(models.Model):
return records return records
class SfShelfLocationLot(models.Model): class Sf_stock_move_line(models.Model):
_name = 'sf.shelf.location.lot'
_description = '批次数量'
name = fields.Char('名称', related='lot_id.name')
shelf_location_id = fields.Many2one('sf.shelf.location', string="货位")
lot_id = fields.Many2one('stock.lot', string='批次号')
qty = fields.Integer('数量')
qty_num = fields.Integer('变更数量')
@api.onchange('qty_num')
def _onchange_qty_num(self):
for item in self:
if item.qty_num > item.qty:
raise ValidationError('变更数量不能比库存数量大!!!')
class SfStockMoveLine(models.Model):
_name = 'stock.move.line' _name = 'stock.move.line'
_inherit = ['stock.move.line', 'printing.utils'] _inherit = ['stock.move.line', 'printing.utils']
@@ -853,7 +825,6 @@ class SfStockMoveLine(models.Model):
obj = self.env['sf.shelf.location'].search([('name', '=', obj = self.env['sf.shelf.location'].search([('name', '=',
self.destination_location_id.name)]) self.destination_location_id.name)])
if record.lot_id: if record.lot_id:
if record.product_id.tracking == 'serial':
shelf_location_obj = self.env['sf.shelf.location'].search( shelf_location_obj = self.env['sf.shelf.location'].search(
[('product_sn_id', '=', record.lot_id.id)]) [('product_sn_id', '=', record.lot_id.id)])
if shelf_location_obj: if shelf_location_obj:
@@ -863,10 +834,6 @@ class SfStockMoveLine(models.Model):
else: else:
if obj: if obj:
obj.product_sn_id = record.lot_id.id obj.product_sn_id = record.lot_id.id
elif record.product_id.tracking == 'lot':
self.put_shelf_location(record)
if not obj.product_id:
obj.product_id = record.product_id.id
else: else:
if obj: if obj:
obj.product_id = record.product_id.id obj.product_id = record.product_id.id
@@ -886,83 +853,20 @@ class SfStockMoveLine(models.Model):
raise ValidationError( raise ValidationError(
'%s】货位已经被占用,请重新选择!!!' % item.destination_location_id.barcode) '%s】货位已经被占用,请重新选择!!!' % item.destination_location_id.barcode)
def put_shelf_location(self, vals):
"""
对货位的批量数据进行数量计算
"""
for record in vals:
if record.lot_id and record.product_id.tracking == 'lot':
if record.current_location_id:
location_lot = self.env['sf.shelf.location.lot'].sudo().search(
[('shelf_location_id', '=', record.current_location_id.id), ('lot_id', '=', record.lot_id.id)])
if location_lot:
location_lot.qty -= record.qty_done
if location_lot.qty == 0:
location_lot.unlink()
elif location_lot.qty < 0:
raise ValidationError('%s】货位【%s】批次的【%s】产品数量不足!' % (
record.current_location_id.barcode, record.lot_id.name, record.product_id.name))
else:
raise ValidationError('%s】货位不存在【%s】批次的【%s】产品' % (
record.current_location_id.barcode, record.lot_id.name, record.product_id.name))
if record.destination_location_id:
location_lot = self.env['sf.shelf.location.lot'].sudo().search(
[('shelf_location_id', '=', record.destination_location_id.id),
('lot_id', '=', record.lot_id.id)])
if location_lot:
location_lot.qty += record.qty_done
else:
self.env['sf.shelf.location.lot'].sudo().create({
'shelf_location_id': record.destination_location_id.id,
'lot_id': record.lot_id.id,
'qty': record.qty_done
})
if not record.destination_location_id.product_id:
record.destination_location_id.product_id = record.product_id.id
@api.model_create_multi
def create(self, vals_list):
records = super(SfStockMoveLine, self).create(vals_list)
self.put_shelf_location(records)
return records
class SfStockPicking(models.Model): class SfStockPicking(models.Model):
_inherit = 'stock.picking' _inherit = 'stock.picking'
check_in = fields.Char(string='查询是否为入库单', compute='_check_is_in') check_in = fields.Char(string='查询是否为入库单', compute='_check_is_in')
def batch_stock_move(self):
"""
批量调拨,非就绪状态的会被忽略,完成后有通知提示
"""
for record in self:
if record.state != 'assigned':
continue
record.action_set_quantities_to_reservation()
record.button_validate()
notification_message = '批量调拨完成!请注意,状态非就绪的单据会被忽略'
return {
'effect': {
'fadeout': 'fast',
'message': notification_message,
'img_url': '/web/image/%s/%s/image_1024' % (
self.create_uid._name, self.create_uid.id) if 0 else '/web/static/img/smile.svg',
'type': 'rainbow_man',
}
}
@api.depends('name') @api.depends('name')
def _check_is_in(self): def _check_is_in(self):
""" """
判断是否为出库单 判断是否为出库单
""" """
for record in self: if self.name:
if record.name: is_check_in = self.name.split('/')
is_check_in = record.name.split('/') self.check_in = is_check_in[1]
record.check_in = is_check_in[1]
def button_validate(self): def button_validate(self):
""" """
@@ -990,9 +894,6 @@ class SfStockPicking(models.Model):
if move and move.product_id.cutting_tool_material_id.name == '刀柄' or '托盘' in ( if move and move.product_id.cutting_tool_material_id.name == '刀柄' or '托盘' in (
move.product_id.fixture_material_id.name or ''): move.product_id.fixture_material_id.name or ''):
for item in move.move_line_nosuggest_ids: for item in move.move_line_nosuggest_ids:
if item.rfid:
if self.env['stock.lot'].search([('rfid', '=', item.rfid)]):
raise ValidationError('该Rfid【%s】在系统中已经存在,请重新录入!' % item.rfid)
if item.location_dest_id.name == '进货': if item.location_dest_id.name == '进货':
if not item.rfid: if not item.rfid:
raise ValidationError('你需要提供%s的Rfid' % move.product_id.name) raise ValidationError('你需要提供%s的Rfid' % move.product_id.name)
@@ -1143,10 +1044,7 @@ class CustomStockMove(models.Model):
move_lines = self.move_line_ids # 获取当前 stock.move 对应的所有 stock.move.line 记录 move_lines = self.move_line_ids # 获取当前 stock.move 对应的所有 stock.move.line 记录
for line in move_lines: for line in move_lines:
if line.lot_name: # 确保 lot_name 存在 if line.lot_name: # 确保 lot_name 存在
lot_name = line.lot_name qr_data = self.compute_lot_qr_code(line.lot_name)
if line.product_id.categ_id.name == '坯料':
lot_name = lot_name.split('[', 1)[0]
qr_data = self.compute_lot_qr_code(lot_name)
# 假设 stock.move.line 模型中有一个字段叫做 lot_qr_code 用于存储二维码数据 # 假设 stock.move.line 模型中有一个字段叫做 lot_qr_code 用于存储二维码数据
line.lot_qr_code = qr_data line.lot_qr_code = qr_data
return result return result

View File

@@ -20,7 +20,7 @@ class MrsShelfLocationDataSync(models.Model):
paired_data = list(zip(my_data, their_data)) paired_data = list(zip(my_data, their_data))
return paired_data return paired_data
shelf_1_obj = self.env['sf.shelf'].search([('name', '=', '一号产线-一号线边刀架')], limit=1) shelf_1_obj = self.env['sf.shelf'].search([('name', '=', '一号线边刀架')], limit=1)
tool_location_objs_1 = self.env['sf.shelf.location'].search([('shelf_id', '=', shelf_1_obj.id)], order='id') tool_location_objs_1 = self.env['sf.shelf.location'].search([('shelf_id', '=', shelf_1_obj.id)], order='id')
location_codes_1 = [location.barcode for location in tool_location_objs_1] location_codes_1 = [location.barcode for location in tool_location_objs_1]
@@ -32,7 +32,7 @@ class MrsShelfLocationDataSync(models.Model):
aligned_data_1 = align_data(location_codes_1, their_data_1) aligned_data_1 = align_data(location_codes_1, their_data_1)
# 2 # 2
shelf_2_obj = self.env['sf.shelf'].search([('name', '=', '一号产线-二号线边刀架')], limit=1) shelf_2_obj = self.env['sf.shelf'].search([('name', '=', '二号线边刀架')], limit=1)
tool_location_objs_2 = self.env['sf.shelf.location'].search([('shelf_id', '=', shelf_2_obj.id)], order='id') tool_location_objs_2 = self.env['sf.shelf.location'].search([('shelf_id', '=', shelf_2_obj.id)], order='id')
location_codes_2 = [location.barcode for location in tool_location_objs_2] location_codes_2 = [location.barcode for location in tool_location_objs_2]
@@ -44,7 +44,7 @@ class MrsShelfLocationDataSync(models.Model):
aligned_data_2 = align_data(location_codes_2, their_data_2) aligned_data_2 = align_data(location_codes_2, their_data_2)
# 4 # 4
shelf_4_obj = self.env['sf.shelf'].search([('name', '=', '一号产线-一号线边料架')], limit=1) shelf_4_obj = self.env['sf.shelf'].search([('name', '=', '一号线边料架')], limit=1)
tool_location_objs_4 = self.env['sf.shelf.location'].search([('shelf_id', '=', shelf_4_obj.id)], order='id') tool_location_objs_4 = self.env['sf.shelf.location'].search([('shelf_id', '=', shelf_4_obj.id)], order='id')
location_codes_4 = [location.barcode for location in tool_location_objs_4] location_codes_4 = [location.barcode for location in tool_location_objs_4]
@@ -56,7 +56,7 @@ class MrsShelfLocationDataSync(models.Model):
aligned_data_4 = align_data(location_codes_4, their_data_4) aligned_data_4 = align_data(location_codes_4, their_data_4)
# 3 # 3
shelf_3_obj = self.env['sf.shelf'].search([('name', '=', '一号产线-二号线边料架')], limit=1) shelf_3_obj = self.env['sf.shelf'].search([('name', '=', '一号线边料架')], limit=1)
tool_location_objs_3 = self.env['sf.shelf.location'].search([('shelf_id', '=', shelf_3_obj.id)], order='id') tool_location_objs_3 = self.env['sf.shelf.location'].search([('shelf_id', '=', shelf_3_obj.id)], order='id')
location_codes_3 = [location.barcode for location in tool_location_objs_3] location_codes_3 = [location.barcode for location in tool_location_objs_3]
@@ -68,7 +68,7 @@ class MrsShelfLocationDataSync(models.Model):
aligned_data_3 = align_data(location_codes_3, their_data_3) aligned_data_3 = align_data(location_codes_3, their_data_3)
# 5 # 5
shelf_5_obj = self.env['sf.shelf'].search([('name', '=', '一号产线-三号线边料架')], limit=1) shelf_5_obj = self.env['sf.shelf'].search([('name', '=', '一号线边料架')], limit=1)
tool_location_objs_5 = self.env['sf.shelf.location'].search([('shelf_id', '=', shelf_5_obj.id)], order='id') tool_location_objs_5 = self.env['sf.shelf.location'].search([('shelf_id', '=', shelf_5_obj.id)], order='id')
location_codes_5 = [location.barcode for location in tool_location_objs_5] location_codes_5 = [location.barcode for location in tool_location_objs_5]
@@ -95,29 +95,12 @@ class MrsShelfLocationDataSync(models.Model):
return code_pair[0] return code_pair[0]
return None # 如果没有找到对应的值返回None或适当的默认值 return None # 如果没有找到对应的值返回None或适当的默认值
# 定时更新所有设备机床刀库信息
equipment_ids = self.env['maintenance.equipment'].search(
[('equipment_type', '=', '机床'), ('function_type', '!=', False)])
for equipment_id in equipment_ids:
if equipment_id:
equipment_id.register_equipment_tool()
shelfinfo = self.env['sf.shelf.location'].get_sf_shelf_location_info() shelfinfo = self.env['sf.shelf.location'].get_sf_shelf_location_info()
print('shelfinfo:', shelfinfo) print('shelfinfo:', shelfinfo)
for item in shelfinfo: for item in shelfinfo:
shelf_barcode = find_our_code(item['Postion'], total_data) shelf_barcode = find_our_code(item['Postion'], total_data)
location_id = self.env['sf.shelf.location'].search([('barcode', '=', shelf_barcode)], limit=1) location_id = self.env['sf.shelf.location'].search([('barcode', '=', shelf_barcode)], limit=1)
if location_id: if location_id:
# 如果是线边刀库信息,则对功能刀具移动生成记录
if 'Tool' in item['Postion']:
tool = self.env['sf.functional.cutting.tool.entity'].sudo().search(
[('rfid', '=', item['RfidCode']), ('functional_tool_status', '!=', '已拆除')])
tool.tool_in_out_stock_location(location_id)
if tool:
location_id.product_sn_id = tool.barcode_id.id
else:
location_id.product_sn_id = False
else:
stock_lot_obj = self.env['stock.lot'].search([('rfid', '=', item['RfidCode'])], limit=1) stock_lot_obj = self.env['stock.lot'].search([('rfid', '=', item['RfidCode'])], limit=1)
if stock_lot_obj: if stock_lot_obj:
location_id.product_sn_id = stock_lot_obj.id location_id.product_sn_id = stock_lot_obj.id

View File

@@ -1,9 +1,7 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_sf_shelf_location_group_sf_stock_user_group_sf_stock_user,sf.shelf.location,model_sf_shelf_location,sf_base.group_sf_stock_user,1,0,0,0 access_sf_shelf_location_group_sf_stock_user_group_sf_stock_user,sf.shelf.location,model_sf_shelf_location,sf_base.group_sf_stock_user,1,0,0,0
access_sf_shelf_location_lot_group_sf_stock_user_group_sf_stock_user,sf.shelf.location.lot,model_sf_shelf_location_lot,sf_base.group_sf_stock_user,1,0,0,0
access_sf_shelf_location_group_sf_stock_manager,sf.shelf.location,model_sf_shelf_location,sf_base.group_sf_stock_manager,1,1,1,0 access_sf_shelf_location_group_sf_stock_manager,sf.shelf.location,model_sf_shelf_location,sf_base.group_sf_stock_manager,1,1,1,0
access_sf_shelf_location_lot_group_sf_stock_manager,sf.shelf.location.lot,model_sf_shelf_location_lot,sf_base.group_sf_stock_manager,1,1,1,0
access_sf_shelf_group_sf_stock_user_group_sf_stock_user,sf.shelf.group.sf.stock.user,model_sf_shelf,sf_base.group_sf_stock_user,1,0,0,0 access_sf_shelf_group_sf_stock_user_group_sf_stock_user,sf.shelf.group.sf.stock.user,model_sf_shelf,sf_base.group_sf_stock_user,1,0,0,0
access_sf_shelf_group_sf_stock_manager,sf.shelf.group.sf.stock.manager,model_sf_shelf,sf_base.group_sf_stock_manager,1,1,1,0 access_sf_shelf_group_sf_stock_manager,sf.shelf.group.sf.stock.manager,model_sf_shelf,sf_base.group_sf_stock_manager,1,1,1,0
@@ -103,7 +101,6 @@ access_stock_replenish_option_group_sf_stock_user,stock.replenishment.option,sto
access_mrp_production_group_sf_stock_user,mrp.production,mrp.model_mrp_production,sf_base.group_sf_stock_user,1,1,1,0 access_mrp_production_group_sf_stock_user,mrp.production,mrp.model_mrp_production,sf_base.group_sf_stock_user,1,1,1,0
access_sf_shelf_location_group_plan_dispatch,sf.shelf.location,model_sf_shelf_location,sf_base.group_plan_dispatch,1,0,0,0 access_sf_shelf_location_group_plan_dispatch,sf.shelf.location,model_sf_shelf_location,sf_base.group_plan_dispatch,1,0,0,0
access_sf_shelf_location_lot_group_plan_dispatch,sf.shelf.location.lot,model_sf_shelf_location_lot,sf_base.group_plan_dispatch,1,0,0,0
access_stock_move,stock.move,stock.model_stock_move,sf_base.group_plan_dispatch,1,1,1,0 access_stock_move,stock.move,stock.model_stock_move,sf_base.group_plan_dispatch,1,1,1,0
access_stock_picking_group_plan_dispatch,stock.picking,stock.model_stock_picking,sf_base.group_plan_dispatch,1,0,0,0 access_stock_picking_group_plan_dispatch,stock.picking,stock.model_stock_picking,sf_base.group_plan_dispatch,1,0,0,0
access_stock_lot_group_plan_dispatch,stock.lot,stock.model_stock_lot,sf_base.group_plan_dispatch,1,0,0,0 access_stock_lot_group_plan_dispatch,stock.lot,stock.model_stock_lot,sf_base.group_plan_dispatch,1,0,0,0
@@ -145,9 +142,6 @@ access_sf_shelf_location_wizard_group_sf_stock_manager,sf_shelf_location_wizard_
access_sf_shelf_location_group_sf_tool_user,sf.shelf.location.group_sf_tool_user,model_sf_shelf_location,sf_base.group_sf_tool_user,1,1,0,0 access_sf_shelf_location_group_sf_tool_user,sf.shelf.location.group_sf_tool_user,model_sf_shelf_location,sf_base.group_sf_tool_user,1,1,0,0
access_sf_shelf_group_user,sf.shelf.location.group_user,model_sf_shelf_location,base.group_user,1,1,0,0 access_sf_shelf_group_user,sf.shelf.location.group_user,model_sf_shelf_location,base.group_user,1,1,0,0
access_sf_shelf_location_lot_group_sf_tool_user,sf.shelf.location.lot.group_sf_tool_user,model_sf_shelf_location_lot,sf_base.group_sf_tool_user,1,1,0,0
access_sf_shelf_lot_group_user,sf.shelf.location.lot.group_user,model_sf_shelf_location_lot,base.group_user,1,1,0,0
access_ir_model_group_sf_stock_user,ir_model_group_sf_stock_user,base.model_ir_model,sf_base.group_sf_stock_user,1,1,0,0 access_ir_model_group_sf_stock_user,ir_model_group_sf_stock_user,base.model_ir_model,sf_base.group_sf_stock_user,1,1,0,0
access_mrp_workorder_group_sf_stock_user,mrp_workorder_group_sf_stock_user,mrp.model_mrp_workorder,sf_base.group_sf_stock_user,1,0,0,0 access_mrp_workorder_group_sf_stock_user,mrp_workorder_group_sf_stock_user,mrp.model_mrp_workorder,sf_base.group_sf_stock_user,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_sf_shelf_location_group_sf_stock_user_group_sf_stock_user sf.shelf.location model_sf_shelf_location sf_base.group_sf_stock_user 1 0 0 0
3 access_sf_shelf_location_lot_group_sf_stock_user_group_sf_stock_user access_sf_shelf_location_group_sf_stock_manager sf.shelf.location.lot sf.shelf.location model_sf_shelf_location_lot model_sf_shelf_location sf_base.group_sf_stock_user sf_base.group_sf_stock_manager 1 0 1 0 1 0
access_sf_shelf_location_group_sf_stock_manager sf.shelf.location model_sf_shelf_location sf_base.group_sf_stock_manager 1 1 1 0
4 access_sf_shelf_location_lot_group_sf_stock_manager access_sf_shelf_group_sf_stock_user_group_sf_stock_user sf.shelf.location.lot sf.shelf.group.sf.stock.user model_sf_shelf_location_lot model_sf_shelf sf_base.group_sf_stock_manager sf_base.group_sf_stock_user 1 1 0 1 0 0
access_sf_shelf_group_sf_stock_user_group_sf_stock_user sf.shelf.group.sf.stock.user model_sf_shelf sf_base.group_sf_stock_user 1 0 0 0
5 access_sf_shelf_group_sf_stock_manager sf.shelf.group.sf.stock.manager model_sf_shelf sf_base.group_sf_stock_manager 1 1 1 0
6 access_procurement_group procurement.group stock.model_procurement_group base.group_user 1 1 1 0
7 access_stock_warehouse_manager_group_sf_stock_user stock.warehouse.manager stock.model_stock_warehouse sf_base.group_sf_stock_user 1 1 1 0
101 access_stock_move access_stock_picking_group_plan_dispatch stock.move stock.picking stock.model_stock_move stock.model_stock_picking sf_base.group_plan_dispatch 1 1 0 1 0 0
102 access_stock_picking_group_plan_dispatch access_stock_lot_group_plan_dispatch stock.picking stock.lot stock.model_stock_picking stock.model_stock_lot sf_base.group_plan_dispatch 1 0 0 0
103 access_stock_lot_group_plan_dispatch access_stock_lot_group_plan_director stock.lot stock.model_stock_lot sf_base.group_plan_dispatch sf_base.group_plan_director 1 0 1 0 1 0
access_stock_lot_group_plan_director stock.lot stock.model_stock_lot sf_base.group_plan_director 1 1 1 0
104 access_stock_warehouse_orderpoint stock.warehouse.orderpoint stock.model_stock_warehouse_orderpoint sf_base.group_plan_dispatch 1 1 0 0
105 access_stock_inventory_conflict stock.inventory.conflict stock.model_stock_inventory_conflict sf_base.group_plan_dispatch 1 0 0 0
106 access_stock_inventory_warning stock.inventory.warning stock.model_stock_inventory_warning sf_base.group_plan_dispatch 1 0 0 0
142
143
144
145
146
147

View File

@@ -149,9 +149,6 @@
<button name="action_assign" type="object" string="检查可用量" <button name="action_assign" type="object" string="检查可用量"
groups="sf_base.group_sf_stock_user"/> groups="sf_base.group_sf_stock_user"/>
</xpath> </xpath>
<xpath expr="//header" position="inside">
<button name="batch_stock_move" type='object' string="批量调拨"/>
</xpath>
</field> </field>
</record> </record>

View File

@@ -133,11 +133,9 @@
type="action" type="action"
context="{'default_name':name, context="{'default_name':name,
'default_current_name':name, 'default_current_name':name,
'default_current_product_sn_ids':product_sn_ids,
'default_lot_id':product_sn_id,
'default_current_shelf_id':shelf_id, 'default_current_shelf_id':shelf_id,
'default_current_location_id':location_id, 'default_current_location_id':location_id,
'default_current_barcode_id':id, 'default_current_barcode':barcode,
'default_current_product_id':product_id, 'default_current_product_id':product_id,
}" }"
class="btn-primary" attrs="{'invisible':[('location_status','!=','占用')]}"/> class="btn-primary" attrs="{'invisible':[('location_status','!=','占用')]}"/>
@@ -171,16 +169,8 @@
<field name="name" readonly="1"/> <field name="name" readonly="1"/>
<field name="shelf_id" readonly="1"/> <field name="shelf_id" readonly="1"/>
<field name="location_id" readonly="1"/> <field name="location_id" readonly="1"/>
<field name="product_sn_id" options="{'no_create': True}"/>
<field name="product_id"/> <field name="product_id"/>
<field name="product_sn_id" options="{'no_create': True}"
attrs="{'invisible': [('product_sn_ids', '!=', [])]}"/>
<field name="product_sn_ids"
attrs="{'invisible': [('product_sn_ids', '=', [])]}">
<tree edit="1" create="0" delete="0" editable="bottom">
<field name="lot_id" readonly="1"/>
<field name="qty" readonly="1"/>
</tree>
</field>
<field name="product_num" readonly="1"/> <field name="product_num" readonly="1"/>
<field name="location_status"/> <field name="location_status"/>
<field name="storage_time" widget="datetime"/> <field name="storage_time" widget="datetime"/>

View File

@@ -8,23 +8,17 @@ class ShelfLocationWizard(models.TransientModel):
name = fields.Char('') name = fields.Char('')
lot_id = fields.Many2one('stock.lot', string="序列号", readonly=True)
current_location_id = fields.Many2one('stock.location', string='所属库区', readonly=True) current_location_id = fields.Many2one('stock.location', string='所属库区', readonly=True)
current_shelf_id = fields.Many2one('sf.shelf', string='当前货架', readonly=True) current_shelf_id = fields.Many2one('sf.shelf', string='当前货架', readonly=True)
current_barcode_id = fields.Many2one('sf.shelf.location', string='当前货位编码', readonly=True) current_barcode = fields.Char('当前货位编码', readonly=True)
current_name = fields.Char('当前货位名称', readonly=True) current_name = fields.Char('当前货位名称', readonly=True)
current_product_id = fields.Many2one('product.product', string='产品', readonly=True) current_product_id = fields.Many2one('product.product', string='产品', readonly=True)
current_product_sn_ids = fields.Many2many('sf.shelf.location.lot', 'shelf_location_wizard', string='产品批次号',
readonly=True)
destination_location_id = fields.Many2one('stock.location', string='目标库区', compute='_compute_destination_name')
destination_shelf_id = fields.Many2one('sf.shelf', string='目标货架', compute='_compute_destination_name') destination_shelf_id = fields.Many2one('sf.shelf', string='目标货架', compute='_compute_destination_name')
destination_barcode_id = fields.Many2one('sf.shelf.location', string='目标货位编码', required=True, destination_barcode_id = fields.Many2one('sf.shelf.location', string='目标货位编码', required=True,
domain="[('product_id', 'in', (False, current_product_id))]") domain="")
destination_name = fields.Char('目标货位名称', compute='_compute_destination_name') destination_name = fields.Char('目标货位名称', compute='_compute_destination_name')
destination_product_sn_ids = fields.Many2many('sf.shelf.location.lot', 'shelf_location_wizard', string='批次号',
domain="[('shelf_location_id', '=', current_barcode_id)]")
def return_domain(self): def return_domain(self):
val = [('location_status', '=', '空闲')] val = [('location_status', '=', '空闲')]
@@ -38,11 +32,9 @@ class ShelfLocationWizard(models.TransientModel):
def _compute_destination_name(self): def _compute_destination_name(self):
if self.destination_barcode_id: if self.destination_barcode_id:
self.destination_name = self.destination_barcode_id.name self.destination_name = self.destination_barcode_id.name
self.destination_location_id = self.destination_barcode_id.location_id.id
self.destination_shelf_id = self.destination_barcode_id.shelf_id.id self.destination_shelf_id = self.destination_barcode_id.shelf_id.id
else: else:
self.destination_name = '' self.destination_name = ''
self.destination_location_id = False
self.destination_shelf_id = False self.destination_shelf_id = False
# #
@@ -51,46 +43,22 @@ class ShelfLocationWizard(models.TransientModel):
# if self.destination_barcode_id: # if self.destination_barcode_id:
# self.destination_shelf_id = self.destination_barcode_id.shelf_id.id # self.destination_shelf_id = self.destination_barcode_id.shelf_id.id
def create_stock_moves(self, lot_id, num):
# 创建产品货位变更的库存移动记录
stock_move_id = self.env['stock.move'].sudo().create({
'name': 'HWBG/%s' % self.id,
'product_id': self.current_product_id.id,
'location_id': self.current_location_id.id,
'location_dest_id': self.destination_location_id.id,
'product_uom_qty': num,
'state': 'done'
})
# 创建移动历史记录
stock_move_line_id = self.env['stock.move.line'].sudo().create({
'product_id': self.current_product_id.id,
'lot_id': lot_id.id,
'move_id': stock_move_id.id,
'current_location_id': self.current_barcode_id.id,
'destination_location_id': self.destination_barcode_id.id,
'install_tool_time': fields.Datetime.now(),
'qty_done': num,
'state': 'done'
})
return stock_move_id, stock_move_line_id
def confirm_the_change(self): def confirm_the_change(self):
if self.destination_barcode_id: shelf_location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.current_barcode)])
if self.lot_id: # 变更货位
self.current_barcode_id.product_sn_id = False if self.destination_barcode_id and shelf_location:
self.destination_barcode_id.product_sn_id = self.lot_id.id if self.destination_barcode_id.product_id and self.destination_barcode_id.product_id == shelf_location.product_id and not self.destination_barcode_id.product_sn_id:
self.create_stock_moves(self.lot_id, 1) self.destination_barcode_id.product_num += shelf_location.product_num
elif self.current_product_sn_ids:
for current_product_sn_id in self.current_product_sn_ids:
self.create_stock_moves(current_product_sn_id.lot_id, current_product_sn_id.qty_num)
current_product_sn_id.write({
'qty_num': 0
})
else: else:
raise ValidationError('没有需要变更的批次/序列号!') self.destination_barcode_id.product_sn_id = shelf_location.product_sn_id.id
self.destination_barcode_id.product_id = shelf_location.product_id.id
self.destination_barcode_id.product_num = shelf_location.product_num
shelf_location.product_sn_id = False
shelf_location.product_id = False
shelf_location.product_num = 0
else: else:
raise ValidationError('请选择目标货位编码!') raise ValidationError('目标货位出错,请联系管理员!')
# 关闭弹出窗口 # 关闭弹出窗口
return {'type': 'ir.actions.act_window_close'} return {'type': 'ir.actions.act_window_close'}

View File

@@ -6,46 +6,28 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="货位变更"> <form string="货位变更">
<sheet> <sheet>
<group col="1"> <group>
<group string="初始货位"> <group string="初始货位">
<group> <group>
<field name="current_location_id"/> <field name="current_location_id"/>
<field name="current_shelf_id" string="货架"/> <field name="current_shelf_id" string="货架"/>
<field name="current_barcode" string="编码"/>
<field name="current_name" string="名称"/> <field name="current_name" string="名称"/>
</group> </group>
<group>
<field name="current_barcode_id" string="编码"/>
<field name="lot_id" attrs="{'invisible': [('lot_id', '=', False)]}"/>
</group>
<field name="current_product_sn_ids"
attrs="{'invisible': [('current_product_sn_ids', '=', [])]}">
<tree edit="1" create="0" delete="0" editable="bottom">
<field name="lot_id" readonly="1"/>
<field name="qty" readonly="1"/>
</tree>
</field>
</group> </group>
<group string="目标货位"> <group string="目标货位">
<group> <group>
<field name="destination_location_id"/> <field name="current_location_id"/>
<field name="destination_shelf_id" string="货架" options="{'no_create': True}"/> <field name="destination_shelf_id" string="货架" options="{'no_create': True}"
placeholder="请选择目标货架"/>
<field name="destination_barcode_id" string="编码" options="{'no_create': True}"
placeholder="请选择目标货位"
domain="['|', ('location_status', '=', '空闲'), ('product_id', '=', current_product_id)]"/>
<field name="destination_name" string="名称"/> <field name="destination_name" string="名称"/>
<field name="current_product_id" invisible="1"/> <field name="current_product_id" invisible="1"/>
</group> </group>
<group>
<field name="destination_barcode_id" string="编码" options="{'no_create': True}"
placeholder="请选择目标货位"/>
<field name="lot_id" attrs="{'invisible': [('lot_id', '=', False)]}"/>
</group> </group>
</group> </group>
<field name="destination_product_sn_ids"
attrs="{'invisible': [('current_product_sn_ids', '=', [])]}">
<tree edit="1" create="0" delete="1" editable="bottom">
<field name="lot_id" readonly="1"/>
<field name="qty_num"/>
</tree>
</field>
</group>
</sheet> </sheet>
<footer> <footer>
<button string="确定" name="confirm_the_change" type="object" class="btn-primary" <button string="确定" name="confirm_the_change" type="object" class="btn-primary"