Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/前端样式修改
This commit is contained in:
2
jikimo_purchase_request/__init__.py
Normal file
2
jikimo_purchase_request/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from . import models
|
||||
22
jikimo_purchase_request/__manifest__.py
Normal file
22
jikimo_purchase_request/__manifest__.py
Normal file
@@ -0,0 +1,22 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
{
|
||||
'name': '机企猫 采购申请',
|
||||
'version': '16.0.1.0.0',
|
||||
'summary': """ 机企猫 采购申请 """,
|
||||
'author': '机企猫',
|
||||
'website': 'https://bfw.jikimo.com',
|
||||
'category': 'purchase',
|
||||
'depends': ['sf_manufacturing', 'purchase_request'],
|
||||
'data': [
|
||||
|
||||
],
|
||||
# 'assets': {
|
||||
# 'web.assets_backend': [
|
||||
# 'jikimo_purchase_request/static/src/**/*'
|
||||
# ],
|
||||
# },
|
||||
'application': True,
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
'license': 'LGPL-3',
|
||||
}
|
||||
2
jikimo_purchase_request/models/__init__.py
Normal file
2
jikimo_purchase_request/models/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from . import product_template
|
||||
17
jikimo_purchase_request/models/product_template.py
Normal file
17
jikimo_purchase_request/models/product_template.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from odoo import models, fields
|
||||
|
||||
class ProductTemplate(models.Model):
|
||||
_inherit = 'product.template'
|
||||
|
||||
purchase_request_id = fields.Many2one('purchase.request', string='采购申请')
|
||||
|
||||
def no_bom_product_create(self, product_id, item, order_id, route_type, i, finish_product):
|
||||
""" 创建坯料时,复制采购申请 """
|
||||
template_id = super(ProductTemplate, self).no_bom_product_create(product_id, item, order_id, route_type, i, finish_product)
|
||||
template_id.purchase_request = product_id.purchase_request
|
||||
return template_id
|
||||
|
||||
def copy_template(self, product_template_id):
|
||||
""" 复制成品模板时,复制采购申请 """
|
||||
super(ProductTemplate, self).copy_template(product_template_id)
|
||||
self.purchase_request = product_template_id.purchase_request
|
||||
@@ -81,8 +81,29 @@ class StockPicking(models.Model):
|
||||
return quality_pickings
|
||||
|
||||
def action_cancel(self):
|
||||
"""
|
||||
调拨单取消后,关联取消质量检查单
|
||||
"""
|
||||
context = self.env.context
|
||||
if not context.get('cancel_check_picking') and self.sudo().mapped('check_ids').filtered(
|
||||
lambda x: x.quality_state in ['pass', 'fail']):
|
||||
self.env.cr.rollback()
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'picking.check.cancel.wizard',
|
||||
'name': '取消质检单',
|
||||
'view_mode': 'form',
|
||||
'target': 'new',
|
||||
'context': {
|
||||
'default_picking_id': self.id,
|
||||
'cancel_check_picking': True}
|
||||
}
|
||||
elif self.check_ids.filtered(lambda x: x.quality_state != 'cancel'):
|
||||
self.sudo().mapped('check_ids').filtered(lambda x: x.quality_state != 'cancel').write({
|
||||
'quality_state': 'cancel'
|
||||
})
|
||||
res = super(StockPicking, self).action_cancel()
|
||||
self.sudo().mapped('check_ids').filtered(lambda x: x.quality_state == 'none').unlink()
|
||||
# self.sudo().mapped('check_ids').filtered(lambda x: x.quality_state == 'none').unlink()
|
||||
return res
|
||||
|
||||
def action_open_quality_check_picking(self):
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_quality_check_wizard,access.quality_check_wizard,model_quality_check_wizard,quality.group_quality_user,1,1,1,0
|
||||
access_picking_check_cancel_wizard,access.picking_check_cancel_wizard,model_picking_check_cancel_wizard,quality.group_quality_user,1,1,1,0
|
||||
|
||||
|
@@ -112,3 +112,18 @@ class QualityCheckWizard(models.TransientModel):
|
||||
default_current_check_id=self.current_check_id.id,
|
||||
)
|
||||
return action
|
||||
|
||||
|
||||
class PickingCheckCancelWizard(models.TransientModel):
|
||||
_name = 'picking.check.cancel.wizard'
|
||||
_description = 'picking check cancel wizard'
|
||||
|
||||
picking_id = fields.Many2one('stock.picking', 'stock picking')
|
||||
|
||||
def confirm_picking_check(self):
|
||||
self.picking_id.action_cancel()
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
def cancel_picking_check(self):
|
||||
# 这里是取消后的逻辑
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
@@ -118,4 +118,21 @@
|
||||
<field name="context">{}</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- ================================================================================================== -->
|
||||
<record id="picking_check_cancel_wizard_form" model="ir.ui.view">
|
||||
<field name="name">picking.check.cancel.wizard</field>
|
||||
<field name="model">picking.check.cancel.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Quality Check Failed">
|
||||
<div>质量检查单已完成,继续取消吗?</div>
|
||||
<div class="'color': 'red'">注意:关联质量检查单也将被取消。</div>
|
||||
<footer>
|
||||
<button name="confirm_picking_check" type="object" class="btn-primary" string="确认"/>
|
||||
<button name="cancel_picking_check" type="object" string="取消"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
@@ -57,15 +57,24 @@ class MrsMaterialModel(models.Model):
|
||||
remark = fields.Text("备注")
|
||||
gain_way = fields.Selection(
|
||||
[("自加工", "自加工"), ("外协", "委外加工"), ("采购", "采购")],
|
||||
default="", string="获取方式")
|
||||
default="采购", string="获取方式")
|
||||
supplier_ids = fields.One2many('sf.supplier.sort', 'materials_model_id', string='供应商')
|
||||
active = fields.Boolean('有效', default=True)
|
||||
|
||||
@api.constrains("gain_way")
|
||||
def _check_supplier_ids(self):
|
||||
for item in self:
|
||||
if item.gain_way in ('外协', '采购') and not item.supplier_ids:
|
||||
raise UserError("请添加供应商")
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
res = super(MrsMaterialModel, self).create(vals)
|
||||
if not vals.get('supplier_ids'):
|
||||
supplier_id = self.env['res.partner'].search([('name', '=', '湖南傲派自动化设备有限公司')], limit=1)
|
||||
res.supplier_ids = [(0, 0, {'materials_model_id': res.id, 'partner_id': supplier_id.id or False})]
|
||||
return res
|
||||
else:
|
||||
return res
|
||||
# @api.constrains("gain_way")
|
||||
# def _check_supplier_ids(self):
|
||||
# for item in self:
|
||||
# if item.gain_way in ('外协', '采购') and not item.supplier_ids:
|
||||
# raise UserError("请添加供应商")
|
||||
|
||||
|
||||
class MrsProductionProcessCategory(models.Model):
|
||||
|
||||
@@ -262,13 +262,13 @@
|
||||
<group>
|
||||
<field name="materials_no" readonly="1" force_save="1"/>
|
||||
<field name="gain_way" required="0"/>
|
||||
<field name="tensile_strength" required="1"/>
|
||||
<field name="hardness" required="1"/>
|
||||
<field name="density" readonly="1"/>
|
||||
<field name="density" readonly="1" required="1" class="custom_required"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="rough_machining" required="1"/>
|
||||
<field name="finish_machining" required="1"/>
|
||||
<field name="tensile_strength" required="1"/>
|
||||
<field name="hardness" required="1"/>
|
||||
<field name="need_h" default="false" readonly="1"/>
|
||||
<field name="mf_materia_post" attrs="{'invisible':[('need_h','=',False)]} "
|
||||
readonly="1"/>
|
||||
@@ -297,7 +297,7 @@
|
||||
<record model="ir.ui.view" id="sf_materials_model_tree">
|
||||
<field name="model">sf.materials.model</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="材料型号" delete="0">
|
||||
<tree string="材料型号" delete="0" create="0">
|
||||
<field name="materials_no"/>
|
||||
<field name="materials_code"/>
|
||||
<field name="name"/>
|
||||
|
||||
@@ -365,7 +365,7 @@ class MrpProduction(models.Model):
|
||||
and production.schedule_state == '已排' and production.is_rework is False):
|
||||
production.state = 'pending_cam'
|
||||
if any((wo.test_results == '返工' and wo.state == 'done' and
|
||||
(production.programming_state in ['已编程'] or 'PTD' in wo.individuation_page_list))
|
||||
(production.programming_state in ['已编程'] or(wo.individuation_page_list and 'PTD' in wo.individuation_page_list)))
|
||||
or (wo.is_rework is True and wo.state == 'done' and production.programming_state in ['编程中', '已编程'])
|
||||
for wo in production.workorder_ids) or production.is_rework is True:
|
||||
production.state = 'rework'
|
||||
|
||||
@@ -1442,7 +1442,8 @@ class ResMrpWorkOrder(models.Model):
|
||||
record.production_id.process_state = '待加工'
|
||||
# 生成工件配送单
|
||||
record.workpiece_delivery_ids = record._json_workpiece_delivery_list()
|
||||
if record.routing_type == 'CNC加工' or 'PTD' in record.individuation_page_list:
|
||||
if (record.routing_type == 'CNC加工' or
|
||||
(record.individuation_page_list and 'PTD' in record.individuation_page_list)):
|
||||
if record.routing_type == 'CNC加工':
|
||||
record.process_state = '待解除装夹'
|
||||
# record.write({'process_state': '待加工'})
|
||||
@@ -1675,32 +1676,31 @@ class ResMrpWorkOrder(models.Model):
|
||||
move_subcontract_workorder_ids = fields.One2many('stock.move', 'subcontract_workorder_id', string='组件')
|
||||
|
||||
# ==============================配置化页签--个性化记录===================================
|
||||
routing_workcenter_id = fields.Many2one('mrp.routing.workcenter', compute='_compute_routing_workcenter_id',
|
||||
store=True, string='工序作业')
|
||||
individuation_page_ids = fields.Many2many('sf.work.individuation.page', string='个性化记录', store=True,
|
||||
compute='_compute_individuation_page_ids')
|
||||
individuation_page_list = fields.Char('个性化记录', default=None)
|
||||
routing_work_center_id = fields.Many2one('mrp.routing.workcenter', compute='_compute_routing_work_center_id',
|
||||
store=True, string='工序作业')
|
||||
individuation_page_ids = fields.Many2many('sf.work.individuation.page', string='个性化记录',
|
||||
related='routing_work_center_id.individuation_page_ids')
|
||||
individuation_page_list = fields.Char('个性化记录', default='', compute='_compute_individuation_page_ids', store=True)
|
||||
|
||||
@api.depends('name')
|
||||
def _compute_routing_workcenter_id(self):
|
||||
def _compute_routing_work_center_id(self):
|
||||
for mw in self:
|
||||
routing_workcenter_id = self.env['mrp.routing.workcenter'].sudo().search(
|
||||
[('name', '=', mw.name), ('routing_type', '=', mw.routing_type)])
|
||||
if routing_workcenter_id:
|
||||
mw.routing_workcenter_id = routing_workcenter_id.id
|
||||
if not mw.routing_work_center_id and mw.name:
|
||||
routing_work_center_id = self.env['mrp.routing.workcenter'].sudo().search(
|
||||
[('name', 'in', mw.name.split('-')), ('routing_type', '=', mw.routing_type)])
|
||||
if routing_work_center_id:
|
||||
mw.routing_work_center_id = routing_work_center_id.id
|
||||
|
||||
@api.depends('routing_workcenter_id.individuation_page_ids')
|
||||
@api.depends('individuation_page_ids')
|
||||
def _compute_individuation_page_ids(self):
|
||||
for mw in self:
|
||||
if mw.routing_workcenter_id:
|
||||
mw.individuation_page_ids = mw.routing_workcenter_id.individuation_page_ids.ids
|
||||
# 初始化页签配置
|
||||
mw.individuation_page_list = None
|
||||
# 根据工单对应的【作业_个性化记录】配置页签
|
||||
individuation_page_list = [item.code for item in mw.routing_workcenter_id.individuation_page_ids]
|
||||
if individuation_page_list:
|
||||
mw.individuation_page_list = list(set(individuation_page_list))
|
||||
|
||||
mw.individuation_page_list = '[]'
|
||||
if mw.routing_work_center_id:
|
||||
if mw.individuation_page_ids:
|
||||
# 根据工单对应的【作业_个性化记录】配置页签
|
||||
individuation_page_list = [item.code for item in mw.individuation_page_ids]
|
||||
if individuation_page_list:
|
||||
mw.individuation_page_list = list(set(individuation_page_list))
|
||||
# =============================================================================================
|
||||
|
||||
is_inspect = fields.Boolean('需送检', compute='_compute_is_inspect', store=True, default=False)
|
||||
|
||||
@@ -503,14 +503,6 @@
|
||||
</group>
|
||||
</page>
|
||||
|
||||
<page string="2D加工图纸" attrs='{"invisible": ["!", ("individuation_page_list", "ilike", "2D_MD")]}'>
|
||||
<field name="machining_drawings" widget="adaptive_viewer"/>
|
||||
</page>
|
||||
|
||||
<page string="质检标准" attrs='{"invisible": ["!", ("individuation_page_list", "ilike", "QIS")]}'>
|
||||
<field name="quality_standard" widget="adaptive_viewer"/>
|
||||
</page>
|
||||
|
||||
<page string="工件配送" attrs='{"invisible": ["!", ("individuation_page_list", "ilike", "WD")]}'>
|
||||
<field name="workpiece_delivery_ids">
|
||||
<tree editable="bottom">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of SmartGo. See LICENSE file for full copyright and licensing details.
|
||||
import logging
|
||||
import traceback
|
||||
|
||||
import requests
|
||||
|
||||
@@ -90,7 +91,8 @@ class ResConfigSettings(models.TransientModel):
|
||||
_logger.info("同步坯料冗余完成")
|
||||
|
||||
except Exception as e:
|
||||
_logger.info("sf_all_sync error: %s" % e)
|
||||
traceback_error = traceback.format_exc()
|
||||
_logger.error("sf_all_sync error:%s" % traceback_error)
|
||||
raise ValidationError("数据错误导致同步失败,请联系管理员")
|
||||
|
||||
@api.model
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import models
|
||||
from . import wizard
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
'views/view.xml',
|
||||
'views/quality_cnc_test_view.xml',
|
||||
'views/mrp_workorder.xml',
|
||||
'views/quality_check_view.xml'
|
||||
'views/quality_check_view.xml',
|
||||
'wizard/check_picking_wizard_view.xml',
|
||||
],
|
||||
|
||||
'assets': {
|
||||
|
||||
@@ -5,3 +5,4 @@ from . import custom_quality
|
||||
from . import quality
|
||||
from . import quality_cnc_test
|
||||
from . import mrp_workorder
|
||||
from . import stock
|
||||
|
||||
@@ -93,7 +93,8 @@ class QualityCheck(models.Model):
|
||||
raise ValidationError('请填写【判定结果】里的信息')
|
||||
if self.test_results == '合格':
|
||||
raise ValidationError('请重新选择【判定结果】-【检测结果】')
|
||||
if self.workorder_id.routing_type != 'CNC加工' and 'PTD' not in self.workorder_id.individuation_page_list:
|
||||
if (self.workorder_id.routing_type != 'CNC加工' and self.workorder_id.individuation_page_list
|
||||
and 'PTD' not in self.workorder_id.individuation_page_list):
|
||||
self.workorder_id.production_id.write({'detection_result_ids': [(0, 0, {
|
||||
'rework_reason': self.reason,
|
||||
'detailed_reason': self.detailed_reason,
|
||||
|
||||
39
sf_quality/models/stock.py
Normal file
39
sf_quality/models/stock.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class StockPicking(models.Model):
|
||||
_inherit = 'stock.picking'
|
||||
|
||||
def button_validate(self):
|
||||
"""
|
||||
调拨单若关联了质量检查单,验证调拨单时,应校验是否有不合格品,若存在,应弹窗提示:
|
||||
“警告:存在不合格产品XXXX n 件、YYYYY m件,继续调拨请点“确认”,否则请取消?”
|
||||
"""
|
||||
context = self.env.context
|
||||
if not context.get('again_validate') and self.quality_check_ids.filtered(lambda qc: qc.quality_state == 'fail'):
|
||||
# 回滚事务,为二次确认/取消做准备
|
||||
self.env.cr.rollback()
|
||||
quality_check_ids = self.quality_check_ids.filtered(lambda qc: qc.quality_state == 'fail')
|
||||
product_list = list(set([quality_check_id.product_id for quality_check_id in quality_check_ids]))
|
||||
fail_check_text = ''
|
||||
for product_id in product_list:
|
||||
check_ids = quality_check_ids.filtered(lambda qc: qc.product_id == product_id)
|
||||
number = sum(check_ids.mapped('qty_line'))
|
||||
if number != 0:
|
||||
fail_check_text = (f'{fail_check_text}、{product_id.name} {number}件'
|
||||
if fail_check_text != '' else f'{product_id.name} {number}件')
|
||||
else:
|
||||
fail_check_text = (f'{fail_check_text}、{product_id.name}'
|
||||
if fail_check_text != '' else f'{product_id.name}')
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'picking.validate.check.wizard',
|
||||
'name': '质检不合格提示',
|
||||
'view_mode': 'form',
|
||||
'target': 'new',
|
||||
'context': {
|
||||
'default_picking_id': self.id,
|
||||
'default_fail_check_text': f'警告:存在不合格产品{fail_check_text},继续调拨请点“确认”,否则请取消?',
|
||||
'again_validate': True}
|
||||
}
|
||||
return super(StockPicking, self).button_validate()
|
||||
@@ -73,6 +73,6 @@ access_quality_cnc_test_group_quality_director,quality_cnc_test_group_quality_di
|
||||
|
||||
access_quality_cnc_test_group_sf_equipment_user,quality_cnc_test_group_sf_equipment_user,model_quality_cnc_test,sf_base.group_sf_equipment_user,1,1,0,0
|
||||
|
||||
|
||||
access_picking_validate_check_wizard,access.picking_validate_check_wizard,model_picking_validate_check_wizard,quality.group_quality_user,1,1,1,0
|
||||
|
||||
|
||||
|
||||
|
1
sf_quality/wizard/__init__.py
Normal file
1
sf_quality/wizard/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import check_picking_wizard
|
||||
17
sf_quality/wizard/check_picking_wizard.py
Normal file
17
sf_quality/wizard/check_picking_wizard.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from odoo import api, models,fields
|
||||
|
||||
|
||||
class PickingValidateCheckWizard(models.TransientModel):
|
||||
_name = 'picking.validate.check.wizard'
|
||||
_description = '调拨质检不合格二次验证'
|
||||
|
||||
picking_id = fields.Many2one('stock.picking', '调拨单')
|
||||
fail_check_text = fields.Text('提示信息')
|
||||
|
||||
def confirm_picking_validate_check(self):
|
||||
self.picking_id.button_validate()
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
def cancel_picking_validate_check(self):
|
||||
# 这里是取消后的逻辑
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
15
sf_quality/wizard/check_picking_wizard_view.xml
Normal file
15
sf_quality/wizard/check_picking_wizard_view.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<odoo>
|
||||
<record id="picking_validate_check_wizard_form" model="ir.ui.view">
|
||||
<field name="name">picking.validate.check.wizard</field>
|
||||
<field name="model">picking.validate.check.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<field name="fail_check_text" readonly="True"/>
|
||||
<footer>
|
||||
<button name="confirm_picking_validate_check" type="object" class="btn-primary" string="确认"/>
|
||||
<button name="cancel_picking_validate_check" type="object" string="取消"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user