Compare commits
87 Commits
feature/cu
...
feature/消息
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f1514bd14 | ||
|
|
6b61df9d50 | ||
|
|
d182641d81 | ||
|
|
c6aeff2006 | ||
|
|
eaaa13fb9a | ||
|
|
f92bd8263c | ||
|
|
247bebbd75 | ||
|
|
39ed32f3e9 | ||
|
|
78a456849c | ||
|
|
da815c8ea1 | ||
|
|
32e3c2f79f | ||
|
|
c478b72e04 | ||
|
|
78b0529809 | ||
|
|
17ffac63cb | ||
|
|
acee32cc39 | ||
|
|
b36cf745c2 | ||
|
|
a24279f6e6 | ||
|
|
68b89999a9 | ||
|
|
7c38c7f643 | ||
|
|
4937c3a812 | ||
|
|
05469c71b8 | ||
|
|
210eea3b0b | ||
|
|
f58d1058f7 | ||
|
|
0622d7525f | ||
|
|
7556c09ac2 | ||
|
|
5344e97b7e | ||
|
|
1b10b7bb53 | ||
|
|
9ab164f0fe | ||
|
|
3b07b26303 | ||
|
|
29a32be8d2 | ||
|
|
3620412a13 | ||
|
|
5e72e3d1dd | ||
|
|
4137b304f3 | ||
|
|
caac651ab4 | ||
|
|
30e496442f | ||
|
|
c28c00a47b | ||
|
|
4f4fdeecb5 | ||
|
|
8742f9b98b | ||
|
|
d7ce69f474 | ||
|
|
cf46cff7e5 | ||
|
|
c124e2962c | ||
|
|
f4312c4d4e | ||
|
|
5928456ffe | ||
|
|
305ea9dff7 | ||
|
|
bdfc393099 | ||
|
|
1e1bd63acf | ||
|
|
fa20bb6eb5 | ||
|
|
c82db7159d | ||
|
|
89d6752012 | ||
|
|
3060b35ab2 | ||
|
|
17ad976a32 | ||
|
|
9f3b351544 | ||
|
|
5dc7dc8e0a | ||
|
|
f1868168af | ||
|
|
f084b5d765 | ||
|
|
854c3ceef2 | ||
|
|
4269ce58db | ||
|
|
3555be86c6 | ||
|
|
764472111f | ||
|
|
ce4fc8b8ab | ||
|
|
67f4917491 | ||
|
|
ad885f1e39 | ||
|
|
993d720c40 | ||
|
|
da75a8cd35 | ||
|
|
b35f842915 | ||
|
|
4e7993d035 | ||
|
|
946f02003e | ||
|
|
435315a166 | ||
|
|
676f8eb7eb | ||
|
|
6e9f66506a | ||
|
|
f3e08f5ccc | ||
|
|
c9d7d70d3c | ||
|
|
ee6e457bbd | ||
|
|
ab5b4c477f | ||
|
|
9330be3753 | ||
|
|
a3a2c96d00 | ||
|
|
31187755b9 | ||
|
|
178f538997 | ||
|
|
304f6ad5ba | ||
|
|
8b40714dad | ||
|
|
cb8e415e60 | ||
|
|
889049b107 | ||
|
|
610028c5f4 | ||
|
|
abfac28094 | ||
|
|
24d8d37e0a | ||
|
|
6780d4e758 | ||
|
|
675fb54d37 |
@@ -139,6 +139,7 @@ patch(ListRenderer.prototype, 'jikimo_frontend.ListRenderer', {
|
|||||||
owl.onMounted(() => {
|
owl.onMounted(() => {
|
||||||
this.activeElement = this.uiService.activeElement;
|
this.activeElement = this.uiService.activeElement;
|
||||||
this.setRequired()
|
this.setRequired()
|
||||||
|
// this.listherHeaderBodyNum()
|
||||||
})
|
})
|
||||||
return this._super(...arguments);
|
return this._super(...arguments);
|
||||||
},
|
},
|
||||||
@@ -165,6 +166,25 @@ patch(ListRenderer.prototype, 'jikimo_frontend.ListRenderer', {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e)
|
console.log(e)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
listherHeaderBodyNum() {
|
||||||
|
const dom = this.tableRef.el
|
||||||
|
try {
|
||||||
|
const thead = $(dom).children('thead')
|
||||||
|
const tbody = $(dom).children('tbody')
|
||||||
|
const thead_tr = thead.children().eq(0)
|
||||||
|
const tbody_tr = tbody.children().eq(0)
|
||||||
|
const thead_th_num = thead_tr.children().length
|
||||||
|
const tbody_tr_num = tbody_tr.children().length
|
||||||
|
const num = thead_th_num - tbody_tr_num
|
||||||
|
console.log('num', num);
|
||||||
|
if(num == -1) {
|
||||||
|
thead_tr.prepend('<td>序号</td>')
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
'version': '0.1',
|
'version': '0.1',
|
||||||
|
|
||||||
# any module necessary for this one to work correctly
|
# any module necessary for this one to work correctly
|
||||||
'depends': ['purchase', 'base_tier_validation', 'documents'],
|
'depends': ['purchase', 'base_tier_validation', 'documents', 'purchase_request', 'account'],
|
||||||
|
|
||||||
# always loaded
|
# always loaded
|
||||||
'data': [
|
'data': [
|
||||||
@@ -33,4 +33,10 @@
|
|||||||
'demo': [
|
'demo': [
|
||||||
'demo/demo.xml',
|
'demo/demo.xml',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'assets': {
|
||||||
|
'web.assets_backend': [
|
||||||
|
'jikimo_purchase_tier_validation/static/src/js/ir_model_extend.js',
|
||||||
|
],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ _logger = logging.getLogger(__name__)
|
|||||||
class jikimo_purchase_tier_validation(models.Model):
|
class jikimo_purchase_tier_validation(models.Model):
|
||||||
_name = 'purchase.order'
|
_name = 'purchase.order'
|
||||||
_inherit = ['purchase.order', 'tier.validation']
|
_inherit = ['purchase.order', 'tier.validation']
|
||||||
|
_description = "采购订单"
|
||||||
|
|
||||||
_tier_validation_buttons_xpath = "/form/header/button[@id='draft_confirm'][1]"
|
_tier_validation_buttons_xpath = "/form/header/button[@id='draft_confirm'][1]"
|
||||||
|
|
||||||
@@ -21,7 +22,7 @@ class jikimo_purchase_tier_validation(models.Model):
|
|||||||
def button_confirm(self):
|
def button_confirm(self):
|
||||||
for record in self:
|
for record in self:
|
||||||
if record.need_validation and record.validation_status != 'validated':
|
if record.need_validation and record.validation_status != 'validated':
|
||||||
raise ValidationError(_('请先完成审批!'))
|
raise ValidationError(_('此操作需要至少对一条记录进行审批。\n请发起审批申请。'))
|
||||||
return super().button_confirm()
|
return super().button_confirm()
|
||||||
|
|
||||||
# def button_confirm(self):
|
# def button_confirm(self):
|
||||||
@@ -63,7 +64,38 @@ class jikimo_purchase_tier_validation(models.Model):
|
|||||||
if error_messages:
|
if error_messages:
|
||||||
raise ValidationError('\n'.join(error_messages))
|
raise ValidationError('\n'.join(error_messages))
|
||||||
|
|
||||||
return super(jikimo_purchase_tier_validation, self).request_validation()
|
# 添加通知消息
|
||||||
|
if hasattr(record, 'message_post'):
|
||||||
|
current_user = self.env.user.name
|
||||||
|
record.message_post(
|
||||||
|
body=f"<strong>{current_user}</strong> 提交审批",
|
||||||
|
message_type='notification',
|
||||||
|
subtype_xmlid='mail.mt_note'
|
||||||
|
)
|
||||||
|
res = super(jikimo_purchase_tier_validation, self).request_validation()
|
||||||
|
self.state = 'to approve'
|
||||||
|
return res
|
||||||
|
|
||||||
|
def restart_validation(self):
|
||||||
|
res = super(jikimo_purchase_tier_validation, self).restart_validation()
|
||||||
|
self.state = 'draft'
|
||||||
|
return res
|
||||||
|
|
||||||
|
def _validate_tier(self, tiers=False):
|
||||||
|
res = super(jikimo_purchase_tier_validation, self)._validate_tier(tiers)
|
||||||
|
self.state = 'approved'
|
||||||
|
return res
|
||||||
|
|
||||||
|
def _rejected_tier(self, tiers=False):
|
||||||
|
res = super(jikimo_purchase_tier_validation, self)._rejected_tier(tiers)
|
||||||
|
self.state = 'draft'
|
||||||
|
return res
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def _get_under_validation_exceptions(self):
|
||||||
|
res = super(jikimo_purchase_tier_validation, self)._get_under_validation_exceptions()
|
||||||
|
res.append("state")
|
||||||
|
return res
|
||||||
|
|
||||||
# 上传合同文件
|
# 上传合同文件
|
||||||
def upload_contract_file(self):
|
def upload_contract_file(self):
|
||||||
@@ -152,3 +184,18 @@ class jikimo_purchase_tier_validation(models.Model):
|
|||||||
'sticky': False,
|
'sticky': False,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class jikimo_purchase_request(models.Model):
|
||||||
|
_inherit = 'purchase.request'
|
||||||
|
_description = "采购申请"
|
||||||
|
|
||||||
|
|
||||||
|
class jikimo_account_payment(models.Model):
|
||||||
|
_inherit = 'account.payment'
|
||||||
|
_description = "付款单"
|
||||||
|
|
||||||
|
|
||||||
|
class jikimo_account_move(models.Model):
|
||||||
|
_inherit = 'account.move'
|
||||||
|
_description = "发票账单"
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
/** @odoo-module **/
|
||||||
|
|
||||||
|
import {registerPatch} from "@mail/model/model_core";
|
||||||
|
|
||||||
|
registerPatch({
|
||||||
|
name: "ir.model.review",
|
||||||
|
fields: {
|
||||||
|
availableWebViews: {
|
||||||
|
compute() {
|
||||||
|
return ["list", "form", "activity"];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -8,6 +8,10 @@
|
|||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<xpath expr="//header/button[@name='button_cancel']" position="replace">
|
<xpath expr="//header/button[@name='button_cancel']" position="replace">
|
||||||
</xpath>
|
</xpath>
|
||||||
|
<xpath expr="//header/field[@name='state']" position="replace">
|
||||||
|
<field name="state" widget="statusbar" statusbar_visible="draft,sent,to approve, approved, purchase" readonly="1"/>
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
|
||||||
<xpath expr="//header/button[last()]" position="after">
|
<xpath expr="//header/button[last()]" position="after">
|
||||||
<button name="button_cancel" states="draft,to approve,sent,purchase" string="取消" type="object" data-hotkey="x" />
|
<button name="button_cancel" states="draft,to approve,sent,purchase" string="取消" type="object" data-hotkey="x" />
|
||||||
@@ -16,7 +20,7 @@
|
|||||||
<xpath expr="//header/button[@name='action_rfq_send'][1]" position="before">
|
<xpath expr="//header/button[@name='action_rfq_send'][1]" position="before">
|
||||||
<field name="validation_status" invisible="1"/>
|
<field name="validation_status" invisible="1"/>
|
||||||
<field name="is_upload_contract_file" invisible="1"/>
|
<field name="is_upload_contract_file" invisible="1"/>
|
||||||
<button name="upload_contract_file" string="上传合同" type="object" class="oe_highlight" attrs="{'invisible': ['|', ('validation_status', '!=', 'no'), ('is_upload_contract_file', '=', True)]}"/>
|
<button name="upload_contract_file" string="上传合同" type="object" class="oe_highlight" attrs="{'invisible': ['|', '|', ('validation_status', '!=', 'no'), ('is_upload_contract_file', '=', True), ('state', 'not in', ['draft', 'sent'])]}"/>]}"/>
|
||||||
<button name="delete_contract_file" string="删除合同" type="object" class="oe_highlight" attrs="{'invisible': ['|', ('validation_status', '!=', 'no'), ('is_upload_contract_file', '=', False)]}"/>
|
<button name="delete_contract_file" string="删除合同" type="object" class="oe_highlight" attrs="{'invisible': ['|', ('validation_status', '!=', 'no'), ('is_upload_contract_file', '=', False)]}"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//notebook/page[1]" position="before">
|
<xpath expr="//notebook/page[1]" position="before">
|
||||||
|
|||||||
@@ -23,4 +23,4 @@ class ProductTemplate(models.Model):
|
|||||||
self.is_bfm = product_template_id.is_bfm
|
self.is_bfm = product_template_id.is_bfm
|
||||||
self.is_manual_processing = product_template_id.is_manual_processing
|
self.is_manual_processing = product_template_id.is_manual_processing
|
||||||
# 复制 seller_ids
|
# 复制 seller_ids
|
||||||
self.seller_ids = [(0, 0, {'partner_id': seller.partner_id.id, 'delay': 1.0}) for seller in product_template_id.seller_ids]
|
self.seller_ids = [(0, 0, {'partner_id': seller.partner_id.id, 'delay': 1.0, 'price': seller.price}) for seller in product_template_id.seller_ids]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
'sequence': 120,
|
'sequence': 120,
|
||||||
'summary': 'Control the quality of your products',
|
'summary': 'Control the quality of your products',
|
||||||
'website': 'https://www.odoo.com/app/quality',
|
'website': 'https://www.odoo.com/app/quality',
|
||||||
'depends': ['quality'],
|
'depends': ['quality', 'sf_manufacturing'],
|
||||||
'description': """
|
'description': """
|
||||||
Quality Control
|
Quality Control
|
||||||
===============
|
===============
|
||||||
|
|||||||
@@ -159,6 +159,34 @@ class QualityCheck(models.Model):
|
|||||||
is_lot_tested_fractionally = fields.Boolean(related='point_id.is_lot_tested_fractionally')
|
is_lot_tested_fractionally = fields.Boolean(related='point_id.is_lot_tested_fractionally')
|
||||||
testing_percentage_within_lot = fields.Float(related="point_id.testing_percentage_within_lot")
|
testing_percentage_within_lot = fields.Float(related="point_id.testing_percentage_within_lot")
|
||||||
product_tracking = fields.Selection(related='product_id.tracking')
|
product_tracking = fields.Selection(related='product_id.tracking')
|
||||||
|
quality_check_type = fields.Selection([
|
||||||
|
('采购入库检', '采购入库检'),
|
||||||
|
('客供料入库检', '客供料入库检'),
|
||||||
|
('退货入库检', '退货入库检'),
|
||||||
|
('生产入库检', '生产入库检'),
|
||||||
|
('外协入库检', '外协入库检'),
|
||||||
|
('成品发货检', '成品发货检'),
|
||||||
|
('工序外协发货检', '工序外协发货检'),
|
||||||
|
('委外坯料发货检', '委外坯料发货检')], string='类型', compute='_compute_quality_check_type', store=True)
|
||||||
|
|
||||||
|
@api.depends('picking_id')
|
||||||
|
def _compute_quality_check_type(self):
|
||||||
|
for check in self:
|
||||||
|
if check.picking_id:
|
||||||
|
picking_type = check.picking_id.picking_type_id.sequence_code
|
||||||
|
type_mapping = {
|
||||||
|
'IN': '采购入库检',
|
||||||
|
'DL': '客供料入库检',
|
||||||
|
'RET': '退货入库检',
|
||||||
|
'SFP': '生产入库检',
|
||||||
|
'OCIN': '外协入库检',
|
||||||
|
'OUT': '成品发货检',
|
||||||
|
'OCOUT': '工序外协发货检',
|
||||||
|
'RES': '委外坯料发货检',
|
||||||
|
}
|
||||||
|
check.quality_check_type = type_mapping.get(picking_type, False)
|
||||||
|
else:
|
||||||
|
check.quality_check_type = False
|
||||||
|
|
||||||
@api.depends('measure_success')
|
@api.depends('measure_success')
|
||||||
def _compute_warning_message(self):
|
def _compute_warning_message(self):
|
||||||
@@ -301,6 +329,19 @@ class QualityAlert(models.Model):
|
|||||||
_inherit = "quality.alert"
|
_inherit = "quality.alert"
|
||||||
|
|
||||||
title = fields.Char('Title')
|
title = fields.Char('Title')
|
||||||
|
part_number = fields.Char(string='零件图号', compute='_compute_part_info', store=True)
|
||||||
|
part_name = fields.Char(string='零件名称', compute='_compute_part_info', store=True)
|
||||||
|
|
||||||
|
@api.depends('product_id', 'picking_id')
|
||||||
|
def _compute_part_info(self):
|
||||||
|
for alert in self:
|
||||||
|
if alert.product_tmpl_id.categ_id.name == '成品':
|
||||||
|
alert.part_number = alert.product_id.part_number
|
||||||
|
alert.part_name = alert.product_id.part_name
|
||||||
|
elif alert.product_id.categ_id.name == '坯料':
|
||||||
|
if alert.picking_id.move_ids_without_package:
|
||||||
|
alert.part_number = alert.picking_id.move_ids_without_package[0].part_number
|
||||||
|
alert.part_name = alert.picking_id.move_ids_without_package[0].part_name
|
||||||
|
|
||||||
def action_see_check(self):
|
def action_see_check(self):
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -90,6 +90,8 @@
|
|||||||
<field name="lot_id" context="{'default_product_id': product_id}"
|
<field name="lot_id" context="{'default_product_id': product_id}"
|
||||||
groups="stock.group_production_lot"/>
|
groups="stock.group_production_lot"/>
|
||||||
<field name="picking_id"/>
|
<field name="picking_id"/>
|
||||||
|
<field name="part_name"/>
|
||||||
|
<field name="part_number"/>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="team_id"/>
|
<field name="team_id"/>
|
||||||
@@ -150,6 +152,10 @@
|
|||||||
<field name="date_assign" position="after">
|
<field name="date_assign" position="after">
|
||||||
<field name="company_id" groups="base.main_company"/>
|
<field name="company_id" groups="base.main_company"/>
|
||||||
</field>
|
</field>
|
||||||
|
<field name="product_tmpl_id" position="after">
|
||||||
|
<field name="part_name" optional="show"/>
|
||||||
|
<field name="part_number" optional="show"/>
|
||||||
|
</field>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
@@ -260,6 +266,8 @@
|
|||||||
<field name="company_id" invisible="1"/>
|
<field name="company_id" invisible="1"/>
|
||||||
<field name="product_id" attrs="{'invisible' : [('measure_on', '=', 'operation')]}"/>
|
<field name="product_id" attrs="{'invisible' : [('measure_on', '=', 'operation')]}"/>
|
||||||
<field name="measure_on" attrs="{'readonly': [('point_id', '!=', False)]}"/>
|
<field name="measure_on" attrs="{'readonly': [('point_id', '!=', False)]}"/>
|
||||||
|
<field name="part_name"/>
|
||||||
|
<field name="part_number"/>
|
||||||
<field name="show_lot_text" invisible="1"/>
|
<field name="show_lot_text" invisible="1"/>
|
||||||
<field name="move_line_id" invisible="1"/>
|
<field name="move_line_id" invisible="1"/>
|
||||||
<field name="product_tracking" invisible="1"/>
|
<field name="product_tracking" invisible="1"/>
|
||||||
@@ -448,6 +456,10 @@
|
|||||||
<filter string="Control Point" name="groupby_point_id" context="{'group_by': 'point_id'}"/>
|
<filter string="Control Point" name="groupby_point_id" context="{'group_by': 'point_id'}"/>
|
||||||
<filter string="Team" name="groupby_team_id" context="{'group_by': 'team_id'}"/>
|
<filter string="Team" name="groupby_team_id" context="{'group_by': 'team_id'}"/>
|
||||||
</group>
|
</group>
|
||||||
|
<searchpanel>
|
||||||
|
<field name="quality_check_type" icon="fa-filter" enable_counters="1"/>
|
||||||
|
<field name="quality_state" icon="fa-filter" enable_counters="1"/>
|
||||||
|
</searchpanel>
|
||||||
</search>
|
</search>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
@@ -507,6 +519,7 @@
|
|||||||
<field name="name">Quality Checks</field>
|
<field name="name">Quality Checks</field>
|
||||||
<field name="res_model">quality.check</field>
|
<field name="res_model">quality.check</field>
|
||||||
<field name="view_mode">tree,kanban,form,pivot,graph</field>
|
<field name="view_mode">tree,kanban,form,pivot,graph</field>
|
||||||
|
<field name="context">{'is_web_request': True}</field>
|
||||||
<field name="help" type="html">
|
<field name="help" type="html">
|
||||||
<p class="o_view_nocontent_smiling_face">
|
<p class="o_view_nocontent_smiling_face">
|
||||||
No quality check found
|
No quality check found
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
# 只有它被屏蔽了
|
# 只有它被屏蔽了
|
||||||
# 'views/SfWorkOrderBarcodes.xml',
|
# 'views/SfWorkOrderBarcodes.xml',
|
||||||
'views/WorkCenterBarcodes.xml',
|
'views/WorkCenterBarcodes.xml',
|
||||||
'views/Stock_picking_Barcodes.xml',
|
# 'views/Stock_picking_Barcodes.xml',
|
||||||
'views/machine_monitor.xml',
|
'views/machine_monitor.xml',
|
||||||
'views/machine_info_present.xml',
|
'views/machine_info_present.xml',
|
||||||
'views/delivery_record.xml',
|
'views/delivery_record.xml',
|
||||||
|
|||||||
21
sf_manufacturing/i18n/zh_CN.po
Normal file
21
sf_manufacturing/i18n/zh_CN.po
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#. module: sf_manufacturing
|
||||||
|
#. odoo-python
|
||||||
|
#: code:addons/sf_manufacturing/models/mrp_production.py:0
|
||||||
|
#, python-format
|
||||||
|
msgid "You must enter a serial number for %s"
|
||||||
|
msgstr "您必须为%s输入一个序列号。"
|
||||||
|
|
||||||
|
|
||||||
|
#. module: sf_manufacturing
|
||||||
|
#. odoo-python
|
||||||
|
#: code:addons/sf_manufacturing/models/mrp_production.py:0
|
||||||
|
#, python-format
|
||||||
|
msgid "You must enter a serial number for each line of %s"
|
||||||
|
msgstr "您必须为以下各%s行输入序列号"
|
||||||
|
|
||||||
|
#. module: sf_manufacturing
|
||||||
|
#. odoo-python
|
||||||
|
#: code:addons/sf_manufacturing/models/mrp_production.py:0
|
||||||
|
#, python-format
|
||||||
|
msgid "You have %s incomplete supplies: %s"
|
||||||
|
msgstr "您有%s补给未完成: %s"
|
||||||
@@ -790,6 +790,7 @@ class MrpProduction(models.Model):
|
|||||||
groupby(production_all, key=lambda x: x.product_id.id)}
|
groupby(production_all, key=lambda x: x.product_id.id)}
|
||||||
for product_id, pd in grouped_product_ids.items():
|
for product_id, pd in grouped_product_ids.items():
|
||||||
product_id_to_production_names[product_id] = [p.name for p in pd]
|
product_id_to_production_names[product_id] = [p.name for p in pd]
|
||||||
|
sorted_workorders = None
|
||||||
for production in production_all:
|
for production in production_all:
|
||||||
proc_workorders = []
|
proc_workorders = []
|
||||||
process_parameter_workorder = self.env['mrp.workorder'].search(
|
process_parameter_workorder = self.env['mrp.workorder'].search(
|
||||||
@@ -841,6 +842,8 @@ class MrpProduction(models.Model):
|
|||||||
# self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production)
|
# self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production)
|
||||||
# self.env['purchase.order'].get_purchase_order(consecutive_workorders, production,
|
# self.env['purchase.order'].get_purchase_order(consecutive_workorders, production,
|
||||||
# product_id_to_production_names)
|
# product_id_to_production_names)
|
||||||
|
if not sorted_workorders:
|
||||||
|
return
|
||||||
for workorders in reversed(sorted_workorders):
|
for workorders in reversed(sorted_workorders):
|
||||||
self.env['stock.picking'].create_outcontract_picking(workorders, production, sorted_workorders)
|
self.env['stock.picking'].create_outcontract_picking(workorders, production, sorted_workorders)
|
||||||
self.env['purchase.order'].get_purchase_order(workorders, production, product_id_to_production_names)
|
self.env['purchase.order'].get_purchase_order(workorders, production, product_id_to_production_names)
|
||||||
@@ -1578,18 +1581,12 @@ class MrpProduction(models.Model):
|
|||||||
first_order = self.env['mrp.production'].search(
|
first_order = self.env['mrp.production'].search(
|
||||||
[('origin', '=', order.origin), ('product_id', '=', order.product_id.id)], limit=1, order='id asc')
|
[('origin', '=', order.origin), ('product_id', '=', order.product_id.id)], limit=1, order='id asc')
|
||||||
order.picking_ids = self.env['stock.picking'].search([
|
order.picking_ids = self.env['stock.picking'].search([
|
||||||
('group_id', '!=', False), ('state', '!=', 'cancel'),
|
('group_id', '=', first_order.procurement_group_id.id), ('group_id', '!=', False),
|
||||||
'|', # 表示“或”的开始
|
|
||||||
('group_id', '=', order.procurement_group_id.id),
|
|
||||||
('related_group_ids', '=', order.procurement_group_id.id)
|
|
||||||
])
|
])
|
||||||
order.delivery_count = len(first_order.picking_ids)
|
order.delivery_count = len(first_order.picking_ids)
|
||||||
else:
|
else:
|
||||||
order.picking_ids = self.env['stock.picking'].search([
|
order.picking_ids = self.env['stock.picking'].search([
|
||||||
('group_id', '!=', False),('state', '!=', 'cancel'),
|
('group_id', '=', order.procurement_group_id.id), ('group_id', '!=', False),
|
||||||
'|', # 表示“或”的开始
|
|
||||||
('group_id', '=', order.procurement_group_id.id),
|
|
||||||
('related_group_ids', '=', order.procurement_group_id.id)
|
|
||||||
])
|
])
|
||||||
order.delivery_count = len(order.picking_ids)
|
order.delivery_count = len(order.picking_ids)
|
||||||
|
|
||||||
@@ -1621,6 +1618,26 @@ class MrpProduction(models.Model):
|
|||||||
})
|
})
|
||||||
return action
|
return action
|
||||||
|
|
||||||
|
def _subcontract_sanity_check(self):
|
||||||
|
for production in self:
|
||||||
|
if production.product_tracking != 'none' and not self.lot_producing_id:
|
||||||
|
raise UserError(_('You must enter a serial number for %s') % production.product_id.name)
|
||||||
|
for sml in production.move_raw_ids.move_line_ids:
|
||||||
|
if sml.tracking != 'none' and not sml.lot_id:
|
||||||
|
picking_ids = production.picking_ids.filtered(
|
||||||
|
lambda p: p.state not in ['done', 'cancel'])
|
||||||
|
picking_num = len(picking_ids)
|
||||||
|
picking_info = ', '.join(
|
||||||
|
['%s:%s' % (picking.picking_type_id.name, picking.name) for picking in picking_ids]
|
||||||
|
)
|
||||||
|
if picking_info:
|
||||||
|
raise UserError(_('You have %s incomplete supplies: %s') % (
|
||||||
|
picking_num, picking_info))
|
||||||
|
else:
|
||||||
|
raise UserError(
|
||||||
|
_('You must enter a serial number for each line of %s') % sml.product_id.display_name)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class sf_detection_result(models.Model):
|
class sf_detection_result(models.Model):
|
||||||
_name = 'sf.detection.result'
|
_name = 'sf.detection.result'
|
||||||
|
|||||||
@@ -1456,6 +1456,9 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
|
|
||||||
# 解绑托盘
|
# 解绑托盘
|
||||||
def unbind_tray(self):
|
def unbind_tray(self):
|
||||||
|
for item in self:
|
||||||
|
self.env['stock.lot'].sudo().search([('rfid', '=', item.rfid_code)]).write(
|
||||||
|
{'tool_material_status': '可用'})
|
||||||
self.production_id.workorder_ids.write({
|
self.production_id.workorder_ids.write({
|
||||||
'rfid_code': False,
|
'rfid_code': False,
|
||||||
'tray_serial_number': False,
|
'tray_serial_number': False,
|
||||||
|
|||||||
@@ -10,9 +10,42 @@ from odoo.tools import OrderedSet
|
|||||||
# _get_surface_technics_purchase_ids
|
# _get_surface_technics_purchase_ids
|
||||||
class PurchaseOrder(models.Model):
|
class PurchaseOrder(models.Model):
|
||||||
_inherit = 'purchase.order'
|
_inherit = 'purchase.order'
|
||||||
|
production_count = fields.Integer(
|
||||||
|
"关联制造订单",
|
||||||
|
compute='_compute_workorder_count',
|
||||||
|
)
|
||||||
|
|
||||||
|
def action_view_production(self):
|
||||||
|
origins = [order.name for order in self.picking_ids]
|
||||||
|
production_id = self.env['mrp.production'].search([('origin', 'in', origins)])
|
||||||
|
if not production_id:
|
||||||
|
return
|
||||||
|
action = {
|
||||||
|
'res_model': 'mrp.production',
|
||||||
|
'type': 'ir.actions.act_window',
|
||||||
|
}
|
||||||
|
if len(production_id) == 1:
|
||||||
|
action.update({
|
||||||
|
'view_mode': 'form',
|
||||||
|
'res_id': production_id.id,
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
action.update({
|
||||||
|
'name': _("制造订单列表"),
|
||||||
|
'domain': [('id', 'in', production_id.ids)],
|
||||||
|
'view_mode': 'tree,form',
|
||||||
|
})
|
||||||
|
return action
|
||||||
|
|
||||||
|
|
||||||
|
def _compute_workorder_count(self):
|
||||||
|
for purchase in self:
|
||||||
|
origins = [order.name for order in purchase.picking_ids]
|
||||||
|
production_id = self.env['mrp.production'].search([('origin', 'in', origins)])
|
||||||
|
purchase.production_count = len(production_id)
|
||||||
def button_confirm(self):
|
def button_confirm(self):
|
||||||
super().button_confirm()
|
super().button_confirm()
|
||||||
workorders = self.env['mrp.workorder'].search([('purchase_id', '=', self.id)])
|
workorders = self.env['mrp.workorder'].search([('purchase_id', '=', self.id),('state', '!=', 'cancel')])
|
||||||
for workorder in workorders:
|
for workorder in workorders:
|
||||||
if workorder.routing_type == '表面工艺' and workorder.is_subcontract is True:
|
if workorder.routing_type == '表面工艺' and workorder.is_subcontract is True:
|
||||||
move_out = workorder.move_subcontract_workorder_ids[1]
|
move_out = workorder.move_subcontract_workorder_ids[1]
|
||||||
|
|||||||
@@ -148,61 +148,8 @@ class SaleOrder(models.Model):
|
|||||||
self.env.ref("base.user_admin")).bom_create(product, bom_type, 'product')
|
self.env.ref("base.user_admin")).bom_create(product, bom_type, 'product')
|
||||||
product_bom_purchase.with_user(self.env.ref("base.user_admin")).bom_create_line_has(
|
product_bom_purchase.with_user(self.env.ref("base.user_admin")).bom_create_line_has(
|
||||||
purchase_embryo)
|
purchase_embryo)
|
||||||
result = super(SaleOrder, self).action_confirm()
|
return super(SaleOrder, self).action_confirm()
|
||||||
self.merge_picking()
|
|
||||||
return result
|
|
||||||
|
|
||||||
def merge_picking(self):
|
|
||||||
"""
|
|
||||||
合并多个stock.picking为一个新的stock.picking。
|
|
||||||
:param picking_ids: 需要合并的stock.picking记录ID列表
|
|
||||||
:return: 合并后的新的stock.picking对象
|
|
||||||
"""
|
|
||||||
picking_idss = self.env['stock.picking'].search([('retrospect_ref', 'ilike','%'+ self.name +'%')])
|
|
||||||
for pick in picking_idss:
|
|
||||||
print('qfwowio',pick)
|
|
||||||
picking_ids = self.env['stock.picking'].search([('retrospect_ref', '=', self.default_code)])
|
|
||||||
if not picking_ids:
|
|
||||||
return
|
|
||||||
# 获取需要合并的 stock.picking 记录
|
|
||||||
# 创建一个新的 stock.picking 作为合并结果
|
|
||||||
group = self.env['procurement.group'].create({
|
|
||||||
'name': self.name,
|
|
||||||
'partner_id': self.partner_id.id,
|
|
||||||
})
|
|
||||||
new_picking = self.env['stock.picking'].create({
|
|
||||||
'partner_id': picking_ids[0].partner_id.id,
|
|
||||||
'location_id': picking_ids[0].location_id.id,
|
|
||||||
'location_dest_id': picking_ids[0].location_dest_id.id,
|
|
||||||
'move_ids': False,
|
|
||||||
'sale_id': self.id,
|
|
||||||
'picking_type_id': picking_ids[0].picking_type_id.id,
|
|
||||||
'origin': '合并自: ' + ','.join([p.origin for p in picking_ids]),
|
|
||||||
'retrospect_ref':self.default_code,
|
|
||||||
'person_of_delivery':picking_ids[0].person_of_delivery,
|
|
||||||
'telephone_of_delivery': picking_ids[0].telephone_of_delivery,
|
|
||||||
'address_of_delivery': picking_ids[0].address_of_delivery,
|
|
||||||
'group_id':picking_ids[0].group_id.id
|
|
||||||
})
|
|
||||||
# 合并所有 move_lines
|
|
||||||
for picking in picking_ids:
|
|
||||||
for move in picking.move_ids:
|
|
||||||
# 复制 move_lines 到新的 picking
|
|
||||||
new_move_vals = move.copy_data()[0]
|
|
||||||
new_move_vals['picking_id']=new_picking.id
|
|
||||||
self.env['stock.move'].create(new_move_vals)
|
|
||||||
for pick in picking_idss:
|
|
||||||
print('qfwowio',pick)
|
|
||||||
# 处理合并后的配送单状态
|
|
||||||
new_picking.action_confirm() # 确认新的配送单
|
|
||||||
for pick in picking_idss:
|
|
||||||
print('qfwowio',pick)
|
|
||||||
new_picking.action_assign() # 分配新的配送单
|
|
||||||
|
|
||||||
# 删除原有的配送单
|
|
||||||
picking_ids.write({'state': 'cancel'}) # 将原配送单状态更改为取消
|
|
||||||
|
|
||||||
return new_picking
|
|
||||||
class SaleOrderLine(models.Model):
|
class SaleOrderLine(models.Model):
|
||||||
_inherit = 'sale.order.line'
|
_inherit = 'sale.order.line'
|
||||||
part_number = fields.Char('零件图号', related='product_id.part_number', readonly=True)
|
part_number = fields.Char('零件图号', related='product_id.part_number', readonly=True)
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ class sf_technology_design(models.Model):
|
|||||||
return workorders_values_str
|
return workorders_values_str
|
||||||
|
|
||||||
def write(self, vals):
|
def write(self, vals):
|
||||||
print('qwfojkqwfkio')
|
|
||||||
return super(sf_technology_design, self).write(vals)
|
return super(sf_technology_design, self).write(vals)
|
||||||
def unlink_technology_design(self):
|
def unlink_technology_design(self):
|
||||||
self.active = False
|
self.active = False
|
||||||
|
|||||||
@@ -587,53 +587,35 @@ class StockPicking(models.Model):
|
|||||||
telephone_of_delivery = fields.Char('电话号码', compute='_compute_move_ids', store=True)
|
telephone_of_delivery = fields.Char('电话号码', compute='_compute_move_ids', store=True)
|
||||||
address_of_delivery = fields.Char('联系地址', compute='_compute_move_ids', store=True)
|
address_of_delivery = fields.Char('联系地址', compute='_compute_move_ids', store=True)
|
||||||
|
|
||||||
retrospect_ref = fields.Char('平台订单号', compute='_compute_move_ids', store=True)
|
retrospect_ref = fields.Char('追溯参考', compute='_compute_move_ids', store=True)
|
||||||
sale_name = fields.Char('销售订单', compute='_compute_move_ids', store=True)
|
sale_order_id = fields.Many2one('sale.order', '销售单号', compute='_compute_move_ids', store=True)
|
||||||
picking_type_sequence_code = fields.Char(related='picking_type_id.sequence_code')
|
picking_type_sequence_code = fields.Char(related='picking_type_id.sequence_code')
|
||||||
related_group_ids = fields.Many2many(
|
|
||||||
'procurement.group', string='关联捕获组',
|
|
||||||
readonly=True, compute='_compute_related_group_ids', store=True)
|
|
||||||
@api.depends('origin')
|
|
||||||
def _compute_related_group_ids(self):
|
|
||||||
for record in self:
|
|
||||||
if not record.origin:
|
|
||||||
continue
|
|
||||||
names = record.origin.split(',')
|
|
||||||
related_group_ids = self.env['procurement.group'].search([('name', 'in', names)])
|
|
||||||
record.related_group_ids = [(6, 0, related_group_ids.ids)]
|
|
||||||
|
|
||||||
@api.depends('move_ids', 'move_ids.product_id')
|
@api.depends('move_ids', 'move_ids.product_id')
|
||||||
def _compute_move_ids(self):
|
def _compute_move_ids(self):
|
||||||
for item in self:
|
for item in self:
|
||||||
if item.move_ids:
|
if item.move_ids:
|
||||||
if item.picking_type_id.sequence_code == 'DL':
|
product_id = item.move_ids[0].product_id
|
||||||
sale_name = item.move_ids[0].product_id.with_context(lang='zh_CN').name.split('-')[1]
|
if product_id:
|
||||||
item.sale_name=sale_name
|
sale_info = None
|
||||||
if 'S' in sale_name:
|
if product_id.categ_id.type == '坯料' and product_id.name.startswith('R-S'):
|
||||||
sale_id = self.env['sale.order'].sudo().search([('name', '=', sale_name)])
|
parts = product_id.name.split('-')
|
||||||
item.person_of_delivery = sale_id.person_of_delivery
|
if len(parts) >= 3:
|
||||||
item.telephone_of_delivery = sale_id.telephone_of_delivery
|
sale_name = parts[1]
|
||||||
item.address_of_delivery = sale_id.address_of_delivery
|
sale_info = self.env['sale.order'].sudo().search(
|
||||||
|
[('name', '=', sale_name)])
|
||||||
else:
|
else:
|
||||||
raise ValidationError('坯料名称格式错误,正确格式为[R-S???-?]!!!')
|
sale_order_line = self.env['sale.order.line'].sudo().search(
|
||||||
move_ids = []
|
[('product_id', '=', product_id.id)])
|
||||||
for move_id in item.move_ids:
|
if sale_order_line:
|
||||||
move_ids.append(move_id.product_id.id)
|
sale_info = sale_order_line[0].order_id
|
||||||
boms = self.env['mrp.bom'].sudo().search([('bom_line_ids.product_id', 'in', move_ids)])
|
if sale_info:
|
||||||
if boms:
|
item.sale_order_id = sale_info.id
|
||||||
codes_list = []
|
item.retrospect_ref = sale_info.order_code
|
||||||
for bom in boms:
|
if item.picking_type_id.sequence_code == 'DL':
|
||||||
if bom.product_tmpl_id.default_code:
|
item.person_of_delivery = sale_info.person_of_delivery
|
||||||
code_list = bom.product_tmpl_id.default_code.split('-')
|
item.telephone_of_delivery = sale_info.telephone_of_delivery
|
||||||
if len(code_list) >= 4:
|
item.address_of_delivery = sale_info.address_of_delivery
|
||||||
code = '-'.join(code_list[:4])
|
|
||||||
if code not in codes_list:
|
|
||||||
codes_list.append(code)
|
|
||||||
else:
|
|
||||||
raise ValidationError('坯料成品的内部参考值格式错误')
|
|
||||||
item.retrospect_ref = ','.join(codes_list)
|
|
||||||
elif item.picking_type_id.sequence_code in ['INT', 'PC']:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# 设置外协出入单的名称
|
# 设置外协出入单的名称
|
||||||
def _get_name_Res(self, rescode):
|
def _get_name_Res(self, rescode):
|
||||||
@@ -669,52 +651,61 @@ class StockPicking(models.Model):
|
|||||||
if move_out:
|
if move_out:
|
||||||
workorder = move_out.subcontract_workorder_id
|
workorder = move_out.subcontract_workorder_id
|
||||||
workorder.button_start()
|
workorder.button_start()
|
||||||
|
if self.location_id.name == '成品存货区' and self.location_dest_id.name == '客户':
|
||||||
|
sale_id = self.env['sale.order'].sudo().search(
|
||||||
|
[('name', '=', self.origin)])
|
||||||
|
stock_picking_list = self.env['stock.picking'].sudo().search(
|
||||||
|
[('id', 'in', sale_id.picking_ids.ids)])
|
||||||
|
stock_picking = stock_picking_list.filtered(lambda p: p.state not in ("done", "cancel"))
|
||||||
|
if sale_id and not stock_picking:
|
||||||
|
sale_id.write({'state': 'delivered'})
|
||||||
return res
|
return res
|
||||||
|
|
||||||
# 创建 外协出库入单
|
# 创建 外协出库入单
|
||||||
def create_outcontract_picking(self, workorders, item, sorted_workorders):
|
def create_outcontract_picking(self, workorders, item, sorted_workorders):
|
||||||
for workorder in workorders:
|
for workorder in workorders:
|
||||||
if workorder.move_subcontract_workorder_ids:
|
if workorder.move_subcontract_workorder_ids:
|
||||||
workorder.move_subcontract_workorder_ids.write({'state': 'waiting'})
|
workorder.move_subcontract_workorder_ids.write({'state': 'cancel'})
|
||||||
workorder.move_subcontract_workorder_ids.picking_id.write({'state': 'waiting'})
|
workorder.move_subcontract_workorder_ids.picking_id.write({'state': 'cancel'})
|
||||||
|
# 创建一个新的补货组
|
||||||
|
procurement_group_id = self.env['procurement.group'].create({
|
||||||
|
'name': workorder.name,
|
||||||
|
'partner_id': self.partner_id.id,
|
||||||
|
})
|
||||||
|
move_dest_id = False
|
||||||
|
# 如果当前工单是是制造订单的最后一个工艺外协工单
|
||||||
|
if workorder == next((workorder for workorder in reversed(sorted_workorders) if workorder.is_subcontract),
|
||||||
|
None):
|
||||||
|
move_dest_id = item.move_raw_ids[0].id
|
||||||
else:
|
else:
|
||||||
# 创建一个新的补货组
|
# 从sorted_workorders中找到上一工单的move
|
||||||
procurement_group_id = self.env['procurement.group'].create({
|
if len(sorted_workorders) > 1:
|
||||||
'name': workorder.name,
|
move_dest_id = \
|
||||||
'partner_id': self.partner_id.id,
|
sorted_workorders[sorted_workorders.index(workorder) + 1].move_subcontract_workorder_ids[1].id
|
||||||
})
|
new_picking = True
|
||||||
move_dest_id = False
|
outcontract_picking_type_in = self.env.ref(
|
||||||
# 如果当前工单是是制造订单的最后一个工艺外协工单
|
'sf_manufacturing.outcontract_picking_in').id,
|
||||||
if workorder == next((workorder for workorder in reversed(item.workorder_ids) if workorder.is_subcontract), None):
|
outcontract_picking_type_out = self.env.ref(
|
||||||
move_dest_id = item.move_raw_ids[0].id
|
'sf_manufacturing.outcontract_picking_out').id,
|
||||||
else:
|
moves_in = self.env['stock.move'].sudo().create(
|
||||||
# 从sorted_workorders中找到上一工单的move
|
self.env['stock.move']._get_stock_move_values_Res(item, outcontract_picking_type_in,
|
||||||
if len(sorted_workorders) > 1:
|
procurement_group_id.id, move_dest_id))
|
||||||
move_dest_id = sorted_workorders[sorted_workorders.index(workorder)+1].move_subcontract_workorder_ids[1].id
|
picking_in = self.create(
|
||||||
new_picking = True
|
moves_in._get_new_picking_values_Res(item, workorder, 'WH/OCIN/'))
|
||||||
outcontract_picking_type_in = self.env.ref(
|
# pick_ids.append(picking_in.id)
|
||||||
'sf_manufacturing.outcontract_picking_in').id,
|
moves_in.write(
|
||||||
outcontract_picking_type_out = self.env.ref(
|
{'picking_id': picking_in.id, 'state': 'waiting'})
|
||||||
'sf_manufacturing.outcontract_picking_out').id,
|
moves_in._assign_picking_post_process(new=new_picking)
|
||||||
moves_in = self.env['stock.move'].sudo().create(
|
moves_out = self.env['stock.move'].sudo().create(
|
||||||
self.env['stock.move']._get_stock_move_values_Res(item, outcontract_picking_type_in,
|
self.env['stock.move']._get_stock_move_values_Res(item, outcontract_picking_type_out,
|
||||||
procurement_group_id.id, move_dest_id))
|
procurement_group_id.id, moves_in.id))
|
||||||
picking_in = self.create(
|
workorder.write({'move_subcontract_workorder_ids': [(6, 0, [moves_in.id, moves_out.id])]})
|
||||||
moves_in._get_new_picking_values_Res(item, workorder, 'WH/OCIN/'))
|
picking_out = self.create(
|
||||||
# pick_ids.append(picking_in.id)
|
moves_out._get_new_picking_values_Res(item, workorder, 'WH/OCOUT/'))
|
||||||
moves_in.write(
|
# pick_ids.append(picking_out.id)
|
||||||
{'picking_id': picking_in.id, 'state': 'waiting'})
|
moves_out.write(
|
||||||
moves_in._assign_picking_post_process(new=new_picking)
|
{'picking_id': picking_out.id, 'state': 'waiting'})
|
||||||
moves_out = self.env['stock.move'].sudo().create(
|
moves_out._assign_picking_post_process(new=new_picking)
|
||||||
self.env['stock.move']._get_stock_move_values_Res(item, outcontract_picking_type_out,
|
|
||||||
procurement_group_id.id, moves_in.id))
|
|
||||||
workorder.write({'move_subcontract_workorder_ids': [(6, 0, [moves_in.id, moves_out.id])]})
|
|
||||||
picking_out = self.create(
|
|
||||||
moves_out._get_new_picking_values_Res(item, workorder, 'WH/OCOUT/'))
|
|
||||||
# pick_ids.append(picking_out.id)
|
|
||||||
moves_out.write(
|
|
||||||
{'picking_id': picking_out.id, 'state': 'waiting'})
|
|
||||||
moves_out._assign_picking_post_process(new=new_picking)
|
|
||||||
|
|
||||||
@api.depends('move_type', 'immediate_transfer', 'move_ids.state', 'move_ids.picking_id')
|
@api.depends('move_type', 'immediate_transfer', 'move_ids.state', 'move_ids.picking_id')
|
||||||
def _compute_state(self):
|
def _compute_state(self):
|
||||||
@@ -738,6 +729,34 @@ class ReStockMove(models.Model):
|
|||||||
materiel_length = fields.Float(string='物料长度', digits=(16, 4))
|
materiel_length = fields.Float(string='物料长度', digits=(16, 4))
|
||||||
materiel_width = fields.Float(string='物料宽度', digits=(16, 4))
|
materiel_width = fields.Float(string='物料宽度', digits=(16, 4))
|
||||||
materiel_height = fields.Float(string='物料高度', digits=(16, 4))
|
materiel_height = fields.Float(string='物料高度', digits=(16, 4))
|
||||||
|
part_number = fields.Char(string='零件图号', compute='_compute_part_info', store=True)
|
||||||
|
part_name = fields.Char(string='零件名称', compute='_compute_part_info', store=True)
|
||||||
|
|
||||||
|
@api.depends('product_id')
|
||||||
|
def _compute_part_info(self):
|
||||||
|
for move in self:
|
||||||
|
if move.product_id.categ_id.type == '成品':
|
||||||
|
move.part_number = move.product_id.part_number
|
||||||
|
move.part_name = move.product_id.part_name
|
||||||
|
elif move.product_id.categ_id.type == '坯料':
|
||||||
|
if move.origin:
|
||||||
|
origin = move.origin.split(',')[0] if ',' in move.origin else move.origin
|
||||||
|
mrp_productio_info = self.env['mrp.production'].sudo().search(
|
||||||
|
[('name', '=', origin)])
|
||||||
|
if mrp_productio_info:
|
||||||
|
move.part_number = mrp_productio_info.part_number
|
||||||
|
move.part_name = mrp_productio_info.part_name
|
||||||
|
else:
|
||||||
|
purchase_order_info = self.env['purchase.order'].sudo().search(
|
||||||
|
[('name', '=', origin)])
|
||||||
|
if purchase_order_info:
|
||||||
|
mrp_production_ids = purchase_order_info._get_mrp_productions().ids
|
||||||
|
if mrp_production_ids:
|
||||||
|
mrp_productio_info = self.env['mrp.production'].sudo().search(
|
||||||
|
[('id', '=', mrp_production_ids[0])])
|
||||||
|
if mrp_productio_info:
|
||||||
|
move.part_number = mrp_productio_info.part_number
|
||||||
|
move.part_name = mrp_productio_info.part_name
|
||||||
|
|
||||||
def _get_stock_move_values_Res(self, item, picking_type_id, group_id, move_dest_ids=False):
|
def _get_stock_move_values_Res(self, item, picking_type_id, group_id, move_dest_ids=False):
|
||||||
route_id = self.env.ref('sf_manufacturing.route_surface_technology_outsourcing').id
|
route_id = self.env.ref('sf_manufacturing.route_surface_technology_outsourcing').id
|
||||||
|
|||||||
@@ -10,6 +10,18 @@
|
|||||||
<field name="related_product" optional="show"/>
|
<field name="related_product" optional="show"/>
|
||||||
<field name="part_number" optional="show"/>
|
<field name="part_number" optional="show"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
<xpath expr="//sheet//div[@class='oe_button_box']" position="inside">
|
||||||
|
<button class="oe_stat_button" name="action_view_production" type="object" icon="fa-wrench"
|
||||||
|
attrs="{'invisible': [('production_count', '=', 0)]}"
|
||||||
|
>
|
||||||
|
<div class="o_field_widget o_stat_info">
|
||||||
|
<span class="o_stat_value">
|
||||||
|
<field name="production_count"/>
|
||||||
|
</span>
|
||||||
|
<span class="o_stat_text">制造订单</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -17,6 +17,12 @@
|
|||||||
<field name="model">stock.picking</field>
|
<field name="model">stock.picking</field>
|
||||||
<field name="inherit_id" ref="stock.view_picking_form"/>
|
<field name="inherit_id" ref="stock.view_picking_form"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//field[@name='backorder_id']" position="after">
|
||||||
|
<field name="retrospect_ref"/>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//field[@name='origin']" position="after">
|
||||||
|
<field name="sale_order_id"/>
|
||||||
|
</xpath>
|
||||||
<xpath expr="//field[@name='user_id']" position="after">
|
<xpath expr="//field[@name='user_id']" position="after">
|
||||||
<field name="picking_type_sequence_code" invisible="1"/>
|
<field name="picking_type_sequence_code" invisible="1"/>
|
||||||
<field name="retrospect_ref"
|
<field name="retrospect_ref"
|
||||||
@@ -26,6 +32,10 @@
|
|||||||
attrs="{'invisible':[('picking_type_sequence_code','!=','DL')]}"/>
|
attrs="{'invisible':[('picking_type_sequence_code','!=','DL')]}"/>
|
||||||
<field name="address_of_delivery" attrs="{'invisible':[('picking_type_sequence_code','!=','DL')]}"/>
|
<field name="address_of_delivery" attrs="{'invisible':[('picking_type_sequence_code','!=','DL')]}"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
<xpath expr="//field[@name='product_id']" position="after">
|
||||||
|
<field name="part_number" optional="show"/>
|
||||||
|
<field name="part_name" optional="show"/>
|
||||||
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
@@ -34,8 +44,10 @@
|
|||||||
<field name="model">stock.picking</field>
|
<field name="model">stock.picking</field>
|
||||||
<field name="inherit_id" ref="stock.vpicktree"/>
|
<field name="inherit_id" ref="stock.vpicktree"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//field[@name='origin']" position="before">
|
||||||
|
<field name="sale_order_id" string="销售单号"/>
|
||||||
|
</xpath>
|
||||||
<xpath expr="//field[@name='origin']" position="after">
|
<xpath expr="//field[@name='origin']" position="after">
|
||||||
<field name="sale_name"/>
|
|
||||||
<field name="retrospect_ref"/>
|
<field name="retrospect_ref"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
@@ -46,8 +58,13 @@
|
|||||||
<field name="model">stock.picking</field>
|
<field name="model">stock.picking</field>
|
||||||
<field name="inherit_id" ref="stock.view_picking_internal_search"/>
|
<field name="inherit_id" ref="stock.view_picking_internal_search"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//field[@name='name']" position="replace">
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="retrospect_ref"/>
|
||||||
|
<field name="sale_order_id" string="销售单号"/>
|
||||||
|
</xpath>
|
||||||
<xpath expr="//filter[@name='picking_type']" position="after">
|
<xpath expr="//filter[@name='picking_type']" position="after">
|
||||||
<filter string="追溯参考" name="retrospect_ref" domain="[]"
|
<filter string="追溯参考" name="retrospect" domain="[]"
|
||||||
context="{'group_by': 'retrospect_ref'}"/>
|
context="{'group_by': 'retrospect_ref'}"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
'category': 'sf',
|
'category': 'sf',
|
||||||
'website': 'https://www.sf.jikimo.com',
|
'website': 'https://www.sf.jikimo.com',
|
||||||
'depends': ['sale', 'purchase', 'sf_plan', 'jikimo_message_notify', 'stock', 'sf_quality', 'mrp',
|
'depends': ['sale', 'purchase', 'sf_plan', 'jikimo_message_notify', 'stock', 'sf_quality', 'mrp',
|
||||||
'sf_manufacturing','product'],
|
'sf_manufacturing', 'product', 'quality'],
|
||||||
'data': [
|
'data': [
|
||||||
'data/bussiness_node.xml',
|
'data/bussiness_node.xml',
|
||||||
'data/cron_data.xml',
|
'data/cron_data.xml',
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
'views/mrp_workorder_views.xml',
|
'views/mrp_workorder_views.xml',
|
||||||
'views/purchase_order_view.xml',
|
'views/purchase_order_view.xml',
|
||||||
|
'views/stock_picking_view.xml',
|
||||||
],
|
],
|
||||||
'test': [
|
'test': [
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -150,5 +150,10 @@
|
|||||||
<field name="name">采购单已逾期提醒</field>
|
<field name="name">采购单已逾期提醒</field>
|
||||||
<field name="model">purchase.order</field>
|
<field name="model">purchase.order</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<record id="bussiness_quality_check" model="jikimo.message.bussiness.node">
|
||||||
|
<field name="name">待质检提醒</field>
|
||||||
|
<field name="model">product.product</field>
|
||||||
|
</record>
|
||||||
</data>
|
</data>
|
||||||
</odoo>
|
</odoo>
|
||||||
@@ -389,5 +389,17 @@
|
|||||||
事项:[共有{{num}}个采购订单已逾期]({{url}})
|
事项:[共有{{num}}个采购订单已逾期]({{url}})
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<record id="template_quality_check" model="jikimo.message.template">
|
||||||
|
<field name="name">待质检提醒</field>
|
||||||
|
<field name="model_id" ref="product.model_product_product"/>
|
||||||
|
<field name="model">product.product</field>
|
||||||
|
<field name="bussiness_node_id" ref="bussiness_quality_check"/>
|
||||||
|
<field name="msgtype">markdown</field>
|
||||||
|
<field name="urgency">normal</field>
|
||||||
|
<field name="content">### 待质检提醒:
|
||||||
|
单号:产品[{{name}}]({{url}})
|
||||||
|
事项:有{{num}}个质检单需要处理。</field>
|
||||||
|
</record>
|
||||||
</data>
|
</data>
|
||||||
</odoo>
|
</odoo>
|
||||||
@@ -13,3 +13,4 @@ from . import sf_message_maintenance_logs
|
|||||||
from . import sf_message_mrp_production_wizard
|
from . import sf_message_mrp_production_wizard
|
||||||
from . import sf_message_mrp_production_adjust_wizard
|
from . import sf_message_mrp_production_adjust_wizard
|
||||||
from . import sf_message_product
|
from . import sf_message_product
|
||||||
|
from . import sf_message_quality_check
|
||||||
|
|||||||
@@ -63,8 +63,9 @@ class SFMessageMrpProduction(models.Model):
|
|||||||
[('origin', 'in', mrp_production_names), ('state', '=', 'assigned')])
|
[('origin', 'in', mrp_production_names), ('state', '=', 'assigned')])
|
||||||
if stock_picking_num >= 1:
|
if stock_picking_num >= 1:
|
||||||
url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
||||||
action_id = self.env.ref('stock.action_picking_tree_ready').id
|
action_id = self.env.ref('sf_message.action_picking_outsourced_tree_ready').id
|
||||||
url_with_id = f"{url}/web#view_type=list&action={action_id}"
|
menu_id = self.env.ref('stock.menu_stock_root').id
|
||||||
|
url_with_id = f"{url}/web#view_type=list&action={action_id}&menu_id={menu_id}"
|
||||||
content = content.replace('{{name}}', mrp_production.product_id.name).replace('{{url}}',
|
content = content.replace('{{name}}', mrp_production.product_id.name).replace('{{url}}',
|
||||||
url_with_id).replace(
|
url_with_id).replace(
|
||||||
'{{num}}', str(stock_picking_num))
|
'{{num}}', str(stock_picking_num))
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from odoo import models, fields, api, _
|
|||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
|
|
||||||
class SFMessagePlan(models.Model):
|
class SFMessageProduct(models.Model):
|
||||||
_name = 'product.product'
|
_name = 'product.product'
|
||||||
_inherit = ['product.product', 'jikimo.message.dispatch']
|
_inherit = ['product.product', 'jikimo.message.dispatch']
|
||||||
|
|
||||||
@@ -28,7 +28,19 @@ class SFMessagePlan(models.Model):
|
|||||||
'{{number}}', str(production_num)).replace(
|
'{{number}}', str(production_num)).replace(
|
||||||
'{{request_url}}', url)
|
'{{request_url}}', url)
|
||||||
contents.append(content)
|
contents.append(content)
|
||||||
return contents
|
if message_queue_id.message_template_id.name == '待质检提醒':
|
||||||
|
content = message_queue_id.message_template_id.content
|
||||||
|
product_product = self.env['product.product'].sudo().search([('id', '=', int(message_queue_id.res_id))])
|
||||||
|
quality_check_num = self.env['quality.check'].sudo().search_count(
|
||||||
|
[('product_id', '=', product_product.id), ('quality_state', '=', 'none')])
|
||||||
|
if quality_check_num >= 1:
|
||||||
|
url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
||||||
|
action_id = self.env.ref('quality_control.quality_check_action_report').id
|
||||||
|
url_with_id = f"{url}/web#view_type=list&action={action_id}"
|
||||||
|
content = content.replace('{{name}}', product_product.name).replace('{{url}}', url_with_id).replace(
|
||||||
|
'{{num}}', str(quality_check_num))
|
||||||
|
contents.append(content)
|
||||||
|
return contents, message_queue_ids
|
||||||
|
|
||||||
def get_request_url(self):
|
def get_request_url(self):
|
||||||
url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
||||||
|
|||||||
34
sf_message/models/sf_message_quality_check.py
Normal file
34
sf_message/models/sf_message_quality_check.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import logging
|
||||||
|
from odoo import models, fields, api, _
|
||||||
|
|
||||||
|
|
||||||
|
class SFMessageQualityCheck(models.Model):
|
||||||
|
_name = 'quality.check'
|
||||||
|
_inherit = ['quality.check', 'jikimo.message.dispatch']
|
||||||
|
|
||||||
|
@api.model_create_multi
|
||||||
|
def create(self, vals_list):
|
||||||
|
result = super().create(vals_list)
|
||||||
|
try:
|
||||||
|
# 判断是否为web页面创建请求
|
||||||
|
is_web_request = self.env.context.get('is_web_request', False)
|
||||||
|
if not is_web_request:
|
||||||
|
for obj in result:
|
||||||
|
jikimo_message_queue = self.get_message_queue(obj.product_id.id)
|
||||||
|
if not jikimo_message_queue:
|
||||||
|
obj.product_id.add_queue('待质检提醒')
|
||||||
|
except Exception as e:
|
||||||
|
logging.info('add_queue待质检提醒 error:%s' % e)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def get_message_queue(self, res_id):
|
||||||
|
business_node_id = self.env.ref('sf_message.bussiness_quality_check').id
|
||||||
|
message_template = self.env["jikimo.message.template"].sudo().search([
|
||||||
|
("name", "=", '待质检提醒'),
|
||||||
|
("bussiness_node_id", "=", business_node_id)
|
||||||
|
], limit=1)
|
||||||
|
jikimo_message_queue = self.env['jikimo.message.queue'].sudo().search(
|
||||||
|
[('res_id', '=', res_id), ("message_status", "in", ("pending", "sent")),
|
||||||
|
('message_template_id', '=', message_template.id)])
|
||||||
|
return jikimo_message_queue
|
||||||
@@ -32,7 +32,7 @@ class SFMessageSale(models.Model):
|
|||||||
for purchase_order_id in purchase_order_ids:
|
for purchase_order_id in purchase_order_ids:
|
||||||
if purchase_order_id.purchase_type == 'outsourcing':
|
if purchase_order_id.purchase_type == 'outsourcing':
|
||||||
purchase_order_id.add_queue('委外加工采购单提醒')
|
purchase_order_id.add_queue('委外加工采购单提醒')
|
||||||
if purchase_order_id.purchase_type == 'standard':
|
if purchase_order_id.purchase_type == 'outside':
|
||||||
purchase_order_id.add_queue('外购订单采购单提醒')
|
purchase_order_id.add_queue('外购订单采购单提醒')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.info('add_queue error:%s' % e)
|
logging.info('add_queue error:%s' % e)
|
||||||
|
|||||||
37
sf_message/views/stock_picking_view.xml
Normal file
37
sf_message/views/stock_picking_view.xml
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<record id="view_picking_internal_search_sf" model="ir.ui.view">
|
||||||
|
<field name="name">stock.picking.search</field>
|
||||||
|
<field name="model">stock.picking</field>
|
||||||
|
<field name="inherit_id" ref="stock.view_picking_internal_search"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//filter[@name='activities_exception']" position="before">
|
||||||
|
<filter name="outsourced" string="外协出库" domain="[('picking_type_id.name', '=', '外协出库')]"
|
||||||
|
invisible="1"/>
|
||||||
|
<separator/>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
<record id="action_picking_outsourced_tree_ready" model="ir.actions.act_window">
|
||||||
|
<field name="name">待办</field>
|
||||||
|
<field name="res_model">stock.picking</field>
|
||||||
|
<field name="type">ir.actions.act_window</field>
|
||||||
|
<field name="view_mode">tree,kanban,form,calendar</field>
|
||||||
|
<field name="domain"></field>
|
||||||
|
<field name="context">{'search_default_outsourced': 1,'contact_display': 'partner_address',
|
||||||
|
'search_default_available': 1}
|
||||||
|
</field>
|
||||||
|
<field name="search_view_id" ref="stock.view_picking_internal_search"/>
|
||||||
|
<field name="help" type="html">
|
||||||
|
<p class="o_view_nocontent_smiling_face">
|
||||||
|
没有仓库调拨。 让我们创建一个!
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
移动允许您将产品从一个位置移动到另外一个位置。
|
||||||
|
</p>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</odoo>
|
||||||
@@ -292,6 +292,9 @@ class RePurchaseOrder(models.Model):
|
|||||||
# 合同概况
|
# 合同概况
|
||||||
contract_summary = fields.Text(string='合同概况')
|
contract_summary = fields.Text(string='合同概况')
|
||||||
|
|
||||||
|
# 选择是否为紧急采购
|
||||||
|
urgent_purchase = fields.Selection([('no', '否'), ('yes', '是')], string='紧急采购', default='no')
|
||||||
|
|
||||||
@api.depends('origin')
|
@api.depends('origin')
|
||||||
def _compute_purchase_type(self):
|
def _compute_purchase_type(self):
|
||||||
for purchase in self:
|
for purchase in self:
|
||||||
@@ -361,6 +364,7 @@ class RePurchaseOrder(models.Model):
|
|||||||
purchase_order = pp._get_surface_technics_purchase_ids()
|
purchase_order = pp._get_surface_technics_purchase_ids()
|
||||||
if purchase_order:
|
if purchase_order:
|
||||||
purchase_order.write({'state': 'draft'})
|
purchase_order.write({'state': 'draft'})
|
||||||
|
pp.purchase_id = [(6, 0, [purchase_order.id])]
|
||||||
else:
|
else:
|
||||||
server_template = self.env['product.template'].search(
|
server_template = self.env['product.template'].search(
|
||||||
[('server_product_process_parameters_id', '=', pp.surface_technics_parameters_id.id),
|
[('server_product_process_parameters_id', '=', pp.surface_technics_parameters_id.id),
|
||||||
|
|||||||
@@ -9,12 +9,16 @@
|
|||||||
<xpath expr="//header/button[@name='action_view_picking']" position="attributes">
|
<xpath expr="//header/button[@name='action_view_picking']" position="attributes">
|
||||||
<attribute name="invisible">1</attribute>
|
<attribute name="invisible">1</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
<xpath expr="//header/button[@name='button_confirm']" position="replace">
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//header/button[@name='button_confirm']" position="replace">
|
||||||
|
</xpath>
|
||||||
<xpath expr="//header/button[@name='action_rfq_send'][1]" position="before">
|
<xpath expr="//header/button[@name='action_rfq_send'][1]" position="before">
|
||||||
<button name="button_confirm" type="object" states="sent" string="Confirm Order"
|
<button name="button_confirm" type="object" string="确认订单"
|
||||||
context="{'validate_analytic': True}" class="oe_highlight" id="bid_confirm"
|
context="{'validate_analytic': True}" class="oe_highlight" id="draft_confirm"
|
||||||
data-hotkey="v"/>
|
groups="sf_base.group_purchase,sf_base.group_purchase_director"
|
||||||
<button name="button_confirm" type="object" states="draft" context="{'validate_analytic': True}"
|
attrs="{'invisible': [('state', 'in', ['purchase', 'done', 'cancel'])]}"
|
||||||
string="Confirm Order" id="draft_confirm"/>
|
/>
|
||||||
<button name="action_view_picking"
|
<button name="action_view_picking"
|
||||||
string="接收产品" class="oe_highlight" type="object"
|
string="接收产品" class="oe_highlight" type="object"
|
||||||
attrs="{'invisible': ['|', '|' , ('is_shipped', '=', True), ('state','not in', ('purchase','done')), ('incoming_picking_count', '=', 0)]}"
|
attrs="{'invisible': ['|', '|' , ('is_shipped', '=', True), ('state','not in', ('purchase','done')), ('incoming_picking_count', '=', 0)]}"
|
||||||
@@ -25,11 +29,11 @@
|
|||||||
<xpath expr="//header/button[@name='button_cancel'][2]" position="attributes">
|
<xpath expr="//header/button[@name='button_cancel'][2]" position="attributes">
|
||||||
<attribute name="invisible">1</attribute>
|
<attribute name="invisible">1</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//header/button[@name='button_confirm'][3]" position="attributes">
|
<xpath expr="//field[@name='user_id']" position="attributes">
|
||||||
<attribute name="invisible">1</attribute>
|
<attribute name="string">采购员</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//header/button[@name='button_confirm'][4]" position="attributes">
|
<xpath expr="//field[@name='origin']" position="attributes">
|
||||||
<attribute name="invisible">1</attribute>
|
<attribute name="string">源单据</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
||||||
<field name="partner_id" position="replace">
|
<field name="partner_id" position="replace">
|
||||||
@@ -38,13 +42,6 @@
|
|||||||
<field name="currency_id" position="after">
|
<field name="currency_id" position="after">
|
||||||
<field name="remark" attrs="{'readonly': [('state', 'in', ['purchase'])]}" string="订单备注"/>
|
<field name="remark" attrs="{'readonly': [('state', 'in', ['purchase'])]}" string="订单备注"/>
|
||||||
</field>
|
</field>
|
||||||
<xpath expr="//form/header/button[@name='button_confirm'][2]" position="replace">
|
|
||||||
<button name="button_confirm" type="object" context="{'validate_analytic': True}"
|
|
||||||
string="确认订单" id="draft_confirm"
|
|
||||||
groups="sf_base.group_purchase,sf_base.group_purchase_director"
|
|
||||||
attrs="{'invisible': [('state', 'in', ['purchase', 'cancel'])]}"
|
|
||||||
/>
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//form/header/button[@name='action_rfq_send'][1]" position="replace">
|
<xpath expr="//form/header/button[@name='action_rfq_send'][1]" position="replace">
|
||||||
<button name="action_rfq_send" states="draft" string="通过Email发送采购单" type="object"
|
<button name="action_rfq_send" states="draft" string="通过Email发送采购单" type="object"
|
||||||
context="{'send_rfq':True}" class="oe_highlight" data-hotkey="g"
|
context="{'send_rfq':True}" class="oe_highlight" data-hotkey="g"
|
||||||
@@ -81,10 +78,6 @@
|
|||||||
<xpath expr="//form/header/button[@name='action_create_invoice'][2]" position="attributes">
|
<xpath expr="//form/header/button[@name='action_create_invoice'][2]" position="attributes">
|
||||||
<attribute name="groups">sf_base.group_purchase,sf_base.group_purchase_director</attribute>
|
<attribute name="groups">sf_base.group_purchase,sf_base.group_purchase_director</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//form/header/button[@name='button_confirm']" position="attributes">
|
|
||||||
<attribute name="groups">sf_base.group_purchase,sf_base.group_purchase_director</attribute>
|
|
||||||
<!-- <button name="action_create_invoice" string="创建账单" type="object" class="oe_highlight" context="{'create_bill':True}" attrs="{'invisible': ['|', ('state', 'not in', ('purchase', 'done')), ('invoice_status', 'in', ('no', 'invoiced'))]}" data-hotkey="w" groups="sf_base.group_purchase,sf_base.group_purchase_director"/> -->
|
|
||||||
</xpath>
|
|
||||||
<!-- <xpath expr="//form/header/button[@name='action_create_invoice[2]']" position="attributes">-->
|
<!-- <xpath expr="//form/header/button[@name='action_create_invoice[2]']" position="attributes">-->
|
||||||
<!-- <attribute name="groups">sf_base.group_purchase,sf_base.group_purchase_director</attribute>-->
|
<!-- <attribute name="groups">sf_base.group_purchase,sf_base.group_purchase_director</attribute>-->
|
||||||
<!-- </xpath>-->
|
<!-- </xpath>-->
|
||||||
@@ -181,6 +174,7 @@
|
|||||||
<field name="partner_id" position="after">
|
<field name="partner_id" position="after">
|
||||||
<field name="purchase_type" string="采购类型" readonly="1"/>
|
<field name="purchase_type" string="采购类型" readonly="1"/>
|
||||||
<field name="picking_type_id" string="作业类型" domain="[('code','=','incoming'), '|', ('warehouse_id', '=', False), ('warehouse_id.company_id', '=', company_id)]" options="{'no_create': True}" groups="stock.group_stock_multi_locations"/>
|
<field name="picking_type_id" string="作业类型" domain="[('code','=','incoming'), '|', ('warehouse_id', '=', False), ('warehouse_id.company_id', '=', company_id)]" options="{'no_create': True}" groups="stock.group_stock_multi_locations"/>
|
||||||
|
<field name="urgent_purchase"/>
|
||||||
<label for="date_planned" string="最近交货日期"/>
|
<label for="date_planned" string="最近交货日期"/>
|
||||||
<div name="date_planned_div" class="o_row">
|
<div name="date_planned_div" class="o_row">
|
||||||
<field name="date_planned" attrs="{'readonly': [('state', 'not in', ('draft', 'sent', 'to approve', 'purchase'))]}"/>
|
<field name="date_planned" attrs="{'readonly': [('state', 'not in', ('draft', 'sent', 'to approve', 'purchase'))]}"/>
|
||||||
@@ -235,6 +229,9 @@
|
|||||||
<xpath expr="//field[@name='user_id']" position="attributes">
|
<xpath expr="//field[@name='user_id']" position="attributes">
|
||||||
<attribute name="string">采购员</attribute>
|
<attribute name="string">采购员</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
<xpath expr="//field[@name='origin']" position="attributes">
|
||||||
|
<attribute name="string">源单据</attribute>
|
||||||
|
</xpath>
|
||||||
<xpath expr="//field[@name='activity_ids']" position="attributes">
|
<xpath expr="//field[@name='activity_ids']" position="attributes">
|
||||||
<attribute name="optional">hide</attribute>
|
<attribute name="optional">hide</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
@@ -292,6 +289,9 @@
|
|||||||
<xpath expr="//field[@name='user_id']" position="attributes">
|
<xpath expr="//field[@name='user_id']" position="attributes">
|
||||||
<attribute name="string">采购员</attribute>
|
<attribute name="string">采购员</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
<xpath expr="//field[@name='origin']" position="attributes">
|
||||||
|
<attribute name="string">源单据</attribute>
|
||||||
|
</xpath>
|
||||||
<xpath expr="//field[@name='user_id']" position="after">
|
<xpath expr="//field[@name='user_id']" position="after">
|
||||||
<field name="delivery_warning" optional="show"/>
|
<field name="delivery_warning" optional="show"/>
|
||||||
<field name="date_planned" string="最近交货日期" optional="show" widget="date"/>
|
<field name="date_planned" string="最近交货日期" optional="show" widget="date"/>
|
||||||
|
|||||||
@@ -13,6 +13,74 @@ _logger = logging.getLogger(__name__)
|
|||||||
class StockPicking(models.Model):
|
class StockPicking(models.Model):
|
||||||
_inherit = 'stock.picking'
|
_inherit = 'stock.picking'
|
||||||
|
|
||||||
|
pro_purchase_count = fields.Integer('坯料采购单数量', compute='_compute_pro_purchase_count', store=True)
|
||||||
|
|
||||||
|
@api.depends('name')
|
||||||
|
def _compute_pro_purchase_count(self):
|
||||||
|
for sp in self:
|
||||||
|
if sp:
|
||||||
|
po_ids = self.env['purchase.order'].sudo().search([
|
||||||
|
('origin', 'like', sp.name), ('purchase_type', '=', 'standard')])
|
||||||
|
if po_ids:
|
||||||
|
sp.pro_purchase_count = len(po_ids)
|
||||||
|
|
||||||
|
def pro_purchase_order(self):
|
||||||
|
"""
|
||||||
|
坯料采购
|
||||||
|
"""
|
||||||
|
po_ids = self.env['purchase.order'].sudo().search([
|
||||||
|
('origin', 'like', self.name), ('purchase_type', '=', 'standard')])
|
||||||
|
action = {
|
||||||
|
'res_model': 'purchase.order',
|
||||||
|
'type': 'ir.actions.act_window',
|
||||||
|
}
|
||||||
|
if len(po_ids) == 1:
|
||||||
|
action.update({
|
||||||
|
'view_mode': 'form',
|
||||||
|
'res_id': po_ids.id,
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
action.update({
|
||||||
|
'name': _("采购订单列表"),
|
||||||
|
'domain': [('id', 'in', po_ids.ids)],
|
||||||
|
'view_mode': 'tree,form',
|
||||||
|
})
|
||||||
|
return action
|
||||||
|
|
||||||
|
pro_out_purchase_count = fields.Integer('坯料委外单数量', compute='_compute_pro_out_purchase_count', store=True)
|
||||||
|
|
||||||
|
@api.depends('name')
|
||||||
|
def _compute_pro_out_purchase_count(self):
|
||||||
|
for sp in self:
|
||||||
|
if sp:
|
||||||
|
po_ids = self.env['purchase.order'].sudo().search([
|
||||||
|
('origin', 'like', sp.name), ('purchase_type', '=', 'outsourcing')])
|
||||||
|
if po_ids:
|
||||||
|
sp.pro_out_purchase_count = len(po_ids)
|
||||||
|
|
||||||
|
def pro_out_purchase_order(self):
|
||||||
|
"""
|
||||||
|
坯料委外
|
||||||
|
"""
|
||||||
|
po_ids = self.env['purchase.order'].sudo().search([
|
||||||
|
('origin', 'like', self.name), ('purchase_type', '=', 'outsourcing')])
|
||||||
|
action = {
|
||||||
|
'res_model': 'purchase.order',
|
||||||
|
'type': 'ir.actions.act_window',
|
||||||
|
}
|
||||||
|
if len(po_ids) == 1:
|
||||||
|
action.update({
|
||||||
|
'view_mode': 'form',
|
||||||
|
'res_id': po_ids.id,
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
action.update({
|
||||||
|
'name': _("委外订单列表"),
|
||||||
|
'domain': [('id', 'in', po_ids.ids)],
|
||||||
|
'view_mode': 'tree,form',
|
||||||
|
})
|
||||||
|
return action
|
||||||
|
|
||||||
# 重写验证,下发发货到bfm
|
# 重写验证,下发发货到bfm
|
||||||
def button_validate(self):
|
def button_validate(self):
|
||||||
info = super(StockPicking, self).button_validate()
|
info = super(StockPicking, self).button_validate()
|
||||||
|
|||||||
@@ -1,6 +1,28 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<odoo>
|
<odoo>
|
||||||
<data>
|
<data>
|
||||||
|
<record id="add_check_out_view_picking_form" model="ir.ui.view">
|
||||||
</data>
|
<field name="name">添加坯料采购单链接</field>
|
||||||
|
<field name="model">stock.picking</field>
|
||||||
|
<field name="inherit_id" ref="stock.view_picking_form"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//form//sheet//div[@name='button_box']//button[@name='action_picking_move_tree']" position="before">
|
||||||
|
<button class="oe_stat_button" name="pro_purchase_order" type="object" icon="fa-credit-card"
|
||||||
|
attrs="{'invisible': [('pro_purchase_count', '=', 0)]}">
|
||||||
|
<div class="o_field_widget o_stat_info">
|
||||||
|
<span class="o_stat_value"><field name="pro_purchase_count"/></span>
|
||||||
|
<span class="o_stat_text">坯料采购</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
<button class="oe_stat_button" name="pro_out_purchase_order" type="object" icon="fa-credit-card"
|
||||||
|
attrs="{'invisible': [('pro_out_purchase_count', '=', 0)]}">
|
||||||
|
<div class="o_field_widget o_stat_info">
|
||||||
|
<span class="o_stat_value"><field name="pro_out_purchase_count"/></span>
|
||||||
|
<span class="o_stat_text">坯料委外</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
</odoo>
|
</odoo>
|
||||||
@@ -21,7 +21,7 @@ class FixtureMaterialSearch(models.Model):
|
|||||||
image = fields.Binary('图片', related='product_id.image_1920')
|
image = fields.Binary('图片', related='product_id.image_1920')
|
||||||
number = fields.Integer('总数量', compute='_compute_number')
|
number = fields.Integer('总数量', compute='_compute_number')
|
||||||
usable_num = fields.Integer('可用数量', compute='_compute_number')
|
usable_num = fields.Integer('可用数量', compute='_compute_number')
|
||||||
have_been_used_num = fields.Integer('在用数量', compute='_compute_number')
|
have_been_used_num = fields.Integer('占用数量', compute='_compute_number')
|
||||||
scrap_num = fields.Integer('报废数量', compute='_compute_number')
|
scrap_num = fields.Integer('报废数量', compute='_compute_number')
|
||||||
|
|
||||||
barcode_ids = fields.One2many('stock.lot', 'fixture_material_search_id', string='序列号', readonly=True)
|
barcode_ids = fields.One2many('stock.lot', 'fixture_material_search_id', string='序列号', readonly=True)
|
||||||
|
|||||||
@@ -126,16 +126,16 @@ class StockLot(models.Model):
|
|||||||
tool_material_search_id = fields.Many2one('sf.tool.material.search', string='刀具物料搜索')
|
tool_material_search_id = fields.Many2one('sf.tool.material.search', string='刀具物料搜索')
|
||||||
fixture_material_search_id = fields.Many2one('sf.fixture.material.search', string='夹具物料搜索')
|
fixture_material_search_id = fields.Many2one('sf.fixture.material.search', string='夹具物料搜索')
|
||||||
tool_material_status = fields.Selection(
|
tool_material_status = fields.Selection(
|
||||||
[('未入库', '未入库'), ('可用', '可用'), ('在用', '空闲'), ('报废', '报废')], string='状态',
|
[('未入库', '未入库'), ('可用', '空闲'), ('在用', '占用'), ('报废', '报废')], string='状态',
|
||||||
compute='_compute_tool_material_status', store=True)
|
compute='_compute_tool_material_status', store=True)
|
||||||
|
|
||||||
@api.depends('quant_ids')
|
@api.depends('quant_ids')
|
||||||
def _compute_tool_material_status(self):
|
def _compute_tool_material_status(self):
|
||||||
for record in self:
|
for record in self:
|
||||||
if record:
|
if record:
|
||||||
if record.product_id.categ_id.name in ['刀具', '夹具']:
|
if record.product_id.categ_id.name in ['刀具']:
|
||||||
if record.quant_ids:
|
if record.quant_ids:
|
||||||
if record.quant_ids[-1].location_id.name in ['刀具房', '夹具房']:
|
if record.quant_ids[-1].location_id.name in ['刀具房']:
|
||||||
record.tool_material_status = '可用'
|
record.tool_material_status = '可用'
|
||||||
elif record.quant_ids[-1].location_id.name == '刀具组装位置':
|
elif record.quant_ids[-1].location_id.name == '刀具组装位置':
|
||||||
record.tool_material_status = '在用'
|
record.tool_material_status = '在用'
|
||||||
|
|||||||
@@ -943,6 +943,8 @@ class SfStockPicking(models.Model):
|
|||||||
for record in self:
|
for record in self:
|
||||||
if record.state != 'assigned':
|
if record.state != 'assigned':
|
||||||
continue
|
continue
|
||||||
|
for move in record.move_ids:
|
||||||
|
move.action_show_details()
|
||||||
record.action_set_quantities_to_reservation()
|
record.action_set_quantities_to_reservation()
|
||||||
record.button_validate()
|
record.button_validate()
|
||||||
|
|
||||||
@@ -1122,7 +1124,7 @@ class SfPickingType(models.Model):
|
|||||||
if not self.env.user.has_group('base.group_system'):
|
if not self.env.user.has_group('base.group_system'):
|
||||||
action['context']['create'] = False
|
action['context']['create'] = False
|
||||||
if self.sequence_code in ['DL', 'INT', 'PC']:
|
if self.sequence_code in ['DL', 'INT', 'PC']:
|
||||||
action['context']['search_default_retrospect_ref'] = 1
|
action['context']['search_default_retrospect'] = 1
|
||||||
return action
|
return action
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user