需求计划
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