Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/新增工件装夹

This commit is contained in:
jinling.yang
2023-07-06 17:33:47 +08:00
33 changed files with 1133 additions and 301 deletions

View File

@@ -156,30 +156,30 @@ if env.user.has_group('mrp.group_mrp_workorder_dependencies'):
</field>
</record>
<record model="ir.actions.act_window" id="mrp_workorder_action_tablet">
<field name="name">Work Orders</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">mrp.workorder</field>
<field name="view_mode">kanban,tree,form</field>
<field name="view_ids" eval="[(5, 0, 0),
(0, 0, {'view_mode': 'kanban', 'view_id': ref('mrp.workcenter_line_kanban')}),
(0, 0, {'view_mode': 'tree', 'view_id': ref('mrp.mrp_production_workorder_tree_editable_view')}) ]"/>
<field name="target">fullscreen</field>
<field name="domain">[('state', 'not in', ['done', 'cancel'])]</field>
<field name="context">{'search_default_workcenter_id': active_id}</field>
<field name="help" type="html">
<p class="o_view_nocontent_workorder">
No work orders to do!
</p><p>
Work orders are operations to do as part of a manufacturing order.
Operations are defined in the bill of materials or added in the manufacturing order directly.
</p><p>
Use the table work center control panel to register operations in the shop floor directly.
The tablet provides worksheets for your workers and allow them to scrap products, track time,
launch a maintenance request, perform quality tests, etc.
</p>
</field>
</record>
<!-- <record model="ir.actions.act_window" id="mrp_workorder_action_tablet">-->
<!-- <field name="name">Work Orders</field>-->
<!-- <field name="type">ir.actions.act_window</field>-->
<!-- <field name="res_model">mrp.workorder</field>-->
<!-- <field name="view_mode">kanban,tree,form</field>-->
<!-- <field name="view_ids" eval="[(5, 0, 0),-->
<!-- (0, 0, {'view_mode': 'kanban', 'view_id': ref('mrp.workcenter_line_kanban')}),-->
<!-- (0, 0, {'view_mode': 'tree', 'view_id': ref('mrp.mrp_production_workorder_tree_editable_view')}) ]"/>-->
<!-- <field name="target">fullscreen</field>-->
<!-- <field name="domain">[('state', 'not in', ['done', 'cancel'])]</field>-->
<!-- <field name="context">{'search_default_workcenter_id': active_id}</field>-->
<!-- <field name="help" type="html">-->
<!-- <p class="o_view_nocontent_workorder">-->
<!-- No work orders to do!-->
<!-- </p><p>-->
<!-- Work orders are operations to do as part of a manufacturing order.-->
<!-- Operations are defined in the bill of materials or added in the manufacturing order directly.-->
<!-- </p><p>-->
<!-- Use the table work center control panel to register operations in the shop floor directly.-->
<!-- The tablet provides worksheets for your workers and allow them to scrap products, track time,-->
<!-- launch a maintenance request, perform quality tests, etc.-->
<!-- </p>-->
<!-- </field>-->
<!-- </record>-->
<!-- override to change the no content image -->
<record model="ir.actions.act_window" id="mrp.mrp_workorder_todo">

View File

@@ -5,50 +5,40 @@ class Assemble(models.Model):
_name = 'sf.assemble'
_description = "组合装夹"
functional_fixture_code = fields.Char(string="功能夹具编码", size=25, required=True)
functional_fixture_name = fields.Char(string="功能夹具名称", size=25, required=True)
functional_fixture_type = fields.Char(string="功能夹具类型", required=True)
chuck_name = fields.Char(string="卡盘名称", required=True)
chuck_brand_id = fields.Many2one('sf.machine.brand', string="卡盘品牌", required=True)
chuck_type_id = fields.Char(string="卡盘类型", required=True)
chuck_model_id = fields.Char(string="卡盘型号", required=True)
tray_name = fields.Char(string="托盘名称", required=True)
tray_brand_id = fields.Many2one('sf.machine.brand', string="托盘品牌", required=True)
tray_type_id = fields.Char(string="托盘类型", required=True)
tray_model_id = fields.Char(string="托盘型号", required=True)
real_code = fields.Char(string="真实坯料编码", size=25, required=True)
real_name = fields.Char(string="真实坯料名称", size=25, required=True)
total_wight = fields.Float(string="总重量", required=True)
functional_fixture_code = fields.Char(string="功能夹具编码", readonly=True)
name = fields.Char(string="功能夹具名称", readonly=True)
functional_fixture_type_id = fields.Many2one('sf.functional.fixture.type', string="功能夹具类型", readonly=True)
chuck_name = fields.Char(string="卡盘名称")
chuck_brand_id = fields.Many2one('sf.machine.brand', string="卡盘品牌")
chuck_type_id = fields.Char(string="卡盘类型")
chuck_model_id = fields.Char(string="卡盘型号")
tray_name = fields.Char(string="托盘名称")
tray_brand_id = fields.Many2one('sf.machine.brand', string="托盘品牌")
tray_type_id = fields.Char(string="托盘类型")
tray_model_id = fields.Char(string="托盘型号")
real_code = fields.Char(string="真实坯料编码")
real_name = fields.Char(string="真实坯料名称")
real_width = fields.Float(string="真实宽度")
real_length = fields.Float(string="真实长度")
real_height = fields.Float(string="真实高度")
real_diameter = fields.Float(string="真实直径")
total_wight = fields.Float(string="总重量")
maximum_carrying_weight = fields.Char(string="最大承载重量[kg]")
maximum_clamping_force = fields.Char(string="最大夹持力[n]")
production_line = fields.Char(string="生产线", required=True)
production_line = fields.Char(string="生产线")
# 以下为智能工厂工单带过来的机床信息
machine_tool = fields.Many2one('sf.machine_tool', string="机床名称", required=True)
machine_tool_startime = fields.Date(string="机床开始加工时间", required=True)
machine_tool = fields.Many2one('sf.machine_tool', string="机床名称")
machine_tool_startime = fields.Date(string="机床开始加工时间")
# 以下为智能工厂工单带过来的信息
apply_staff = fields.Char(string="申请人", required=True)
machine_tool_code = fields.Char(string="机床编码", required=True)
apply_time = fields.Date(string="申请时间", required=True)
apply_reason = fields.Char(string="申请原因", required=True)
apply_staff = fields.Char(string="申请人")
machine_tool_code = fields.Char(string="机床编码")
apply_time = fields.Date(string="申请时间")
apply_reason = fields.Char(string="申请原因")
# 以下为装夹的信息
preset_staff = fields.Char(string="预调名称", required=True)
preset_time = fields.Date(string="预调时间", required=True)
material_taker = fields.Char(string="领料人", required=True)
material_removal_time = fields.Date(string="领料出库时间", required=True)
remark = fields.Char(string="备注", required=True)
preset_staff = fields.Char(string="预调名称")
preset_time = fields.Date(string="预调时间")
material_taker = fields.Char(string="领料人")
material_removal_time = fields.Date(string="领料出库时间")
remark = fields.Char(string="备注")
# 以下为出库的信息
stock_removal_code = fields.Char(string="出库人")

View File

@@ -10,8 +10,8 @@
<search string="工件夹具">
<field name="functional_fixture_code" string="编码"
filter_domain="[('functional_fixture_code', 'ilike', self)]"/>
<field name="functional_fixture_name" string="名称"
filter_domain="[('functional_fixture_name', 'ilike', self)]"/>
<field name="name" string="名称"
filter_domain="[('name', 'ilike', self)]"/>
<!-- <field name="material_id" string="材质"-->
<!-- filter_domain="[('material_id.name', 'ilike', self)]"/>-->
</search>
@@ -24,8 +24,8 @@
<field name="arch" type="xml">
<tree string="工件夹具">
<field name="functional_fixture_code"/>
<field name="functional_fixture_name"/>
<field name="functional_fixture_type"/>
<field name="name"/>
<field name="functional_fixture_type_id"/>
<field name="chuck_type_id"/>
<field name="chuck_name"/>
<field name="chuck_brand_id"/>
@@ -65,87 +65,57 @@
<group string="基本信息">
<group>
<field name="functional_fixture_code"/>
</group>
<group>
<field name="functional_fixture_type"/>
</group>
</group>
<!-- <group string="坯料(工件)申请信息">-->
<!-- <group>-->
<!-- <field name="functional_fixture_code"/>-->
<!-- <field name="functional_fixture_type"/>-->
<!--&lt;!&ndash; <field name="surface_accuracy"/>&ndash;&gt;-->
<!-- </group>-->
<!-- <group>-->
<!-- <field name="functional_fixture_name"/>-->
<!-- <label for="apply_length" string="尺寸[mm]"-->
<!-- />-->
<!-- <div class="o_address_format"-->
<!-- >-->
<!-- <label for="apply_length" string="长"/>-->
<!-- <field name="apply_length" class="o_address_zip"-->
<!-- options="{'format': false}"-->
<!-- />-->
<!-- <span>&amp;nbsp;</span>-->
<!-- <label for="apply_width" string="宽"/>-->
<!-- <field name="apply_width" class="o_address_zip"-->
<!-- options="{'format': false}"-->
<!-- />-->
<!-- <span>&amp;nbsp;</span>-->
<!-- <label for="apply_height" string="高"/>-->
<!-- <field name="apply_height" class="o_address_zip"-->
<!-- options="{'format': false}"-->
<!-- />-->
<!-- </div>-->
<!-- <field name="apply_weight"/>-->
<!-- <field name="apply_diameter"/>-->
<!-- </group>-->
<!-- </group>-->
<group string="坯料(工件)装夹信息">
<group string="卡盘">
<field name="chuck_name"/>
<field name="chuck_brand_id"/>
<field name="chuck_type_id"/>
<field name="chuck_model_id"/>
</group>
<group string="托盘">
<field name="tray_name"/>
<field name="tray_brand_id"/>
<field name="tray_type_id"/>
<field name="tray_model_id"/>
</group>
<group>
<field name="real_code"/>
<field name="real_name"/>
<!-- <label for="real_length" string="尺寸[mm]"-->
<!-- />-->
<!-- <div class="o_address_format"-->
<!-- >-->
<!-- <label for="real_length" string="长"/>-->
<!-- <field name="real_length" class="o_address_zip"-->
<!-- options="{'format': false}"-->
<!-- />-->
<!-- <span>&amp;nbsp;</span>-->
<!-- <label for="real_width" string="宽"/>-->
<!-- <field name="real_width" class="o_address_zip"-->
<!-- options="{'format': false}"-->
<!-- />-->
<!-- <span>&amp;nbsp;</span>-->
<!-- <label for="real_height" string="高"/>-->
<!-- <field name="real_height" class="o_address_zip"-->
<!-- options="{'format': false}"-->
<!-- />-->
<!-- </div>-->
<!-- <field name="real_diameter"/>-->
</group>
</group>
<group string="其他">
<group>
<field name="functional_fixture_type_id"/>
<field name="remark"/>
</group>
<group>
<field name="name"/>
</group>
</group>
<notebook>
<page string="装夹" name="clamping" attrs="{'invisible': [('chuck_type_id', '=', False)]}">
<group>
<group string="卡盘">
<field name="chuck_type_id"></field>
<field name="chuck_name"></field>
<field name="chuck_brand_id"></field>
<field name="chuck_model_id"></field>
</group>
<group string="托盘">
<field name="tray_type_id"></field>
<field name="tray_name"></field>
<field name="tray_brand_id"></field>
<field name="tray_model_id"></field>
</group>
<group string="坯料">
<field name="real_code" string="坯料编码"></field>
<field name="real_name" string="坯料名称"></field>
<label for="real_length" string="尺寸[mm]"/>
<div class="o_address_format">
<label for="real_length" string="长"/>
<field name="real_length" class="o_address_zip"
options="{'format': false}"/>
<span>&amp;nbsp;</span>
<label for="real_width" string="宽"/>
<field name="real_width" class="o_address_zip"
options="{'format': false}"/>
<span>&amp;nbsp;</span>
<label for="real_height" string="高"/>
<field name="real_height" class="o_address_zip"
options="{'format': false}"/>
</div>
<field name="real_diameter" string="直径[mm]"></field>
</group>
</group>
</page>
<page string="出库" name="stock_removal"
attrs="{'invisible': [('production_line', '=', False)]}">
<group>
<field name="production_line"></field>
<field name="machine_tool" string="机台"></field>
</group>
</page>
</notebook>
</sheet>
</form>
</field>

View File

@@ -4,22 +4,24 @@
<field name="name">sf.stock.removal.wizard.form.view</field>
<field name="model">sf.stock.removal.wizard</field>
<field name="arch" type="xml">
<form string="出库">
<group>
<form string="装夹">
<sheet>
<group>
<field name="code" string="编码"></field>
<field name="type" string="类型"></field>
<field name="machine_tool" string="类型"></field>
<group>
<field name="code" string="功能夹具编码"></field>
<field name="type" string="类型"></field>
<field name="machine_tool" string="机台"></field>
</group>
<group>
<field name="name" string="功能夹具名称"></field>
<field name="production_line"></field>
</group>
</group>
<group>
<field name="name" string="名称"></field>
<field name="production_line" string="类型"></field>
</group>
</group>
<footer>
<button string="确定" name="submit" type="object" class="oe_highlight"/>
<button string="取消" class="btn btn-secondary" special="cancel"/>
</footer>
<footer>
<button string="确定" name="submit" type="object" class="oe_highlight"/>
<button string="取消" class="btn btn-secondary" special="cancel"/>
</footer>
</sheet>
</form>
</field>
</record>

View File

@@ -5,70 +5,74 @@
<field name="model">sf.workpiece.clamping.wizard</field>
<field name="arch" type="xml">
<form string="装夹">
<group string="坯料(工件)申请信息">
<group>
<field name="apply_code" string="编码"></field>
<field name="material_id" string="材质"></field>
<sheet>
<group string="坯料(工件)申请信息">
<group>
<field name="apply_code" string="坯料编码"></field>
<field name="material_id" string="坯料材质"></field>
</group>
<group>
<field name="apply_name" string="坯料名称"></field>
<label for="apply_length" string="尺寸[mm]"/>
<div class="o_address_format">
<label for="apply_length" string="长"/>
<field name="apply_length" class="o_address_zip"
options="{'format': false}"/>
<span>&amp;nbsp;</span>
<label for="apply_width" string="宽"/>
<field name="apply_width" class="o_address_zip"
options="{'format': false}"/>
<span>&amp;nbsp;</span>
<label for="apply_height" string="高"/>
<field name="apply_height" class="o_address_zip"
options="{'format': false}"/>
</div>
<field name="apply_diameter" string="直径[mm]"></field>
</group>
</group>
<group string="坯料(工件)装夹信息">
<group string="卡盘">
<field name="chuck_type_id"></field>
<field name="chuck_name"></field>
<field name="chuck_brand_id"></field>
<field name="chuck_model_id"></field>
</group>
<group string="托盘">
<field name="tray_type_id"></field>
<field name="tray_name"></field>
<field name="tray_brand_id"></field>
<field name="tray_model_id"></field>
</group>
<group string="坯料">
<field name="real_code" string="坯料编码"></field>
<field name="real_name" string="坯料名称"></field>
<label for="real_length" string="尺寸[mm]"/>
<div class="o_address_format">
<label for="real_length" string="长"/>
<field name="real_length" class="o_address_zip"
options="{'format': false}"/>
<span>&amp;nbsp;</span>
<label for="real_width" string="宽"/>
<field name="real_width" class="o_address_zip"
options="{'format': false}"/>
<span>&amp;nbsp;</span>
<label for="real_height" string="高"/>
<field name="real_height" class="o_address_zip"
options="{'format': false}"/>
</div>
<field name="real_diameter" string="直径[mm]"></field>
</group>
</group>
<group>
<field name="apply_name" string="名称"></field>
<label for="apply_length" string="尺寸[mm]"/>
<div class="o_address_format">
<label for="apply_length" string="长"/>
<field name="apply_length" class="o_address_zip"
options="{'format': false}"/>
<span>&amp;nbsp;</span>
<label for="apply_width" string="宽"/>
<field name="apply_width" class="o_address_zip"
options="{'format': false}"/>
<span>&amp;nbsp;</span>
<label for="apply_height" string="高"/>
<field name="apply_height" class="o_address_zip"
options="{'format': false}"/>
</div>
<field name="apply_diameter" string="直径"></field>
<group>
<field name="preset_program_information"></field>
</group>
</group>
</group>
<group string="坯料(工件)装夹信息">
<group string="卡盘">
<field name="chuck_type_id"></field>
<field name="chuck_name"></field>
<field name="chuck_brand_id"></field>
<field name="chuck_model_id"></field>
</group>
<group string="托盘">
<field name="tray_type_id"></field>
<field name="tray_name"></field>
<field name="tray_brand_id"></field>
<field name="tray_model_id"></field>
</group>
<group string="坯料">
<field name="real_code"></field>
<field name="real_name"></field>
<label for="real_length" string="尺寸[mm]"/>
<div class="o_address_format">
<label for="real_length" string="长"/>
<field name="real_length" class="o_address_zip"
options="{'format': false}"/>
<span>&amp;nbsp;</span>
<label for="real_width" string="宽"/>
<field name="real_width" class="o_address_zip"
options="{'format': false}"/>
<span>&amp;nbsp;</span>
<label for="real_height" string="高"/>
<field name="real_height" class="o_address_zip"
options="{'format': false}"/>
</div>
<field name="real_diameter" string="直径"></field>
</group>
<group>
<field name="preset_program_information"></field>
</group>
</group>
<footer>
<button string="确定" name="submit" type="object" class="oe_highlight"/>
<button string="取消" class="btn btn-secondary" special="cancel"/>
</footer>
<footer>
<button string="确定" name="submit" type="object" class="oe_highlight"/>
<button string="取消" class="btn btn-secondary" special="cancel"/>
</footer>
</sheet>
</form>
</field>
</record>

View File

@@ -33,8 +33,8 @@ class StatusChange(models.Model):
'process_start_time': process_start_time,
},
}
url1 = config['bfm_url'] + '/api/get/state/get_order'
requests.post(url1, json=json1, data=None)
# url1 = config['bfm_url'] + '/api/get/state/get_order'
# requests.post(url1, json=json1, data=None)
logging.info('接口已经执行=============')
return res
@@ -57,8 +57,8 @@ class StatusChange(models.Model):
'state': '待派单',
},
}
url1 = config['bfm_url'] + '/api/get/state/cancel_order'
requests.post(url1, json=json1, data=None)
# url1 = config['bfm_url'] + '/api/get/state/cancel_order'
# requests.post(url1, json=json1, data=None)
return res

View File

@@ -24,8 +24,7 @@ class SfEquipmentSaintenanceStandards(models.Model):
created_user_id = fields.Many2one('res.users', string='创建人', default=lambda self: self.env.user)
maintenance_equipment_category_id = fields.Many2one('maintenance.equipment.category', string='设备类别')
maintenance_equipment_ids = fields.Many2many('maintenance.equipment', 'sf_maintenance_equipment_ids', string='设备')
maintenance_projects = fields.Char('维保项目')
maintenance_standards = fields.Char('维保标准')
maintenance_standards_ids = fields.One2many('maintenance.standards', 'equipment_maintenance_standards_id', string='维保项目')
eq_maintenance_ids = fields.One2many('maintenance.equipment', 'eq_maintenance_id', string='保养设备')
overhaul_ids = fields.One2many('maintenance.equipment', 'overhaul_id', string='检修设备')
@@ -37,7 +36,14 @@ class SfEquipmentSaintenanceStandards(models.Model):
if record.maintenance_type == '检修':
record.write({'overhaul_ids': [(6, 0, record.maintenance_equipment_ids.ids)]})
class SfSaintenanceStandards(models.Model):
_name = 'maintenance.standards'
_description = '维保项目'
name = fields.Char('维保项目')
maintenance_standards = fields.Char('维保标准')
equipment_maintenance_standards_id = fields.Many2one('equipment.maintenance.standards', string='设备维保标准')
maintenance_request_id = fields.Many2one('maintenance.request', string='设备维保计划')

View File

@@ -4,10 +4,12 @@ import base64
from odoo import api, fields, models, SUPERUSER_ID, _
from odoo.exceptions import UserError
import logging
from datetime import date, datetime, timedelta
import requests
import json
from odoo.addons.sf_base.commons.common import Common
class SfMaintenanceEquipmentCategory(models.Model):
_inherit = 'maintenance.equipment.category'
_description = '设备类别'
@@ -20,6 +22,7 @@ class SfMaintenanceEquipment(models.Model):
_description = '设备'
crea_url = "/api/machine_tool/create"
def get_no(self):
partner = self.env['maintenance.equipment'].sudo().search(
[('MTcode', '!=', '')],
@@ -33,19 +36,23 @@ class SfMaintenanceEquipment(models.Model):
num = "%04d" % m
return num
equipment_maintenance_standards_ids = fields.Many2many('equipment.maintenance.standards', 'sf_maintenance_equipment_ids', string='设备维保标准')
eq_maintenance_id =fields.Many2one('equipment.maintenance.standards', string='设备保标准', domain="[('maintenance_type','=','保养')]")
equipment_maintenance_standards_ids = fields.Many2many('equipment.maintenance.standards',
'sf_maintenance_equipment_ids', string='设备保标准')
eq_maintenance_id = fields.Many2one('equipment.maintenance.standards', string='设备保养标准',
domain="[('maintenance_type','=','保养')]")
overhaul_date = fields.Date(string='下次预防检修')
overhaul_period = fields.Integer(string='预防检修频次')
overhaul_duration = fields.Float(string='检修时长')
overhaul_id = fields.Many2one('equipment.maintenance.standards', string='设备检修标准', domain="[('maintenance_type','=','检修')]")
overhaul_id = fields.Many2one('equipment.maintenance.standards', string='设备检修标准',
domain="[('maintenance_type','=','检修')]")
@api.onchange('eq_maintenance_id', 'overhaul_id')
def _compute_equipment_maintenance_standards_ids(self):
for record in self:
if record.eq_maintenance_id and record.overhaul_id:
record.equipment_maintenance_standards_ids = [(6, 0, [record.eq_maintenance_id.id, record.overhaul_id.id])]
record.equipment_maintenance_standards_ids = [
(6, 0, [record.eq_maintenance_id.id, record.overhaul_id.id])]
break
if record.eq_maintenance_id:
record.equipment_maintenance_standards_ids = [(6, 0, [record.eq_maintenance_id.id])]
@@ -56,12 +63,10 @@ class SfMaintenanceEquipment(models.Model):
else:
record.equipment_maintenance_standards_ids = False
MTcode = fields.Char("编码", default=get_no)
created_user = fields.Many2one('res.users', string='创建人', default=lambda self: self.env.user)
equipment_type = fields.Selection([('机床', '机床')], related='category_id.equipment_type')
code = fields.Char('行业编码')
code = fields.Char('机台号')
name = fields.Char('名称')
knife_type = fields.Selection(
[("BT40", "BT40"), ("BT30", "BT30")],
@@ -139,7 +144,16 @@ class SfMaintenanceEquipment(models.Model):
control_system_id = fields.Many2one('sf.machine.control_system',
string="控制系统")
active = fields.Boolean('有效', default=True)
code = fields.Char('编码')
def name_get(self):
result = []
for parameter in self:
if parameter.code:
name = parameter.name + '-' + parameter.code
else:
name = parameter.name
result.append((parameter.id, name))
return result
@api.constrains('rotate_speed')
def _check_rotate_speed(self):
@@ -279,7 +293,6 @@ class SfMaintenanceEquipment(models.Model):
'tool_diameter_max': item.tool_diameter_max,
'machine_tool_category': item.machine_tool_category.code,
}
machine_tool_list.append(val)
# kw = machine_tool_list
@@ -293,4 +306,168 @@ class SfMaintenanceEquipment(models.Model):
else:
raise UserError("没有注册机床信息")
# 修改原生方法,生成维保日期
@api.depends('effective_date', 'period', 'maintenance_ids.request_date', 'maintenance_ids.close_date',
'overhaul_period')
def _compute_next_maintenance(self):
date_now = fields.Date.context_today(self)
equipments = self.filtered(lambda x: x.period > 0)
if equipments:
for equipment in equipments:
next_maintenance_todo = self.env['maintenance.request'].search([
('equipment_id', '=', equipment.id),
('sf_maintenance_type', '=', '保养'),
('stage_id.done', '!=', True),
('close_date', '=', False)], order="request_date asc", limit=1)
last_maintenance_done = self.env['maintenance.request'].search([
('equipment_id', '=', equipment.id),
('sf_maintenance_type', '=', '保养'),
('stage_id.done', '=', True),
('close_date', '!=', False)], order="close_date desc", limit=1)
if next_maintenance_todo and last_maintenance_done:
next_date = next_maintenance_todo.request_date
date_gap = next_maintenance_todo.request_date - last_maintenance_done.close_date
# If the gap between the last_maintenance_done and the next_maintenance_todo one is bigger than 2 times the period and next request is in the future
# We use 2 times the period to avoid creation too closed request from a manually one created
if date_gap > timedelta(0) and date_gap > timedelta(
days=equipment.period) * 2 and next_maintenance_todo.request_date > date_now:
# If the new date still in the past, we set it for today
if last_maintenance_done.close_date + timedelta(days=equipment.period) < date_now:
next_date = date_now
else:
next_date = last_maintenance_done.close_date + timedelta(days=equipment.period)
elif next_maintenance_todo:
next_date = next_maintenance_todo.request_date
date_gap = next_maintenance_todo.request_date - date_now
# If next maintenance to do is in the future, and in more than 2 times the period, we insert an new request
# We use 2 times the period to avoid creation too closed request from a manually one created
if date_gap > timedelta(0) and date_gap > timedelta(days=equipment.period) * 2:
next_date = date_now + timedelta(days=equipment.period)
elif last_maintenance_done:
next_date = last_maintenance_done.close_date + timedelta(days=equipment.period)
# If when we add the period to the last maintenance done and we still in past, we plan it for today
if next_date < date_now:
next_date = date_now
else:
next_date = equipment.effective_date + timedelta(days=equipment.period)
equipment.next_action_date = next_date
else:
self.next_action_date = False
overhaul_equipments = self.filtered(lambda x: x.overhaul_period > 0)
if overhaul_equipments:
for equipment in overhaul_equipments:
next_maintenance_todo = self.env['maintenance.request'].search([
('equipment_id', '=', equipment.id),
('sf_maintenance_type', '=', '检修'),
('stage_id.done', '!=', True),
('close_date', '=', False)], order="request_date asc", limit=1)
last_maintenance_done = self.env['maintenance.request'].search([
('equipment_id', '=', equipment.id),
('sf_maintenance_type', '=', '检修'),
('stage_id.done', '=', True),
('close_date', '!=', False)], order="close_date desc", limit=1)
if next_maintenance_todo and last_maintenance_done:
next_date = next_maintenance_todo.request_date
date_gap = next_maintenance_todo.request_date - last_maintenance_done.close_date
# If the gap between the last_maintenance_done and the next_maintenance_todo one is bigger than 2 times the period and next request is in the future
# We use 2 times the period to avoid creation too closed request from a manually one created
if date_gap > timedelta(0) and date_gap > timedelta(
days=equipment.overhaul_period) * 2 and next_maintenance_todo.request_date > date_now:
# If the new date still in the past, we set it for today
if last_maintenance_done.close_date + timedelta(days=equipment.overhaul_period) < date_now:
next_date = date_now
else:
next_date = last_maintenance_done.close_date + timedelta(days=equipment.overhaul_period)
elif next_maintenance_todo:
next_date = next_maintenance_todo.request_date
date_gap = next_maintenance_todo.request_date - date_now
# If next maintenance to do is in the future, and in more than 2 times the period, we insert an new request
# We use 2 times the period to avoid creation too closed request from a manually one created
if date_gap > timedelta(0) and date_gap > timedelta(days=equipment.overhaul_period) * 2:
next_date = date_now + timedelta(days=equipment.overhaul_period)
elif last_maintenance_done:
next_date = last_maintenance_done.close_date + timedelta(days=equipment.overhaul_period)
# If when we add the period to the last maintenance done and we still in past, we plan it for today
if next_date < date_now:
next_date = date_now
else:
next_date = equipment.effective_date + timedelta(days=equipment.overhaul_period)
equipment.overhaul_date = next_date
else:
self.overhaul_date = False
# 拼接维保请求字符串
def _prepare_maintenance_request_vals(self, date):
self.ensure_one()
return {
'name': _('Preventive Maintenance - %s', self.name),
'request_date': date,
'schedule_date': date,
'category_id': self.category_id.id,
'equipment_id': self.id,
'maintenance_type': 'preventive',
'owner_user_id': self.owner_user_id.id,
'user_id': self.technician_user_id.id,
'maintenance_team_id': self.maintenance_team_id.id,
'duration': self.maintenance_duration,
'company_id': self.company_id.id or self.env.company.id,
'equipment_maintenance_id': self.eq_maintenance_id.id,
'sf_maintenance_type': '保养'
}
# 拼接维保请求字符串
def _prepare_maintenance_request_vals1(self, date):
self.ensure_one()
return {
'name': _('Preventive Maintenance - %s', self.name),
'request_date': date,
'schedule_date': date,
'category_id': self.category_id.id,
'equipment_id': self.id,
'maintenance_type': 'preventive',
'owner_user_id': self.owner_user_id.id,
'user_id': self.technician_user_id.id,
'maintenance_team_id': self.maintenance_team_id.id,
'duration': self.overhaul_duration,
'company_id': self.company_id.id or self.env.company.id,
'equipment_maintenance_id': self.overhaul_id.id,
'sf_maintenance_type': '检修'
}
# 创建维保请求
def _create_new_request(self, date):
self.ensure_one()
vals = self._prepare_maintenance_request_vals(date)
maintenance_requests = self.env['maintenance.request'].create(vals)
return maintenance_requests
def _create_new_request1(self, date):
self.ensure_one()
vals = self._prepare_maintenance_request_vals1(date)
maintenance_requests = self.env['maintenance.request'].create(vals)
return maintenance_requests
# 生成维保请求定时器
@api.model
def _cron_generate_requests(self):
"""
Generates maintenance request on the next_action_date or today if none exists
"""
for equipment in self.search([('period', '>', 0)]):
next_requests = self.env['maintenance.request'].search([('stage_id.done', '=', False),
('equipment_id', '=', equipment.id),
('maintenance_type', '=', 'preventive'),
('request_date', '=', equipment.next_action_date),
('sf_maintenance_type', '=', '保养')])
if not next_requests:
equipment._create_new_request(equipment.next_action_date)
for equipment in self.search([('overhaul_period', '>', 0)]):
next_requests = self.env['maintenance.request'].search([('stage_id.done', '=', False),
('equipment_id', '=', equipment.id),
('maintenance_type', '=', 'preventive'),
('request_date', '=', equipment.overhaul_date),
('sf_maintenance_type', '=', '检修')])
if not next_requests:
equipment._create_new_request1(equipment.overhaul_date)

View File

@@ -26,8 +26,8 @@ class SfMaintenanceEquipmentCategory(models.Model):
record.equipment_maintenance_id = False
maintenance_projects = fields.Char(string='维保项目', related='equipment_maintenance_id.maintenance_projects')
maintenance_standards = fields.Char(string='维保标准', related='equipment_maintenance_id.maintenance_standards')
maintenance_standards = fields.One2many('maintenance.standards','maintenance_request_id', string='维保标准', related='equipment_maintenance_id.maintenance_standards_ids')
@api.constrains('equipment_maintenance_id')
def _check_equipment_maintenance_id(self):
@@ -35,6 +35,12 @@ class SfMaintenanceEquipmentCategory(models.Model):
if not record.equipment_maintenance_id:
raise UserError(_("设备维保标准不能为空,请选择后再保存"))
def confirm_maintenance(self):
self.write({'stage_id': 2})
def confirm_maintenance_done(self):
self.write({'stage_id': 3})

View File

@@ -2,5 +2,6 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_equipment_maintenance_standards,equipment_maintenance_standards,model_equipment_maintenance_standards,base.group_user,1,1,1,1
access_sf_maintenance_logs,sf_maintenance_logs,model_sf_maintenance_logs,base.group_user,1,1,1,1
access_maintenance_equipment,maintenance_equipment,model_maintenance_equipment,base.group_user,1,1,1,1
access_maintenance_standards,maintenance_standards,model_maintenance_standards,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_equipment_maintenance_standards equipment_maintenance_standards model_equipment_maintenance_standards base.group_user 1 1 1 1
3 access_sf_maintenance_logs sf_maintenance_logs model_sf_maintenance_logs base.group_user 1 1 1 1
4 access_maintenance_equipment maintenance_equipment model_maintenance_equipment base.group_user 1 1 1 1
5 access_maintenance_standards maintenance_standards model_maintenance_standards base.group_user 1 1 1 1
6
7

View File

@@ -2,31 +2,42 @@
<odoo>
<record id="view_equipment_maintenance_standards_form" model="ir.ui.view">
<field name="name">equipment.maintenance.standards.form</field>
<field name="model">equipment.maintenance.standards</field>
<field name="arch" type="xml">
<form string="设备维保标准">
<sheet>
<group>
<field name="code" readonly="1" force_save="1"/>
<field name="maintenance_type" required="1"/>
<field name="name" required="1"/>
<field name="created_user_id"/>
<field name="maintenance_equipment_category_id" required="1"/>
<field name="maintenance_equipment_ids" widget="many2many_tags"/>
<field name="maintenance_projects" required="1"/>
<field name="maintenance_standards" required="1"/>
<field name="eq_maintenance_ids"/>
<field name="overhaul_ids" />
<record id="view_equipment_maintenance_standards_form" model="ir.ui.view">
<field name="name">equipment.maintenance.standards.form</field>
<field name="model">equipment.maintenance.standards</field>
<field name="arch" type="xml">
<form string="设备维保标准">
<sheet>
<group>
<field name="code" readonly="1" force_save="1"/>
<field name="maintenance_type" required="1"/>
<field name="name" required="1"/>
<field name="eq_maintenance_ids" invisible='1'/>
<field name="overhaul_ids" invisible='1'/>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_equipment_maintenance_standards_tree" model="ir.ui.view">
</group>
<group>
<field name="created_user_id"/>
<field name="maintenance_equipment_category_id" required="1"/>
<field name="maintenance_equipment_ids" widget="many2many_tags"/>
</group>
<notebook>
<page string="维保项目">
<field name="maintenance_standards_ids" widget="ony2many">
<tree editable="top" create="true" string="维保项目">
<field name="name"/>
<field name="maintenance_standards"/>
</tree>
</field>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="view_equipment_maintenance_standards_tree" model="ir.ui.view">
<field name="name">equipment.maintenance.standards.tree</field>
<field name="model">equipment.maintenance.standards</field>
<field name="arch" type="xml">
@@ -36,9 +47,7 @@
<field name="name" required="1"/>
<field name="maintenance_equipment_category_id" required="1"/>
<field name="maintenance_equipment_ids"/>
<field name="maintenance_projects" required="1"/>
<field name="maintenance_standards" required="1"/>
<field name="created_user_id"/>
<field name="created_user_id"/>
<field name="create_date" string="创建时间"/>
</tree>
@@ -50,7 +59,7 @@
<field name="model">equipment.maintenance.standards</field>
<field name="arch" type="xml">
<search>
<searchpanel>
<searchpanel>
<field name="maintenance_type" icon="fa-building" enable_counters="1"/>
</searchpanel>
<field name="code" string="编码"/>
@@ -58,14 +67,11 @@
<field name="name" string="日常机床保养"/>
<field name="created_user_id" string="创建人"/>
<field name="maintenance_equipment_category_id" string="设备类别"/>
<field name="maintenance_projects" string="维保项目"/>
<field name="maintenance_standards" string="维保标准"/>
</search>
</field>
</record>
<record id="action_equipment_maintenance_standards" model="ir.actions.act_window">
<field name="name">设备维保标准</field>
<field name="type">ir.actions.act_window</field>
@@ -79,12 +85,12 @@
</field>
</record>
<menuitem
id="menu_equipment_maintenance_standards"
name="设备维保标准"
parent="maintenance.menu_maintenance_configuration"
action="action_equipment_maintenance_standards"
sequence="4"/>
<menuitem
id="menu_equipment_maintenance_standards"
name="设备维保标准"
parent="maintenance.menu_maintenance_configuration"
action="action_equipment_maintenance_standards"
sequence="4"/>
</odoo>

View File

@@ -7,6 +7,10 @@
<field name="model">maintenance.request</field>
<field name="inherit_id" ref="maintenance.hr_equipment_request_view_form"/>
<field name="arch" type="xml">
<xpath expr="//button[@name='archive_equipment_request']" position="before">
<button name="confirm_maintenance" string="确认维保计划" type="object" class="btn-primary" attrs="{'invisible': [('stage_id', '!=', 1)]}" />
<button name="confirm_maintenance_done" string="标记已完成" type="object" class="btn-primary" attrs="{'invisible': [('stage_id', '!=', 2)]}" />
</xpath>
<xpath expr="//field[@name='maintenance_type']" position="replace">
<field name="sf_maintenance_type" widget="radio"/>
<field name="equipment_maintenance_id"/>
@@ -17,8 +21,12 @@
<notebook>
<page string="维保标准" attrs="{'invisible': [('equipment_maintenance_id', '=', False)]}">
<group>
<field name="maintenance_projects"/>
<field name="maintenance_standards"/>
<field name="maintenance_standards" widget="ony2many">
<tree create="False" string="维保项目">
<field name="name"/>
<field name="maintenance_standards"/>
</tree>
</field>
</group>
</page>

View File

@@ -16,7 +16,7 @@
'security/group_security.xml',
'security/ir.model.access.csv',
'report/tray_report.xml',
'views/mrp_maintenance_views.xml',
# 'views/mrp_maintenance_views.xml',
'views/mrp_routing_workcenter_view.xml',
'views/mrp_workcenter_views.xml',
'views/mrp_workorder_view.xml',

View File

@@ -11,6 +11,8 @@ class MrpProduction(models.Model):
maintenance_count = fields.Integer(compute='_compute_maintenance_count', string="Number of maintenance requests")
request_ids = fields.One2many('maintenance.request', 'production_id')
model_file = fields.Binary('模型文件', related='product_id.model_file')
schedule_state = fields.Selection([('未排', '未排'), ('已排', '已排')],
string='排程状态', default='未排')
@api.depends('request_ids')
def _compute_maintenance_count(self):
@@ -336,7 +338,7 @@ class MrpProduction(models.Model):
current_sequence += 1
if work.name == '获取CNC加工程序':
work.button_start()
work.fetchCNC()
#work.fetchCNC()
# 创建工单并进行排序
def _create_workorder(self):

View File

@@ -28,7 +28,7 @@ class ResMrpWorkOrder(models.Model):
store=True, check_company=True, string="材料")
product_tmpl_id_materials_type_id = fields.Many2one(related='production_id.product_tmpl_id.materials_type_id',
readonly=True, store=True, check_company=True, string="型号")
workcenter_id = fields.Many2one('mrp.workcenter', required=False)
workcenter_id = fields.Many2one('mrp.workcenter', string='工作中心', required=False)
users_ids = fields.Many2many("res.users", 'users_workorder', related="workcenter_id.users_ids")
processing_panel = fields.Char('加工面')
sequence = fields.Integer(string='工序')
@@ -106,6 +106,8 @@ class ResMrpWorkOrder(models.Model):
picking_in_id = fields.Many2one('stock.picking', string='外协入库单')
picking_out_id = fields.Many2one('stock.picking', string='外协出库单')
supplier_id = fields.Many2one('res.partner', string='外协供应商')
equipment_id = fields.Many2one('maintenance.equipment', string='加工设备')
schedule_state = fields.Selection(related='production_id.schedule_state', store=True)
def get_no_data(self, production_id):
process_parameter_workorder = self.search(
@@ -165,7 +167,7 @@ class ResMrpWorkOrder(models.Model):
'operation_id': False,
'name': route.route_workcenter_id.name,
'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,
'work_state': '' if not route.routing_type == '获取CNC加工程序' else '待发起',
'workcenter_id': self.env['mrp.routing.workcenter'].get_workcenter(route.workcenter_ids.ids,

View File

@@ -231,18 +231,8 @@ class ProductionLot(models.Model):
1]
now = datetime.now().strftime("%Y-%m-%d")
# formatted_date = now.strftime("%Y-%m-%d")
if product.integral_cutting_tool_type_id:
return "%s-%s-%03d" % (product.integral_cutting_tool_type_id.code, now, 1)
if product.blade_type_id:
return "%s-%s-%03d" % (product.blade_type_id.code, now, 1)
if product.cutter_bar_type_id:
return "%s-%s-%03d" % (product.cutter_bar_type_id.code, now, 1)
if product.cutter_pad_type_id:
return "%s-%s-%03d" % (product.cutter_pad_type_id.code, now, 1)
if product.handle_type_id:
return "%s-%s-%03d" % (product.handle_type_id.code, now, 1)
if product.chuck_type_id:
return "%s-%s-%03d" % (product.chuck_type_id.code, now, 1)
if product.cutting_tool_model_id:
return "%s-%s-%03d" % (product.cutting_tool_model_id.code, now, 1)
return "%s-%03d" % (product.name, 1)

View File

@@ -7,9 +7,11 @@
<field name="arch" type="xml">
<field name="name" position="replace">
<field name="is_subcontract" invisible="1"/>
<field name="name" decoration-success="is_subcontract" decoration-bf="is_subcontract"/>
</field>
<field name="name" position="before">
<field name="schedule_state"/>
<field name="sequence"/>
<field name='user_permissions' invisible="1"/>
</field>
@@ -19,6 +21,9 @@
<field name="state" position="after">
<field name="work_state" optional="hide"/>
</field>
<field name="product_id" position="after">
<field name="equipment_id" optional="hide"/>
</field>
<xpath expr="//field[@name='date_planned_start']" position="replace">
<field name="date_planned_start" string="计划开始日期" optional="show"/>
</xpath>
@@ -73,7 +78,7 @@
(0, 0, {'view_mode': 'kanban', 'view_id': ref('mrp.workcenter_line_kanban')}) ]"/>
<!-- <field name="target">fullscreen</field>-->
<field name="target">current</field>
<field name="domain">[('state', '!=', 'cancel')]</field>
<field name="domain">[('state', '!=', 'cancel'),('schedule_state', '=', '已排')]</field>
<field name="context">{'search_default_workcenter_id': active_id}</field>
<field name="help" type="html">
<p class="o_view_nocontent_workorder">
@@ -91,6 +96,28 @@
</field>
</record>
<record model="ir.actions.act_window" id="mrp_workorder_action_scheduled">
<field name="name">工单</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">mrp.workorder</field>
<field name="view_mode">tree,kanban,form</field>
<field name="view_id" ref="view_mrp_production_workorder_tree_editable_inherit_sf"/>
<!-- <field name="view_ids" eval="[(5, 0, 0),-->
<!-- (0, 0, {'view_mode': 'tree', 'view_id': ref('mrp.mrp_production_workorder_tree_view')}),-->
<!-- (0, 0, {'view_mode': 'kanban', 'view_id': ref('mrp.workcenter_line_kanban')}) ]"/>-->
<!-- <field name="target">fullscreen</field>-->
<!-- <field name="search_view_id" ref="mrp.view_mrp_production_workorder_form_view_filter"/>-->
<!-- <field name="domain">[('state', '!=', 'cancel'),('schedule_state', '=', '已排')]</field>-->
<!-- <field name="context">{'search_default_workcenter_id': active_id}</field>-->
<field name="help" type="html">
<p class="o_view_nocontent_workorder">
没有已排程的工单!
</p>
</field>
</record>
<!-- <record model="ir.ui.view" id="view_mrp_production_workorder_form_inherit_sf">-->
<!-- <field name="name">mrp.production.workorder.form.inherit.sf</field>-->
<!-- <field name="model">mrp.workorder</field>-->
@@ -126,9 +153,9 @@
attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '!=', 'blocked'),('name','=','获取CNC加工程序')]}"/>
</xpath>
<!-- 隐藏物料清单-->
<!-- <xpath expr="//page[@name='components']" position="attributes">-->
<!-- <attribute name="invisible">1</attribute>-->
<!-- </xpath>-->
<!-- <xpath expr="//page[@name='components']" position="attributes">-->
<!-- <attribute name="invisible">1</attribute>-->
<!-- </xpath>-->
<!-- 隐藏物料清单-->
<field name="production_id" position="after" invisible="0">
@@ -141,6 +168,9 @@
sum="real duration"/>
<field name="processing_panel" readonly="1"
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
<field name="equipment_id"
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
</group>
<group attrs='{"invisible": [("routing_type","=","获取CNC加工程序")]}'>
<div>
@@ -165,7 +195,7 @@
<group>
<div class="col-12 col-lg-6 o_setting_box" style="white-space: nowrap">
<button type="object" class="oe_highlight" name="fetchCNC" string="获取CNC程序代码"
/>
/>
</div>
</group>

View File

@@ -787,6 +787,10 @@ class MachineToolType(models.Model):
result = json.loads(r['result'])
if result['status'] == 1:
for item in result['machine_tool_type_all_list']:
if item.get('machine_tool_picture'):
image = base64.b64decode(item['machine_tool_picture'])
else:
image = ''
brand = self.env['sf.machine_tool.type'].search(
[("code", '=', item['code'])])
if not brand:
@@ -811,7 +815,7 @@ class MachineToolType(models.Model):
[('code', '=', item['control_system_id'])]).id,
"active": item['active'],
'brand_id': self.env['sf.machine.brand'].search([('code', '=', item['brand_id'])]).id,
'machine_tool_picture': base64.b64decode(item['machine_tool_picture']),
'machine_tool_picture':image,
"heightened_way": item['heightened_way'],
"workpiece_load": item['workpiece_load'],
"lead_screw": item['lead_screw'],

View File

@@ -0,0 +1 @@
from . import models

View File

@@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': '机企猫智能工厂 计划管理',
'version': '1.0',
'summary': '智能工厂计划管理',
'sequence': 1,
'description': """
在本模块,定义了计划管理的清单和原型
""",
'category': 'sf',
'website': 'https://www.sf.jikimo.com',
'depends': [],
'data': [
'security/ir.model.access.csv',
'views/paln_base_view.xml',
'views/menu_view.xml'
],
'demo': [
],
'assets': {
'web.assets_qweb': [
],
'web.assets_backend':[
]
},
'license': 'LGPL-3',
'installable': True,
'application': False,
'auto_install': False,
}

View File

@@ -0,0 +1,2 @@
from . import calendar_base
from . import base

View File

@@ -0,0 +1,43 @@
from odoo import models, fields
class ProductionLine(models.Model):
_name = 'sf.production.line'
_description = '生产线'
name = fields.Char(string='生产线名称')
class WorkingProcedure(models.Model):
_name = 'sf.working.procedure'
_description = '工序'
name = fields.Char(string='工序名称')
content = fields.Char(string='主要加工内容')
WorkingProcedure_to_ProductionLine_id = fields.Many2one('sf.production.line')
class ProcedureEquipmentResourceSetting(models.Model):
_name = 'sf.procedure.equipment.resource.setting'
_description = '工序设备资源设置'
equipment_to_working_procedure_id = fields.Many2one('sf.working.procedure', string='工序')
name = fields.Char(string='设备名称')
machine_tool_name = fields.Char(string='机台号')
brand = fields.Char(string='品牌')
model = fields.Char(string='型号')
production_capacity = fields.Char(string='产能')
working_calendar = fields.Many2one('sf.work.log.setting', string='工作日历')
working_shift = fields.Char(string='班次')
create_time = fields.Datetime(string='新增时间', default=lambda self: fields.Datetime.now())
stale_dated_time = fields.Datetime(string='过期时间')
status = fields.Selection([('0', '正常'), ('1', '故障停机'), ('2', '计划停机')], string='设备状态', default='0')
participate_in_scheduling = fields.Boolean(string='参与排程', default=True)

View File

@@ -0,0 +1,50 @@
from odoo import models, fields, api
import re
class WorkLogSetting(models.Model):
_name = 'sf.work.log.setting'
_description = '工作日历设置'
name = fields.Char(string='工作日历名称')
# start_time = fields.Char(string='日开始时间')
start_time = fields.Datetime(string='日开始时间')
end_time = fields.Char(string='日结束时间')
duration = fields.Char(string='时长')
day_off = fields.Char(string='休息日')
user_defined_working_shift_status = fields.Boolean(string='自定义班次', default=False)
working_shift = fields.Char(string='班次')
working_shift_char = fields.Char(string='班次')
working_shift_select = fields.Selection([('0', '早班00:00-08:00'),
('1', '白班08:00-16:00'),
('2', '晚班16:00-24:00'),
('3', '长白班08:00-20:00'),
('4', '长晚班20:00-08:00')], string='班次')
status = fields.Boolean(string='状态', default=True)
update_person = fields.Char(string='更新人', default=lambda self: self.env.user.name)
update_time = fields.Datetime(string='更新时间', default=lambda self: fields.Datetime.now())
@api.onchange('working_shift_char', 'working_shift_select')
def _onchange_working_shift(self):
for record in self:
if record.working_shift_select:
record.working_shift = record.working_shift_select
else:
record.working_shift = record.working_shift_char
# @api.onchange('start_time')
# def _onchange_start_time(self):
# pattern = re.compile(r'^(([0-9]|1[0-9]|2[0-3]):[0-5][0-9])|24:00$')
# if self.start_time and not pattern.match(self.start_time):
# raise models.ValidationError('输入的日开始时间不正确,请重新输入!')
@api.onchange('end_time')
def _onchange_end_time(self):
pattern = re.compile(r'^(([0-9]|1[0-9]|2[0-3]):[0-5][0-9])|24:00$')
for record in self:
if record.end_time and not pattern.match(record.end_time):
raise models.ValidationError('输入的日结束时间不正确,请重新输入!')

View File

@@ -0,0 +1,11 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_sf_work_log_setting,sf.work.log.setting,model_sf_work_log_setting,base.group_user,1,1,1,1
access_sf_production_line,sf.production.line,model_sf_production_line,base.group_user,1,1,1,1
access_sf_working_procedure,sf.working.procedure,model_sf_working_procedure,base.group_user,1,1,1,1
access_sf_procedure_equipment_resource_setting,sf.procedure.equipment.resource.setting,model_sf_procedure_equipment_resource_setting,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_sf_work_log_setting sf.work.log.setting model_sf_work_log_setting base.group_user 1 1 1 1
3 access_sf_production_line sf.production.line model_sf_production_line base.group_user 1 1 1 1
4 access_sf_working_procedure sf.working.procedure model_sf_working_procedure base.group_user 1 1 1 1
5 access_sf_procedure_equipment_resource_setting sf.procedure.equipment.resource.setting model_sf_procedure_equipment_resource_setting base.group_user 1 1 1 1

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<menuitem id="menu_sf_plan_manage"
name="计划管理"
parent="mrp.menu_mrp_root"
sequence="22"
/>
<menuitem id="menu_sf_basic_setting"
name="基础设置"
parent="menu_sf_plan_manage"
sequence="0"
/>
<menuitem id="menu_sf_work_log_setting"
name="工作日历设置"
parent="menu_sf_basic_setting"
action="sf_work_log_setting_act"
sequence="0"
/>
<menuitem id="menu_sf_procedure_equipment_resource_setting"
name="工序设备资源设置"
parent="menu_sf_basic_setting"
action="sf_procedure_equipment_resource_setting_act"
sequence="10"
/>
</odoo>

View File

@@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!--========================================工作日历设置========================================-->
<record id="sf_work_log_setting_tree" model="ir.ui.view">
<field name="name">工作日历设置</field>
<field name="model">sf.work.log.setting</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
<field name="start_time"/>
<field name="end_time"/>
<field name="duration"/>
<field name="day_off"/>
<field name="working_shift"/>
<field name="status"/>
<field name="update_person"/>
<field name="update_time"/>
</tree>
</field>
</record>
<record id="sf_work_log_setting_form" model="ir.ui.view">
<field name="name">工作日历设置</field>
<field name="model">sf.work.log.setting</field>
<field name="arch" type="xml">
<form>
<sheet string-="工作日历设置">
<group string="基础信息">
<field name="name"/>
</group>
<group string="选择班次">
<group>
<field name="user_defined_working_shift_status"/>
<field name="working_shift" invisible="True"/>
</group>
<group>
<field name="working_shift_char" attrs="{'invisible': [('user_defined_working_shift_status', '=', False)]}"/>
<field name="working_shift_select" attrs="{'invisible': [('user_defined_working_shift_status', '!=', False)]}"/>
</group>
</group>
<group string="工作时间">
<group>
<!-- <field name="start_time" widget="char" placeholder="请输入的时间为00:00-24:00"/>-->
<field name="start_time" options="{'no_date': True, 'format': 'HH:mm:ss'}"/>
<field name="duration"/>
</group>
<group>
<field name="end_time" widget="char" placeholder="请输入的时间为00:00-24:00"/>
<field name="day_off"/>
</group>
</group>
<group string="日历状态">
<field name="status"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="sf_work_log_setting_act" model="ir.actions.act_window">
<field name="name">工作日历设置</field>
<field name="res_model">sf.work.log.setting</field>
<field name="view_mode">tree,form</field>
</record>
<!--========================================工序设备资源设置========================================-->
<record id="sf_procedure_equipment_resource_setting_tree" model="ir.ui.view">
<field name="name">工序设备资源设置</field>
<field name="model">sf.procedure.equipment.resource.setting</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
<field name="machine_tool_name"/>
<field name="brand"/>
<field name="model"/>
<field name="production_capacity"/>
<field name="working_calendar"/>
<field name="working_shift"/>
<field name="create_time"/>
<field name="stale_dated_time"/>
<field name="status"/>
<field name="participate_in_scheduling"/>
</tree>
</field>
</record>
<!-- <record id="sf_procedure_equipment_resource_setting_form" model="ir.ui.view">-->
<!-- <field name="name">工序设备资源设置</field>-->
<!-- <field name="model">sf.procedure.equipment.resource.setting</field>-->
<!-- <field name="arch" type="xml">-->
<!-- <form>-->
<!-- </form>-->
<!-- </field>-->
<!-- </record>-->
<record id="sf_procedure_equipment_resource_setting_act" model="ir.actions.act_window">
<field name="name">工序设备资源设置</field>
<field name="res_model">sf.procedure.equipment.resource.setting</field>
<field name="view_mode">tree,form</field>
</record>
</odoo>

3
sf_warehouse/__init__.py Normal file
View File

@@ -0,0 +1,3 @@
# -*-coding:utf-8-*-
from . import models

View File

@@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': '机企猫智能工厂 库存管理',
'version': '1.0',
'summary': '智能工厂库存管理',
'sequence': 1,
'description': """
在本模块升级了odoo原生的库存模块
""",
'category': 'sf',
'website': 'https://www.sf.jikimo.com',
'depends': ['stock', ],
'data': [
#'security/group_security.xml',
# 'security/ir.model.access.csv',
'views/view.xml',
],
'demo': [
],
'assets': {
'web.assets_qweb': [
],
'web.assets_backend':[
# 'sf_tool_management/static/src/change.scss'
]
},
'license': 'LGPL-3',
'installable': True,
'application': False,
'auto_install': False,
}

View File

@@ -0,0 +1,2 @@
from . import model

View File

@@ -0,0 +1,178 @@
# -*- coding: utf-8 -*-
from odoo import fields, models, api
from odoo.exceptions import ValidationError, UserError
class SfLocation(models.Model):
_inherit = 'stock.location'
# 重写字段定义
name = fields.Char('Location Name', required=True, size=20)
barcode = fields.Char('Barcode', copy=False, required=True, size=15)
# 仓库类别selection仓库、库区、库位、货位
location_type = fields.Selection([
('仓库', '仓库'),
('库区', '库区'),
('货架', '货架'),
('货位', '货位')
], string='仓库类别')
# 仓库类型(分类:成品库、坯料库、原材料库、刀具库、线边料库、线边刀库)
location_category = fields.Selection([
('成品库', '成品库'),
('坯料库', '坯料库'),
('原材料库', '原材料库'),
('刀具库', '刀具库'),
('线边料库', '线边料库'),
('线边刀库', '线边刀库')
], string='仓库类型')
# 库区类型selection拣货区、存货区、收货区、退货区、次品区
area_type = fields.Selection([
('拣货区', '拣货区'),
('存货区', '存货区'),
('收货区', '收货区'),
('退货区', '退货区'),
('次品区', '次品区')
], string='库区类型')
# 货架独有字段通道、方向、货架高度m、货架层数、层数容量
channel = fields.Char(string='通道', required=True)
direction = fields.Selection([
('R', 'R'),
('L', 'L')
], string='方向', required=True)
shelf_height = fields.Float(string='货架高度(m)')
shelf_layer = fields.Integer(string='货架层数', required=True)
layer_capacity = fields.Integer(string='层数容量', required=True)
# 货位独有字段:货位状态、产品(关联产品对象)、产品序列号(关联产品序列号对象)
location_status = fields.Selection([
('空闲', '空闲'),
('占用', '占用'),
('禁用', '禁用')
], string='货位状态', default='空闲')
# product_id = fields.Many2one('product.template', string='产品')
product_id = fields.Many2one('product.product', string='产品', compute='_compute_product_id', readonly=True)
product_sn_id = fields.Many2one('stock.lot', string='产品序列号')
# 添加SQL约束
_sql_constraints = [
('name_uniq', 'unique(name)', '位置名称必须唯一!'),
]
hide_location_type = fields.Boolean(compute='_compute_hide_what', string='隐藏仓库')
hide_area = fields.Boolean(compute='_compute_hide_what', string='隐藏库区')
hide_shelf = fields.Boolean(compute='_compute_hide_what', string='隐藏货架')
hide_location = fields.Boolean(compute='_compute_hide_what', string='隐藏货位')
# @api.constrains('shelf_height')
# def _check_shelf_height(self):
# for record in self:
# if not (0 <= record.shelf_height < 1000): # 限制字段值在0到999之间
# raise UserError('shelf_height的值必须在0到1000之间')
#
# @api.constrains('shelf_layer')
# def _check_shelf_layer(self):
# for record in self:
# if not (0 < record.shelf_layer < 1000):
# raise UserError('shelf_layer的值必须在0到999之间,且不能为0')
#
# @api.constrains('layer_capacity')
# def _check_layer_capacity(self):
# for record in self:
# if not (0 <= record.layer_capacity < 1000):
# raise UserError('layer_capacity的值必须在0到999之间,且不能为0')
@api.depends('product_sn_id')
def _compute_product_id(self):
for record in self:
if record.product_sn_id:
record.product_id = record.product_sn_id.product_id
record.location_status = '占用'
else:
record.product_id = False
record.location_status = '空闲'
@api.depends('location_type')
def _compute_hide_what(self):
"""
根据仓库类别,隐藏不需要的字段
:return:
"""
for record in self:
record.hide_location_type = False
record.hide_area = False
record.hide_shelf = False
record.hide_location = False
if record.location_type and record.location_type == '仓库':
record.hide_location_type = True
elif record.location_type and record.location_type == '库区':
record.hide_area = True
elif record.location_type and record.location_type == '货架':
record.hide_shelf = True
elif record.location_type and record.location_type == '货位':
record.hide_location = True
else:
pass
# # 添加Python约束
# @api.constrains('name', 'barcode')
# def _check_len(self):
# for rec in self:
# if len(rec.name) > 20:
# raise ValidationError("Location Name length must be less equal than 20!")
# if len(rec.barcode) > 15:
# raise ValidationError("Barcode length must be less equal than 15!")
# @api.model
# def default_get(self, fields):
# print('fields:', fields)
# res = super(SfLocation, self).default_get(fields)
# print('res:', res)
# if 'barcode' in fields and 'barcode' not in res:
# # 这里是你生成barcode的代码
# pass
# # res['barcode'] = self.generate_barcode() # 假设你有一个方法generate_barcode来生成barcode
# return res
# @api.model
# def create(self, vals):
# """
# 重写create方法当仓库类型为货架时自动生成其下面的货位数量为货架层数*层数容量
# """
# res = super(SfLocation, self).create(vals)
# if res.location_type == '货架':
# for i in range(res.shelf_layer):
# for j in range(res.layer_capacity):
# self.create({
# 'name': res.name + '-' + str(i+1) + '-' + str(j+1),
# 'location_id': res.id,
# 'location_type': '货位',
# 'barcode': self.generate_barcode(res, i, j),
# 'location_status': '空闲'
# })
# return res
# 生成货位
def create_location(self):
if self.location_type == '货架':
for i in range(self.shelf_layer):
for j in range(self.layer_capacity):
self.create({
'name': self.name + '-' + str(i + 1) + '' + '-' + str(j + 1) + '位置',
'location_id': self.id,
'location_type': '货位',
'barcode': self.generate_barcode(i, j),
'location_status': '空闲'
})
def generate_barcode(self, i, j):
# 这里是你生成barcode的代码
area_type_barcode = self.location_id.barcode
i_str = str(i + 1).zfill(3) # 确保是两位数如果不足两位左侧补0
j_str = str(j + 1).zfill(3) # 确保是两位数如果不足两位左侧补0
return area_type_barcode + self.channel + self.direction + '-' + self.barcode + '-' + i_str + '-' + j_str
# def generate_barcode(self, i, j):
# # 这里是你生成barcode的代码
# area_type_barcode = self.location_id.barcode
# return area_type_barcode + self.channel + self.direction + '-' + self.barcode + '-' + str(i + 1) + '-' + str(j + 1)

View File

@@ -0,0 +1,4 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_stock_location,stock.location,model_stock_location,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_stock_location stock.location model_stock_location base.group_user 1 1 1 1

View File

@@ -0,0 +1,11 @@
.modal-content .o_cp_buttons {
display:none
}
.modal-content .o_control_panel {
display:none
}
.modal-content .o_list_button {
}

129
sf_warehouse/views/view.xml Normal file
View File

@@ -0,0 +1,129 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="view_location_tree2_sf_inherit" model="ir.ui.view">
<field name="name">stock.location.tree.sf.inherit</field>
<field name="model">stock.location</field>
<field name="inherit_id" ref="stock.view_location_tree2"/>
<field name="arch" type="xml">
<xpath expr="//tree/field[@name='complete_name']" position="before">
<field name="barcode"/>
</xpath>
</field>
</record>
<record id="view_location_form_sf_inherit" model="ir.ui.view">
<field name="name">stock.location.form.sf.inherit</field>
<field name="model">stock.location</field>
<field name="inherit_id" ref="stock.view_location_form"/>
<field name="arch" type="xml">
<xpath expr="//form/sheet/group" position="before">
<group string="基本信息">
<group>
<field name="hide_location_type" invisible="1"/>
<field name="hide_area" invisible="1"/>
<field name="hide_shelf" invisible="1"/>
<field name="hide_location" invisible="1"/>
<field name="barcode" string="编码"/>
<field name="location_type"/>
<field name="channel" attrs="{'invisible': [('hide_shelf', '=', False)], 'required': [('hide_shelf', '!=', False)]}"/>
<field name="direction" attrs="{'invisible': [('hide_shelf', '=', False)], 'required': [('hide_shelf', '!=', False)]}"/>
<field name="product_sn_id" attrs="{'invisible': [('hide_location', '=', False)], 'required': [('hide_location', '!=', False)]}"/>
</group>
<group>
<field name="location_category" attrs="{'invisible': [('hide_location_type', '=', False)], 'required': [('hide_location_type', '!=', False)]}"/>
<field name="area_type" attrs="{'invisible': [('hide_area', '=', False)], 'required': [('hide_area', '!=', False)]}"/>
<field name="shelf_height" attrs="{'invisible': [('hide_shelf', '=', False)], 'required': [('hide_shelf', '!=', False)]}"/>
<field name="shelf_layer" attrs="{'invisible': [('hide_shelf', '=', False)], 'required': [('hide_shelf', '!=', False)]}"/>
<field name="layer_capacity" attrs="{'invisible': [('hide_shelf', '=', False)], 'required': [('hide_shelf', '!=', False)]}"/>
<field name="product_id" attrs="{'invisible': [('hide_location', '=', False)], 'required': [('hide_location', '!=', False)]}"/>
<field name="location_status" attrs="{'invisible': [('hide_location', '=', False)], 'required': [('hide_location', '!=', False)]}"/>
</group>
</group>
</xpath>
<!-- <xpath expr="//form/sheet/div/button" position="before"> -->
<!-- <button string="生成货位" name="create_location" type="object" class="oe_highlight" attrs="{'invisible': [('hide_shelf', '=', False)]}"/> -->
<!-- </xpath> -->
<xpath expr="//form/sheet" position="before">
<header>
<button string="生成货位" name="create_location" type="object" class="oe_highlight" attrs="{'invisible': [('hide_shelf', '=', False)]}"/>
</header>
</xpath>
</field>
</record>
<record id="view_location_search_sf_inherit" model="ir.ui.view">
<field name="name">stock.location.search.sf.inherit</field>
<field name="model">stock.location</field>
<field name="inherit_id" ref="stock.view_location_search"/>
<field name="arch" type="xml">
<xpath expr="//search[1]" position="inside">
<searchpanel class="account_root">
<!-- <field name="location_type" icon="fa-filter"/> -->
<field name="location_id" select="multi" domain="[('location_type', '=', '货架')]"/>
</searchpanel>
</xpath>
</field>
</record>
<record id="example_kanban_view" model="ir.ui.view">
<field name="name">example.kanban</field>
<field name="model">stock.location</field>
<field name="arch" type="xml">
<kanban class="o_kanban_mobile">
<templates>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_card">
<!-- 标题 -->
<div class="o_kanban_card_header">
<div class="o_kanban_card_header_title">
<field name="name"/>
</div>
</div>
<!-- 内容 -->
<div class="o_kanban_record_bottom">
<field name="location_status"/>
</div>
<div class="o_kanban_record_bottom">
<field name="product_sn_id"/>
<span> | </span>
<field name="product_id"/>
</div>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<record id="kanban_action_id" model="ir.actions.act_window">
<field name="name">货位状态</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">stock.location</field>
<field name="view_mode">kanban,form</field>
</record>
<!-- <record id="example_action" model="ir.actions.act_window"> -->
<!-- <field name="name">Example</field> -->
<!-- <field name="type">ir.actions.act_window</field> -->
<!-- <field name="res_model">stock.location</field> -->
<!-- <field name="view_mode">kanban</field> -->
<!-- <field name="searchpanel">true</field> -->
<!-- <field name="searchpanel_field_label">货架</field> -->
<!-- <field name="searchpanel_field_name">parent_id</field> -->
<!-- <field name="searchpanel_field_group_by">['parent_id']</field> -->
<!-- <field name="domain">[('location_type', '=', '货位')]</field> -->
<!-- </record> -->
<menuitem id="menu_stock_location" name="货位状态" parent="stock.menu_stock_root"
sequence="50"
action="kanban_action_id"/>
</data>
</odoo>