Compare commits

..

58 Commits

Author SHA1 Message Date
胡尧
61baa49d85 Merge branch 'feature/6694' into feature/merge-6694 2025-05-15 09:22:44 +08:00
胡尧
063c7a94c5 Accept Merge Request #2121: (feature/rollback-develop1 -> develop)
Merge Request: 修复误回退的代码

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2121?initial=true
2025-05-15 09:15:54 +08:00
胡尧
b783af6ef3 修复误回退的代码 2025-05-15 09:15:27 +08:00
胡尧
22cbe1bd9d 回退代码 2025-05-15 09:13:51 +08:00
胡尧
cc196e25da Accept Merge Request #2120: (feature/rollback-develop1 -> develop)
Merge Request: 退回至未合并工艺外协代码

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2120?initial=true
2025-05-15 09:03:49 +08:00
胡尧
961754428b 退回至未合并工艺外协代码 2025-05-15 09:02:31 +08:00
胡尧
f6d8cb6267 编程单增加零件图号 2025-05-15 08:45:02 +08:00
廖丹龙
7e47a85167 Accept Merge Request #2119: (feature/tool_standard_library_process -> develop)
Merge Request: sf-制造-工艺外协的采购订单确认后,外协的调拨单的作业详情的预留数量跟完成数量不对

Created By: @廖丹龙
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @廖丹龙
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2119
2025-05-14 17:53:14 +08:00
liaodanlong
2644df4fd5 sf-制造-工艺外协的采购订单确认后,外协的调拨单的作业详情的预留数量跟完成数量不对 2025-05-14 17:45:42 +08:00
胡尧
c898e02860 解决制造申请字段未复制到成品中 2025-05-14 17:02:04 +08:00
廖丹龙
e14aa35d90 Accept Merge Request #2118: (feature/tool_standard_library_process -> develop)
Merge Request: sf-制造-工艺外协的采购订单确认后,外协的调拨单的作业详情的预留数量跟完成数量不对

Created By: @廖丹龙
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @廖丹龙
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2118
2025-05-14 17:00:42 +08:00
liaodanlong
9392819375 sf-制造-工艺外协的采购订单确认后,外协的调拨单的作业详情的预留数量跟完成数量不对 2025-05-14 16:58:05 +08:00
liaodanlong
ea3d9e5375 sf-制造-工艺外协的采购订单确认后,外协的调拨单的作业详情的预留数量跟完成数量不对 2025-05-14 16:46:29 +08:00
胡尧
7db0a44420 Accept Merge Request #2117: (feature/6694 -> develop)
Merge Request: 修改中控日志接口授权为none

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2117?initial=true
2025-05-14 16:09:30 +08:00
胡尧
5477582a69 修改中控日志接口授权为none 2025-05-14 16:09:06 +08:00
liaodanlong
238840b647 sf-制造-工艺外协的采购订单确认后,外协的调拨单的作业详情的预留数量跟完成数量不对 2025-05-14 14:54:36 +08:00
廖丹龙
51e25d8847 Accept Merge Request #2116: (feature/tool_standard_library_process -> develop)
Merge Request: 空值判断

Created By: @廖丹龙
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @廖丹龙
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2116
2025-05-14 14:14:02 +08:00
liaodanlong
c6f06a4c32 外协调拨单就绪条件修改 2025-05-14 14:12:06 +08:00
liaodanlong
5b61a801c5 空值判断 2025-05-14 13:57:57 +08:00
廖丹龙
2893524902 Accept Merge Request #2115: (feature/tool_standard_library_process -> develop)
Merge Request: sf-制造-产品-表单详情中-工艺参数显示内容=未归档,未绑定产品的工艺参数

Created By: @廖丹龙
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @廖丹龙
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2115?initial=true
2025-05-14 12:22:10 +08:00
liaodanlong
ed55e36f45 sf-制造-产品-表单详情中-工艺参数显示内容=未归档,未绑定产品的工艺参数 2025-05-14 11:49:14 +08:00
廖丹龙
c811f26104 Accept Merge Request #2114: (feature/tool_standard_library_process -> develop)
Merge Request: sf-制造-产品-表单详情中-工艺参数显示内容=未归档,未绑定产品的工艺参数

Created By: @廖丹龙
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @廖丹龙
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2114
2025-05-14 11:11:29 +08:00
liaodanlong
3763b60758 sf-制造-产品-表单详情中-工艺参数显示内容=未归档,未绑定产品的工艺参数 2025-05-14 10:48:01 +08:00
廖丹龙
976907bd92 Accept Merge Request #2112: (feature/tool_standard_library_process -> develop)
Merge Request: 外协采购单使用采购申请创建出来的采购单

Created By: @廖丹龙
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @廖丹龙
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2112
2025-05-14 10:35:47 +08:00
liaodanlong
50c3b31ece 外协采购单使用采购申请创建出来的采购单 2025-05-14 10:24:21 +08:00
liaodanlong
8afc8bb3a6 外协调拨单只有当制造订单状态变为已编程才能就绪 2025-05-14 10:03:26 +08:00
廖丹龙
a0427d424f Accept Merge Request #2111: (feature/tool_standard_library_process -> develop)
Merge Request: sf-制造-工艺外协的采购订单确认后,外协的调拨单的作业详情的预留数量跟完成数量不对

Created By: @廖丹龙
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @廖丹龙
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2111
2025-05-13 16:35:45 +08:00
liaodanlong
3148ce5a15 外协调拨单不同产品的调拨单混合到一起了 2025-05-13 15:49:02 +08:00
liaodanlong
8e726e1bf6 sf-制造-工艺外协的采购订单确认后,外协的调拨单的作业详情的预留数量跟完成数量不对 2025-05-13 15:01:54 +08:00
liaodanlong
4c0f9cfb39 外协工单零件图号零件名称 2025-05-13 11:04:45 +08:00
廖丹龙
86d3bd38c5 Accept Merge Request #2110: (feature/tool_standard_library_process -> develop)
Merge Request: 调拨单就绪问题处理

Created By: @廖丹龙
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @廖丹龙
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2110
2025-05-13 10:25:20 +08:00
liaodanlong
a8e4c7d9a0 调拨单报错问题处理 2025-05-13 10:24:09 +08:00
liaodanlong
7501832637 调拨单就绪问题处理 2025-05-13 10:01:58 +08:00
liaodanlong
ce0ead4da6 sf-工序-手动创建工艺可选参数及产品问题 2025-05-12 17:13:52 +08:00
廖丹龙
343e2f9f24 Accept Merge Request #2109: (feature/tool_standard_library_process -> develop)
Merge Request: 调拨单就绪问题处理

Created By: @廖丹龙
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @廖丹龙
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2109
2025-05-12 15:42:10 +08:00
liaodanlong
6d3793ee30 调拨单就绪问题处理 2025-05-12 15:21:10 +08:00
胡尧
9cb22d810e 增加接口日志 2025-05-12 15:14:04 +08:00
廖丹龙
43f7e97c28 Accept Merge Request #2108: (feature/tool_standard_library_process -> develop)
Merge Request: 调拨单就绪问题处理

Created By: @廖丹龙
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @廖丹龙
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2108
2025-05-12 15:12:06 +08:00
liaodanlong
9e6f3fa864 Merge branch 'refs/heads/develop' into feature/tool_standard_library_process
# Conflicts:
#	sf_manufacturing/models/purchase_order.py
2025-05-12 15:03:25 +08:00
liaodanlong
ed50d7c9a7 调拨单就绪问题处理 2025-05-12 14:55:19 +08:00
liaodanlong
89e23050e6 打印错误日志堆栈信息 2025-05-12 14:54:43 +08:00
胡尧
b7f912453f Accept Merge Request #2107: (feature/6694 -> develop)
Merge Request: 解决代码问题

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2107?initial=true
2025-05-12 14:48:07 +08:00
胡尧
cab6b6fa2a 解决代码问题 2025-05-12 14:46:15 +08:00
胡尧
35bf954529 增加中控接口调用日志记录 2025-05-12 11:50:35 +08:00
liaodanlong
1040844b0a 采购申请跳转处理 2025-05-12 11:01:51 +08:00
liaodanlong
36a13c04de 采购申请数量与产品数量不一致问题 2025-05-12 10:55:21 +08:00
liaodanlong
f4318bd997 Merge remote-tracking branch 'origin/feature/tool_standard_library_process' into feature/tool_standard_library_process 2025-05-12 10:25:09 +08:00
liaodanlong
d47a30977c 已归档的表面工艺可选参数不进行产品创建 2025-05-12 10:24:22 +08:00
胡尧
ceb38aa483 Accept Merge Request #2106: (feature/tool_standard_library_process -> develop)
Merge Request: 工艺外协代码

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2106
2025-05-12 08:41:26 +08:00
胡尧
11ecad5ef2 解决冲突 2025-05-12 08:41:12 +08:00
管欢
8249d1427f Accept Merge Request #2105: (feature/采购申请优化 -> develop)
Merge Request: 采购申请数量修改过滤取消

Created By: @管欢
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @管欢
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2105
2025-05-09 18:28:56 +08:00
胡尧
d7f7bb9a57 Accept Merge Request #2104: (release/release_2.13 -> develop)
Merge Request: 处理特殊表面工艺采购单确认报错的问题

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2104?initial=true
2025-05-09 15:26:50 +08:00
胡尧
2f6c41c999 Accept Merge Request #2103: (release/release_2.13 -> develop)
Merge Request: 修改制造目录文件结构

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2103?initial=true
2025-05-09 14:58:09 +08:00
liaodanlong
b5339046b9 工艺外协代码 2025-05-08 16:42:18 +08:00
liaodanlong
51c517145b 工艺外协代码 2025-05-07 17:17:41 +08:00
liaodanlong
efc4ae31c9 工艺外协代码 2025-05-07 11:00:32 +08:00
liaodanlong
0863238819 Merge branch 'refs/heads/develop' into feature/tool_standard_library_process 2025-05-07 11:00:24 +08:00
liaodanlong
95c25ac7b8 工艺外协代码 2025-04-29 13:39:36 +08:00
48 changed files with 832 additions and 699 deletions

View File

@@ -13,7 +13,6 @@
'views/purchase_request_view.xml',
'wizard/purchase_request_line_make_purchase_order_view.xml',
'views/purchase_request_line_view.xml',
'views/stock_picking_views.xml',
],
'assets': {
'web.assets_backend': [

View File

@@ -1043,7 +1043,7 @@ msgstr "询价单"
#. module: purchase_request
#: model:ir.model.fields,field_description:purchase_request.field_purchase_request_line__purchased_qty
msgid "RFQ/PO Qty"
msgstr "已订购数"
msgstr ""
#. module: purchase_request
#. odoo-python

View File

@@ -5,4 +5,3 @@ from . import sale_order
from . import mrp_production
from . import purchase_order
from . import stock_rule
from . import stock_picking

View File

@@ -20,7 +20,8 @@ class MrpProduction(models.Model):
# 由于采购申请合并了所有销售订单行的采购,所以不区分产品
first_mp = self.env['mrp.production'].search(
[('origin', '=', item.origin)], limit=1, order='id asc')
pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', first_mp.name)])
pr_ids = self.env['purchase.request'].sudo().search(
[('origin', 'like', first_mp.name), ('is_subcontract', '!=', 'True')])
item.pr_mp_count = len(pr_ids)
# pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', item.name), ('is_subcontract', '!=', 'True')])
@@ -29,18 +30,10 @@ class MrpProduction(models.Model):
采购请求
"""
self.ensure_one()
# pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', self.name),('is_subcontract', '!=', True)])
# if self.product_id.product_tmpl_id.single_manufacturing == True and not self.is_remanufacture:
# first_order = self.env['mrp.production'].search(
# [('origin', '=', self.origin), ('product_id', '=', self.product_id.id)], limit=1, order='id asc')
# pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', first_order.name)])
# else:
# pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', self.name)])
# 由于采购申请合并了所有销售订单行的采购,所以不区分产品
first_mp = self.env['mrp.production'].search(
[('origin', '=', self.origin)], limit=1, order='id asc')
pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', first_mp.name)])
pr_ids = self.env['purchase.request'].sudo().search(
[('origin', 'like', first_mp.name), ('is_subcontract', '!=', 'True')])
action = {
'res_model': 'purchase.request',
@@ -54,7 +47,7 @@ class MrpProduction(models.Model):
else:
action.update({
'name': _("%s生成采购请求单", self.name),
'domain': [('id', 'in', pr_ids)],
'domain': [('id', 'in', pr_ids.ids)],
'view_mode': 'tree,form',
})
return action

View File

@@ -13,7 +13,11 @@ class ProductTemplate(models.Model):
template_id.purchase_request = product_id.purchase_request
return template_id
class ProdcutProduct(models.Model):
_inherit = 'product.product'
def copy_template(self, product_template_id):
""" 复制成品模板时,复制采购申请 """
super(ProductTemplate, self).copy_template(product_template_id)
super(ProdcutProduct, self).copy_template(product_template_id)
self.purchase_request = product_template_id.purchase_request

View File

@@ -1,35 +0,0 @@
from odoo import fields, api, models, _
class StockPicking(models.Model):
_inherit = "stock.picking"
purchase_request_count = fields.Integer('采购订单数量', compute='_compute_purchase_request')
@api.depends('name')
def _compute_purchase_request(self):
for record in self:
purchase_request_ids = self.env['purchase.request'].search([('origin', '=', record.name)])
record.purchase_request_count = len(purchase_request_ids)
def action_view_purchase_request(self):
self.ensure_one()
purchase_request_ids = self.env['purchase.request'].search([('origin', '=', self.name)])
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': _("%s生成采购请求单", self.name),
'domain': [('id', 'in', purchase_request_ids.ids)],
'view_mode': 'tree,form',
})
return action

View File

@@ -48,8 +48,8 @@ class StockRule(models.Model):
# 如果补货组相同,并且产品相同,则合并
procurements_dict = defaultdict()
for procurement, rule in procurements:
if (procurement.product_id.id, procurement.values['group_id'], rule.id) not in procurements_dict:
procurements_dict[(procurement.product_id.id, procurement.values['group_id'], rule.id)] = {
if (procurement.product_id, procurement.values['group_id'], rule) not in procurements_dict:
procurements_dict[(procurement.product_id, procurement.values['group_id'], rule)] = {
'product_id': procurement.product_id,
'product_qty': procurement.product_qty,
'product_uom': procurement.product_uom,
@@ -61,8 +61,7 @@ class StockRule(models.Model):
'rule': rule
}
else:
procurements_dict[(procurement.product_id.id, procurement.values['group_id'], rule.id)]['product_qty'] += procurement.product_qty
procurements_dict[(procurement.product_id.id, procurement.values['group_id'], rule.id)]['values']['move_dest_ids'] |= procurement.values['move_dest_ids']
procurements_dict[(procurement.product_id, procurement.values['group_id'], rule)]['product_qty'] += procurement.product_qty
new_procurements = []
for k, p in procurements_dict.items():
new_procurements.append((

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="stock_pikcing_inherited_form_jikimo_purchase_request" model="ir.ui.view">
<field name="name">stock.pikcing.inherited.form.jikimo.purchase.request</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.view_picking_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='button_box']/button" position="before">
<button class="oe_stat_button" name="action_view_purchase_request" type="object" icon="fa-credit-card"
attrs="{'invisible': [('purchase_request_count', '=', 0)]}">
<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

@@ -119,11 +119,3 @@ class PurchaseRequestLineMakePurchaseOrderItem(models.TransientModel):
_inherit = "purchase.request.line.make.purchase.order.item"
supply_method = fields.Selection(related='line_id.supply_method', string='供货方式')
wiz_id = fields.Many2one(
comodel_name="purchase.request.line.make.purchase.order",
string="Wizard",
required=False,
ondelete="cascade",
readonly=True,
)

View File

@@ -6,6 +6,10 @@ class ProductTemplate(models.Model):
is_manual_processing = fields.Boolean(string='人工线下加工')
is_customer_provided = fields.Boolean(string='客供料')
class ProductProduct(models.Model):
_inherit = 'product.product'
def copy_template(self, product_template_id):
if not isinstance(product_template_id, ProductTemplate):
raise ValueError('%s必须是ProductTemplate类型' % product_template_id)

View File

@@ -4,6 +4,7 @@ import json
import logging
from odoo.addons.sf_mrs_connect.controllers.controllers import Sf_Mrs_Connect
from odoo.addons.sf_manufacturing.controllers.controllers import Manufacturing_Connect
from odoo.addons.sf_base.decorators.api_log import api_log
from datetime import datetime
_logger = logging.getLogger(__name__)
@@ -12,6 +13,7 @@ class WorkorderExceptionConroller(http.Controller):
@http.route('/AutoDeviceApi/BillError', type='json', auth='public', methods=['GET', 'POST'], csrf=False,
cors="*")
@api_log('工单对接错误', requester='中控系统')
def workder_exception(self, **kw):
"""
记录工单异常

View File

@@ -141,7 +141,7 @@ class QualityCheck(models.Model):
# # 出厂检验报告编号
# report_number = fields.Char('出厂检验报告编号', compute='_compute_report_number', readonly=True)
# 总数量值为调拨单_产品明细_数量
total_qty = fields.Char('总数量', compute='_compute_total_qty', store=True)
total_qty = fields.Char('总数量', compute='_compute_total_qty')
column_nums = fields.Integer('测量值列数', default=1)
@@ -153,9 +153,9 @@ class QualityCheck(models.Model):
for move in record.picking_id.move_ids_without_package:
if move.product_id == record.product_id:
total_qty = int(move.product_uom_qty)
record.total_qty = total_qty if total_qty > 0 else 0
record.total_qty = total_qty if total_qty > 0 else ''
else:
record.total_qty = 0
record.total_qty = ''
# 检验数
check_qty = fields.Integer('检验数', default=lambda self: self._get_default_check_qty())
@@ -735,9 +735,8 @@ class QualityCheck(models.Model):
def _compute_qty_to_test(self):
for qc in self:
if qc.is_lot_tested_fractionally:
rounding = qc.product_id.uom_id.rounding if qc.product_id.uom_id else 0.01
qc.qty_to_test = float_round(qc.qty_line * qc.testing_percentage_within_lot / 100,
precision_rounding=rounding, rounding_method="UP")
precision_rounding=self.product_id.uom_id.rounding, rounding_method="UP")
else:
qc.qty_to_test = qc.qty_line

View File

@@ -23,8 +23,8 @@ class QualityCheckWizard(models.TransientModel):
lot_name = fields.Char(related='current_check_id.lot_name')
lot_line_id = fields.Many2one(related='current_check_id.lot_line_id')
qty_line = fields.Float(related='current_check_id.qty_line')
qty_to_test = fields.Float(related='current_check_id.qty_to_test', string='待检')
qty_tested = fields.Float(related='current_check_id.qty_tested', string='已检', readonly=False)
qty_to_test = fields.Float(related='current_check_id.qty_to_test')
qty_tested = fields.Float(related='current_check_id.qty_tested', readonly=False)
measure = fields.Float(related='current_check_id.measure', readonly=False)
measure_on = fields.Selection(related='current_check_id.measure_on')
quality_state = fields.Selection(related='current_check_id.quality_state')

View File

@@ -103,12 +103,19 @@ class PrintingUtils(models.AbstractModel):
self.send_to_printer(host, port, zpl_code)
def add_qr_code_to_pdf(self, pdf_path:str, content:str, buttom_text:Optional[str]=False):
def add_qr_code_to_pdf(
self,
pdf_path:str,
content:str,
qr_code_buttom_text:Optional[str]=False,
buttom_text:Optional[str]=False,
):
"""
在PDF文件中添加二维码
:param pdf_path: PDF文件路径
:param content: 二维码内容
:param buttom_text: 二维码下方文字
:param qr_code_buttom_text: 二维码下方文字
:param buttom_text: 正文下方文字
:return: 是否成功
"""
if not os.path.exists(pdf_path):
@@ -156,8 +163,9 @@ class PrintingUtils(models.AbstractModel):
existing_pdf = PdfFileReader(original_file)
output = PdfFileWriter()
# 处理一页
page = existing_pdf.getPage(0)
# 处理最后一页
last_page = existing_pdf.getNumPages() - 1
page = existing_pdf.getPage(last_page)
# 获取页面尺寸
page_width = float(page.mediaBox.getWidth())
page_height = float(page.mediaBox.getHeight())
@@ -179,14 +187,22 @@ class PrintingUtils(models.AbstractModel):
qr_y = margin + 20 # 将二维码向上移动一点,为文字留出空间
c.drawImage(qr_temp_path, page_width - qr_size - margin, qr_y, width=qr_size, height=qr_size)
if buttom_text:
if qr_code_buttom_text:
# 在二维码下方绘制文字
text = buttom_text
text = qr_code_buttom_text
text_width = c.stringWidth(text, "SimSun" if font_found else "Helvetica", 10) # 准确计算文字宽度
text_x = page_width - qr_size - margin + (qr_size - text_width) / 2 # 文字居中对齐
text_y = margin + 20 # 文字位置靠近底部
c.drawString(text_x, text_y, text)
if buttom_text:
# 在下方中间添加文字
text = button_text
text_width = c.stringWidth(text, "SimSun" if font_found else "Helvetica", 10) # 准确计算文字宽度
text_x = (page_width - text_width) / 2 # 文字居中对齐
text_y = margin + 20 # 文字位置靠近底部
c.drawString(text_x, text_y, text)
c.save()
# 读取带有二维码的临时PDF
@@ -196,12 +212,13 @@ class PrintingUtils(models.AbstractModel):
# 合并原始页面和二维码页面
page.mergePage(qr_page)
output.addPage(page)
# 添加剩余的页面
for i in range(1, existing_pdf.getNumPages()):
for i in range(0, last_page):
output.addPage(existing_pdf.getPage(i))
output.addPage(page)
# 保存最终的PDF到一个临时文件
final_temp_path = pdf_path + '.tmp'
with open(final_temp_path, "wb") as output_file:

View File

@@ -4,6 +4,7 @@ import json
import logging
from odoo import http
from odoo.http import request
from odoo.addons.sf_base.decorators.api_log import api_log
_logger = logging.getLogger(__name__)
@@ -11,6 +12,7 @@ class Manufacturing_Connect(http.Controller):
@http.route('/AutoDeviceApi/MachineToolGroup', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
cors="*")
@api_log('机床刀具组', requester='中控系统')
def get_maintenance_tool_groups_Info(self, **kw):
"""
机床刀具组接口

View File

@@ -27,6 +27,9 @@ def api_log(name=None, requester=None):
# 执行原始函数
result = func(*args, **kwargs)
origin_result = result
if isinstance(result, str):
result = json.loads(result)
# 计算响应时间
end_time = datetime.now()
@@ -41,7 +44,7 @@ def api_log(name=None, requester=None):
'response_data': json.dumps(result, ensure_ascii=False),
'remote_addr': remote_addr,
'response_time': response_time,
'status': result.get('code', 500),
'status': result.get('code') or result.get('ErrorCode') or 500,
'requester': requester,
'responser': '智能工厂'
}
@@ -49,7 +52,7 @@ def api_log(name=None, requester=None):
# 异步创建日志记录
request.env['api.request.log'].sudo().with_context(tracking_disable=True).create(log_vals)
return result
return origin_result
except Exception as e:
_logger.error(f"API日志记录失败: {str(e)}")

View File

@@ -1,4 +1,9 @@
from odoo import models, fields, api
import json, ast
import logging
import requests
_logger = logging.getLogger(__name__)
class ApiRequestLog(models.Model):
@@ -16,3 +21,52 @@ class ApiRequestLog(models.Model):
status = fields.Integer('状态码')
requester = fields.Char('请求方')
responser = fields.Char('响应方')
@api.model
def log_request(self, method, url, name=None, responser=None, **kwargs):
# Log the request
request_headers = kwargs.get('headers', {})
request_body = kwargs.get('json') or kwargs.get('params') or {}
_logger.info(f"Request: {method} {url} Headers: {request_headers} Body: {request_body}")
# Make the actual request
response = requests.request(method, url, **kwargs)
# Log the response
response_status = response.status_code
response_headers = response.headers
response_body = response.text
response_time = response.elapsed.total_seconds()
_logger.info(f"Response: Status: {response_status} Headers: {response_headers} Body: {response_body}")
try:
# 如果是字符串,先尝试用 ast.literal_eval 安全地转换成 Python 对象
if isinstance(response_body, str):
response_body_obj = json.loads(response_body)
else:
response_body_obj = response_body
# 再使用 json.dumps 转换成标准的 JSON 字符串
response_body = json.dumps(response_body_obj, ensure_ascii=False)
except Exception as e:
_logger.warning(f"转换 response_body 到标准 JSON 失败: {str(e)}")
# 如果转换失败,保持原样
# Save to database
self.sudo().create({
'name': name,
'path': url,
'method': method,
'request_data': request_body,
'response_data': response_body,
'remote_addr': None,
'response_time': response_time,
'status': response_status,
'requester': '智能工厂',
'responser': responser
})
return response

View File

@@ -1,16 +1,16 @@
# import logging
# from odoo import fields, models, api
# from odoo.exceptions import UserError
# from odoo.tools import str2bool
#
#
# class ResMrpRoutingWorkcenter(models.Model):
# _inherit = 'mrp.routing.workcenter'
# def init(self):
# super(ResMrpRoutingWorkcenter, self).init()
# # 在模块初始化时触发计算字段的更新
# records = self.search([])
# if str2bool(self.env['ir.config_parameter'].get_param('sf.production.process.parameter.is_init_workcenter',default='False')):
# return
# records.optional_process_parameters_date()
# self.env['ir.config_parameter'].set_param('sf.production.process.parameter.is_init_workcenter', True)
import logging
from odoo import fields, models, api
from odoo.exceptions import UserError
from odoo.tools import str2bool
class ResMrpRoutingWorkcenter(models.Model):
_inherit = 'mrp.routing.workcenter'
def init(self):
super(ResMrpRoutingWorkcenter, self).init()
# 在模块初始化时触发计算字段的更新
records = self.search([])
if str2bool(self.env['ir.config_parameter'].get_param('sf.production.process.parameter.is_init_workcenter',default='False')):
return
records.optional_process_parameters_date()
self.env['ir.config_parameter'].set_param('sf.production.process.parameter.is_init_workcenter', True)

View File

@@ -1,85 +1,87 @@
# # -*- coding: utf-8 -*-
# import logging
# from odoo import fields, models, api
# from odoo.exceptions import UserError
# from odoo.tools import str2bool
#
#
# class SfProductionProcessParameter(models.Model):
# _inherit = 'sf.production.process.parameter'
#
#
# @api.model
# def create(self, vals):
# # if vals.get('code', '/') == '/' or vals.get('code', '/') is False:
# # vals['code'] = '101'+self.routing_id.code +self.env['ir.sequence'].next_by_code('sf.production.process.parameter')
# if vals.get('routing_id'):
# # vals['gain_way'] = '外协'
# routing_id = self.env['mrp.routing.workcenter'].browse(vals.get('routing_id'))
# if routing_id.surface_technics_id and not vals.get('process_id'):
# vals['process_id'] = routing_id.surface_technics_id.id
# if vals.get('code', '/') == '/' or vals.get('code', '/') is False:
# vals['code'] = '101' + routing_id.code + self.env['ir.sequence'].next_by_code(
# 'sf.production.process.parameter')
# obj = super(SfProductionProcessParameter, self).create(vals)
# return obj
# def create_service_product(self):
# service_categ = self.env.ref(
# 'sf_dlm.product_category_surface_technics_sf').sudo()
#
# product_name = f"{self.process_id.name}_{self.name}"
# product_id = self.env['product.template'].search(
# [("name", '=', product_name)])
# if product_id:
# product_id.server_product_process_parameters_id = self.id
# else:
# res_partner = self.env['res.partner'].search([('name','=','湖南傲派自动化设备有限公司')])
# self.env['product.template'].create({
# 'detailed_type': 'service',
# 'name': product_name,
# 'invoice_policy': 'delivery',
# 'categ_id': service_categ.id,
# 'description': f"基于{self.name}创建的服务产品",
# 'sale_ok': True, # 可销售
# 'purchase_ok': True, # 可采购
# 'server_product_process_parameters_id': self.id,
# 'seller_ids': [(0, 0, {
# # 'delay': 1,
# 'partner_id': res_partner.id,
# 'price': 1, })],
# })
#
# def create_work_center(self):
# production_process_parameter = self
# if not production_process_parameter.process_id:
# return
# if not production_process_parameter.routing_id:
# workcenter_id = self.env['mrp.routing.workcenter'].search(
# [("surface_technics_id", '=', production_process_parameter.process_id.id)])
# if not workcenter_id:
# outsourcing_work_center = self.env['mrp.workcenter'].search(
# [("name", '=', '外协工作中心')])
# routing_id = self.env['mrp.routing.workcenter'].create({
# 'workcenter_ids': [(6, 0, outsourcing_work_center.ids)],
# 'routing_tag': 'special',
# 'routing_type': '表面工艺',
# 'is_outsource': True,
# 'surface_technics_id': production_process_parameter.process_id.id,
# 'name': production_process_parameter.process_id.name,
# })
# production_process_parameter.routing_id = routing_id.id
# else:
# production_process_parameter.routing_id = workcenter_id.id
#
# def init(self):
# super(SfProductionProcessParameter, self).init()
# # 在模块初始化时触发计算字段的更新
# records = self.search([])
# if str2bool(self.env['ir.config_parameter'].get_param('sf.production.process.parameter.is_init_process',
# default='False')):
# return
# for record in records:
# if not record.outsourced_service_products:
# record.create_service_product()
# record.create_work_center()
# self.env['ir.config_parameter'].set_param('sf.production.process.parameter.is_init_process', True)
# -*- coding: utf-8 -*-
import logging
from odoo import fields, models, api
from odoo.exceptions import UserError
from odoo.tools import str2bool
class SfProductionProcessParameter(models.Model):
_inherit = 'sf.production.process.parameter'
@api.model
def create(self, vals):
# if vals.get('code', '/') == '/' or vals.get('code', '/') is False:
# vals['code'] = '101'+self.routing_id.code +self.env['ir.sequence'].next_by_code('sf.production.process.parameter')
if vals.get('routing_id'):
# vals['gain_way'] = '外协'
routing_id = self.env['mrp.routing.workcenter'].browse(vals.get('routing_id'))
if routing_id.surface_technics_id and not vals.get('process_id'):
vals['process_id'] = routing_id.surface_technics_id.id
if vals.get('code', '/') == '/' or vals.get('code', '/') is False:
vals['code'] = '101' + routing_id.code + self.env['ir.sequence'].next_by_code(
'sf.production.process.parameter')
obj = super(SfProductionProcessParameter, self).create(vals)
return obj
def create_service_product(self):
if not self.active:
return
service_categ = self.env.ref(
'sf_dlm.product_category_surface_technics_sf').sudo()
product_name = f"{self.process_id.name}_{self.name}"
product_id = self.env['product.template'].search(
[("name", '=', product_name)])
if product_id:
product_id.server_product_process_parameters_id = self.id
else:
res_partner = self.env['res.partner'].search([('name','=','湖南傲派自动化设备有限公司')])
self.env['product.template'].create({
'detailed_type': 'service',
'name': product_name,
'invoice_policy': 'delivery',
'categ_id': service_categ.id,
'description': f"基于{self.name}创建的服务产品",
'sale_ok': True, # 可销售
'purchase_ok': True, # 可采购
'server_product_process_parameters_id': self.id,
'seller_ids': [(0, 0, {
# 'delay': 1,
'partner_id': res_partner.id,
'price': 1, })],
})
def create_work_center(self):
production_process_parameter = self
if not production_process_parameter.process_id:
return
if not production_process_parameter.routing_id:
workcenter_id = self.env['mrp.routing.workcenter'].search(
[("surface_technics_id", '=', production_process_parameter.process_id.id)])
if not workcenter_id:
outsourcing_work_center = self.env['mrp.workcenter'].search(
[("name", '=', '外协工作中心')])
routing_id = self.env['mrp.routing.workcenter'].create({
'workcenter_ids': [(6, 0, outsourcing_work_center.ids)],
'routing_tag': 'special',
'routing_type': '表面工艺',
'is_outsource': True,
'surface_technics_id': production_process_parameter.process_id.id,
'name': production_process_parameter.process_id.name,
})
production_process_parameter.routing_id = routing_id.id
else:
production_process_parameter.routing_id = workcenter_id.id
def init(self):
super(SfProductionProcessParameter, self).init()
# 在模块初始化时触发计算字段的更新
records = self.search([])
if str2bool(self.env['ir.config_parameter'].get_param('sf.production.process.parameter.is_init_process',
default='False')):
return
for record in records:
if not record.outsourced_service_products:
record.create_service_product()
record.create_work_center()
self.env['ir.config_parameter'].set_param('sf.production.process.parameter.is_init_process', True)

View File

@@ -41,7 +41,9 @@
attrs="{'invisible': [('categ_type', 'not in', ['成品','坯料', '原材料'])],'readonly': [('id', '!=', False)]}"/>
<field name="server_product_process_parameters_id" string="工艺参数"
options="{'no_create': True}"
attrs="{'invisible': ['|',('detailed_type', '!=', 'service'),('detailed_type', '=', False)]}"/>
attrs="{'invisible': ['|',('detailed_type', '!=', 'service'),('detailed_type', '=', False)]}"
domain="[('active', '=', 'True'),('outsourced_service_products', '!=', 'True')]"
/>
<field name="cutting_tool_material_id" class="custom_required"
options="{'no_create': True}"
attrs="{'invisible': [('categ_type', '!=', '刀具')],'required': [('categ_type', '=', '刀具')],'readonly': [('id', '!=', False)]}"

View File

@@ -48,6 +48,7 @@
'views/mrp_workorder_batch_replan.xml',
'views/purchase_order_view.xml',
'views/product_template_views.xml',
'views/stock_warehouse_orderpoint.xml',
],
'assets': {

View File

@@ -6,12 +6,14 @@ from datetime import datetime
from odoo.addons.sf_manufacturing.models.agv_scheduling import RepeatTaskException
from odoo import http
from odoo.http import request
from odoo.addons.sf_base.decorators.api_log import api_log
class Manufacturing_Connect(http.Controller):
@http.route('/AutoDeviceApi/GetWoInfo', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
cors="*")
@api_log('获取工单', requester='中控系统')
def get_Work_Info(self, **kw):
"""
自动化传递工单号获取工单信息
@@ -54,6 +56,7 @@ class Manufacturing_Connect(http.Controller):
@http.route('/AutoDeviceApi/GetShiftPlan', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
cors="*")
@api_log('获取日计划', requester='中控系统')
def get_ShiftPlan(self, **kw):
"""
自动化每天获取机台日计划
@@ -107,6 +110,7 @@ class Manufacturing_Connect(http.Controller):
@http.route('/AutoDeviceApi/QcCheck', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
cors="*")
@api_log('工件预调(前置三元检测)', requester='中控系统')
def get_qcCheck(self, **kw):
"""
工件预调(前置三元检测)
@@ -149,6 +153,7 @@ class Manufacturing_Connect(http.Controller):
@http.route('/AutoDeviceApi/FeedBackStart', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
cors="*")
@api_log('工单开始', requester='中控系统')
def button_Work_START(self, **kw):
"""
工单任务开始
@@ -198,6 +203,7 @@ class Manufacturing_Connect(http.Controller):
@http.route('/AutoDeviceApi/FeedBackEnd', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
cors="*")
@api_log('工单结束', requester='中控系统')
def button_Work_End(self, **kw):
"""
工单任务结束
@@ -249,6 +255,7 @@ class Manufacturing_Connect(http.Controller):
@http.route('/AutoDeviceApi/PartQualityInspect', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
cors="*")
@api_log('零件检测(后置三元检测)', requester='中控系统')
def PartQualityInspect(self, **kw):
"""
零件质检
@@ -295,6 +302,7 @@ class Manufacturing_Connect(http.Controller):
@http.route('/AutoDeviceApi/CMMProgDolod', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
cors="*")
@api_log('CMM测量程序下载', requester='中控系统')
def CMMProgDolod(self, **kw):
"""
中控系统传递RFID编号给MES获取测量程序文件。Ftp下载文件
@@ -335,6 +343,7 @@ class Manufacturing_Connect(http.Controller):
@http.route('/AutoDeviceApi/NCProgDolod', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
cors="*")
@api_log('CAM加工程序下载', requester='中控系统')
def NCProgDolod(self, **kw):
"""
中控系统传递RFID编号给MES获取程序单及程序文件。Ftp下载文件
@@ -376,6 +385,7 @@ class Manufacturing_Connect(http.Controller):
@http.route('/AutoDeviceApi/LocationChange', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
cors="*")
@api_log('库位变更', requester='中控系统')
def LocationChange(self, **kw):
"""
库位变更
@@ -480,6 +490,7 @@ class Manufacturing_Connect(http.Controller):
@http.route('/AutoDeviceApi/AGVToProduct', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
cors="*")
@api_log('AGV运送上产线', requester='中控系统')
def AGVToProduct(self, **kw):
"""
AGV运送上产线完成
@@ -552,6 +563,7 @@ class Manufacturing_Connect(http.Controller):
@http.route('/AutoDeviceApi/AGVDownProduct', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
cors="*")
@api_log('AGV运送下产线', requester='中控系统')
def AGVDownProduct(self, **kw):
"""
MES调度AGV搬运零件AGV托盘到产线接驳站。

View File

@@ -18,3 +18,4 @@ from . import quick_easy_order
from . import purchase_order
from . import quality_check
from . import purchase_request_line
from . import stock_warehouse_orderpoint

View File

@@ -900,40 +900,43 @@ class MrpProduction(models.Model):
for workorder in production.workorder_ids:
workorder.duration_expected = workorder._get_duration_expected()
# def _create_subcontract_purchase_request(self, purchase_request_line):
# sorted_list = sorted(purchase_request_line, key=itemgetter('name'))
# grouped_purchase_request_line = {
# k: list(g)
# for k, g in groupby(sorted_list, key=itemgetter('name'))
# }
# for name, request_line in grouped_purchase_request_line.items():
# request_line_sorted_list = sorted(request_line, key=itemgetter('product_id'))
# grouped_purchase_request_line_sorted_list = {
# k: list(g)
# for k, g in groupby(request_line_sorted_list, key=itemgetter('product_id'))
# }
# purchase_request_model = self.env["purchase.request"]
# origin = ", ".join({item['production_name'] for item in request_line_sorted_list if item.get('production_name')})
# pr = purchase_request_model.create({
# "origin": origin,
# "company_id": self.company_id.id,
# "picking_type_id": self.env.ref('stock.picking_type_in').id,
# "group_id": request_line[0].get('group_id'),
# "requested_by": self.env.context.get("uid", self.env.uid),
# "assigned_to": False,
# "bom_id": self[0].bom_id.id,
# "is_subcontract":True,
# })
# self[0].bom_id.bom_line_ids.product_id.route_ids = [(4,self.env.ref(
# 'sf_stock.stock_route_process_outsourcing').id)]
# for product_id, request_line_list in grouped_purchase_request_line_sorted_list.items():
# cur_request_line = request_line_list[0]
# cur_request_line['product_qty'] = len(request_line_list)
# cur_request_line['request_id'] = pr.id
# cur_request_line['origin'] = ", ".join({item['production_name'] for item in request_line_list if item.get('production_name')})
# cur_request_line.pop('group_id', None)
# cur_request_line.pop('production_name', None)
# self.env["purchase.request.line"].create(cur_request_line)
def _create_subcontract_purchase_request(self, purchase_request_line):
sorted_list = sorted(purchase_request_line, key=itemgetter('name'))
grouped_purchase_request_line = {
k: list(g)
for k, g in groupby(sorted_list, key=itemgetter('name'))
}
for name, request_line in grouped_purchase_request_line.items():
request_line_sorted_list = sorted(request_line, key=itemgetter('product_id'))
grouped_purchase_request_line_sorted_list = {
k: list(g)
for k, g in groupby(request_line_sorted_list, key=itemgetter('product_id'))
}
purchase_request_model = self.env["purchase.request"]
origin = ", ".join({item['production_name'] for item in request_line_sorted_list if item.get('production_name')})
pr = purchase_request_model.create({
"origin": origin,
"company_id": self.company_id.id,
"picking_type_id": self.env.ref('stock.picking_type_in').id,
"group_id": request_line[0].get('group_id'),
"requested_by": self.env.context.get("uid", self.env.uid),
"assigned_to": False,
"bom_id": self[0].bom_id.id,
"is_subcontract":True,
})
self[0].bom_id.bom_line_ids.product_id.route_ids = [(4,self.env.ref(
'sf_stock.stock_route_process_outsourcing').id)]
for product_id, request_line_list in grouped_purchase_request_line_sorted_list.items():
cur_request_line = request_line_list[0]
if cur_request_line['product_qty'] == 1:
cur_request_line['product_qty'] = len(request_line_list)
# cur_request_line['product_qty'] = cur_request_line['product_qty']
cur_request_line['request_id'] = pr.id
cur_request_line['origin'] = ", ".join({item['production_name'] for item in request_line_list if item.get('production_name')})
cur_request_line.pop('group_id', None)
cur_request_line.pop('production_name', None)
self.env["purchase.request.line"].create(cur_request_line)
pr.button_approved()
# 外协出入库单处理
def get_subcontract_pick_purchase(self):
@@ -961,14 +964,14 @@ class MrpProduction(models.Model):
if not sorted_workorders:
return
for workorders in reversed(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)
# purchase_request_line = purchase_request_line + self.env['purchase.order'].get_purchase_request(
# workorders, production)
# all_workorders += workorders
# self._create_subcontract_purchase_request(purchase_request_line)
# for workorder in all_workorders:
# workorder._compute_pr_mp_count()
# 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)
purchase_request_line = purchase_request_line + self.env['purchase.order'].get_purchase_request(
workorders, production)
all_workorders += workorders
self._create_subcontract_purchase_request(purchase_request_line)
for workorder in all_workorders:
workorder._compute_pr_mp_count()
# 工单排序
def _reset_work_order_sequence1(self, k):
for rec in self:

View File

@@ -1,7 +1,7 @@
import logging
from odoo import fields, models, api
from odoo.exceptions import UserError
# from odoo.tools import str2bool
from odoo.tools import str2bool
class ResMrpRoutingWorkcenter(models.Model):
@@ -25,20 +25,20 @@ class ResMrpRoutingWorkcenter(models.Model):
workcenter_ids = fields.Many2many('mrp.workcenter', 'rel_workcenter_route', required=True)
bom_id = fields.Many2one('mrp.bom', required=False)
surface_technics_id = fields.Many2one('sf.production.process', string="表面工艺")
# optional_process_parameters = fields.One2many('sf.production.process.parameter','routing_id',string='可选工艺参数')
optional_process_parameters = fields.One2many('sf.production.process.parameter','routing_id',string='可选工艺参数')
reserved_duration = fields.Float('预留时长', default=30, tracking=True)
is_outsource = fields.Boolean('外协', default=False)
individuation_page_ids = fields.Many2many('sf.work.individuation.page', string='个性化记录')
# @api.onchange('surface_technics_id')
# def optional_process_parameters_date(self):
# for record in self:
# if not record.surface_technics_id:
# continue
# parameter_ids = self.env['sf.production.process.parameter'].search([
# ('process_id', '=', record.surface_technics_id.id),
# ])
# record.optional_process_parameters = parameter_ids.ids
@api.onchange('surface_technics_id')
def optional_process_parameters_date(self):
for record in self:
if not record.surface_technics_id:
continue
parameter_ids = self.env['sf.production.process.parameter'].search([
('process_id', '=', record.surface_technics_id.id),
])
record.optional_process_parameters = parameter_ids.ids
# @api.model
# def _auto_init(self):

View File

@@ -21,16 +21,16 @@ class ResWorkcenter(models.Model):
related='equipment_id.production_line_id', store=True)
is_process_outsourcing = fields.Boolean('工艺外协')
users_ids = fields.Many2many("res.users", 'users_workcenter', tracking=True)
# @api.constrains('name')
# def _check_unique_name_code(self):
# for record in self:
# # 检查是否已经存在相同的 name 和 code 组合
# existing = self.search([
# ('name', '=', record.name),
# ('id', '!=', record.id) # 排除当前记录
# ])
# if existing:
# raise ValueError('记录已存在')
@api.constrains('name')
def _check_unique_name_code(self):
for record in self:
# 检查是否已经存在相同的 name 和 code 组合
existing = self.search([
('name', '=', record.name),
('id', '!=', record.id) # 排除当前记录
])
if existing:
raise ValueError('记录已存在')
def write(self, vals):
if 'users_ids' in vals:
old_users = self.users_ids

View File

@@ -70,21 +70,22 @@ class ResMrpWorkOrder(models.Model):
delivery_warning = fields.Selection([('normal', '正常'), ('warning', '告警'), ('overdue', '逾期')], string='时效',
tracking=True)
back_button_display = fields.Boolean(default=False, compute='_compute_back_button_display', store=True)
# pr_mp_count = fields.Integer('采购申请单数量', compute='_compute_pr_mp_count', store=True)
#
# @api.depends('state')
# def _compute_pr_mp_count(self):
# for item in self:
# if not item.is_subcontract:
# item.pr_mp_count = 0
# continue
# pr_ids = self.env['purchase.request'].sudo().search(
# [('origin', 'like', item.production_id.name), ('is_subcontract', '=', 'True'),
# ('state', '!=', 'rejected')])
# if pr_ids:
# item.pr_mp_count = len(pr_ids)
# else:
# item.pr_mp_count = 0
pr_mp_count = fields.Integer('采购申请单数量', compute='_compute_pr_mp_count', store=True)
@api.depends('state')
def _compute_pr_mp_count(self):
for item in self:
if not item.is_subcontract:
item.pr_mp_count = 0
continue
pr_ids = self.env['purchase.request'].sudo().search(
[('origin', 'like', item.production_id.name), ('is_subcontract', '=', 'True'),
('state', '!=', 'rejected')])
if pr_ids:
item.pr_mp_count = len(pr_ids)
else:
item.pr_mp_count = 0
@api.depends('state')
def _compute_back_button_display(self):
for record in self:
@@ -442,49 +443,39 @@ class ResMrpWorkOrder(models.Model):
@api.depends('state', 'production_id.name')
def _compute_surface_technics_purchase_ids(self):
for order in self:
if order.routing_type == '表面工艺' and order.state not in ['cancel']:
domain = [('purchase_type', '=', 'consignment'),
('origin', 'like', '%' + self.production_id.name + '%'),
('state', '!=', 'cancel')]
# domain = [('purchase_type', '=', 'consignment'),
# ('origin', 'like', '%' + self.production_id.name + '%'),
# ('state', '!=', 'cancel')]
purchase = self.env['purchase.order'].search(domain)
order.surface_technics_purchase_count = 0
if not purchase:
order.surface_technics_purchase_count = 0
for po in purchase:
if any(
line.product_id and line.product_id.server_product_process_parameters_id == order.surface_technics_parameters_id
for line in po.order_line):
order.surface_technics_purchase_count = 1
pr_ids = self.env['purchase.request'].sudo().search(
[('origin', 'like', self.production_id.name), ('is_subcontract', '=', 'True'),
('state', '!=', 'rejected')])
if pr_ids.purchase_count:
order.surface_technics_purchase_count = pr_ids.purchase_count
else:
order.surface_technics_purchase_count = 0
# def action_view_pr_mrp_workorder(self):
# """
# 采购请求
# """
# self.ensure_one()
# pr_ids = self.env['purchase.request'].sudo().search(
# [('origin', 'like', self.production_id.name), ('is_subcontract', '=', 'True'),
# ('state', '!=', 'rejected')])
# action = {
# 'res_model': 'purchase.request',
# 'type': 'ir.actions.act_window',
# }
# if len(pr_ids) == 1:
# action.update({
# 'view_mode': 'form',
# 'res_id': pr_ids[0].id,
# })
# else:
# action.update({
# 'name': _("从 %s生成采购请求单", self.name),
# 'domain': [('id', 'in', pr_ids)],
# 'view_mode': 'tree,form',
# })
# return action
def action_view_pr_mrp_workorder(self):
"""
采购请求
"""
self.ensure_one()
pr_ids = self.env['purchase.request'].sudo().search(
[('origin', 'like', self.production_id.name), ('is_subcontract', '=', 'True'),
('state', '!=', 'rejected')])
action = {
'res_model': 'purchase.request',
'type': 'ir.actions.act_window',
}
if len(pr_ids) == 1:
action.update({
'view_mode': 'form',
'res_id': pr_ids[0].id,
})
else:
action.update({
'name': _("%s生成采购请求单", self.name),
'domain': [('id', 'in', pr_ids)],
'view_mode': 'tree,form',
})
return action
def action_view_surface_technics_purchase(self):
self.ensure_one()
# if self.routing_type == '表面工艺':
@@ -501,19 +492,23 @@ class ResMrpWorkOrder(models.Model):
# if technology_design.is_auto is False:
# domain = [('origin', '=', self.production_id.name)]
# else:
purchase_orders_id = self._get_surface_technics_purchase_ids()
result = {
"type": "ir.actions.act_window",
"res_model": "purchase.order",
"res_id": purchase_orders_id.id,
# "domain": [['id', 'in', self.purchase_id]],
"name": _("Purchase Orders"),
'view_mode': 'form',
}
return result
pr_ids = self.env['purchase.request'].sudo().search(
[('origin', 'like', self.production_id.name), ('is_subcontract', '=', 'True'),
('state', '!=', 'rejected')])
# purchase_orders_id = self._get_surface_technics_purchase_ids()
# result = {
# "type": "ir.actions.act_window",
# "res_model": "purchase.order",
# "res_id": purchase_orders_id.id,
# # "domain": [['id', 'in', self.purchase_id]],
# "name": _("Purchase Orders"),
# 'view_mode': 'form',
# }
return pr_ids.action_view_purchase_order()
def _get_surface_technics_purchase_ids(self):
domain = [('origin', 'like', '%' + self.production_id.name + '%'), ('purchase_type', '=', 'consignment'), ('state', '!=', 'cancel')]
domain = [('origin', 'like', '%' + self.production_id.name + '%'), ('purchase_type', '=', 'consignment'),
('state', '!=', 'cancel')]
# domain = [('origin', 'like', '%' + self.production_id.name + '%'), ('purchase_type', '=', 'consignment')]
# domain = [('group_id', '=', self.production_id.procurement_group_id.id), ('purchase_type', '=', 'consignment')]
purchase_orders = self.env['purchase.order'].search(domain, order='id desc')
@@ -1243,6 +1238,13 @@ class ResMrpWorkOrder(models.Model):
}]
return workorders_values_str
def check_lot_exists(self, picking_id, lot_id):
return bool(
picking_id.move_ids.move_line_ids.filtered(
lambda line: line.lot_id.id == lot_id
)
)
def _process_compute_state(self):
sorted_workorders = sorted(self, key=lambda x: x.sequence)
for workorder in sorted_workorders:
@@ -1264,20 +1266,37 @@ class ResMrpWorkOrder(models.Model):
workorder.state = 'pending'
continue
# ================= 如果制造订单制造类型为【人工线下加工】==========================
# lot_id = workorder.production_id.move_raw_ids.move_line_ids.lot_id
# picking_ids = workorder.production_id.picking_ids.filtered(
# lambda wk: wk.location_id.name == '外协收料区' and wk.location_dest_id.name == '制造前')
# exists = any(
# move_line.lot_id == lot_id
# for picking in picking_ids
# for move in picking.move_ids
# for move_line in move.move_line_ids
# )
if (workorder.production_id.production_type == '人工线下加工'
and workorder.production_id.schedule_state == ''
and len(workorder.production_id.picking_ids.filtered(
lambda w: w.state not in ['done', 'cancel'])) == 0):
and workorder.production_id.programming_state == '编程'):
# and workorder.production_id.programming_state == '已编程'
if workorder.is_subcontract is True:
if workorder.production_id.state == 'rework':
workorder.state = 'waiting'
continue
purchase_orders_id = self._get_surface_technics_purchase_ids()
if purchase_orders_id.state == 'purchase':
purchase_count = 0
for purchase_order in purchase_orders_id:
for purchase_order_line in purchase_order.order_line:
if purchase_order_line.product_id.server_product_process_parameters_id.id == workorder.surface_technics_parameters_id.id:
purchase_count = purchase_order_line.product_qty
if purchase_orders_id.state == 'purchase' and purchase_count>=workorder.production_id.product_qty:
workorder.state = 'ready'
move_out = workorder.move_subcontract_workorder_ids[1]
picking_id = workorder.production_id.picking_ids.filtered(
lambda wk: wk.location_id.name == '制造前' and wk.location_dest_id.name == '外协加工区')
move_out = picking_id.move_ids
# move_out = workorder.move_subcontract_workorder_ids[1]
for mo in move_out:
if workorder.production_id.bom_id.bom_line_ids.product_id.id != mo.product_id.id:
continue
if mo.state != 'done':
mo.write({'state': 'assigned', 'production_id': False})
if not mo.move_line_ids:
@@ -1293,6 +1312,7 @@ class ResMrpWorkOrder(models.Model):
else:
workorder.state = 'ready'
continue
continue
# ================= 如果制造订单刀具状态为[无效刀、缺刀] 或者 制造订单状态为[返工]==========================
if (workorder.production_id.tool_state in ['1', '2'] or workorder.production_id.state == 'rework'
or workorder.production_id.schedule_state != '已排'
@@ -1308,15 +1328,18 @@ class ResMrpWorkOrder(models.Model):
if workorder.is_subcontract is False:
workorder.state = 'ready'
else:
if len(workorder.production_id.picking_ids.filtered(
lambda w: w.state not in ['done',
'cancel'])) == 0 and workorder.production_id.programming_state == '已编程':
if workorder.production_id.programming_state == '已编程':
purchase_orders_id = self._get_surface_technics_purchase_ids()
if purchase_orders_id:
if purchase_orders_id.state == 'purchase':
workorder.state = 'ready'
move_out = workorder.move_subcontract_workorder_ids[1]
picking_id = workorder.production_id.picking_ids.filtered(
lambda
wk: wk.location_id.name == '制造前' and wk.location_dest_id.name == '外协加工区')
move_out = picking_id.move_ids
for mo in move_out:
if workorder.production_id.bom_id.bom_line_ids.product_id.id != mo.product_id.id:
continue
if mo.state != 'done':
mo.write({'state': 'assigned', 'production_id': False})
if not mo.move_line_ids:
@@ -1325,7 +1348,6 @@ class ResMrpWorkOrder(models.Model):
else:
workorder.state = 'waiting'
@api.depends('production_availability', 'blocked_by_workorder_ids', 'blocked_by_workorder_ids.state',
'production_id.tool_state', 'production_id.schedule_state', 'sequence',
'production_id.programming_state')
@@ -1357,7 +1379,8 @@ class ResMrpWorkOrder(models.Model):
# 判断是否有坯料的序列号信息
boolean = False
if self.production_id.move_raw_ids:
if self.production_id.move_raw_ids[0].product_id.categ_type == '坯料' and self.production_id.move_raw_ids[0].product_id.tracking == 'serial':
if self.production_id.move_raw_ids[0].product_id.categ_type == '坯料' and \
self.production_id.move_raw_ids[0].product_id.tracking == 'serial':
if self.production_id.move_raw_ids[0].move_line_ids:
if self.production_id.move_raw_ids[0].move_line_ids[0].lot_id.name:
boolean = True
@@ -1365,6 +1388,15 @@ class ResMrpWorkOrder(models.Model):
boolean = True
if not boolean:
raise UserError('制造订单【%s】缺少组件的序列号信息!' % self.production_id.name)
self.pro_code = False # 默认值
if (
self.production_id
and self.production_id.move_raw_ids
and len(self.production_id.move_raw_ids) > 0
and self.production_id.move_raw_ids[0].move_line_ids
and len(self.production_id.move_raw_ids[0].move_line_ids) > 0
and self.production_id.move_raw_ids[0].move_line_ids[0].lot_id
):
self.pro_code = self.production_id.move_raw_ids[0].move_line_ids[0].lot_id.name
# cnc校验
if self.production_id.production_type == '自动化产线加工':
@@ -1389,7 +1421,10 @@ class ResMrpWorkOrder(models.Model):
# 表面工艺外协出库单
if self.routing_type == '表面工艺':
if self.is_subcontract is True:
move_out = self.move_subcontract_workorder_ids[1]
picking_id = self.production_id.picking_ids.filtered(
lambda wk: wk.location_id.name == '制造前' and wk.location_dest_id.name == '外协加工区')
move_out = picking_id.move_ids
# move_out = self.move_subcontract_workorder_ids[1]
# move_out = self.env['stock.move'].search(
# [('location_id', '=', self.env['stock.location'].search(
# [('barcode', 'ilike', 'WH-PREPRODUCTION')]).id),
@@ -1397,6 +1432,8 @@ class ResMrpWorkOrder(models.Model):
# [('barcode', 'ilike', 'VL-SPOC')]).id),
# ('origin', '=', self.production_id.name), ('state', 'not in', ['cancel', 'done'])])
for mo in move_out:
if self.production_id.bom_id.bom_line_ids.product_id.id != mo.product_id.id:
continue
if mo.state != 'done':
mo.write({'state': 'assigned', 'production_id': False})
if not mo.move_line_ids:
@@ -1529,6 +1566,7 @@ class ResMrpWorkOrder(models.Model):
lambda wo: wo.is_subcontract == True and wo.state != 'cancel').sorted('sequence')
if self == subcontract_workorders[-1]:
# 给下一个库存移动就绪
if self.move_subcontract_workorder_ids:
self.move_subcontract_workorder_ids[0].move_dest_ids._action_done()
# self.production_id.button_mark_done()
tem_date_planned_finished = record.date_planned_finished

View File

@@ -59,6 +59,88 @@ class PurchaseOrder(models.Model):
production_id = self.env['mrp.production'].search([('origin', 'in', origins)])
purchase.production_count = len(production_id)
def process_replenish(self,production,total_qty):
record = self
bom_line_id = production.bom_id.bom_line_ids
replenish = self.env['stock.warehouse.orderpoint'].search([
('product_id', '=', bom_line_id.product_id.id),
(
'location_id', '=', self.env.ref('sf_stock.stock_location_outsourcing_material_receiving_area').id),
# ('state', 'in', ['draft', 'confirmed'])
], limit=1)
if not replenish:
replenish_model = self.env['stock.warehouse.orderpoint']
replenish = replenish_model.create({
'product_id': bom_line_id.product_id.id,
'location_id': self.env.ref(
'sf_stock.stock_location_outsourcing_material_receiving_area').id,
'route_id': self.env.ref('sf_stock.stock_route_process_outsourcing').id,
'group_id': record.group_id.id,
'qty_to_order': total_qty,
'origin': record.name,
})
else:
replenish.write({
'product_id': bom_line_id.product_id.id,
'location_id': self.env.ref(
'sf_stock.stock_location_outsourcing_material_receiving_area').id,
'route_id': self.env.ref('sf_stock.stock_route_process_outsourcing').id,
'group_id': record.group_id.id,
'qty_to_order': total_qty + replenish.qty_to_order,
'origin': record.name + ',' + replenish.origin,
})
replenish.action_replenish()
def outsourcing_service_replenishment(self):
record = self
if record.purchase_type != 'consignment':
return
grouped_lines = {}
for line in record.order_line:
if line.related_product.id not in grouped_lines:
grouped_lines[line.related_product.id] = []
grouped_lines[line.related_product.id].append(line)
for product_id,lines in grouped_lines.items():
production = self.env['mrp.production'].search([('product_id', '=', product_id)], limit=1)
if not production:
continue
total_qty = sum(line.product_qty for line in lines)
record.process_replenish(production,total_qty)
for product_id,lines in grouped_lines.items():
productions = self.env['mrp.production'].search([('product_id', '=', product_id)], limit=1)
if not productions:
continue
# production.bom_id.bom_line_ids.product_id
location_id = self.env['stock.location'].search([('name', '=', '制造前')])
quants = self.env['stock.quant'].search([
('product_id', '=', productions.bom_id.bom_line_ids.product_id.id),
('location_id', '=', location_id.id)
])
total_qty = sum(quants.mapped('quantity')) # 计算该位置的总库存量
is_available = total_qty > 0
if not is_available:
raise UserError('请先完成坯料入库')
for production_id in productions:
work_ids = production_id.workorder_ids.filtered(
lambda wk: wk.state not in ['done', 'rework', 'cancel'])
if not work_ids:
continue
min_sequence_wk = min(work_ids, key=lambda wk: wk.sequence)
if min_sequence_wk.is_subcontract and min_sequence_wk.state == 'ready':
picking_id = production_id.picking_ids.filtered(
lambda wk: wk.location_id.name == '制造前' and wk.location_dest_id.name == '外协加工区')
move_out = picking_id.move_ids
for mo in move_out:
if production_id.bom_id.bom_line_ids.product_id.id != mo.product_id.id:
continue
if mo.state != 'done':
mo.write({'state': 'assigned', 'production_id': False})
if not mo.move_line_ids:
self.env['stock.move.line'].create(
mo.get_move_line(production_id, min_sequence_wk))
# product = self.env['mrp.production'].search([('product_id', '=', product_id)], limit=1)
# match = re.search(r'(S\d{5}-\d)',product.name)
# pass
def button_confirm(self):
for record in self:
for line in record.order_line:
@@ -66,39 +148,14 @@ class PurchaseOrder(models.Model):
raise UserError('请对【产品】中的【数量】进行输入')
if line.price_unit <= 0:
raise UserError('请对【产品】中的【单价】进行输入')
# if record.purchase_type == 'consignment':
# bom_line_id = record.order_line[0].purchase_request_lines.request_id.bom_id.bom_line_ids
# replenish = self.env['stock.warehouse.orderpoint'].search([
# ('product_id', '=', bom_line_id.product_id.id),
# (
# 'location_id', '=', self.env.ref('sf_stock.stock_location_outsourcing_material_receiving_area').id),
# # ('state', 'in', ['draft', 'confirmed'])
# ], limit=1)
# if not replenish:
# replenish_model = self.env['stock.warehouse.orderpoint']
# replenish = replenish_model.create({
# 'product_id': bom_line_id.product_id.id,
# 'location_id': self.env.ref(
# 'sf_stock.stock_location_outsourcing_material_receiving_area').id,
# 'route_id': self.env.ref('sf_stock.stock_route_process_outsourcing').id,
# 'group_id': record.group_id.id,
# 'qty_to_order': 1,
# 'origin': record.name,
# })
# else:
# replenish.write({
# 'product_id': bom_line_id.product_id.id,
# 'location_id': self.env.ref(
# 'sf_stock.stock_location_outsourcing_material_receiving_area').id,
# 'route_id': self.env.ref('sf_stock.stock_route_process_outsourcing').id,
# 'group_id': record.group_id.id,
# 'qty_to_order': 1 + replenish.qty_to_order,
# 'origin': record.name + ',' + replenish.origin,
# })
# replenish.action_replenish()
record.outsourcing_service_replenishment()
res = super(PurchaseOrder, self).button_confirm()
for line in self.order_line:
# 将产品不追踪序列号的行项目设置qty_done
if not line.move_ids:
continue
if line.move_ids and line.move_ids[0].product_id.tracking == 'none':
line.move_ids[0].quantity_done = line.move_ids[0].product_qty
return res
@@ -171,6 +228,24 @@ class PurchaseOrderLine(models.Model):
)
record.part_number = filtered_order_line.product_id.part_number
record.part_name = filtered_order_line.product_id.part_name
elif record.order_id.purchase_type == 'consignment':
product_name = ''
match = re.search(r'(S\d{5}-\d)', record.related_product.name)
# 如果匹配成功,提取结果
if match:
product_name = match.group(0)
sale_order_name = ''
match_sale = re.search(r'S(\d+)', record.related_product.name)
if match_sale:
sale_order_name = match_sale.group(0)
sale_order = self.env['sale.order'].sudo().search(
[('name', '=', sale_order_name)])
if sale_order:
filtered_order_line = sale_order.order_line.filtered(
lambda order_line: re.search(f'{product_name}$', order_line.product_id.name)
)
record.part_number = filtered_order_line.product_id.part_number
record.part_name = filtered_order_line.product_id.part_name
else:
record.part_number = record.product_id.part_number
record.part_name = record.product_id.part_name

View File

@@ -1,30 +1,30 @@
# # -*- coding: utf-8 -*-
# import base64
# import datetime
# import logging
# import json
# import os
# import re
# import traceback
# from operator import itemgetter
#
# import requests
# from itertools import groupby
# from collections import defaultdict, namedtuple
#
# from odoo import api, fields, models, SUPERUSER_ID, _
# from odoo.exceptions import UserError, ValidationError
# from odoo.tools import float_compare, float_round, float_is_zero, format_datetime
#
#
# class PurchaseRequestLine(models.Model):
# _inherit = 'purchase.request'
# is_subcontract = fields.Boolean(string='是否外协',default=False)
# class PurchaseRequestLine(models.Model):
# _inherit = 'purchase.request.line'
# is_subcontract = fields.Boolean(string='是否外协')
#
#
# class PurchaseRequest(models.Model):
# _inherit = 'purchase.request'
# bom_id = fields.Many2one('mrp.bom')
# -*- coding: utf-8 -*-
import base64
import datetime
import logging
import json
import os
import re
import traceback
from operator import itemgetter
import requests
from itertools import groupby
from collections import defaultdict, namedtuple
from odoo import api, fields, models, SUPERUSER_ID, _
from odoo.exceptions import UserError, ValidationError
from odoo.tools import float_compare, float_round, float_is_zero, format_datetime
class PurchaseRequestLine(models.Model):
_inherit = 'purchase.request'
is_subcontract = fields.Boolean(string='是否外协',default=False)
class PurchaseRequestLine(models.Model):
_inherit = 'purchase.request.line'
is_subcontract = fields.Boolean(string='是否外协')
class PurchaseRequest(models.Model):
_inherit = 'purchase.request'
bom_id = fields.Many2one('mrp.bom')

View File

@@ -56,10 +56,10 @@ class SaleOrder(models.Model):
'jikimo_sale_multiple_supply_methods.product_template_manual_processing').sudo()
# 复制成品模板上的属性
line.product_id.product_tmpl_id.copy_template(product_template_id)
line.product_id.copy_template(product_template_id)
# 将模板上的single_manufacturing属性复制到成品上
line.product_id.single_manufacturing = product_template_id.single_manufacturing
line.product_id.tracking = product_template_id.tracking
# line.product_id.single_manufacturing = product_template_id.single_manufacturing
# line.product_id.tracking = product_template_id.tracking
order_id = self
product = line.product_id
@@ -76,7 +76,7 @@ class SaleOrder(models.Model):
'embryo_redundancy_id': line.embryo_redundancy_id,
}
product_name = ''
match = re.search(r'(S\d{5}-\d)', product.name)
match = re.search(r'(S\d{5}-\d*)', product.name)
# 如果匹配成功,提取结果
if match:
product_name = match.group(0)

View File

@@ -7,74 +7,73 @@ from odoo.exceptions import UserError, ValidationError
class SfProductionProcessParameter(models.Model):
_inherit = 'sf.production.process.parameter'
# service_products = fields.Many2one(
# 'product.template',
# string='外协服务产品',compute='_compute_service_products',inverse='_inverse_service_products',
# store=True
# )
# outsourced_service_products = fields.One2many(
# 'product.template', # 另一个模型的名称
# 'server_product_process_parameters_id', # 对应的 Many2one 字段名称
# string='外协服务产品'
# )
# is_product_button = fields.Boolean(compute='_compute_is_product_button',default=False)
# is_delete_button = fields.Boolean(compute='_compute_is_delete_button', default=False)
# routing_id = fields.Many2one('mrp.routing.workcenter', string="工序")
#
# @api.depends('outsourced_service_products')
# def _compute_service_products(self):
# for record in self:
# # 假设取第一条作为主明细
# record.service_products = record.outsourced_service_products.id if record.outsourced_service_products else False
#
# def _inverse_service_products(self):
# for record in self:
# if record.service_products:
# # 确保关联关系正确
# record.outsourced_service_products = record.service_products.ids if record.service_products else False
# else:
# record.outsourced_service_products = False
# def name_get(self):
# result = []
# for record in self:
# name = f"{record.process_id.name} - {record.name}" # 自定义显示格式
# result.append((record.id, name))
# return result
# @api.constrains('outsourced_service_products')
# def _validate_partner_limit(self):
# for record in self:
# if len(record.outsourced_service_products) > 1:
# raise ValidationError("工艺参数不能与多个产品关联")
#
# @api.onchange('outsourced_service_products')
# def _onchange_validate_partner_limit(self):
# for record in self:
# if len(record.outsourced_service_products) > 1:
# raise ValidationError("工艺参数不能与多个产品关联")
# @api.depends('outsourced_service_products')
# def _compute_is_product_button(self):
# for record in self:
# if record.outsourced_service_products:
# record.is_product_button = True
# else:
# record.is_product_button = False
#
# def has_wksp_prefix(self):
# """
# 判断字符串是否以WKSP开头不区分大小写
# :param text: 要检查的字符串
# :return: True/False
# """
# return self.code.upper().startswith('101'+self.routing_id.code)
# @api.depends('outsourced_service_products','code')
# def _compute_is_delete_button(self):
# for record in self:
# if record.outsourced_service_products and record.has_wksp_prefix():
# record.is_delete_button = False
# elif record.outsourced_service_products:
# record.is_delete_button = True
# else:
# record.is_delete_button = True
service_products = fields.Many2one(
'product.template',
string='外协服务产品',compute='_compute_service_products',inverse='_inverse_service_products',
store=True
)
outsourced_service_products = fields.One2many(
'product.template', # 另一个模型的名称
'server_product_process_parameters_id', # 对应的 Many2one 字段名称
string='外协服务产品'
)
is_product_button = fields.Boolean(compute='_compute_is_product_button',default=False)
is_delete_button = fields.Boolean(compute='_compute_is_delete_button', default=False)
routing_id = fields.Many2one('mrp.routing.workcenter', string="工序")
def _inverse_service_products(self):
for record in self:
if record.service_products:
# 确保关联关系正确
record.outsourced_service_products = record.service_products.ids if record.service_products else False
else:
record.outsourced_service_products = False
@api.depends('outsourced_service_products')
def _compute_service_products(self):
for record in self:
# 假设取第一条作为主明细
record.service_products = record.outsourced_service_products[0].id if record.outsourced_service_products else False
def name_get(self):
result = []
for record in self:
name = f"{record.process_id.name} - {record.name}" # 自定义显示格式
result.append((record.id, name))
return result
@api.constrains('outsourced_service_products')
def _validate_partner_limit(self):
for record in self:
if len(record.outsourced_service_products) > 1:
raise ValidationError("工艺参数不能与多个产品关联")
@api.onchange('outsourced_service_products')
def _onchange_validate_partner_limit(self):
for record in self:
if len(record.outsourced_service_products) > 1:
raise ValidationError("工艺参数不能与多个产品关联")
@api.depends('outsourced_service_products')
def _compute_is_product_button(self):
for record in self:
if record.outsourced_service_products:
record.is_product_button = True
else:
record.is_product_button = False
def has_wksp_prefix(self):
"""
判断字符串是否以WKSP开头不区分大小写
:param text: 要检查的字符串
:return: True/False
"""
return self.code.upper().startswith('101'+self.routing_id.code)
@api.depends('outsourced_service_products','code')
def _compute_is_delete_button(self):
for record in self:
if record.outsourced_service_products and record.has_wksp_prefix():
record.is_delete_button = False
elif record.outsourced_service_products:
record.is_delete_button = True
else:
record.is_delete_button = True
@api.model
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
if self._context.get('route_id'):
@@ -90,19 +89,19 @@ class SfProductionProcessParameter(models.Model):
return self._search(domain, limit=limit, access_rights_uid=name_get_uid)
return super()._name_search(name, args, operator, limit, name_get_uid)
# def action_create_service_product(self):
# if self.id: # 如果是已存在的记录
# self.write({}) # 空写入会触发保存
# else: # 如果是新记录
# self = self.create(self._convert_to_write(self.read()[0]))
# return {
# 'type': 'ir.actions.act_window',
# 'name': '向导名称',
# 'res_model': 'product.creation.wizard',
# 'view_mode': 'form',
# 'target': 'new',
# 'context': {'default_process_parameter_id': self.id}, # 传递当前记录ID
# }
def action_create_service_product(self):
if self.id: # 如果是已存在的记录
self.write({}) # 空写入会触发保存
else: # 如果是新记录
self = self.create(self._convert_to_write(self.read()[0]))
return {
'type': 'ir.actions.act_window',
'name': '向导名称',
'res_model': 'product.creation.wizard',
'view_mode': 'form',
'target': 'new',
'context': {'default_process_parameter_id': self.id}, # 传递当前记录ID
}
#
# return {
# 'name': '创建服务产品',
@@ -116,6 +115,6 @@ class SfProductionProcessParameter(models.Model):
# },
# }
# def action_hide_service_products(self):
# # self.outsourced_service_products.active = False
# self.active = False
def action_hide_service_products(self):
# self.outsourced_service_products.active = False
self.active = False

View File

@@ -631,28 +631,62 @@ class StockPicking(models.Model):
move.action_clear_lines_show_details()
move.action_show_details()
res = super().button_validate()
picking_type_in = self.env.ref('sf_manufacturing.outcontract_picking_in').id
if res is True and self.picking_type_id.id == picking_type_in:
lot_ids = None
product_ids = self.move_ids.mapped('product_id')
if not self.move_ids[0].product_id.single_manufacturing and self.move_ids[0].product_id.tracking == 'none':
lot_ids = self.move_ids.move_line_ids.mapped('lot_id')
production_ids = self.sale_order_id.mrp_production_ids if self.sale_order_id else self.env['mrp.production']
if res and self.location_id.name == '外协收料区' and self.location_dest_id.name == '制造前':
# 如果是最后一张外协入库单,则设置库存位置的预留数量
move_in = self.move_ids
if move_in:
workorder = move_in.subcontract_workorder_id
workorders = workorder.production_id.workorder_ids
subcontract_workorders = workorders.filtered(
lambda wo: wo.is_subcontract == True and wo.state != 'cancel').sorted('sequence')
# if workorder == subcontract_workorders[-1]:
# self.env['stock.quant']._update_reserved_quantity(
# move_in.product_id, move_in.location_dest_id, move_in.product_uom_qty,
# lot_id=move_in.move_line_ids.lot_id,
# package_id=False, owner_id=False, strict=False
# )
workorder.button_finish()
picking_type_out = self.env.ref('sf_manufacturing.outcontract_picking_out').id
if res and self.picking_type_id.id == picking_type_out:
move_out = self.move_ids
if move_out:
workorder = move_out.subcontract_workorder_id
workorder.button_start()
for production_id in production_ids:
if lot_ids:
lot_id = production_id.move_raw_ids.move_line_ids.lot_id
# picking_ids = production_id.picking_ids.filtered(
# lambda wk: wk.location_id.name == '外协收料区' and wk.location_dest_id.name == '制造前')
if lot_id in lot_ids:
workorder_id = production_id.workorder_ids.filtered(
lambda a: a.state == 'progress' and a.is_subcontract)
if not workorder_id:
continue
workorder_id.button_finish()
else:
workorder_id = production_id.workorder_ids.filtered(lambda a: a.state == 'progress' and a.is_subcontract)
if not workorder_id:
continue
workorder_id.button_finish()
# lot_id = workorder.production_id.move_raw_ids.move_line_ids.lot_id
# picking_ids = workorder.production_id.picking_ids.filtered(
# lambda wk: wk.location_id.name == '外协收料区' and wk.location_dest_id.name == '制造前')
# if move_in:
# workorder = move_in.subcontract_workorder_id
# workorders = workorder.production_id.workorder_ids
# subcontract_workorders = workorders.filtered(
# lambda wo: wo.is_subcontract == True and wo.state != 'cancel').sorted('sequence')
# # if workorder == subcontract_workorders[-1]:
# # self.env['stock.quant']._update_reserved_quantity(
# # move_in.product_id, move_in.location_dest_id, move_in.product_uom_qty,
# # lot_id=move_in.move_line_ids.lot_id,
# # package_id=False, owner_id=False, strict=False
# # )
# workorder.button_finish()
if res and self.location_id.name == '制造前' and self.location_dest_id.name == '外协加工区':
for production_id in production_ids:
if lot_ids:
lot_id = production_id.move_raw_ids.move_line_ids.lot_id
# picking_ids = production_id.picking_ids.filtered(
# lambda wk: wk.location_id.name == '外协收料区' and wk.location_dest_id.name == '制造前')
if lot_id in lot_ids:
workorder_id = production_id.workorder_ids.filtered(
lambda a: a.state == 'progress' and a.is_subcontract)
if not workorder_id:
continue
workorder_id.button_finish()
else:
workorder_id = production_id.workorder_ids.filtered(lambda a: a.state == 'ready' and a.is_subcontract)
if not workorder_id:
continue
workorder_id.button_start()
if self.location_id.name == '成品存货区' and self.location_dest_id.name == '客户':
sale_id = self.env['sale.order'].sudo().search(
[('name', '=', self.origin)])
@@ -896,6 +930,8 @@ class ReStockMove(models.Model):
}
def get_move_line(self, production_id, sorted_workorders):
# if not self.move_ids[0].product_id.single_manufacturing and self.move_ids[0].product_id.tracking == 'none':
qty = production_id.product_qty
return {
'move_id': self.id,
'product_id': self.product_id.id,
@@ -903,7 +939,7 @@ class ReStockMove(models.Model):
'location_id': self.picking_id.location_id.id,
'location_dest_id': self.picking_id.location_dest_id.id,
'picking_id': self.picking_id.id,
'reserved_uom_qty': self.product_uom_qty,
'reserved_uom_qty': qty,
'lot_id': production_id.move_line_raw_ids.lot_id.id,
'company_id': self.env.company.id,
# 'workorder_id': '' if not sorted_workorders else sorted_workorders.id,

View File

@@ -0,0 +1,11 @@
# -*- coding: utf-8 -*-
# Part of SmartGo. See LICENSE file for full copyright and licensing details.
import base64
from io import BytesIO
from odoo import api, fields, models, SUPERUSER_ID, _
class StockWarehouseOrderpoint(models.Model):
_inherit = 'stock.warehouse.orderpoint'
origin = fields.Char(string='来源')
_order = 'create_date DESC'

View File

@@ -383,7 +383,7 @@
<field name="process_parameters_id"
attrs="{'readonly': [('id', '!=', False),('routing_tag', '=', 'standard')]}"
string="参数" context="{'route_id':route_id,'production_id': production_id}"
options="{'no_create': True}"/>
options="{'no_create': True}" domain="[('routing_id', '=', 'route_id')]"/>
<field name="panel" readonly="1"/>
<field name="routing_tag" readonly="1" widget="badge"
decoration-success="routing_tag == 'standard'"

View File

@@ -22,26 +22,26 @@
<field name="is_repeat"/>
<field name="reserved_duration"/>
</field>
<!-- <xpath expr="//notebook/page[1]" position="before">-->
<!-- <page string="可选工艺参数">-->
<!-- <field name="optional_process_parameters">-->
<!-- <tree editable="bottom">-->
<!-- <field name="is_product_button" invisible="1"/>-->
<!-- <field name="is_delete_button" invisible="1"/>-->
<!-- <field name="code" attrs="{'readonly': True}"/>-->
<!-- <field name="name" required="1"/>-->
<!-- <field name="service_products" domain="[('detailed_type', '=', 'service'),('server_product_process_parameters_id', '=', False)]"/>-->
<!-- &lt;!&ndash; 按钮列 &ndash;&gt;-->
<!-- <button name="action_create_service_product" string="创建服务产品" type="object"-->
<!-- class="btn-primary"-->
<!-- attrs="{'invisible': [('is_product_button', '=', True)]}" context="{'default_process_parameter_id':id}"/>-->
<!-- <button name="action_hide_service_products" string="删除" type="object"-->
<!-- class="oe_highlight"-->
<!-- attrs="{'invisible': [('is_delete_button', '=', True)]}"/>-->
<!-- </tree>-->
<!-- </field>-->
<!-- </page>-->
<!-- </xpath>-->
<xpath expr="//notebook/page[1]" position="before">
<page string="可选工艺参数">
<field name="optional_process_parameters">
<tree editable="bottom">
<field name="is_product_button" invisible="1"/>
<field name="is_delete_button" invisible="1"/>
<field name="code" attrs="{'readonly': True}"/>
<field name="name" required="1"/>
<field name="service_products" domain="[('detailed_type', '=', 'service'),('server_product_process_parameters_id', '=', False)]"/>
<!-- 按钮列 -->
<button name="action_create_service_product" string="创建服务产品" type="object"
class="btn-primary"
attrs="{'invisible': [('is_product_button', '=', True)]}" context="{'default_process_parameter_id':id}"/>
<button name="action_hide_service_products" string="删除" type="object"
class="oe_highlight"
attrs="{'invisible': [('is_delete_button', '=', True)]}"/>
</tree>
</field>
</page>
</xpath>
</field>
</record>
</data>

View File

@@ -144,17 +144,17 @@
statusbar_visible="pending,waiting,ready,progress,to be detected,done,rework"/>
</xpath>
<xpath expr="//div[@name='button_box']" position="inside">
<!-- <button type="object" name="action_view_pr_mrp_workorder" class="oe_stat_button"-->
<!-- icon="fa-credit-card"-->
<!-- groups="base.group_user,sf_base.group_sf_order_user"-->
<!-- attrs="{'invisible': [('pr_mp_count', '=', 0)]}">-->
<!-- <div class="o_field_widget o_stat_info">-->
<!-- <span class="o_stat_value">-->
<!-- <field name="pr_mp_count"/>-->
<!-- </span>-->
<!-- <span class="o_stat_text">采购申请</span>-->
<!-- </div>-->
<!-- </button>-->
<button type="object" name="action_view_pr_mrp_workorder" class="oe_stat_button"
icon="fa-credit-card"
groups="base.group_user,sf_base.group_sf_order_user"
attrs="{'invisible': [('pr_mp_count', '=', 0)]}">
<div class="o_field_widget o_stat_info">
<span class="o_stat_value">
<field name="pr_mp_count"/>
</span>
<span class="o_stat_text">采购申请</span>
</div>
</button>
<button type="object" name="action_view_surface_technics_purchase" class="oe_stat_button"
icon="fa-credit-card"
groups="base.group_user,sf_base.group_sf_order_user"

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="view_warehouse_orderpoint_tree_editable_inherit" model="ir.ui.view">
<field name="name">补货</field>
<field name="model">stock.warehouse.orderpoint</field>
<field name="inherit_id" ref="stock.view_warehouse_orderpoint_tree_editable"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='qty_to_order']" position="after">
<field name="origin"/>
</xpath>
</field>
</record>
<!-- 继承补货单的搜索视图 -->
</data>
</odoo>

View File

@@ -77,11 +77,11 @@ class ProductionTechnologyReAdjustWizard(models.TransientModel):
if workorders[
0].production_id.product_id.categ_id.type == '成品' and item.programming_state != '已编程':
workorders[0].state = 'waiting'
# pr_ids = self.env['purchase.request'].sudo().search(
# [('origin', 'like', item.name), ('is_subcontract', '=', 'True'), ('state', '!=', 'rejected')])
# if not pr_ids:
# continue
# if not all(pr.state == 'draft' for pr in pr_ids):
# # 如果发现有记录的 state 不是 'draft',抛出异常
# raise UserError("有采购申请的状态不是 '草稿'")
# pr_ids.state = 'rejected'
pr_ids = self.env['purchase.request'].sudo().search(
[('origin', 'like', item.name), ('is_subcontract', '=', 'True'), ('state', '!=', 'rejected')])
if not pr_ids:
continue
if not all(pr.state == 'draft' for pr in pr_ids):
# 如果发现有记录的 state 不是 'draft',抛出异常
raise UserError("有采购申请的状态不是 '草稿'")
pr_ids.state = 'rejected'

View File

@@ -268,8 +268,6 @@ class ReworkWizard(models.TransientModel):
'cmm_ids': new_cnc_workorder.cmm_ids.sudo()._json_cmm_program(
cnc_work.processing_panel, ret),
'cnc_worksheet': old_cnc_rework.cnc_worksheet})
# 复制装夹图纸
new_cnc_workorder.processing_drawing = old_cnc_rework.processing_drawing
# ========== 处理装夹预调 【装夹图纸】 数据 ================
for new_pre_work in new_pre_workorder_ids:
pre_rework = max(self.production_id.workorder_ids.filtered(

View File

@@ -3,6 +3,9 @@ import logging
import os
import json
import base64
import traceback
from odoo import http, fields, models
from odoo.http import request
from odoo.addons.sf_base.controllers.controllers import MultiInheritController
@@ -273,7 +276,8 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController):
except Exception as e:
res = {'status': -1, 'message': '系统解析失败'}
request.cr.rollback()
logging.info('get_cnc_processing_create error:%s' % e)
traceback_error = traceback.format_exc()
logging.error("get_cnc_processing_create error:%s" % traceback_error)
return json.JSONEncoder().encode(res)

View File

@@ -1149,7 +1149,7 @@ class sfProductionProcessParameter(models.Model):
'processing_mm': item['processing_mm'],
'gain_way':'外协',
})
# production_process_parameter.create_service_product()
production_process_parameter.create_service_product()
else:
production_process_parameter.gain_way = '外协'
production_process_parameter.name = item['name']
@@ -1161,9 +1161,9 @@ class sfProductionProcessParameter(models.Model):
[('materials_no', 'in', item['materials_model_ids_codes'])])
production_process_parameter.active = item['active']
production_process_parameter.processing_mm = item['processing_mm']
# if not production_process_parameter.outsourced_service_products:
# production_process_parameter.create_service_product()
# production_process_parameter.create_work_center()
if not production_process_parameter.outsourced_service_products:
production_process_parameter.create_service_product()
production_process_parameter.create_work_center()
else:
raise ValidationError("表面工艺可选参数认证未通过")

View File

@@ -5,7 +5,6 @@ from odoo import fields, models, api
from odoo.exceptions import ValidationError
from datetime import datetime
from odoo.addons.sf_base.commons.common import Common
from odoo.tools import float_round
class QualityCheck(models.Model):
@@ -126,78 +125,18 @@ class QualityCheck(models.Model):
# todo 需修改
val = ['0037818516']
logging.info('获取到的工单信息%s' % val)
r = requests.post(crea_url, json=val, headers=headers)
# r = requests.post(crea_url, json=val, headers=headers)
r = self.env['api.request.log'].log_request(
'get',
crea_url,
name='零件特采',
responser='中控系统',
json=val,
headers=headers
)
ret = r.json()
logging.info('_register_quality_check:%s' % ret)
if ret['Succeed']:
return "零件特采发送成功"
else:
raise ValidationError("零件特采发送失败")
@api.model_create_multi
def create(self, vals_list):
for val in vals_list:
if 'point_id' in val and 'measure_on' not in val:
# 如果没有控制方式字段,则从检查点读取质量方式
point_id = self.env['quality.point'].browse(val['point_id'])
val.update({'measure_on': point_id.measure_on})
return super(QualityCheck, self).create(vals_list)
@api.depends('total_qty','testing_percentage_within_lot', 'is_lot_tested_fractionally')
def _compute_workorder_qty_to_test(self):
for qc in self:
if qc.is_lot_tested_fractionally:
rounding = qc.product_id.uom_id.rounding if qc.product_id.uom_id else 0.01
qc.workorder_qty_to_test = float_round(float(qc.total_qty) * qc.testing_percentage_within_lot / 100,
precision_rounding=rounding, rounding_method="UP")
else:
qc.workorder_qty_to_test = qc.total_qty
@api.depends('picking_id', 'workorder_id')
def _compute_total_qty(self):
super(QualityCheck, self)._compute_total_qty()
for qc in self:
if not qc.picking_id and qc.workorder_id:
qc.total_qty = qc.workorder_id.production_id.product_qty
@api.depends('workorder_qty_to_test')
def _compute_workorder_qty_tested(self):
for qc in self:
qc.workorder_qty_tested = qc.workorder_qty_to_test
workorder_qty_to_test = fields.Float('应检', compute='_compute_workorder_qty_to_test', store=True)
workorder_qty_tested = fields.Float('已检', compute='_compute_workorder_qty_tested', store=True)
workorder_qty_test_failed = fields.Float('不合格数')
@api.onchange('total_qty', 'workorder_qty_test_failed', 'workorder_qty_to_test', 'workorder_qty_tested')
def _onchage_qty(self):
for record in self:
if record.total_qty and record.workorder_qty_to_test and record.workorder_qty_to_test > float(record.total_qty):
record.workorder_qty_to_test = float(record.total_qty)
return {
'warning': {
'title': '警告',
'message': '待检数量不能超过总数量'
}
}
if record.workorder_qty_to_test and record.workorder_qty_tested and record.workorder_qty_tested > record.workorder_qty_to_test:
record.workorder_qty_tested = record.workorder_qty_to_test
return {
'warning': {
'title': '警告',
'message': '已检数量不能超过待检数量'
}
}
if record.workorder_qty_tested and record.workorder_qty_test_failed and record.workorder_qty_test_failed > record.workorder_qty_tested:
record.workorder_qty_test_failed = record.workorder_qty_tested
return {
'warning': {
'title': '警告',
'message': '不合格数量不能超过已检数量'
}
}

View File

@@ -88,42 +88,6 @@
<button name="do_cancel_publish" string="取消发布" type="object" class="btn-primary" confirm="确定取消发布吗?" attrs="{'invisible': ['|',('is_out_check', '=', False), ('publish_status', '!=', 'published')]}"/>
<button name="do_re_publish" string="重新发布" type="object" class="btn-primary" attrs="{'invisible': ['|', ('is_out_check', '=', False), ('publish_status', '!=', 'canceled')]}"/>
</xpath>
<xpath expr="//field[@name='total_qty']" position="attributes">
<attribute name="attrs">{
'invisible': ['&amp;', '|', ('measure_on', '!=', 'product'), ('is_out_check', '=', False), '|', ('measure_on', '!=', 'move_line'), ('workorder_id', '=', False)],
'readonly': ['|', ('measure_on', '!=', 'move_line'), ('workorder_id', '=', False)],
'on_change': ['|', ('measure_on', '!=', 'move_line'), ('workorder_id', '=', False)]
}</attribute>
</xpath>
<xpath expr="//field[@name='total_qty']" position="after">
<label for="workorder_qty_to_test"
attrs="{'invisible': ['|', '&amp;', ('measure_on', '!=', 'move_line'), ('workorder_id', '=', False), ('is_lot_tested_fractionally', '=', False)]}"/>
<div class="o_row"
attrs="{'invisible': ['|', '&amp;', ('measure_on', '!=', 'move_line'), ('workorder_id', '=', False), ('is_lot_tested_fractionally', '=', False)]}">
<field name="workorder_qty_to_test" attrs="{'readonly': 0, 'on_chnage': 1}"/>
<field name="uom_id"/>
</div>
<label for="workorder_qty_tested"
attrs="{'invisible': ['|', '&amp;', ('measure_on', '!=', 'move_line'), ('workorder_id', '=', False), ('is_lot_tested_fractionally', '=', False)]}"/>
<div class="o_row"
attrs="{'invisible': ['|', '&amp;', ('measure_on', '!=', 'move_line'), ('workorder_id', '=', False), ('is_lot_tested_fractionally', '=', False)]}">
<field name="workorder_qty_tested" attrs="{'readonly': [('quality_state', '!=', 'none')], 'on_chnage': 1}"/>
<field name="uom_id"/>
</div>
<label for="workorder_qty_test_failed"
attrs="{'invisible': ['|', '&amp;', ('measure_on', '!=', 'move_line'), ('workorder_id', '=', False), ('is_lot_tested_fractionally', '=', False)]}"/>
<div class="o_row"
attrs="{'invisible': ['|', '&amp;', ('measure_on', '!=', 'move_line'), ('workorder_id', '=', False), ('is_lot_tested_fractionally', '=', False)]}">
<field name="workorder_qty_test_failed" attrs="{'readonly': [('quality_state', '!=', 'none')], 'on_chnage': 1}"/>
<field name="uom_id"/>
</div>
</xpath>
<xpath expr="//label[@for='qty_tested']" position="attributes">
<attribute name="attrs">{'invisible': ['|', '|', ('measure_on', '!=', 'move_line'), ('is_lot_tested_fractionally', '=', False), '&amp;', ('measure_on', '=', 'move_line'), ('workorder_id', '!=', False)]}</attribute>
</xpath>
<xpath expr="//div[@class='o_row'][.//field[@name='qty_tested']]" position="attributes">
<attribute name="attrs">{'invisible': ['|', '|', ('measure_on', '!=', 'move_line'), ('is_lot_tested_fractionally', '=', False), '&amp;', ('measure_on', '=', 'move_line'), ('workorder_id', '!=', False)]}</attribute>
</xpath>
</field>
</record>

View File

@@ -346,10 +346,10 @@ class RePurchaseOrder(models.Model):
if purchase.order_line[0].product_id.categ_id.name == '坯料':
if purchase.order_line[0].product_id.materials_type_id.gain_way == '外协':
purchase.purchase_type = 'outsourcing'
# request_lines = self.order_line.mapped('purchase_request_lines')
# # 检查是否存在 is_subcontract 为 True 的行
# if any(line.is_subcontract for line in request_lines):
# purchase.purchase_type = 'consignment'
request_lines = self.order_line.mapped('purchase_request_lines')
# 检查是否存在 is_subcontract 为 True 的行
if any(line.is_subcontract for line in request_lines):
purchase.purchase_type = 'consignment'
delivery_warning = fields.Selection([('normal', '正常'), ('warning', '预警'), ('overdue', '已逾期')],
@@ -384,27 +384,28 @@ class RePurchaseOrder(models.Model):
if not line.taxes_id:
raise UserError('请对【产品】中的【税】进行选择')
# def get_purchase_request(self, consecutive_process_parameters, production):
# result = []
# for pp in consecutive_process_parameters:
# server_template = self.env['product.template'].search(
# [('server_product_process_parameters_id', '=', pp.surface_technics_parameters_id.id),
# ('detailed_type', '=', 'service')])
# # route_ids
# result.append({
# "product_id": server_template.product_variant_id.id,
# "name": production.procurement_group_id.name,
# "date_required": fields.Datetime.now(),
# "product_uom_id":server_template.uom_id.id,
# "product_qty": 1,
# "request_id": False,
# "move_dest_ids": False,
# "orderpoint_id": False,
# 'is_subcontract':True,
# 'group_id':production.procurement_group_id.id,
# 'production_name':pp.production_id.name,
# })
# return result
def get_purchase_request(self, consecutive_process_parameters, production):
result = []
for pp in consecutive_process_parameters:
server_template = self.env['product.template'].search(
[('server_product_process_parameters_id', '=', pp.surface_technics_parameters_id.id),
('detailed_type', '=', 'service')])
# route_ids
result.append({
"product_id": server_template.product_variant_id.id,
'related_product': production.product_id.id,
"name": production.procurement_group_id.name,
"date_required": fields.Datetime.now(),
"product_uom_id":server_template.uom_id.id,
"product_qty": production.product_qty,
"request_id": False,
"move_dest_ids": False,
"orderpoint_id": False,
'is_subcontract':True,
'group_id':production.procurement_group_id.id,
'production_name':pp.production_id.name,
})
return result
def get_purchase_order(self, consecutive_process_parameters, production, product_id_to_production_names):
for pp in consecutive_process_parameters:

View File

@@ -4,12 +4,14 @@ import json
import base64
from odoo import http
from odoo.http import request
from odoo.addons.sf_base.decorators.api_log import api_log
class Manufacturing_Connect(http.Controller):
@http.route('/AutoDeviceApi/ToolGroup', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False,
cors="*")
@api_log('刀具组', requester='中控系统')
def get_functional_tool_groups_Info(self, **kw):
"""
刀具组接口
@@ -39,6 +41,7 @@ class Manufacturing_Connect(http.Controller):
@http.route('/AutoDeviceApi/ToolInventory', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
cors="*")
@api_log('功能刀具清单', requester='中控系统')
def get_functional_tool_inventory_Info(self, **kw):
"""
功能刀具清单接口
@@ -68,6 +71,7 @@ class Manufacturing_Connect(http.Controller):
@http.route('/AutoDeviceApi/ToolEntity', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
cors="*")
@api_log('功能刀具', requester='中控系统')
def get_functional_tool_entity_Info(self, **kw):
"""
功能刀具列表接口

View File

@@ -51,7 +51,15 @@ class SfMaintenanceEquipment(models.Model):
headers = {'Authorization': config['center_control_Authorization']}
crea_url = config['center_control_url'] + "/AutoDeviceApi/GetToolInfos"
params = {"DeviceId": self.name}
r = requests.get(crea_url, params=params, headers=headers)
# r = requests.get(crea_url, params=params, headers=headers)
r = self.env['api.request.log'].log_request(
'get',
crea_url,
name='机床刀库',
responser='中控系统',
params=params,
headers=headers
)
ret = r.json()
logging.info('机床刀库register_equipment_tool():%s' % ret)
datas = ret['Datas']

View File

@@ -514,7 +514,15 @@ class ShelfLocation(models.Model):
crea_url = config['center_control_url'] + "/AutoDeviceApi/GetLocationInfos"
params = {'DeviceId': device_id}
r = requests.get(crea_url, params=params, headers=headers)
# r = requests.get(crea_url, params=params, headers=headers)
r = self.env['api.request.log'].log_request(
'get',
crea_url,
name='库位信息',
responser='中控系统',
params=params,
headers=headers
)
ret = r.json()