解决合并develop冲突

This commit is contained in:
chenye
2025-07-07 10:03:09 +08:00
25 changed files with 714 additions and 441 deletions

View File

@@ -10,6 +10,7 @@
'data': [ 'data': [
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'views/sale_order_view.xml', 'views/sale_order_view.xml',
'views/purchase_order.xml',
'views/mrp_production.xml', 'views/mrp_production.xml',
'views/purchase_request_view.xml', 'views/purchase_request_view.xml',
'wizard/purchase_request_line_make_purchase_order_view.xml', 'wizard/purchase_request_line_make_purchase_order_view.xml',

View File

@@ -16,6 +16,69 @@ class PurchaseOrder(models.Model):
('rejected', '已驳回') ('rejected', '已驳回')
], string='Status', readonly=True, index=True, copy=False, default='draft', tracking=True) ], string='Status', readonly=True, index=True, copy=False, default='draft', tracking=True)
# 成品采购订单对应的坯料采购申请单和采购订单数量
purchase_request_count = fields.Integer('子·采购申请数量', compute='_compute_purchase_request')
purchase_order_count = fields.Integer('子·采购订单数量', compute='_compute_purchase_request')
@api.depends('state')
def _compute_purchase_request(self):
for record in self:
purchase_request_ids, purchase_order_ids = record.get_purchase_request_order()
record.purchase_request_count = len(purchase_request_ids)
record.purchase_order_count = len(purchase_order_ids)
def action_view_preform_body_purchase_request(self):
self.ensure_one()
name_list = self._get_pinking_name()
purchase_request_ids = self.env['purchase.request'].search([('origin', 'in', name_list)])
action = {
'res_model': 'purchase.request',
'type': 'ir.actions.act_window',
}
if len(purchase_request_ids) == 1:
action.update({
'view_mode': 'form',
'res_id': purchase_request_ids[0].id,
})
else:
action.update({
'name': _("子·采购申请"),
'domain': [('id', 'in', purchase_request_ids.ids)],
'view_mode': 'tree,form',
})
return action
def action_view_preform_body_purchase_order(self):
self.ensure_one()
name_list = self._get_pinking_name()
purchase_order_ids = self.env['purchase.order'].search([('origin', 'in', name_list)])
action = {
'res_model': 'purchase.order',
'type': 'ir.actions.act_window',
}
if len(purchase_order_ids) == 1:
action.update({
'view_mode': 'form',
'res_id': purchase_order_ids[0].id,
})
else:
action.update({
'name': _("子·采购订单"),
'domain': [('id', 'in', purchase_order_ids.ids)],
'view_mode': 'tree,form',
})
return action
def get_purchase_request_order(self):
name_list = self._get_pinking_name()
purchase_request_ids = self.env['purchase.request'].search([('origin', 'in', name_list)])
purchase_order_ids = self.env['purchase.order'].search([('origin', 'in', name_list)])
return purchase_request_ids, purchase_order_ids
def _get_pinking_name(self):
return [picking_id.name for picking_id in self.picking_ids if picking_id.name]
def button_confirm(self): def button_confirm(self):
res = super(PurchaseOrder, self).button_confirm() res = super(PurchaseOrder, self).button_confirm()

View File

@@ -16,6 +16,7 @@ class PurchaseRequest(models.Model):
) )
rule_new_add = fields.Boolean('采购请求为规则创建', default=False, compute='_compute_state', store=True) rule_new_add = fields.Boolean('采购请求为规则创建', default=False, compute='_compute_state', store=True)
rule_purchase_to_request = fields.Boolean('采购单根据规则创建坯料采购申请', default=False)
@api.depends('state') @api.depends('state')
def _compute_state(self): def _compute_state(self):

View File

@@ -45,3 +45,14 @@ class StockPicking(models.Model):
(4, x.id) for x in backorder_ids.move_ids if x.product_id.id in purchase_request_lines.mapped('product_id.id') (4, x.id) for x in backorder_ids.move_ids if x.product_id.id in purchase_request_lines.mapped('product_id.id')
] ]
return res return res
def _subcontracted_produce(self, subcontract_details):
super()._subcontracted_produce(subcontract_details)
# 判断是否根据规则生成新的采购申请单据,如果生成则修改状态为 approved
if self:
pr_ids = self.env["purchase.request"].sudo().search(
[('origin', 'like', self.name), ('rule_purchase_to_request', '=', True), ('state', '=', 'draft')])
if pr_ids:
pr_ids.write({'need_validation': False})
pr_ids.write({"state": "approved", 'need_validation': True, 'rule_new_add': False})

View File

@@ -26,7 +26,7 @@ class StockRule(models.Model):
request_data = rule._prepare_purchase_request( request_data = rule._prepare_purchase_request(
procurement.origin, procurement.values procurement.origin, procurement.values
) )
request_data.update({'rule_new_add': True}) request_data = self._update_request_data(procurement, request_data)
pr = purchase_request_model.create(request_data) pr = purchase_request_model.create(request_data)
cache[domain] = pr cache[domain] = pr
elif ( elif (
@@ -44,6 +44,18 @@ class StockRule(models.Model):
request_line_data.update({'origin': procurement.origin}) request_line_data.update({'origin': procurement.origin})
purchase_request_line_model.create(request_line_data) purchase_request_line_model.create(request_line_data)
def _update_request_data(self, procurement, request_data):
sp = self.env['stock.picking'].sudo().search([('name', '=', procurement.origin)])
if len(sp) == 1:
po = self.env['purchase.order'].sudo().search(
[('name', '=', sp.origin), ('purchase_type', '=', 'outsourcing')])
if po:
request_data.update({'rule_purchase_to_request': True})
else:
request_data.update({'rule_new_add': True})
return request_data
def _run_buy(self, procurements): def _run_buy(self, procurements):
# 如果补货组相同,并且产品相同,则合并 # 如果补货组相同,并且产品相同,则合并
procurements_dict = defaultdict() procurements_dict = defaultdict()

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="purchase_order_form_jikimo_purchase_request" model="ir.ui.view">
<field name="name">purchase.order.inherited.form.jikimo.purchase.request</field>
<field name="model">purchase.order</field>
<field name="inherit_id" ref="mrp_subcontracting_purchase.purchase_order_form_mrp_subcontracting_purchase"/>
<field name="arch" type="xml">
<xpath expr="//div[hasclass('oe_button_box')]/button[@name='action_view_subcontracting_resupply']" position="before">
<button
class="oe_stat_button" name="action_view_preform_body_purchase_order"
type="object" icon="fa-truck" attrs="{'invisible': [('purchase_order_count', '=', 0)]}" groups="stock.group_stock_user">
<div class="o_field_widget o_stat_info">
<span class="o_stat_value"><field name="purchase_order_count"/></span>
<span class="o_stat_text">子·采购订单</span>
</div>
</button>
<button
class="oe_stat_button" name="action_view_preform_body_purchase_request"
type="object" icon="fa-truck" attrs="{'invisible': [('purchase_request_count', '=', 0)]}" groups="stock.group_stock_user">
<div class="o_field_widget o_stat_info">
<span class="o_stat_value"><field name="purchase_request_count"/></span>
<span class="o_stat_text">子·采购申请</span>
</div>
</button>
</xpath>
</field>
</record>
</odoo>

View File

@@ -67,6 +67,16 @@
<field name="part_number"/> <field name="part_number"/>
<field name="part_name" invisible="1"/> <field name="part_name" invisible="1"/>
</xpath> </xpath>
<xpath expr="//tree" position="inside">
<header>
<button
name="%(purchase_request.action_purchase_request_line_make_purchase_order)d"
string="创建询价单"
type="action"
class="btn-primary"
/>
</header>
</xpath>
</field> </field>
</record> </record>

View File

@@ -14,9 +14,13 @@
'data': [ 'data': [
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'data/stock_route_group.xml', 'data/stock_route_group.xml',
<<<<<<< HEAD
'views/sale_order_views.xml', 'views/sale_order_views.xml',
'views/demand_plan.xml', 'views/demand_plan.xml',
'views/demand_main_plan.xml', 'views/demand_main_plan.xml',
=======
'views/demand_plan.xml',
>>>>>>> develop
'views/stock_route.xml', 'views/stock_route.xml',
'wizard/sf_demand_plan_print_wizard_view.xml', 'wizard/sf_demand_plan_print_wizard_view.xml',
'wizard/sf_release_plan_wizard_views.xml', 'wizard/sf_release_plan_wizard_views.xml',

View File

@@ -8,3 +8,4 @@ from . import stock_route
from . import stock_rule from . import stock_rule
from . import purchase_request from . import purchase_request
from . import purchase_order from . import purchase_order

View File

@@ -94,11 +94,17 @@ class SfProductionDemandPlan(models.Model):
model_long = fields.Char('尺寸(mm)', compute='_compute_model_long') model_long = fields.Char('尺寸(mm)', compute='_compute_model_long')
blank_type = fields.Selection([('圆料', '圆料'), ('方料', '方料')], string='坯料分类', blank_type = fields.Selection([('圆料', '圆料'), ('方料', '方料')], string='坯料分类',
related='product_id.blank_type') related='product_id.blank_type')
<<<<<<< HEAD
#blank_precision = fields.Selection([('精坯', '精坯'), ('粗坯', '粗坯')], string='坯料类型', related='product_id.blank_precision') #blank_precision = fields.Selection([('精坯', '精坯'), ('粗坯', '粗坯')], string='坯料类型', related='product_id.blank_precision')
#materials_id = fields.Char('材料', compute='_compute_materials_id', store=True) #materials_id = fields.Char('材料', compute='_compute_materials_id', store=True)
embryo_long = fields.Char('坯料尺寸(mm)', related='demand_plan_id.embryo_long') embryo_long = fields.Char('坯料尺寸(mm)', related='demand_plan_id.embryo_long')
materials_id = fields.Char('材料', related='demand_plan_id.materials_id') materials_id = fields.Char('材料', related='demand_plan_id.materials_id')
=======
blank_precision = fields.Selection([('精坯', '精坯'), ('粗坯', '粗坯')], string='坯料类型', related='product_id.blank_precision')
embryo_long = fields.Char('坯料尺寸(mm)', compute='_compute_embryo_long')
materials_id = fields.Char('材料', compute='_compute_materials_id', store=True)
>>>>>>> develop
model_machining_precision = fields.Selection(selection=_get_machining_precision, string='精度', model_machining_precision = fields.Selection(selection=_get_machining_precision, string='精度',
related='product_id.model_machining_precision') related='product_id.model_machining_precision')
#model_process_parameters_ids = fields.Many2many('sf.production.process.parameter', #model_process_parameters_ids = fields.Many2many('sf.production.process.parameter',
@@ -112,6 +118,7 @@ class SfProductionDemandPlan(models.Model):
product_remark = fields.Char("产品备注", related='product_id.model_remark') product_remark = fields.Char("产品备注", related='product_id.model_remark')
order_code = fields.Char('E-SHOP订单号', related='sale_order_id.order_code') order_code = fields.Char('E-SHOP订单号', related='sale_order_id.order_code')
<<<<<<< HEAD
order_state = fields.Selection( string='订单状态',related='sale_order_line_id.state') 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) #route_id = fields.Many2one('stock.route', string='路线', related='sale_order_line_id.route_id', store=True)
@@ -119,6 +126,15 @@ class SfProductionDemandPlan(models.Model):
domain=[('demand_plan_selectable', '=', True)], compute='_compute_route_ids', domain=[('demand_plan_selectable', '=', True)], compute='_compute_route_ids',
store=True) store=True)
=======
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)
route_ids = fields.Many2many('stock.route', 'stock_route_demand_plan', 'demand_plan_id', 'route_id', '路线',
domain=[('demand_plan_selectable', '=', True)], compute='_compute_route_ids',
store=True)
>>>>>>> develop
contract_date = fields.Date('合同日期', related='sale_order_id.contract_date') contract_date = fields.Date('合同日期', related='sale_order_id.contract_date')
date_order = fields.Datetime('下单日期', related='sale_order_id.date_order') date_order = fields.Datetime('下单日期', related='sale_order_id.date_order')
contract_code = fields.Char('合同号', related='sale_order_id.contract_code', store=True) contract_code = fields.Char('合同号', related='sale_order_id.contract_code', store=True)
@@ -188,6 +204,73 @@ class SfProductionDemandPlan(models.Model):
continue continue
pdp.route_ids = None pdp.route_ids = None
<<<<<<< HEAD
=======
hide_action_stock_picking = fields.Boolean(
string='显示调拨单按钮',
compute='_compute_hide_action_stock_picking',
default=False
)
hide_action_outsourcing_stock_picking = fields.Boolean(
string='委外显示调拨单按钮',
compute='_compute_hide_action_stock_picking',
default=False
)
hide_action_view_programming = fields.Boolean(
string='显示编程单按钮',
compute='_compute_hid_button',
default=False
)
outsourcing_purchase_request = fields.Char('委外采购申请单')
@api.depends('supply_method')
def _compute_route_ids(self):
for pdp in self:
if pdp.supply_method:
group_id = self.env['stock.route.group'].sudo().search([('code', '=', pdp.supply_method)])
route_ids = self.env['stock.route'].sudo().search(
[('demand_plan_selectable', '=', True), ('stock_route_group_ids', '=', group_id.id)])
if route_ids:
pdp.route_ids = route_ids.ids
break
pdp.route_ids = None
@api.depends('sale_order_id.state', 'sale_order_id.mrp_production_ids.schedule_state', 'sale_order_id.order_line',
'sale_order_id.mrp_production_ids.state')
def _compute_status(self):
for record in self:
if record.sale_order_id:
sale_order_state = record.sale_order_id.state
if sale_order_state in ('draft', 'sent', 'supply method'):
record.status = '20' # 待确认
if record.supply_method in ('purchase', 'outsourcing') and sale_order_state in (
'sale', 'processing', 'physical_distribution', 'delivered',
'done') and sale_order_state != 'cancel':
record.status = '60' # 已下达
if record.supply_method in ('automation', 'manual'):
if sale_order_state in (
'sale', 'processing', 'physical_distribution', 'delivered',
'done') and sale_order_state != 'cancel':
record.status = '30' # 需求确认
# 检查所有制造订单的排程单状态,有一个为待排程状态,就为待下达生产
pending_productions = record.sale_order_id.mrp_production_ids.filtered(
lambda p: p.state == 'confirmed' and p.product_id.id == record.product_id.id
)
if pending_productions:
record.status = '50' # 待下达生产
# 检查所有制造订单的排程单状态
if record.sale_order_id.mrp_production_ids:
product_productions = record.sale_order_id.mrp_production_ids.filtered(
lambda p: p.product_id.id == record.product_id.id
)
if product_productions and all(order.schedule_state != '未排' for order in product_productions):
record.status = '60' # 已下达
if sale_order_state == 'cancel' or not record.sale_order_line_id:
record.status = '100' # 取消
>>>>>>> develop
@api.depends('sale_order_line_id.product_id.name') @api.depends('sale_order_line_id.product_id.name')
def _compute_sale_order_line_number(self): def _compute_sale_order_line_number(self):
@@ -205,6 +288,57 @@ class SfProductionDemandPlan(models.Model):
else: else:
line.model_long = None line.model_long = None
<<<<<<< HEAD
=======
@api.depends('product_id.model_long', 'product_id.model_width', 'product_id.model_height', 'product_id.blank_type')
def _compute_embryo_long(self):
for line in self:
if line.product_id:
if line.product_id.blank_type == '圆料':
line.embryo_long = f"Ø{round(line.product_id.model_width, 3)}*{round(line.product_id.model_long, 3)}"
else:
line.embryo_long = f"{round(line.product_id.model_long, 3)}*{round(line.product_id.model_width, 3)}*{round(line.product_id.model_height, 3)}"
else:
line.embryo_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
>>>>>>> develop
@api.depends('sale_order_id.mrp_production_ids.workorder_ids.date_start') @api.depends('sale_order_id.mrp_production_ids.workorder_ids.date_start')
def _compute_actual_start_date(self): def _compute_actual_start_date(self):
for record in self: for record in self:
@@ -312,6 +446,7 @@ class SfProductionDemandPlan(models.Model):
for pro_plan in pro_plan_list: for pro_plan in pro_plan_list:
pro_plan.do_production_schedule() pro_plan.do_production_schedule()
<<<<<<< HEAD
def update_sale_order_state(self): def update_sale_order_state(self):
demand_plan = self.env['sf.demand.main.plan'].sudo().search([('sale_order_id', '=', self.sale_order_id.id)]) demand_plan = self.env['sf.demand.main.plan'].sudo().search([('sale_order_id', '=', self.sale_order_id.id)])
demand_plan_state = demand_plan.filtered(lambda line: line.state != '40') demand_plan_state = demand_plan.filtered(lambda line: line.state != '40')
@@ -319,6 +454,8 @@ class SfProductionDemandPlan(models.Model):
# 修改销售订单为加工中 # 修改销售订单为加工中
self.sale_order_id.state = 'processing' self.sale_order_id.state = 'processing'
=======
>>>>>>> develop
def button_action_print(self): def button_action_print(self):
return { return {
'res_model': 'sf.demand.plan.print.wizard', 'res_model': 'sf.demand.plan.print.wizard',

View File

@@ -19,7 +19,11 @@ class SfStockRoute(models.Model):
[('supply_method', 'in', stock_route_group)]) [('supply_method', 'in', stock_route_group)])
if demand_plan_ids: if demand_plan_ids:
sr.demand_plan_ids = demand_plan_ids.ids sr.demand_plan_ids = demand_plan_ids.ids
<<<<<<< HEAD
continue continue
=======
break
>>>>>>> develop
sr.demand_plan_ids = None sr.demand_plan_ids = None
# def name_get(self): # def name_get(self):

View File

@@ -5,6 +5,7 @@ access_sf_production_demand_plan_for_dispatch,sf.production.demand.plan for disp
access_sf_demand_plan_print_wizard,sf.demand.plan.print.wizard,model_sf_demand_plan_print_wizard,base.group_user,1,0,0,0 access_sf_demand_plan_print_wizard,sf.demand.plan.print.wizard,model_sf_demand_plan_print_wizard,base.group_user,1,0,0,0
access_sf_demand_plan_print_wizard_for_dispatch,sf.demand.plan.print.wizard for dispatch,model_sf_demand_plan_print_wizard,sf_base.group_plan_dispatch,1,1,0,0 access_sf_demand_plan_print_wizard_for_dispatch,sf.demand.plan.print.wizard for dispatch,model_sf_demand_plan_print_wizard,sf_base.group_plan_dispatch,1,1,0,0
<<<<<<< HEAD
access_sf_demand_main_plan,sf.demand.main.plan,model_sf_demand_main_plan,base.group_user,1,0,0,0 access_sf_demand_main_plan,sf.demand.main.plan,model_sf_demand_main_plan,base.group_user,1,0,0,0
access_sf_demand_main_plan_for_dispatch,sf.demand.main.plan for dispatch,model_sf_demand_main_plan,sf_base.group_plan_dispatch,1,1,0,0 access_sf_demand_main_plan_for_dispatch,sf.demand.main.plan for dispatch,model_sf_demand_main_plan,sf_base.group_plan_dispatch,1,1,0,0
@@ -13,3 +14,7 @@ access_stock_route_group_dispatch,stock.route.group.dispatch,model_stock_route_g
access_sf_release_plan_wizard,sf.release.plan.wizard,model_sf_release_plan_wizard,base.group_user,1,0,0,0 access_sf_release_plan_wizard,sf.release.plan.wizard,model_sf_release_plan_wizard,base.group_user,1,0,0,0
access_sf_release_plan_wizard_for_dispatch,sf.release.plan.wizard for dispatch,model_sf_release_plan_wizard,sf_base.group_plan_dispatch,1,1,1,1 access_sf_release_plan_wizard_for_dispatch,sf.release.plan.wizard for dispatch,model_sf_release_plan_wizard,sf_base.group_plan_dispatch,1,1,1,1
=======
access_stock_route_group,stock.route.group,model_stock_route_group,base.group_user,1,0,0,0
access_stock_route_group_dispatch,stock.route.group.dispatch,model_stock_route_group,sf_base.group_plan_dispatch,1,1,0,0
>>>>>>> develop
1 id id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
5 access_sf_demand_plan_print_wizard_for_dispatch access_sf_demand_plan_print_wizard_for_dispatch,sf.demand.plan.print.wizard for dispatch,model_sf_demand_plan_print_wizard,sf_base.group_plan_dispatch,1,1,0,0 sf.demand.plan.print.wizard for dispatch model_sf_demand_plan_print_wizard sf_base.group_plan_dispatch 1 1 0 0
6 access_sf_demand_main_plan <<<<<<< HEAD sf.demand.main.plan model_sf_demand_main_plan base.group_user 1 0 0 0
7 access_sf_demand_main_plan_for_dispatch access_sf_demand_main_plan,sf.demand.main.plan,model_sf_demand_main_plan,base.group_user,1,0,0,0 sf.demand.main.plan for dispatch model_sf_demand_main_plan sf_base.group_plan_dispatch 1 1 0 0
8 access_sf_demand_main_plan_for_dispatch,sf.demand.main.plan for dispatch,model_sf_demand_main_plan,sf_base.group_plan_dispatch,1,1,0,0
9 access_stock_route_group access_stock_route_group,stock.route.group,model_stock_route_group,base.group_user,1,0,0,0 stock.route.group model_stock_route_group base.group_user 1 0 0 0
10 access_stock_route_group_dispatch access_stock_route_group_dispatch,stock.route.group.dispatch,model_stock_route_group,sf_base.group_plan_dispatch,1,1,0,0 stock.route.group.dispatch model_stock_route_group sf_base.group_plan_dispatch 1 1 0 0
11 access_sf_release_plan_wizard access_sf_release_plan_wizard,sf.release.plan.wizard,model_sf_release_plan_wizard,base.group_user,1,0,0,0 sf.release.plan.wizard model_sf_release_plan_wizard base.group_user 1 0 0 0
14 access_stock_route_group,stock.route.group,model_stock_route_group,base.group_user,1,0,0,0
15 access_stock_route_group_dispatch,stock.route.group.dispatch,model_stock_route_group,sf_base.group_plan_dispatch,1,1,0,0
16 >>>>>>> develop
17
18
19
20

View File

@@ -82,3 +82,8 @@
cursor: pointer; cursor: pointer;
} }
} }
th[data-name=processing_time] + th::before{
content: '待执行单据';
line-height: 38px;
}

View File

@@ -28,18 +28,13 @@
<field name="qty_to_deliver"/> <field name="qty_to_deliver"/>
<field name="model_long"/> <field name="model_long"/>
<field name="blank_type" optional="hide"/> <field name="blank_type" optional="hide"/>
<!--<field name="blank_precision"/>--> <field name="blank_precision"/>
<field name="embryo_long"/> <field name="embryo_long"/>
<field name="materials_id"/>
<field name="model_machining_precision"/>
<field name="model_process_parameters_ids" widget="many2many_tags"/>
<field name="product_remark" optional="hide"/> <field name="product_remark" optional="hide"/>
<field name="order_code" optional="hide"/> <field name="order_code" optional="hide"/>
<field name="sale_order_id" optional="hide"/> <field name="sale_order_id" optional="hide"/>
<field name="sale_order_line_number" optional="hide"/> <field name="sale_order_line_number" optional="hide"/>
<field name="order_state"/> <field name="order_state"/>
<field name="route_ids" widget="many2many_tags" optional="hide"
context="{'demand_plan_search_stock_route_id': id}"/>
<field name="contract_date"/> <field name="contract_date"/>
<field name="date_order"/> <field name="date_order"/>
<field name="contract_code"/> <field name="contract_code"/>
@@ -66,6 +61,7 @@
<field name="planned_start_date" attrs="{'readonly': [('status', 'in', ('60','100'))]}"/> <field name="planned_start_date" attrs="{'readonly': [('status', 'in', ('60','100'))]}"/>
<field name="actual_start_date"/> <field name="actual_start_date"/>
<field name="actual_end_date"/> <field name="actual_end_date"/>
<field name="processing_time"/>
<field name="create_date" optional="hide" string="创建时间"/> <field name="create_date" optional="hide" string="创建时间"/>
<field name="create_uid" optional="hide" string="创建人"/> <field name="create_uid" optional="hide" string="创建人"/>
<field name="write_date" string="更新时间"/> <field name="write_date" string="更新时间"/>
@@ -98,7 +94,8 @@
<group expand="0" string="Group By"> <group expand="0" string="Group By">
<filter name="group_by_priority" string="优先级" domain="[]" context="{'group_by': 'priority'}"/> <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_status" string="状态" domain="[]" context="{'group_by': 'status'}"/>
<filter name="group_by_customer_name" string="客户" domain="[]" context="{'group_by': 'customer_name'}"/> <filter name="group_by_customer_name" string="客户" domain="[]"
context="{'group_by': 'customer_name'}"/>
<filter name="group_by_is_incoming_material" string="客供料" domain="[]" <filter name="group_by_is_incoming_material" string="客供料" domain="[]"
context="{'group_by': 'is_incoming_material'}"/> context="{'group_by': 'is_incoming_material'}"/>
<filter name="group_by_supply_method" string="供货方式" domain="[]" <filter name="group_by_supply_method" string="供货方式" domain="[]"

View File

@@ -3,6 +3,7 @@ import logging
import re import re
from odoo import models, fields, api from odoo import models, fields, api
from odoo.exceptions import ValidationError
class ResProductCategory(models.Model): class ResProductCategory(models.Model):
@@ -47,11 +48,14 @@ class ResMrpBomMo(models.Model):
item.subcontractor_name = '' item.subcontractor_name = ''
def bom_create_line_has(self, embryo): def bom_create_line_has(self, embryo):
product = self.product_tmpl_id
if product.unit_number in (0, None, False):
raise ValidationError(f'产品{product.name}单件用量的值不能为{product.unit_number}')
vals = { vals = {
'bom_id': self.id, 'bom_id': self.id,
'product_id': embryo.id, 'product_id': embryo.id,
'product_tmpl_id': embryo.product_tmpl_id.id, 'product_tmpl_id': embryo.product_tmpl_id.id,
'product_qty': 1, 'product_qty': product.unit_number,
'product_uom_id': 1 'product_uom_id': 1
} }
return self.env['mrp.bom.line'].sudo().create(vals) return self.env['mrp.bom.line'].sudo().create(vals)
@@ -122,7 +126,7 @@ class ResMrpBomMo(models.Model):
# 查bom的原材料 # 查bom的原材料
def get_raw_bom(self, product): def get_raw_bom(self, product):
raw_bom = self.env['product.product'].search( raw_bom = self.env['product.product'].search(
[('categ_id.type', '=', '原材料'), ('materials_type_id', '=', product.materials_type_id.id)],limit=1) [('categ_id.type', '=', '原材料'), ('materials_type_id', '=', product.materials_type_id.id)], limit=1)
return raw_bom return raw_bom

View File

@@ -95,6 +95,8 @@
<page string="加工参数"> <page string="加工参数">
<group> <group>
<group string="模型"> <group string="模型">
<field name="blank_type" readonly="1"/>
<field name="blank_precision" readonly="1"/>
<label for="model_long" string="坯料尺寸[mm]"/> <label for="model_long" string="坯料尺寸[mm]"/>
<div class="o_address_format"> <div class="o_address_format">
<label for="model_long" string="长"/> <label for="model_long" string="长"/>
@@ -104,7 +106,7 @@
<label for="model_height" string="高"/> <label for="model_height" string="高"/>
<field name="model_height" class="o_address_zip"/> <field name="model_height" class="o_address_zip"/>
</div> </div>
<field name="blank_type" readonly="1"/> <field name="unit_number" readonly="1"/>
<field name="model_volume" string="体积[mm³]"/> <field name="model_volume" string="体积[mm³]"/>
<field name="product_model_type_id" string="模型类型"/> <field name="product_model_type_id" string="模型类型"/>
<field name="model_processing_panel" placeholder="例如R,U" string="加工面板" <field name="model_processing_panel" placeholder="例如R,U" string="加工面板"

View File

@@ -709,7 +709,9 @@ class Sf_Dashboard_Connect(http.Controller):
and o.create_date <= end_time and o.create_date <= end_time
) )
interval_orders = request.env['mrp.workorder'].sudo().browse(interval_plan_orders.mapped('res_id')) interval_order_ids = set(interval_plan_orders.mapped('res_id'))
interval_orders = request.env['mrp.workorder'].sudo().browse(interval_order_ids)
if line == '业绩总览': if line == '业绩总览':
interval_orders = interval_orders.filtered(lambda o: o.routing_type in ['人工线下加工', 'CNC加工']) interval_orders = interval_orders.filtered(lambda o: o.routing_type in ['人工线下加工', 'CNC加工'])
elif line == '人工线下加工中心': elif line == '人工线下加工中心':
@@ -862,33 +864,37 @@ class Sf_Dashboard_Connect(http.Controller):
""" """
# res = {'status': 1, 'message': '成功', 'not_done_data': [], 'done_data': []} # res = {'status': 1, 'message': '成功', 'not_done_data': [], 'done_data': []}
res = {'status': 1, 'message': '成功', 'data': {}} res = {'status': 1, 'message': '成功', 'data': {}}
# 解决产品名称取到英文的问题
request.update_context(lang='zh_CN')
plan_obj = request.env['sf.production.plan'].sudo() plan_obj = request.env['sf.production.plan'].sudo()
work_order_obj = request.env['mrp.workorder'].sudo() work_order_obj = request.env['mrp.workorder'].sudo()
# 获取mrp.workorder的state字段的selection内容
state_dict = dict(request.env['mrp.workorder'].sudo()._fields['state'].selection)
line_list = ast.literal_eval(kw['line_list']) line_list = ast.literal_eval(kw['line_list'])
begin_time_str = kw['begin_time'].strip('"') begin_time_str = kw['begin_time'].strip('"')
end_time_str = kw['end_time'].strip('"') end_time_str = kw['end_time'].strip('"')
begin_time = datetime.strptime(begin_time_str, '%Y-%m-%d %H:%M:%S') begin_time = datetime.strptime(begin_time_str, '%Y-%m-%d %H:%M:%S')
end_time = datetime.strptime(end_time_str, '%Y-%m-%d %H:%M:%S') end_time = datetime.strptime(end_time_str, '%Y-%m-%d %H:%M:%S')
# print('line_list: %s' % line_list) # print('line_list: %s' % line_list)
not_done_data = []
done_data = []
final_data = {} final_data = {}
not_done_index = 1
done_index = 1
# 获取当前时间并计算24小时前的时间 # 获取当前时间并计算24小时前的时间
current_time = datetime.now() current_time = datetime.now()
time_48_hours_ago = current_time - timedelta(hours=48) time_48_hours_ago = current_time - timedelta(hours=48)
# 计划量目前只能从mail.message中筛选出 # # 计划量目前只能从mail.message中筛选出
plan_order_messages = request.env['mail.message'].sudo().search([ # plan_order_messages = request.env['mail.message'].sudo().search([
('model', '=', 'mrp.workorder'), # ('model', '=', 'mrp.workorder'),
('create_date', '>=', time_48_hours_ago.strftime('%Y-%m-%d %H:%M:%S')), # ('create_date', '>=', time_48_hours_ago.strftime('%Y-%m-%d %H:%M:%S')),
('tracking_value_ids.field_desc', '=', '状态'), # ('tracking_value_ids.field_desc', '=', '状态'),
('tracking_value_ids.new_value_char', 'in', ['就绪', '生产中']) # ('tracking_value_ids.new_value_char', 'in', ['就绪', '生产中'])
]) # ])
for line in line_list: for line in line_list:
not_done_data = []
done_data = []
not_done_index = 1
done_index = 1
if line == '业绩总览': if line == '业绩总览':
work_order_domain = [('routing_type', 'in', ['人工线下加工', 'CNC加工'])] work_order_domain = [('routing_type', 'in', ['人工线下加工', 'CNC加工'])]
@@ -904,17 +910,12 @@ class Sf_Dashboard_Connect(http.Controller):
# [('production_line_id.name', '=', line), ('state', 'not in', ['finished']), # [('production_line_id.name', '=', line), ('state', 'not in', ['finished']),
# ('production_id.state', 'not in', ['cancel', 'done']), ('active', '=', True) # ('production_id.state', 'not in', ['cancel', 'done']), ('active', '=', True)
# ]) # ])
# not_done_orders = work_order_obj.search(work_order_domain + not_done_orders = work_order_obj.search(work_order_domain + [
# [('state', 'in', ['ready', 'progress'])], order='id asc' ('state', 'in', ['ready', 'progress']),
# ) ('date_planned_start', '>=', time_48_hours_ago),
not_done_orders = request.env['mrp.workorder'].sudo().browse(plan_order_messages.mapped('res_id')) ('date_planned_start', '<=', current_time)
if line == '业绩总览': ], order='id asc'
not_done_orders = not_done_orders.filtered(lambda o: o.routing_type in ['人工线下加工', 'CNC加工']) )
elif line == '人工线下加工中心':
not_done_orders = not_done_orders.filtered(lambda o: o.routing_type == '人工线下加工')
else:
not_done_orders = not_done_orders.filtered(lambda o: o.routing_type == 'CNC加工' and o.production_line_id.name == line)
# 完成订单 # 完成订单
# 获取当前时间并计算24小时前的时间 # 获取当前时间并计算24小时前的时间
@@ -922,11 +923,11 @@ class Sf_Dashboard_Connect(http.Controller):
# time_24_hours_ago = current_time - timedelta(hours=24) # time_24_hours_ago = current_time - timedelta(hours=24)
finish_orders = work_order_obj.search(work_order_domain + [ finish_orders = work_order_obj.search(work_order_domain + [
('state', 'in', ['finished']), ('state', 'in', ['done']),
('production_id.state', 'not in', ['cancel']), ('production_id.state', 'not in', ['cancel']),
('date_finished', '>=', time_48_hours_ago) ('date_finished', '>=', time_48_hours_ago)
], order='id asc') ], order='id asc')
# print(finish_orders) # logging.info('完成订单: %s' % finish_orders)
# 获取所有未完成订单的ID列表 # 获取所有未完成订单的ID列表
order_ids = [order.id for order in not_done_orders] order_ids = [order.id for order in not_done_orders]
@@ -962,14 +963,6 @@ class Sf_Dashboard_Connect(http.Controller):
material_match = re.search(material_pattern, blank_name) material_match = re.search(material_pattern, blank_name)
material = material_match.group(1) if material_match else 'No match found' material = material_match.group(1) if material_match else 'No match found'
state_dict = {
'draft': '待排程',
'done': '已排程',
'processing': '生产中',
'finished': '已完成',
'ready': '待加工',
'progress': '生产中',
}
line_dict = { line_dict = {
'sequence': not_done_index, 'sequence': not_done_index,
@@ -985,8 +978,6 @@ class Sf_Dashboard_Connect(http.Controller):
not_done_index += 1 not_done_index += 1
for finish_order in finish_orders: for finish_order in finish_orders:
if not finish_order.actual_end_time:
continue
blank_name = '' blank_name = ''
try: try:
blank_name = finish_order.production_id.move_raw_ids[0].product_id.name blank_name = finish_order.production_id.move_raw_ids[0].product_id.name
@@ -1002,13 +993,13 @@ class Sf_Dashboard_Connect(http.Controller):
line_dict = { line_dict = {
'sequence': done_index, 'sequence': done_index,
'workorder_name': finish_order.name, 'workorder_name': finish_order.production_id.name,
'blank_name': blank_name, 'blank_name': blank_name,
'material': material, 'material': material,
'dimensions': dimensions, 'dimensions': dimensions,
'order_qty': order.qty_produced, 'order_qty': finish_order.qty_produced,
'finish_time': finish_order.actual_end_time.strftime( 'finish_time': finish_order.date_finished.strftime(
'%Y-%m-%d %H:%M:%S') if finish_order.actual_end_time else ' ' '%Y-%m-%d %H:%M:%S') if finish_order.date_finished else ' '
} }
done_data.append(line_dict) done_data.append(line_dict)

View File

@@ -1710,76 +1710,7 @@ class MrpProduction(models.Model):
else: else:
vals['procurement_group_id'] = is_custemer_group_id[key] vals['procurement_group_id'] = is_custemer_group_id[key]
productions = super(MrpProduction, self).create(vals_list) return super(MrpProduction, self).create(vals_list)
# 查询成品工序排序(自动化产线加工),供后续使用
product_model_type_routing_sorts = self.env['sf.product.model.type.routing.sort'].search([], order='sequence asc')
# 查询成品工序排序(人工线下加工),供后续使用
manual_product_model_type_routing_sorts = self.env['sf.manual.product.model.type.routing.sort'].search([], order='sequence asc')
# 查询坯料工序排序,供后续使用
embryo_model_type_routing_sorts = self.env['sf.embryo.model.type.routing.sort'].search([], order='sequence asc')
for production in productions:
# 生成序列号
production.action_generate_serial()
# 创建工序模板
technology_design_values = []
i = 0
if production.product_id.categ_id.type == '成品':
# 根据加工面板的面数及成品工序模板生成工序设计
if production.production_type == '自动化产线加工':
product_routing_workcenter = product_model_type_routing_sorts.filtered(
lambda s: s.product_model_type_id.id == production.product_id.product_model_type_id.id
)
else:
product_routing_workcenter = manual_product_model_type_routing_sorts.filtered(
lambda s: s.manual_product_model_type_id.id == production.product_id.product_model_type_id.id
)
if production.production_type == '自动化产线加工':
for k in (production.product_id.model_processing_panel.split(',')):
for route in product_routing_workcenter:
i += 1
technology_design_values.append(
self.env['sf.technology.design'].json_technology_design_str(k, route, i, False)
)
elif production.production_type == '人工线下加工':
for route in product_routing_workcenter:
i += 1
technology_design_values.append(
self.env['sf.technology.design'].json_technology_design_str('ZM', route, i, False)
)
else:
for route in product_routing_workcenter:
i += 1
technology_design_values.append(
self.env['sf.technology.design'].json_technology_design_str(False, route, i, False)
)
elif production.product_id.categ_id.type == '坯料':
embryo_routing_workcenter = embryo_model_type_routing_sorts.filtered(
lambda s: s.embryo_model_type_id.id == production.product_id.embryo_model_type_id.id
)
for route_embryo in embryo_routing_workcenter:
i += 1
technology_design_values.append(
self.env['sf.technology.design'].json_technology_design_str(False, route_embryo, i, False)
)
# 处理表面工艺
for item in production.product_id.product_model_type_id.surface_technics_routing_tmpl_ids:
if item.route_workcenter_id.surface_technics_id.id:
for process_param in production.product_id.model_process_parameters_ids:
if item.route_workcenter_id.surface_technics_id == process_param.process_id:
technology_design_values.append(
self.env['sf.technology.design'].json_technology_design_str(
False,
item.route_workcenter_id,
i,
process_param
)
)
production.technology_design_ids = technology_design_values
# 设置制造订单状态为待工艺确认
productions.write({'state': 'technology_to_confirmed'})
return productions
@api.depends('procurement_group_id.stock_move_ids.created_purchase_line_id.order_id', @api.depends('procurement_group_id.stock_move_ids.created_purchase_line_id.order_id',
'procurement_group_id.stock_move_ids.move_orig_ids.purchase_line_id.order_id') 'procurement_group_id.stock_move_ids.move_orig_ids.purchase_line_id.order_id')

View File

@@ -27,13 +27,15 @@ class ResProductMo(models.Model):
categ_type = fields.Selection(string='产品的类别', related='categ_id.type', store=True) categ_type = fields.Selection(string='产品的类别', related='categ_id.type', store=True)
model_name = fields.Char('模型名称') model_name = fields.Char('模型名称')
blank_type = fields.Selection([('圆料', '圆料'), ('方料', '方料')], string='坯料分类') blank_type = fields.Selection([('圆料', '圆料'), ('方料', '方料')], string='坯料分类')
blank_precision = fields.Selection([('精坯', '精坯'), ('粗坯', '粗坯')], string='坯料类型')
model_long = fields.Float('模型长(mm)', digits=(16, 3)) model_long = fields.Float('模型长(mm)', digits=(16, 3))
model_width = fields.Float('模型宽(mm)', digits=(16, 3)) model_width = fields.Float('模型宽(mm)', digits=(16, 3))
model_height = fields.Float('模型高(mm)', digits=(16, 3)) model_height = fields.Float('模型高(mm)', digits=(16, 3))
unit_number = fields.Float('单件用量', digits=(16, 3), default=1)
model_volume = fields.Float('模型体积(m³)') model_volume = fields.Float('模型体积(m³)')
model_area = fields.Float('模型表面积(m²)') model_area = fields.Float('模型表面积(m²)')
model_machining_precision = fields.Selection(selection=_get_machining_precision, string='加工精度') model_machining_precision = fields.Selection(selection=_get_machining_precision, string='加工精度')
model_processing_panel = fields.Char('模型加工面板') model_processing_panel = fields.Char('模型加工面板', default='')
model_remark = fields.Char('模型备注说明') model_remark = fields.Char('模型备注说明')
length = fields.Float('长(mm)', digits=(16, 3)) length = fields.Float('长(mm)', digits=(16, 3))
width = fields.Float('宽(mm)', digits=(16, 3)) width = fields.Float('宽(mm)', digits=(16, 3))
@@ -901,15 +903,17 @@ class ResProductMo(models.Model):
vals = { vals = {
'name': product_name, 'name': product_name,
'blank_type': item.get('blank_type'), 'blank_type': item.get('blank_type'),
'blank_precision': item.get('blank_precision'),
'model_long': item.get('blank_length') if blank_bool else self.format_float(item['model_long'] + embryo_redundancy_id.long), 'model_long': item.get('blank_length') if blank_bool else self.format_float(item['model_long'] + embryo_redundancy_id.long),
'model_width': item.get('blank_width') if blank_bool else self.format_float(item['model_width'] + embryo_redundancy_id.width), 'model_width': item.get('blank_width') if blank_bool else self.format_float(item['model_width'] + embryo_redundancy_id.width),
'model_height': item.get('blank_height') if blank_bool else self.format_float(item['model_height'] + embryo_redundancy_id.height), 'model_height': item.get('blank_height') if blank_bool else self.format_float(item['model_height'] + embryo_redundancy_id.height),
'unit_number': item.get('unit_number'),
'model_volume': self.format_float(((item['model_long'] + embryo_redundancy_id.long) * 'model_volume': self.format_float(((item['model_long'] + embryo_redundancy_id.long) *
(item['model_width'] + embryo_redundancy_id.width) * (item['model_width'] + embryo_redundancy_id.width) *
(item['model_height'] + embryo_redundancy_id.height))) if not blank_bool else ( (item['model_height'] + embryo_redundancy_id.height))) if not blank_bool else (
item.get('blank_length') * item.get('blank_width') * item.get('blank_height')), item.get('blank_length') * item.get('blank_width') * item.get('blank_height')),
'product_model_type_id': model_type.id, 'product_model_type_id': model_type.id,
'model_processing_panel': item['processing_panel_detail'], 'model_processing_panel': item['processing_panel_detail'] if item['processing_panel_detail'] else '',
'model_machining_precision': item['model_machining_precision'], 'model_machining_precision': item['model_machining_precision'],
'model_code': item['barcode'], 'model_code': item['barcode'],
'length': item['model_long'], 'length': item['model_long'],

View File

@@ -21,6 +21,7 @@ from odoo.addons.sf_base.commons.common import Common
from odoo.exceptions import UserError from odoo.exceptions import UserError
from io import BytesIO from io import BytesIO
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
from dateutil.relativedelta import relativedelta
class stockWarehouse(models.Model): class stockWarehouse(models.Model):
@@ -163,203 +164,203 @@ class StockRule(models.Model):
[('res_id', '=', res_id), ('res_field', '=', res_field)], limit=1) [('res_id', '=', res_id), ('res_field', '=', res_field)], limit=1)
attachment_info.write({'name': name}) attachment_info.write({'name': name})
# @api.model @api.model
# def _run_manufacture(self, procurements): def _run_manufacture(self, procurements):
# productions_values_by_company = defaultdict(list) productions_values_by_company = defaultdict(list)
# errors = [] errors = []
# for procurement, rule in procurements: for procurement, rule in procurements:
# if float_compare(procurement.product_qty, 0, precision_rounding=procurement.product_uom.rounding) <= 0: if float_compare(procurement.product_qty, 0, precision_rounding=procurement.product_uom.rounding) <= 0:
# # If procurement contains negative quantity, don't create a MO that would be for a negative value. # If procurement contains negative quantity, don't create a MO that would be for a negative value.
# continue continue
# bom = rule._get_matching_bom(procurement.product_id, procurement.company_id, procurement.values) bom = rule._get_matching_bom(procurement.product_id, procurement.company_id, procurement.values)
# productions_values_by_company[procurement.company_id.id].append(rule._prepare_mo_vals(*procurement, bom)) productions_values_by_company[procurement.company_id.id].append(rule._prepare_mo_vals(*procurement, bom))
# if errors: if errors:
# raise ProcurementException(errors) raise ProcurementException(errors)
# for company_id, productions_values in productions_values_by_company.items(): for company_id, productions_values in productions_values_by_company.items():
# # create the MO as SUPERUSER because the current user may not have the rights to do it # create the MO as SUPERUSER because the current user may not have the rights to do it
# # (mto product launched by a sale for example) # (mto product launched by a sale for example)
# '''创建制造订单''' '''创建制造订单'''
# productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company(company_id).create( productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company(company_id).create(
# productions_values) productions_values)
# ''' '''
# 创建工单 创建工单
# ''' '''
# # productions._create_workorder() # productions._create_workorder()
# # #
# # self.env['stock.move'].sudo().create(productions._get_moves_finished_values()) # self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
# productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \ productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \
# ( (
# p.move_dest_ids.procure_method != 'make_to_order' and not p.move_dest_ids.procure_method != 'make_to_order' and not
# p.move_raw_ids and not p.workorder_ids)).action_confirm() p.move_raw_ids and not p.workorder_ids)).action_confirm()
# # 处理 根据制造订单生成的采购单坯料入库时到原材料库,手动将原材料位置该为坯料存货区 # 处理 根据制造订单生成的采购单坯料入库时到原材料库,手动将原材料位置该为坯料存货区
# for production in productions: for production in productions:
# if production.picking_ids: if production.picking_ids:
# product_type_id = production.picking_ids[0].move_ids[0].product_id.categ_id product_type_id = production.picking_ids[0].move_ids[0].product_id.categ_id
# if product_type_id.name == '坯料': if product_type_id.name == '坯料':
# location_id = self.env['stock.location'].search([('name', '=', '坯料存货区')]) location_id = self.env['stock.location'].search([('name', '=', '坯料存货区')])
# if not location_id: if not location_id:
# logging.info(f'没有搜索到【坯料存货区】: {location_id}') logging.info(f'没有搜索到【坯料存货区】: {location_id}')
# break break
# for picking_id in production.picking_ids: for picking_id in production.picking_ids:
# if picking_id.picking_type_id.name == '内部调拨': if picking_id.picking_type_id.name == '内部调拨':
# if picking_id.location_dest_id.product_type != product_type_id: if picking_id.location_dest_id.product_type != product_type_id:
# picking_id.location_dest_id = location_id.id picking_id.location_dest_id = location_id.id
# elif picking_id.picking_type_id.name == '生产发料': elif picking_id.picking_type_id.name == '生产发料':
# if picking_id.location_id.product_type != product_type_id: if picking_id.location_id.product_type != product_type_id:
# picking_id.location_id = location_id.id picking_id.location_id = location_id.id
# for production in productions: for production in productions:
# ''' '''
# 创建制造订单时生成序列号 创建制造订单时生成序列号
# ''' '''
# # production.action_generate_serial() production.action_generate_serial()
# origin_production = production.move_dest_ids and production.move_dest_ids[ origin_production = production.move_dest_ids and production.move_dest_ids[
# 0].raw_material_production_id or False 0].raw_material_production_id or False
# orderpoint = production.orderpoint_id orderpoint = production.orderpoint_id
# if orderpoint and orderpoint.create_uid.id == SUPERUSER_ID and orderpoint.trigger == 'manual': if orderpoint and orderpoint.create_uid.id == SUPERUSER_ID and orderpoint.trigger == 'manual':
# production.message_post( production.message_post(
# body=_('This production order has been created from Replenishment Report.'), body=_('This production order has been created from Replenishment Report.'),
# message_type='comment', message_type='comment',
# subtype_xmlid='mail.mt_note') subtype_xmlid='mail.mt_note')
# elif orderpoint: elif orderpoint:
# production.message_post_with_view( production.message_post_with_view(
# 'mail.message_origin_link', 'mail.message_origin_link',
# values={'self': production, 'origin': orderpoint}, values={'self': production, 'origin': orderpoint},
# subtype_id=self.env.ref('mail.mt_note').id) subtype_id=self.env.ref('mail.mt_note').id)
# elif origin_production: elif origin_production:
# production.message_post_with_view( production.message_post_with_view(
# 'mail.message_origin_link', 'mail.message_origin_link',
# values={'self': production, 'origin': origin_production}, values={'self': production, 'origin': origin_production},
# subtype_id=self.env.ref('mail.mt_note').id) subtype_id=self.env.ref('mail.mt_note').id)
# ''' '''
# 创建生产计划 创建生产计划
# ''' '''
# # 工单耗时 # 工单耗时
# # workorder_duration = 0 workorder_duration = 0
# # for workorder in production.workorder_ids: for workorder in production.workorder_ids:
# # workorder_duration += workorder.duration_expected workorder_duration += workorder.duration_expected
# # sale_order = self.env['sale.order'].sudo().search([('name', '=', production.origin)]) sale_order = self.env['sale.order'].sudo().search([('name', '=', production.origin)])
# # # 如果订单为空,则获取来源制造订单的销售单 # 如果订单为空,则获取来源制造订单的销售单
# # if not sale_order: if not sale_order:
# # mrp_production = self.env['mrp.production'].sudo().search([('name', '=', production.origin)], mrp_production = self.env['mrp.production'].sudo().search([('name', '=', production.origin)],
# # limit=1) limit=1)
# # if mrp_production: if mrp_production:
# # sale_order = self.env['sale.order'].sudo().search([('name', '=', mrp_production.origin)]) sale_order = self.env['sale.order'].sudo().search([('name', '=', mrp_production.origin)])
# # else: else:
# # mrp_production = production mrp_production = production
# # # if sale_order: # if sale_order:
# # # sale_order.write({'schedule_status': 'to schedule'}) # sale_order.write({'schedule_status': 'to schedule'})
# # self.env['sf.production.plan'].sudo().with_company(company_id).create({ self.env['sf.production.plan'].sudo().with_company(company_id).create({
# # 'name': production.name, 'name': production.name,
# # 'order_deadline': sale_order.deadline_of_delivery, 'order_deadline': sale_order.deadline_of_delivery,
# # 'production_id': production.id, 'production_id': production.id,
# # 'date_planned_start': production.date_planned_start, 'date_planned_start': production.date_planned_start,
# # 'origin': mrp_production.origin, 'origin': mrp_production.origin,
# # 'product_qty': production.product_qty, 'product_qty': production.product_qty,
# # 'product_id': production.product_id.id, 'product_id': production.product_id.id,
# # 'state': 'draft', 'state': 'draft',
# # }) })
# all_production = productions all_production = productions
# grouped_product_ids = {k: list(g) for k, g in groupby(all_production, key=lambda x: x.product_id.id)} grouped_product_ids = {k: list(g) for k, g in groupby(all_production, key=lambda x: x.product_id.id)}
# # 初始化一个字典来存储每个product_id对应的生产订单名称列表 # 初始化一个字典来存储每个product_id对应的生产订单名称列表
# product_id_to_production_names = {} product_id_to_production_names = {}
# # 对于每个product_id获取其所有生产订单的名称 # 对于每个product_id获取其所有生产订单的名称
# for product_id, all_production in grouped_product_ids.items(): for product_id, all_production in grouped_product_ids.items():
# # 为同一个product_id创建一个生产订单名称列表 # 为同一个product_id创建一个生产订单名称列表
# product_id_to_production_names[product_id] = [production.name for production in all_production] product_id_to_production_names[product_id] = [production.name for production in all_production]
# for production_item in productions: for production_item in productions:
# technology_design_values = [] technology_design_values = []
# # production_programming = self.env['mrp.production'].search( production_programming = self.env['mrp.production'].search(
# # [('product_id.id', '=', production_item.product_id.id), [('product_id.id', '=', production_item.product_id.id),
# # ('origin', '=', production_item.origin)], ('origin', '=', production_item.origin)],
# # limit=1, order='id asc') limit=1, order='id asc')
# # if production_item.product_id.id in product_id_to_production_names: if production_item.product_id.id in product_id_to_production_names:
# # # 同一个产品多个制造订单对应一个编程单和模型库 # 同一个产品多个制造订单对应一个编程单和模型库
# # # 只调用一次fetchCNC并将所有生产订单的名称作为字符串传递 # 只调用一次fetchCNC并将所有生产订单的名称作为字符串传递
# # if not production_item.programming_no and production_item.production_type in ['自动化产线加工', if not production_item.programming_no and production_item.production_type in ['自动化产线加工',
# # '人工线下加工']: '人工线下加工']:
# # if not production_programming.programming_no: if not production_programming.programming_no:
# # production_item.fetchCNC( production_item.fetchCNC(
# # ', '.join(product_id_to_production_names[production_item.product_id.id])) ', '.join(product_id_to_production_names[production_item.product_id.id]))
# # else: else:
# # production_item.write({'programming_no': production_programming.programming_no, production_item.write({'programming_no': production_programming.programming_no,
# # 'programming_state': '编程中'}) 'programming_state': '编程中'})
# i = 0 i = 0
# if production_item.product_id.categ_id.type == '成品': if production_item.product_id.categ_id.type == '成品':
# # 根据加工面板的面数及成品工序模板生成工序设计 # 根据加工面板的面数及成品工序模板生成工序设计
# if production_item.production_type == '自动化产线加工': if production_item.production_type == '自动化产线加工':
# model = 'sf.product.model.type.routing.sort' model = 'sf.product.model.type.routing.sort'
# domain = [ domain = [
# ('product_model_type_id', '=', production_item.product_id.product_model_type_id.id)] ('product_model_type_id', '=', production_item.product_id.product_model_type_id.id)]
# else: else:
# model = 'sf.manual.product.model.type.routing.sort' model = 'sf.manual.product.model.type.routing.sort'
# domain = [('manual_product_model_type_id', '=', domain = [('manual_product_model_type_id', '=',
# production_item.product_id.product_model_type_id.id)] production_item.product_id.product_model_type_id.id)]
# product_routing_workcenter = self.env[model].search(domain, order='sequence asc') product_routing_workcenter = self.env[model].search(domain, order='sequence asc')
# if production_item.production_type == '自动化产线加工': if production_item.production_type == '自动化产线加工':
# for k in (production_item.product_id.model_processing_panel.split(',')): for k in (production_item.product_id.model_processing_panel.split(',')):
# for route in product_routing_workcenter: for route in product_routing_workcenter:
# i += 1 i += 1
# technology_design_values.append( technology_design_values.append(
# self.env['sf.technology.design'].json_technology_design_str(k, route, i, False)) self.env['sf.technology.design'].json_technology_design_str(k, route, i, False))
# elif production_item.production_type == '人工线下加工': elif production_item.production_type == '人工线下加工':
# for route in product_routing_workcenter: for route in product_routing_workcenter:
# i += 1 i += 1
# technology_design_values.append( technology_design_values.append(
# self.env['sf.technology.design'].json_technology_design_str('ZM', route, i, False)) self.env['sf.technology.design'].json_technology_design_str('ZM', route, i, False))
# else: else:
# for route in product_routing_workcenter: for route in product_routing_workcenter:
# i += 1 i += 1
# technology_design_values.append( technology_design_values.append(
# self.env['sf.technology.design'].json_technology_design_str(False, route, i, False)) self.env['sf.technology.design'].json_technology_design_str(False, route, i, False))
# elif production_item.product_id.categ_id.type == '坯料': elif production_item.product_id.categ_id.type == '坯料':
# embryo_routing_workcenter = self.env['sf.embryo.model.type.routing.sort'].search( embryo_routing_workcenter = self.env['sf.embryo.model.type.routing.sort'].search(
# [('embryo_model_type_id', '=', production_item.product_id.embryo_model_type_id.id)], [('embryo_model_type_id', '=', production_item.product_id.embryo_model_type_id.id)],
# order='sequence asc' order='sequence asc'
# ) )
# for route_embryo in embryo_routing_workcenter: for route_embryo in embryo_routing_workcenter:
# i += 1 i += 1
# technology_design_values.append( technology_design_values.append(
# self.env['sf.technology.design'].json_technology_design_str(False, route_embryo, i, self.env['sf.technology.design'].json_technology_design_str(False, route_embryo, i,
# False)) False))
# surface_technics_arr = [] surface_technics_arr = []
# route_workcenter_arr = [] route_workcenter_arr = []
# for item in production_item.product_id.product_model_type_id.surface_technics_routing_tmpl_ids: for item in production_item.product_id.product_model_type_id.surface_technics_routing_tmpl_ids:
# if item.route_workcenter_id.surface_technics_id.id: if item.route_workcenter_id.surface_technics_id.id:
# for process_param in production_item.product_id.model_process_parameters_ids: for process_param in production_item.product_id.model_process_parameters_ids:
# if item.route_workcenter_id.surface_technics_id == process_param.process_id: if item.route_workcenter_id.surface_technics_id == process_param.process_id:
# surface_technics_arr.append( surface_technics_arr.append(
# item.route_workcenter_id.surface_technics_id.id) item.route_workcenter_id.surface_technics_id.id)
# route_workcenter_arr.append(item.route_workcenter_id.id) route_workcenter_arr.append(item.route_workcenter_id.id)
# if surface_technics_arr: if surface_technics_arr:
# production_process = self.env['sf.production.process'].search( production_process = self.env['sf.production.process'].search(
# [('id', 'in', surface_technics_arr)], [('id', 'in', surface_technics_arr)],
# order='sequence asc' order='sequence asc'
# ) )
# for p in production_process: for p in production_process:
# logging.info('production_process:%s' % p.name) logging.info('production_process:%s' % p.name)
# process_parameters = production_item.product_id.model_process_parameters_ids.filtered( process_parameters = production_item.product_id.model_process_parameters_ids.filtered(
# lambda pm: pm.process_id.id == p.id) lambda pm: pm.process_id.id == p.id)
# for process_parameter in process_parameters: for process_parameter in process_parameters:
# i += 1 i += 1
# route_production_process = self.env[ route_production_process = self.env[
# 'mrp.routing.workcenter'].search( 'mrp.routing.workcenter'].search(
# [('surface_technics_id', '=', p.id), [('surface_technics_id', '=', p.id),
# ('id', 'in', route_workcenter_arr)]) ('id', 'in', route_workcenter_arr)])
# technology_design_values.append( technology_design_values.append(
# self.env['sf.technology.design'].json_technology_design_str(False, self.env['sf.technology.design'].json_technology_design_str(False,
# route_production_process, route_production_process,
# i, i,
# process_parameter)) process_parameter))
# production_item.technology_design_ids = technology_design_values production_item.technology_design_ids = technology_design_values
# productions.write({'state': 'technology_to_confirmed'}) productions.write({'state': 'technology_to_confirmed'})
# return True return True
class ProductionLot(models.Model): class ProductionLot(models.Model):
@@ -727,6 +728,33 @@ class StockPicking(models.Model):
production.workorder_ids.write({'back_button_display': False}) production.workorder_ids.write({'back_button_display': False})
return res return res
def _prepare_subcontract_mo_vals(self, subcontract_move, bom):
subcontract_move.ensure_one()
group = self.env['procurement.group'].sudo().search([('name', '=', self.name)])
if not group:
group = self.env['procurement.group'].create({
'name': self.name,
'partner_id': self.partner_id.id,
})
product = subcontract_move.product_id
warehouse = self._get_warehouse(subcontract_move)
vals = {
'company_id': subcontract_move.company_id.id,
'procurement_group_id': group.id,
'subcontractor_id': subcontract_move.picking_id.partner_id.commercial_partner_id.id,
'picking_ids': [subcontract_move.picking_id.id],
'product_id': product.id,
'product_uom_id': subcontract_move.product_uom.id,
'bom_id': bom.id,
'location_src_id': subcontract_move.picking_id.partner_id.with_company(subcontract_move.company_id).property_stock_subcontractor.id,
'location_dest_id': subcontract_move.picking_id.partner_id.with_company(subcontract_move.company_id).property_stock_subcontractor.id,
'product_qty': subcontract_move.product_uom_qty,
'picking_type_id': warehouse.subcontracting_type_id.id,
'date_planned_start': subcontract_move.date - relativedelta(days=product.produce_delay)
}
return vals
# 创建 外协出库入单 # 创建 外协出库入单
def create_outcontract_picking(self, workorders, item, sorted_workorders): def create_outcontract_picking(self, workorders, item, sorted_workorders):
production = workorders[0].production_id production = workorders[0].production_id

View File

@@ -2,4 +2,3 @@ from . import ftp_operate
from . import res_config_setting from . import res_config_setting
from . import sync_common from . import sync_common
from . import order_price from . import order_price
from . import mrp_production

View File

@@ -1,44 +0,0 @@
from itertools import groupby
from odoo import models, api
from odoo.tools.misc import OrderedSet
class MrpProduction(models.Model):
_inherit = 'mrp.production'
@api.model_create_multi
def create(self, vals_list):
"""
生成编程单
"""
productions = super().create(vals_list)
# 定义变量存储编程单
grouped_product_programming_no = {}
# 定义产品拼接成的制造订单名称
grouped_product_production_name = {}
# 查出所有的制造订单,为了适配通过补货生成的制造订单
all_productions = self.env['mrp.production'].search([('origin', '=', productions[0].origin)])
# 将不同产品的制造订单进行分组
grouped_product_productions = {k: list(g) for k, g in groupby(all_productions, key=lambda x: x.product_id.id)}
for product_id, grouped_productions in grouped_product_productions.items():
# 产品对应的编程单号
if product_id not in grouped_product_programming_no:
# 使用列表推导式获取非空的programming_no
programming_nos = [p.programming_no for p in grouped_productions if p.programming_no if p.programming_no is not False]
if programming_nos:
grouped_product_programming_no[product_id] = programming_nos[0]
grouped_product_production_name[product_id] = ','.join(list(map(lambda p:p.name, grouped_productions)))
# 同一个产品的制造订单只请求一次CNC编程
for production in productions:
if not production.programming_no and production.production_type in ['自动化产线加工','人工线下加工']:
if production.product_id.id not in grouped_product_programming_no:
production.fetchCNC(grouped_product_production_name[production.product_id.id])
grouped_product_programming_no[production.product_id.id] = production.programming_no
else:
production.write({
'programming_no': grouped_product_programming_no[production.product_id.id],
'programming_state': '编程中'
})
return productions

View File

@@ -3,4 +3,3 @@
from . import custom_plan from . import custom_plan
from . import change_manufactuing from . import change_manufactuing
from . import mrp_production

View File

@@ -1,41 +0,0 @@
from odoo import models, api
class MrpProduction(models.Model):
_inherit = 'mrp.production'
@api.model_create_multi
def create(self, vals_list):
"""
创建生产计划
"""
productions = super().create(vals_list)
for production in productions:
# 工单耗时
workorder_duration = 0
for workorder in production.workorder_ids:
workorder_duration += workorder.duration_expected
sale_order = self.env['sale.order'].sudo().search([('name', '=', production.origin)])
# 如果订单为空,则获取来源制造订单的销售单
if not sale_order:
mrp_production = self.env['mrp.production'].sudo().search([('name', '=', production.origin)],
limit=1)
if mrp_production:
sale_order = self.env['sale.order'].sudo().search([('name', '=', mrp_production.origin)])
else:
mrp_production = production
# if sale_order:
# sale_order.write({'schedule_status': 'to schedule'})
self.env['sf.production.plan'].sudo().with_company(production.company_id).create({
'name': production.name,
'order_deadline': sale_order.deadline_of_delivery,
'production_id': production.id,
'date_planned_start': production.date_planned_start,
'origin': mrp_production.origin,
'product_qty': production.product_qty,
'product_id': production.product_id.id,
'state': 'draft',
})
return productions

View File

@@ -1,59 +1,180 @@
import logging
from odoo import api, models from odoo import api, models
from odoo.exceptions import ValidationError, UserError
class StockPicking(models.Model): class StockPicking(models.Model):
_inherit = 'stock.picking' _inherit = 'stock.picking'
def _compute_check(self):
super()._compute_check()
for picking in self:
picking_to_quality = picking.get_picking_to_quality()
if not picking_to_quality:
picking.quality_check_todo = False
break
else:
need_quality_line = picking.get_need_quality_line(picking_to_quality)
if not need_quality_line or all(not line.get('need_done_check_ids') for line in need_quality_line):
picking.quality_check_todo = False
def check_quality(self):
self.ensure_one()
# checkable_products = self.mapped('move_line_ids').mapped('product_id')
# checks = self.check_ids.filtered(lambda check: check.quality_state == 'none' and (
# check.product_id in checkable_products or check.measure_on == 'operation'))
checks = self.env['quality.check']
picking_to_quality = self._get_picking_to_quality()
need_quality_line = self.get_need_quality_line(picking_to_quality)
if need_quality_line and any(line.get('need_done_check_ids') for line in need_quality_line):
for item in need_quality_line:
checks += item.get('need_done_check_ids')
if checks:
return checks.action_open_quality_check_wizard()
return False
def button_validate(self): def button_validate(self):
""" """=
出厂检验报告上传 出厂检验报告上传
""" """
out_quality_checks = self.env['quality.check'].search( out_quality_checks = self.env['quality.check'].search(
[('picking_id', '=', self.id), ('test_type_id.name', '=', '出厂检验报告')]) [('picking_id', '=', self.id), ('test_type_id.name', '=', '出厂检验报告'),
('quality_state', '=', 'pass')])
# out_quality_checks 可能存在多个 # out_quality_checks 可能存在多个
if out_quality_checks: if out_quality_checks:
for out_quality_check in out_quality_checks: for out_quality_check in out_quality_checks:
if not out_quality_check.is_factory_report_uploaded: if not out_quality_check.is_factory_report_uploaded:
if out_quality_check and self.state == 'assigned': if out_quality_check and self.state == 'assigned':
out_quality_check.upload_factory_report() out_quality_check.upload_factory_report()
quality_action = self.pinking_checkout_quality()
if quality_action:
return quality_action
res = super(StockPicking, self).button_validate()
return res
def pinking_checkout_quality(self):
""" """
调拨单若关联了质量检查单,验证调拨单时,应校验是否有不合格品,若存在,应弹窗提示: 调拨单若关联了质量检查单,验证调拨单时,应校验是否有不合格品,若存在,应弹窗提示:
“警告存在不合格产品XXXX n 件、YYYYY m件继续调拨请点“确认”否则请取消 “警告存在不合格产品XXXX n 件、YYYYY m件继续调拨请点“确认”否则请取消
""" """
context = self.env.context try:
if not context.get('again_validate') and self.quality_check_ids.filtered(lambda qc: qc.quality_state == 'fail'): self.ensure_one()
# 回滚事务,为二次确认/取消做准备 context = self.env.context
self.env.cr.rollback() if not context.get('pinking_checkout_quality'):
quality_check_ids = self.quality_check_ids.filtered(lambda qc: qc.quality_state == 'fail') picking_to_quality = self._get_picking_to_quality()
product_list = list(set([quality_check_id.product_id for quality_check_id in quality_check_ids])) if not picking_to_quality: return False
fail_check_text = '' need_quality_val = self.get_need_quality_line(picking_to_quality)
for product_id in product_list: if any(line.get('fail_check_ids') for line in need_quality_val):
check_ids = quality_check_ids.filtered(lambda qc: qc.product_id == product_id) # 回滚事务,为二次确认/取消做准备
if all(check_id.measure_on == 'move_line' for check_id in check_ids): self.env.cr.rollback()
number = sum(check_ids.mapped('qty_line')) # 获取存在失败的 质检单 调拨单明细行
else: check_list = [item for item in need_quality_val if item.get('fail_check_ids')]
number = sum(self.move_ids_without_package.filtered( fail_check_text = ''
lambda ml: ml.product_id == product_id).mapped('quantity_done')) for item in check_list:
if number == 0: move_id, pre_done_qty = item.get('move_id'), item.get('pre_done_qty')
number = sum(self.move_ids_without_package.filtered( fail_check_text = (f'{fail_check_text}{move_id.product_id.display_name} {pre_done_qty}'
lambda ml: ml.product_id == product_id).mapped('reserved_availability')) if fail_check_text != '' else f'{move_id.product_id.display_name} {pre_done_qty}')
if number == 0: return {
number = sum(self.move_ids_without_package.filtered( 'type': 'ir.actions.act_window',
lambda ml: ml.product_id == product_id).mapped('product_uom_qty')) 'res_model': 'picking.validate.check.wizard',
fail_check_text = (f'{fail_check_text}{product_id.display_name} {number}' 'name': '质检不合格提示',
if fail_check_text != '' else f'{product_id.display_name} {number}') 'view_mode': 'form',
return { 'target': 'new',
'type': 'ir.actions.act_window', 'context': {
'res_model': 'picking.validate.check.wizard', 'default_picking_id': self.id,
'name': '质检不合格提示', 'default_fail_check_text': f'警告:存在不合格产品{fail_check_text},继续调拨请点“确认”,否则请取消?',
'view_mode': 'form', 'pinking_checkout_quality': True}
'target': 'new', }
'context': { else:
'default_picking_id': self.id, return False
'default_fail_check_text': f'警告:存在不合格产品{fail_check_text},继续调拨请点“确认”,否则请取消?', except Exception as e:
'again_validate': True} logging.info('pinking_checkout_quality()方法报错:%s' % e)
} raise ValidationError('调拨单验证质检单是否合格时报错,请联系管理员处理!!')
res = super(StockPicking, self).button_validate()
def get_need_quality_line(self, picking_to_quality):
"""
# 对需要进行质检,还没有质检完成的明细行进行统计
# 1、当【质量标准_控制方式】=“产品、作业”,仅校验“预完成数量”>0的产品行对应的质检单必须处理。
2、当【质量标准_控制方式】=“数量”时,仅校验“预完成数量”>0的产品行对应的质检单必须处理
1每一类的“总单数”=【调拨单_需求】时则已处理的质检单“单数”≥“预完成数量”时可执行调拨单验证
2每一类的“总单数”<【调拨单_需求】时则已处理的质检单“单数”≥0时可执行调拨单验证
"""
res = []
for item in picking_to_quality:
need_done_check_ids = self.env['quality.check']
fail_check_ids = self.env['quality.check']
move_id, pre_done_qty, check_ids = item.values()
check_ids_1 = check_ids.filtered(lambda qc: qc.measure_on in ('operation', 'product'))
if check_ids_1:
check_ids_1_done = check_ids_1.filtered(lambda qc: qc.quality_state in ('pass', 'fail'))
check_ids_1_fail = check_ids_1.filtered(lambda qc: qc.quality_state == 'fail')
check_ids_1_none = check_ids_1.filtered(lambda qc: qc.quality_state == 'none')
if check_ids_1 and not check_ids_1_done:
need_done_check_ids += check_ids_1_none
if check_ids_1_fail:
fail_check_ids += check_ids_1_fail
check_ids_2 = check_ids.filtered(lambda qc: qc.measure_on == 'move_line')
if check_ids_2:
check_ids_2_done = check_ids_2.filtered(lambda qc: qc.quality_state in ('pass', 'fail'))
check_ids_2_fail = check_ids_2.filtered(lambda qc: qc.quality_state == 'fail')
check_ids_2_none = check_ids_2.filtered(lambda qc: qc.quality_state == 'none')
# 每一类的“总单数”=【调拨单_需求】时则已处理的质检单“单数”≥“预完成数量”时可执行调拨单验证
if len(check_ids_2) >= move_id.product_uom_qty and len(check_ids_2_done) < pre_done_qty:
need_done_check_ids += check_ids_2_none
# 每一类的“总单数”<【调拨单_需求】时则已处理的质检单“单数”≥0时可执行调拨单验证
elif len(check_ids_2) < move_id.product_uom_qty and len(check_ids_2_done) == 0:
need_done_check_ids += check_ids_2_none
if check_ids_2_fail:
fail_check_ids += check_ids_2_fail
if need_done_check_ids or fail_check_ids:
res.append({'move_id': move_id,
'pre_done_qty': pre_done_qty,
'check_ids': check_ids,
'fail_check_ids': fail_check_ids,
'need_done_check_ids': need_done_check_ids})
return res return res
def get_picking_to_quality(self):
self.ensure_one()
return self._get_picking_to_quality()
def _get_picking_to_quality(self):
"""
对需要质检的明细行进行统计(针对“预完成数量”>0的行)
"""
quality_piking_line_list = []
pre_done_qty_lines = self._get_pinking_pre_done_qty()
for line in pre_done_qty_lines:
move_id, pre_done_qty = line.values()
if pre_done_qty == 0:
continue
product_id = move_id.product_id
check_ids = self.check_ids.filtered(lambda c: c.product_id == product_id)
quality_piking_line_list.append({'move_id': move_id, 'pre_done_qty': pre_done_qty, 'check_ids': check_ids})
return quality_piking_line_list
def _get_pinking_pre_done_qty(self):
"""
return: 明细行 及 预完成数量
1、若调拨单所有明细行的【完成】=0且任意行的【预留】<【需求】,则验证时将会话是否需创建欠单。
---->此时“预完成数量”=【预留】
2、若调拨单任意行的0<【完成】<【需求】,且则验证时将会话是否需创建欠单
---->此时“预完成数量”=【完成】
"""
# if all(move_id.quantity_done == 0 for move_id in self.move_ids_without_package):
# pre_done_qty = [{'move_id': move_id, 'pre_done_qty': move_id.reserved_availability} for move_id in
# self.move_ids_without_package]
# else:
# pre_done_qty = [{'move_id': move_id, 'pre_done_qty': move_id.quantity_done} for move_id in
# self.move_ids_without_package]
pre_done_qty = []
for move_id in self.move_ids_without_package:
if move_id.quantity_done > 0:
pre_done_qty.append({'move_id': move_id, 'pre_done_qty': move_id.quantity_done})
else:
pre_done_qty.append({'move_id': move_id, 'pre_done_qty': move_id.reserved_availability})
return pre_done_qty