需求计划
This commit is contained in:
3
sf_demand_plan/__init__.py
Normal file
3
sf_demand_plan/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import models
|
||||
31
sf_demand_plan/__manifest__.py
Normal file
31
sf_demand_plan/__manifest__.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# -*- 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': ['sf_plan'],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'views/demand_plan.xml',
|
||||
],
|
||||
'demo': [
|
||||
],
|
||||
'assets': {
|
||||
'web.assets_qweb': [
|
||||
],
|
||||
'web.assets_backend': [
|
||||
'sf_demand_plan/static/src/scss/style.css',
|
||||
]
|
||||
},
|
||||
'license': 'LGPL-3',
|
||||
'installable': True,
|
||||
'application': False,
|
||||
'auto_install': False,
|
||||
}
|
||||
4
sf_demand_plan/models/__init__.py
Normal file
4
sf_demand_plan/models/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import sf_production_demand_plan
|
||||
from . import sale_order
|
||||
14
sf_demand_plan/models/sale_order.py
Normal file
14
sf_demand_plan/models/sale_order.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from odoo import models, fields, api, _
|
||||
|
||||
|
||||
class ReSaleOrder(models.Model):
|
||||
_inherit = 'sale.order'
|
||||
|
||||
def sale_order_create_line(self, product, item):
|
||||
ret = super(ReSaleOrder, self).sale_order_create_line(product, item)
|
||||
vals = {
|
||||
'sale_order_id': ret.order_id.id,
|
||||
'sale_order_line_id': ret.id,
|
||||
}
|
||||
self.env['sf.production.demand.plan'].sudo().create(vals)
|
||||
return ret
|
||||
158
sf_demand_plan/models/sf_production_demand_plan.py
Normal file
158
sf_demand_plan/models/sf_production_demand_plan.py
Normal file
@@ -0,0 +1,158 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class sf_production_plan(models.Model):
|
||||
_name = 'sf.production.demand.plan'
|
||||
_description = 'sf_production_demand_plan'
|
||||
|
||||
def _get_machining_precision(self):
|
||||
machinings = self.env['sf.machining.accuracy'].sudo().search([])
|
||||
|
||||
list = [(m.sync_id, m.name) for m in machinings]
|
||||
return list
|
||||
|
||||
priority = fields.Selection([
|
||||
('1', '紧急'),
|
||||
('2', '高'),
|
||||
('3', '中'),
|
||||
('4', '低'),
|
||||
], string='优先级', default='3')
|
||||
status = fields.Selection([
|
||||
('20', '待确认'),
|
||||
('30', '需求确认'),
|
||||
('50', '已下达'),
|
||||
('100', '取消'),
|
||||
], string='状态')
|
||||
|
||||
sale_order_id = fields.Many2one(comodel_name="sale.order",
|
||||
string="销售订单")
|
||||
sale_order_line_id = fields.Many2one(comodel_name="sale.order.line",
|
||||
string="销售订单行")
|
||||
company_id = fields.Many2one(
|
||||
related='sale_order_id.company_id',
|
||||
store=True, index=True, precompute=True)
|
||||
partner_id = fields.Many2one(
|
||||
comodel_name='res.partner',
|
||||
related='sale_order_line_id.order_partner_id',
|
||||
string="客户",
|
||||
store=True, index=True)
|
||||
order_remark = fields.Text(related='sale_order_id.remark',
|
||||
string="订单备注", store=True)
|
||||
glb_url = fields.Char(related='sale_order_line_id.glb_url', string='glb文件地址')
|
||||
product_id = fields.Many2one(
|
||||
comodel_name='product.product',
|
||||
related='sale_order_line_id.product_id',
|
||||
string='产品', store=True, index=True)
|
||||
model_id = fields.Char('模型ID', related='product_id.model_id')
|
||||
part_name = fields.Char('零件名称', related='product_id.part_name')
|
||||
part_number = fields.Char('零件图号', compute='_compute_part_number', store=True)
|
||||
is_incoming_material = fields.Boolean('客供料', related='sale_order_line_id.is_incoming_material', store=True)
|
||||
supply_method = fields.Selection([
|
||||
('automation', "自动化产线加工"),
|
||||
('manual', "人工线下加工"),
|
||||
('purchase', "外购"),
|
||||
('outsourcing', "委外加工"),
|
||||
], string='供货方式', related='sale_order_line_id.supply_method', store=True)
|
||||
product_uom_qty = fields.Float(
|
||||
string="需求数量",
|
||||
related='sale_order_line_id.product_uom_qty', store=True)
|
||||
deadline_of_delivery = fields.Date('客户交期', related='sale_order_id.deadline_of_delivery', store=True)
|
||||
inventory_quantity_auto_apply = fields.Float(
|
||||
string="成品库存",
|
||||
compute='_compute_inventory_quantity_auto_apply'
|
||||
)
|
||||
qty_delivered = fields.Float(
|
||||
"交货数量", related='sale_order_line_id.qty_delivered')
|
||||
qty_to_deliver = fields.Float(
|
||||
"待交货数量", related='sale_order_line_id.qty_to_deliver')
|
||||
model_long = fields.Char('尺寸', compute='_compute_model_long')
|
||||
materials_id = fields.Char('材料', compute='_compute_materials_id', store=True)
|
||||
model_machining_precision = fields.Selection(selection=_get_machining_precision, string='精度',
|
||||
related='product_id.model_machining_precision')
|
||||
model_process_parameters_ids = fields.Many2many('sf.production.process.parameter',
|
||||
'plan_process_parameter_rel',
|
||||
string='表面工艺',
|
||||
compute='_compute_model_process_parameters_ids'
|
||||
|
||||
)
|
||||
product_remark = fields.Char("产品备注", related='product_id.model_remark')
|
||||
order_code = fields.Char('E-SHOP订单号', related='sale_order_id.order_code')
|
||||
order_state = fields.Selection(
|
||||
string='订单状态',
|
||||
related='sale_order_line_id.state')
|
||||
route_id = fields.Many2one('stock.route', string='路线', related='sale_order_line_id.route_id', store=True)
|
||||
date_order = fields.Datetime('下单日期', related='sale_order_id.date_order')
|
||||
plan_remark = fields.Text("计划备注")
|
||||
|
||||
processing_time = fields.Char('程序工时')
|
||||
planned_start_date = fields.Date('计划开工日期')
|
||||
actual_start_date = fields.Date('实际开工日期')
|
||||
actual_end_date = fields.Date('实际完工日期')
|
||||
print_count = fields.Char('打印次数', default='T0C0')
|
||||
|
||||
sequence = fields.Integer('序号')
|
||||
|
||||
@api.depends('product_id.part_number', 'product_id.model_name')
|
||||
def _compute_part_number(self):
|
||||
for line in self:
|
||||
if line.product_id:
|
||||
if line.product_id.part_number:
|
||||
line.part_number = line.product_id.part_number
|
||||
else:
|
||||
if line.product_id.model_name:
|
||||
line.part_number = line.product_id.model_name.rsplit('.', 1)[0]
|
||||
else:
|
||||
line.part_number = None
|
||||
|
||||
@api.depends('product_id.length', 'product_id.width', 'product_id.height')
|
||||
def _compute_model_long(self):
|
||||
for line in self:
|
||||
if line.product_id:
|
||||
line.model_long = f"{line.product_id.length}*{line.product_id.width}*{line.product_id.height}"
|
||||
else:
|
||||
line.model_long = None
|
||||
|
||||
@api.depends('product_id.materials_id')
|
||||
def _compute_materials_id(self):
|
||||
for line in self:
|
||||
if line.product_id:
|
||||
line.materials_id = f"{line.product_id.materials_id.name}*{line.product_id.materials_type_id.name}"
|
||||
else:
|
||||
line.materials_id = None
|
||||
|
||||
@api.depends('product_id.model_process_parameters_ids')
|
||||
def _compute_model_process_parameters_ids(self):
|
||||
for line in self:
|
||||
if line.product_id and line.product_id.model_process_parameters_ids:
|
||||
line.model_process_parameters_ids = [(6, 0, line.product_id.model_process_parameters_ids.ids)]
|
||||
else:
|
||||
line.model_process_parameters_ids = [(5, 0, 0)]
|
||||
|
||||
def _compute_inventory_quantity_auto_apply(self):
|
||||
location_id = self.env['stock.location'].search([('name', '=', '成品存货区')], limit=1).id
|
||||
product_ids = self.mapped('product_id').ids
|
||||
if product_ids:
|
||||
quant_data = self.env['stock.quant'].read_group(
|
||||
domain=[
|
||||
('product_id', 'in', product_ids),
|
||||
('location_id', '=', location_id)
|
||||
],
|
||||
fields=['product_id', 'inventory_quantity_auto_apply'],
|
||||
groupby=['product_id']
|
||||
)
|
||||
quantity_map = {item['product_id'][0]: item['inventory_quantity_auto_apply'] for item in quant_data}
|
||||
else:
|
||||
quantity_map = {}
|
||||
for line in self:
|
||||
if line.product_id:
|
||||
line.inventory_quantity_auto_apply = quantity_map.get(line.product_id.id, 0.0)
|
||||
else:
|
||||
line.inventory_quantity_auto_apply = 0.0
|
||||
|
||||
@api.constrains('planned_start_date')
|
||||
def _check_planned_start_date(self):
|
||||
for record in self:
|
||||
if record.planned_start_date and record.planned_start_date < fields.Date.today():
|
||||
raise ValidationError("计划开工日期必须大于或等于今天。")
|
||||
3
sf_demand_plan/security/ir.model.access.csv
Normal file
3
sf_demand_plan/security/ir.model.access.csv
Normal file
@@ -0,0 +1,3 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_sf_production_demand_plan,sf.production.demand.plan,model_sf_production_demand_plan,base.group_user,1,0,0,0
|
||||
access_sf_production_demand_plan_for_dispatch,sf.production.demand.plan for dispatch,model_sf_production_demand_plan,sf_base.group_plan_dispatch,1,1,0,0
|
||||
|
3
sf_demand_plan/static/src/scss/style.css
Normal file
3
sf_demand_plan/static/src/scss/style.css
Normal file
@@ -0,0 +1,3 @@
|
||||
.demand_plan_tree th:not(.o_list_record_selector,.row_no,[data-name=sequence]) {
|
||||
min-width: 98px !important;
|
||||
}
|
||||
95
sf_demand_plan/views/demand_plan.xml
Normal file
95
sf_demand_plan/views/demand_plan.xml
Normal file
@@ -0,0 +1,95 @@
|
||||
<odoo>
|
||||
<record id="view_sf_production_demand_plan_tree" model="ir.ui.view">
|
||||
<field name="name">sf.production.demand.plan.tree</field>
|
||||
<field name="model">sf.production.demand.plan</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="需求计划" default_order="create_date desc" class="demand_plan_tree">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="priority"/>
|
||||
<field name="status"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="order_remark"/>
|
||||
<field name="glb_url" optional="hide"/>
|
||||
<field name="product_id"/>
|
||||
<field name="model_id" optional="hide"/>
|
||||
<field name="part_name"/>
|
||||
<field name="part_number"/>
|
||||
<field name="is_incoming_material"/>
|
||||
<field name="supply_method"/>
|
||||
<field name="product_uom_qty"/>
|
||||
<field name="deadline_of_delivery"/>
|
||||
<field name="inventory_quantity_auto_apply"/>
|
||||
<field name="qty_delivered"/>
|
||||
<field name="qty_to_deliver"/>
|
||||
<field name="model_long"/>
|
||||
<field name="materials_id"/>
|
||||
<field name="model_machining_precision"/>
|
||||
<field name="model_process_parameters_ids"/>
|
||||
<field name="product_remark" optional="hide"/>
|
||||
<field name="order_code" optional="hide"/>
|
||||
<field name="sale_order_id" optional="hide"/>
|
||||
<field name="sale_order_line_id" optional="hide"/>
|
||||
<field name="order_state"/>
|
||||
<field name="route_id" optional="hide"/>
|
||||
<field name="date_order"/>
|
||||
<field name="plan_remark"/>
|
||||
<field name="processing_time"/>
|
||||
<field name="planned_start_date"/>
|
||||
<field name="actual_start_date"/>
|
||||
<field name="actual_end_date"/>
|
||||
<field name="create_date" optional="hide" string="创建时间"/>
|
||||
<field name="create_uid" optional="hide" string="创建人"/>
|
||||
<field name="write_date" string="更新时间"/>
|
||||
<field name="write_uid" optional="hide" string="更新人"/>
|
||||
<field name="print_count"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_sf_production_demand_plan_search" model="ir.ui.view">
|
||||
<field name="name">sf.production.demand.plan.search</field>
|
||||
<field name="model">sf.production.demand.plan</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field name="order_remark"/>
|
||||
<field name="product_id"/>
|
||||
<field name="part_name"/>
|
||||
<field name="part_number"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="supply_method"/>
|
||||
<field name="materials_id"/>
|
||||
<field name="model_process_parameters_ids"/>
|
||||
<field name="plan_remark"/>
|
||||
<group expand="0" string="Group By">
|
||||
<filter name="group_by_priority" string="优先级" domain="[]" context="{'group_by': 'priority'}"/>
|
||||
<filter name="group_by_status" string="状态" domain="[]" context="{'group_by': 'status'}"/>
|
||||
<filter name="group_by_partner_id" string="客户" domain="[]" context="{'group_by': 'partner_id'}"/>
|
||||
<filter name="group_by_is_incoming_material" string="客供料" domain="[]"
|
||||
context="{'group_by': 'is_incoming_material'}"/>
|
||||
<filter name="group_by_supply_method" string="供货方式" domain="[]"
|
||||
context="{'group_by': 'supply_method'}"/>
|
||||
<filter name="group_by_deadline_of_delivery" string="客户交期" domain="[]"
|
||||
context="{'group_by': 'deadline_of_delivery'}"/>
|
||||
<filter name="group_by_materials_id" string="材料" domain="[]"
|
||||
context="{'group_by': 'materials_id'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="sf_production_demand_plan_action" model="ir.actions.act_window">
|
||||
<field name="name">需求计划</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">sf.production.demand.plan</field>
|
||||
<field name="view_mode">tree</field>
|
||||
</record>
|
||||
|
||||
|
||||
<menuitem
|
||||
id="demand_plan_menu"
|
||||
name="需求计划"
|
||||
sequence="140"
|
||||
action="sf_production_demand_plan_action"
|
||||
parent="sf_plan.sf_production_plan_menu"
|
||||
/>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user