Compare commits
43 Commits
release/re
...
feature/sy
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
61bcd72a41 | ||
|
|
ee87e1dacf | ||
|
|
d0d4db1555 | ||
|
|
62cbb4b796 | ||
|
|
f040406002 | ||
|
|
bfff4ac440 | ||
|
|
a97386c37c | ||
|
|
18ae46207a | ||
|
|
bacddd2ad8 | ||
|
|
dd5794899d | ||
|
|
e5b730b2ef | ||
|
|
aea158de41 | ||
|
|
a933a0ffea | ||
|
|
7575424760 | ||
|
|
6c2eb40e6a | ||
|
|
f10f595fa4 | ||
|
|
6d1de42d76 | ||
|
|
5dc16c039c | ||
|
|
c416cdbeed | ||
|
|
18c7b22319 | ||
|
|
e0ba222382 | ||
|
|
58b00e6442 | ||
|
|
9182dbfb5d | ||
|
|
27516844af | ||
|
|
99237445ac | ||
|
|
9349ca91d3 | ||
|
|
c55f3d77bf | ||
|
|
95716c2e3e | ||
|
|
5f72519dc2 | ||
|
|
c24bba3137 | ||
|
|
01bb6fd0aa | ||
|
|
bf4add6b78 | ||
|
|
7d986fe139 | ||
|
|
fffbfc21c2 | ||
|
|
6451bfbc42 | ||
|
|
5aa848de53 | ||
|
|
4f181e5eba | ||
|
|
2bf43ae9a1 | ||
|
|
d98d04d4ed | ||
|
|
602d6678bc | ||
|
|
8fd0c4e1f1 | ||
|
|
514fd79c3e | ||
|
|
21d052e222 |
@@ -12,12 +12,14 @@
|
||||
'views/mrp_production.xml',
|
||||
'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': [
|
||||
# 'jikimo_purchase_request/static/src/**/*'
|
||||
# ],
|
||||
# },
|
||||
'assets': {
|
||||
'web.assets_backend': [
|
||||
'jikimo_purchase_request/static/src/**/*'
|
||||
],
|
||||
},
|
||||
'application': True,
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -5,3 +5,4 @@ from . import sale_order
|
||||
from . import mrp_production
|
||||
from . import purchase_order
|
||||
from . import stock_rule
|
||||
from . import stock_picking
|
||||
|
||||
@@ -9,12 +9,20 @@ class MrpProduction(models.Model):
|
||||
@api.depends('state')
|
||||
def _compute_pr_mp_count(self):
|
||||
for item in self:
|
||||
pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', item.name)])
|
||||
# if item.product_id.product_tmpl_id.single_manufacturing == True and not item.is_remanufacture:
|
||||
# first_order = self.env['mrp.production'].search(
|
||||
# [('origin', '=', item.origin), ('product_id', '=', item.product_id.id)], limit=1, order='id asc')
|
||||
# pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', first_order.name)])
|
||||
# item.pr_mp_count = len(pr_ids)
|
||||
# else:
|
||||
# pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', item.name)])
|
||||
# item.pr_mp_count = len(pr_ids)
|
||||
# 由于采购申请合并了所有销售订单行的采购,所以不区分产品
|
||||
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)])
|
||||
item.pr_mp_count = len(pr_ids)
|
||||
# pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', item.name), ('is_subcontract', '!=', 'True')])
|
||||
if pr_ids:
|
||||
item.pr_mp_count = len(pr_ids)
|
||||
else:
|
||||
item.pr_mp_count = 0
|
||||
|
||||
def action_view_pr_mp(self):
|
||||
"""
|
||||
@@ -22,7 +30,18 @@ class MrpProduction(models.Model):
|
||||
"""
|
||||
self.ensure_one()
|
||||
# pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', self.name),('is_subcontract', '!=', True)])
|
||||
pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', self.name)])
|
||||
# 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)])
|
||||
|
||||
|
||||
action = {
|
||||
'res_model': 'purchase.request',
|
||||
'type': 'ir.actions.act_window',
|
||||
|
||||
@@ -47,6 +47,19 @@ class PurchaseRequestLine(models.Model):
|
||||
('outsourcing', "委外加工"),
|
||||
], string='供货方式', compute='_compute_supply_method', store=True)
|
||||
|
||||
purchase_request_count = fields.Integer(string='采购申请数量', compute='_compute_purchase_request_count', readonly=True)
|
||||
purchase_count = fields.Integer(string="采购订单数量", compute="_compute_purchase_count", readonly=True)
|
||||
|
||||
@api.depends("purchase_lines")
|
||||
def _compute_purchase_count(self):
|
||||
for rec in self:
|
||||
rec.purchase_count = len(rec.mapped("purchase_lines.order_id"))
|
||||
|
||||
@api.depends('request_id')
|
||||
def _compute_purchase_request_count(self):
|
||||
for order in self:
|
||||
order.purchase_request_count = len(order.request_id)
|
||||
|
||||
@api.depends('origin')
|
||||
def _compute_supply_method(self):
|
||||
for prl in self:
|
||||
@@ -98,3 +111,33 @@ class PurchaseRequestLine(models.Model):
|
||||
else:
|
||||
record.part_number = record.product_id.part_number
|
||||
record.part_name = record.product_id.part_name
|
||||
|
||||
def _compute_qty_to_buy(self):
|
||||
for pr in self:
|
||||
qty_to_buy = sum(pr.mapped("product_qty")) - sum(pr.mapped("qty_done")) - sum(pr.mapped("qty_in_progress"))
|
||||
pr.qty_to_buy = qty_to_buy > 0.0
|
||||
pr.pending_qty_to_receive = qty_to_buy
|
||||
|
||||
def action_view_purchase_request(self):
|
||||
action = self.env["ir.actions.actions"]._for_xml_id("purchase_request.purchase_request_form_action")
|
||||
action.update({
|
||||
'res_id': self.request_id.id,
|
||||
'views': [[False, 'form']],
|
||||
})
|
||||
return action
|
||||
|
||||
def action_view_purchase_order(self):
|
||||
action = self.env["ir.actions.actions"]._for_xml_id("purchase.purchase_rfq")
|
||||
lines = self.mapped("purchase_lines.order_id")
|
||||
if len(lines) > 1:
|
||||
action["domain"] = [("id", "in", lines.ids)]
|
||||
elif lines:
|
||||
action["views"] = [
|
||||
(self.env.ref("purchase.purchase_order_form").id, "form")
|
||||
]
|
||||
action["res_id"] = lines.id
|
||||
origin_context = ast.literal_eval(action['context'])
|
||||
if 'search_default_draft' in origin_context:
|
||||
origin_context.pop('search_default_draft')
|
||||
action['context'] = origin_context
|
||||
return action
|
||||
|
||||
35
jikimo_purchase_request/models/stock_picking.py
Normal file
35
jikimo_purchase_request/models/stock_picking.py
Normal file
@@ -0,0 +1,35 @@
|
||||
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
|
||||
@@ -1,4 +1,5 @@
|
||||
from odoo import api, fields, models
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
class StockRule(models.Model):
|
||||
@@ -44,7 +45,40 @@ class StockRule(models.Model):
|
||||
purchase_request_line_model.create(request_line_data)
|
||||
|
||||
def _run_buy(self, procurements):
|
||||
res = super(StockRule, self)._run_buy(procurements)
|
||||
# 如果补货组相同,并且产品相同,则合并
|
||||
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)] = {
|
||||
'product_id': procurement.product_id,
|
||||
'product_qty': procurement.product_qty,
|
||||
'product_uom': procurement.product_uom,
|
||||
'location_id': procurement.location_id,
|
||||
'name': procurement.name,
|
||||
'origin': procurement.origin,
|
||||
'company_id': procurement.company_id,
|
||||
'values': procurement.values,
|
||||
'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']
|
||||
new_procurements = []
|
||||
for k, p in procurements_dict.items():
|
||||
new_procurements.append((
|
||||
self.env['procurement.group'].Procurement(
|
||||
product_id=p['product_id'],
|
||||
product_qty=p['product_qty'],
|
||||
product_uom=p['product_uom'],
|
||||
location_id=p['location_id'],
|
||||
name=p['name'],
|
||||
origin=p['origin'],
|
||||
company_id=p['company_id'],
|
||||
values=p['values']
|
||||
), p['rule'])
|
||||
)
|
||||
|
||||
res = super(StockRule, self)._run_buy(new_procurements)
|
||||
# 判断是否根据规则生成新的采购申请单据,如果生成则修改状态为 approved
|
||||
origins = list(set([procurement[0].origin for procurement in procurements]))
|
||||
for origin in origins:
|
||||
|
||||
3
jikimo_purchase_request/static/src/change.scss
Normal file
3
jikimo_purchase_request/static/src/change.scss
Normal file
@@ -0,0 +1,3 @@
|
||||
th[data-name=keep_description] {
|
||||
min-width: 220px;
|
||||
}
|
||||
22
jikimo_purchase_request/views/purchase_request_line_view.xml
Normal file
22
jikimo_purchase_request/views/purchase_request_line_view.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<odoo>
|
||||
<record id="purchase_request_line_form_sf" model="ir.ui.view">
|
||||
<field name="name">purchase.request.line.sf.form</field>
|
||||
<field name="model">purchase.request.line</field>
|
||||
<field name="inherit_id" ref="purchase_request.purchase_request_line_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//h1" position="before">
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button type="object" name="action_view_purchase_request" class="oe_stat_button"
|
||||
icon="fa-file">
|
||||
<field name="purchase_request_count" widget="statinfo" string="采购申请"/>
|
||||
</button>
|
||||
<button type="object" name="action_view_purchase_order" class="oe_stat_button"
|
||||
attrs="{'invisible': [('purchase_count', '=', 0)]}" icon="fa-shopping-cart">
|
||||
<field name="purchase_count" widget="statinfo" string="采购订单"/>
|
||||
</button>
|
||||
</div>
|
||||
</xpath>
|
||||
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
21
jikimo_purchase_request/views/stock_picking_views.xml
Normal file
21
jikimo_purchase_request/views/stock_picking_views.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?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>
|
||||
@@ -104,9 +104,26 @@ class PurchaseRequestLineMakePurchaseOrder(models.TransientModel):
|
||||
# 去掉合并必须同一采购组的限制
|
||||
pass
|
||||
|
||||
|
||||
def get_items(self, request_line_ids):
|
||||
request_line_obj = self.env["purchase.request.line"]
|
||||
items = []
|
||||
request_lines = request_line_obj.browse(request_line_ids).filtered(lambda line: line.pending_qty_to_receive > 0)
|
||||
self._check_valid_request_line(request_line_ids)
|
||||
self.check_group(request_lines)
|
||||
for line in request_lines:
|
||||
items.append([0, 0, self._prepare_item(line)])
|
||||
return items
|
||||
|
||||
|
||||
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,
|
||||
)
|
||||
|
||||
@@ -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')
|
||||
total_qty = fields.Char('总数量', compute='_compute_total_qty', store=True)
|
||||
|
||||
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 ''
|
||||
record.total_qty = total_qty if total_qty > 0 else 0
|
||||
else:
|
||||
record.total_qty = ''
|
||||
record.total_qty = 0
|
||||
|
||||
# 检验数
|
||||
check_qty = fields.Integer('检验数', default=lambda self: self._get_default_check_qty())
|
||||
@@ -735,8 +735,9 @@ 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=self.product_id.uom_id.rounding, rounding_method="UP")
|
||||
precision_rounding=rounding, rounding_method="UP")
|
||||
else:
|
||||
qc.qty_to_test = qc.qty_line
|
||||
|
||||
|
||||
@@ -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')
|
||||
qty_tested = fields.Float(related='current_check_id.qty_tested', readonly=False)
|
||||
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)
|
||||
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')
|
||||
|
||||
@@ -1357,11 +1357,10 @@ 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 == '坯料':
|
||||
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:
|
||||
if self.production_id.move_raw_ids[0].move_line_ids[0].lot_id.name:
|
||||
boolean = True
|
||||
if self.production_id.move_raw_ids[0].move_line_ids[0].lot_id.name:
|
||||
boolean = True
|
||||
else:
|
||||
boolean = True
|
||||
if not boolean:
|
||||
|
||||
@@ -1030,6 +1030,7 @@ class ResProductMo(models.Model):
|
||||
'single_manufacturing': product_id.single_manufacturing,
|
||||
'is_bfm': True,
|
||||
'active': True,
|
||||
'tracking': finish_product.tracking, # 坯料的跟踪方式跟随成品
|
||||
}
|
||||
# 外协和采购生成的坯料需要根据材料型号绑定供应商
|
||||
if route_type == 'subcontract' or route_type == 'purchase':
|
||||
|
||||
@@ -96,8 +96,12 @@ class PurchaseOrder(models.Model):
|
||||
# 'origin': record.name + ',' + replenish.origin,
|
||||
# })
|
||||
# replenish.action_replenish()
|
||||
|
||||
return super(PurchaseOrder, self).button_confirm()
|
||||
res = super(PurchaseOrder, self).button_confirm()
|
||||
for line in self.order_line:
|
||||
# 将产品不追踪序列号的行项目设置qty_done
|
||||
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
|
||||
|
||||
|
||||
origin_sale_id = fields.Many2one('sale.order', string='销售订单号', store=True, compute='_compute_origin_sale_id')
|
||||
|
||||
@@ -59,6 +59,7 @@ class SaleOrder(models.Model):
|
||||
line.product_id.product_tmpl_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
|
||||
|
||||
order_id = self
|
||||
product = line.product_id
|
||||
|
||||
@@ -675,6 +675,7 @@ class StockPicking(models.Model):
|
||||
|
||||
# 创建 外协出库入单
|
||||
def create_outcontract_picking(self, workorders, item, sorted_workorders):
|
||||
production = workorders[0].production_id
|
||||
for workorder in workorders:
|
||||
if workorder.move_subcontract_workorder_ids:
|
||||
workorder.move_subcontract_workorder_ids.write({'state': 'cancel'})
|
||||
@@ -706,7 +707,7 @@ class StockPicking(models.Model):
|
||||
})
|
||||
moves_in = self.env['stock.move'].sudo().with_context(context).create(
|
||||
self.env['stock.move']._get_stock_move_values_Res(item, outcontract_picking_type_in,
|
||||
procurement_group_id.id, move_dest_id))
|
||||
procurement_group_id.id, move_dest_id, production.product_uom_qty))
|
||||
picking_in = self.create(
|
||||
moves_in._get_new_picking_values_Res(item, workorder, 'WH/OCIN/'))
|
||||
# pick_ids.append(picking_in.id)
|
||||
@@ -716,7 +717,7 @@ class StockPicking(models.Model):
|
||||
# self.env.context.get('default_production_id')
|
||||
moves_out = self.env['stock.move'].sudo().with_context(context).create(
|
||||
self.env['stock.move']._get_stock_move_values_Res(item, outcontract_picking_type_out,
|
||||
procurement_group_id.id, moves_in.id))
|
||||
procurement_group_id.id, moves_in.id, production.product_uom_qty))
|
||||
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/'))
|
||||
@@ -848,7 +849,7 @@ class ReStockMove(models.Model):
|
||||
traceback_error = traceback.format_exc()
|
||||
logging.error("零件图号 零件名称获取失败:%s" % traceback_error)
|
||||
|
||||
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, product_uom_qty=1.0):
|
||||
route_id = self.env.ref('sf_manufacturing.route_surface_technology_outsourcing').id
|
||||
stock_rule = self.env['stock.rule'].sudo().search(
|
||||
[('route_id', '=', route_id), ('picking_type_id', '=', picking_type_id)])
|
||||
@@ -857,7 +858,7 @@ class ReStockMove(models.Model):
|
||||
'company_id': item.company_id.id,
|
||||
'product_id': item.bom_id.bom_line_ids.product_id.id,
|
||||
'product_uom': item.bom_id.bom_line_ids.product_uom_id.id,
|
||||
'product_uom_qty': 1.0,
|
||||
'product_uom_qty': product_uom_qty,
|
||||
'location_id': stock_rule.location_src_id.id,
|
||||
'location_dest_id': stock_rule.location_dest_id.id,
|
||||
'origin': item.name,
|
||||
@@ -902,7 +903,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': 1.0,
|
||||
'reserved_uom_qty': self.product_uom_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,
|
||||
|
||||
@@ -4,30 +4,32 @@
|
||||
name="Manufacturing"
|
||||
groups="mrp.group_mrp_user,mrp.group_mrp_manager,sf_base.group_sf_mrp_user,sf_base.group_sf_mrp_manager"
|
||||
web_icon="mrp,static/description/icon.svg"
|
||||
sequence="145">
|
||||
sequence="145"/>
|
||||
|
||||
<menuitem id="mrp.menu_mrp_manufacturing"
|
||||
name="Operations"
|
||||
sequence="10"/>
|
||||
<menuitem id="mrp.menu_mrp_manufacturing"
|
||||
name="Operations"
|
||||
parent="mrp.menu_mrp_root"
|
||||
sequence="10"/>
|
||||
|
||||
<menuitem id="mrp.mrp_planning_menu_root"
|
||||
name="Planning"
|
||||
sequence="15"/>
|
||||
<menuitem id="mrp.mrp_planning_menu_root"
|
||||
name="Planning"
|
||||
parent="mrp.menu_mrp_root"
|
||||
sequence="15"/>
|
||||
|
||||
<menuitem id="mrp.enu_mrp_bom"
|
||||
name="Products"
|
||||
sequence="20"/>
|
||||
<menuitem id="mrp.menu_mrp_bom"
|
||||
name="Products"
|
||||
parent="mrp.menu_mrp_root"
|
||||
sequence="20"/>
|
||||
|
||||
<menuitem id="mrp.menu_mrp_reporting"
|
||||
name="Reporting"
|
||||
sequence="25"/>
|
||||
|
||||
<menuitem id="mrp.menu_mrp_configuration"
|
||||
name="Configuration"
|
||||
groups="mrp.group_mrp_manager,sf_base.group_sf_mrp_manager"
|
||||
sequence="100"/>
|
||||
|
||||
</menuitem>
|
||||
<menuitem id="mrp.menu_mrp_reporting"
|
||||
name="Reporting"
|
||||
parent="mrp.menu_mrp_root"
|
||||
sequence="25"/>
|
||||
|
||||
<menuitem id="mrp.menu_mrp_configuration"
|
||||
name="Configuration"
|
||||
parent="mrp.menu_mrp_root"
|
||||
groups="mrp.group_mrp_manager,sf_base.group_sf_mrp_manager"
|
||||
sequence="100"/>
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -268,6 +268,8 @@ 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(
|
||||
|
||||
@@ -5,6 +5,7 @@ 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):
|
||||
@@ -132,3 +133,71 @@ class QualityCheck(models.Model):
|
||||
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': '不合格数量不能超过已检数量'
|
||||
}
|
||||
}
|
||||
@@ -88,6 +88,42 @@
|
||||
<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': ['&', '|', ('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': ['|', '&', ('measure_on', '!=', 'move_line'), ('workorder_id', '=', False), ('is_lot_tested_fractionally', '=', False)]}"/>
|
||||
<div class="o_row"
|
||||
attrs="{'invisible': ['|', '&', ('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': ['|', '&', ('measure_on', '!=', 'move_line'), ('workorder_id', '=', False), ('is_lot_tested_fractionally', '=', False)]}"/>
|
||||
<div class="o_row"
|
||||
attrs="{'invisible': ['|', '&', ('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': ['|', '&', ('measure_on', '!=', 'move_line'), ('workorder_id', '=', False), ('is_lot_tested_fractionally', '=', False)]}"/>
|
||||
<div class="o_row"
|
||||
attrs="{'invisible': ['|', '&', ('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), '&', ('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), '&', ('measure_on', '=', 'move_line'), ('workorder_id', '!=', False)]}</attribute>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -419,7 +419,7 @@ class RePurchaseOrder(models.Model):
|
||||
('detailed_type', '=', 'service')])
|
||||
server_product_process.append((0, 0, {
|
||||
'product_id': server_template.product_variant_id.id,
|
||||
'product_qty': 1,
|
||||
'product_qty': production.product_uom_qty,
|
||||
'product_uom': server_template.uom_id.id,
|
||||
'related_product': production.product_id.id,
|
||||
'manual_part_number': pp.part_number,
|
||||
|
||||
@@ -812,40 +812,49 @@ class SfStockMoveLine(models.Model):
|
||||
# # 从目标stock.move对象获取目标stock.picking对象
|
||||
# dest_picking = dest_move.picking_id if dest_move else False
|
||||
# # 现在,dest_picking就是current_picking的下一步
|
||||
# 添加所有需要的依赖字段
|
||||
@api.depends('location_id')
|
||||
def _compute_current_location_id(self):
|
||||
# 批量获取所有相关记录的picking
|
||||
pickings = self.mapped('picking_id')
|
||||
|
||||
# 构建源picking的移库行与目标位置的映射
|
||||
origin_location_map = {}
|
||||
for picking in pickings:
|
||||
# 获取源picking
|
||||
origin_move = picking.move_ids[:1].move_orig_ids[:1]
|
||||
if not origin_move:
|
||||
continue
|
||||
|
||||
origin_picking = origin_move.picking_id
|
||||
if not origin_picking:
|
||||
continue
|
||||
|
||||
# 为每个picking构建lot_id到location的映射
|
||||
origin_location_map[picking.id] = {
|
||||
move_line.lot_id.id: move_line.destination_location_id
|
||||
for move_line in origin_picking.move_line_ids.filtered(
|
||||
lambda ml: ml.destination_location_id and ml.lot_id
|
||||
)
|
||||
}
|
||||
|
||||
# 批量更新current_location_id
|
||||
for record in self:
|
||||
# 使用record代替self来引用当前遍历到的记录
|
||||
logging.info('record.picking_id.name: %s' % record.picking_id.name)
|
||||
logging.info('record.env: %s' % record.env['stock.picking'].search([('name', '=', record.picking_id.name)]))
|
||||
|
||||
# 获取当前的stock.picking对象
|
||||
current_picking = record.env['stock.picking'].search([('name', '=', record.picking_id.name)], limit=1)
|
||||
|
||||
# 获取当前picking的第一个stock.move对象
|
||||
current_move = current_picking.move_ids[0] if current_picking.move_ids else False
|
||||
|
||||
# 如果存在相关的stock.move对象
|
||||
if current_move:
|
||||
# 获取源stock.move对象
|
||||
origin_move = current_move.move_orig_ids[0] if current_move.move_orig_ids else False
|
||||
|
||||
# 从源stock.move对象获取源stock.picking对象
|
||||
origin_picking = origin_move.picking_id if origin_move else False
|
||||
|
||||
# 如果前一个调拨单有目标货位
|
||||
if origin_picking:
|
||||
for i in current_picking.move_line_ids:
|
||||
for j in origin_picking.move_line_ids:
|
||||
if j.destination_location_id and i.lot_id == j.lot_id:
|
||||
# 更新当前记录的current_location_id字段
|
||||
record.current_location_id = j.destination_location_id
|
||||
# # 获取目标stock.move对象
|
||||
# dest_move = current_move.move_dest_ids[0] if current_move.move_dest_ids else False
|
||||
#
|
||||
# # 从目标stock.move对象获取目标stock.picking对象
|
||||
# dest_picking = dest_move.picking_id if dest_move else False
|
||||
# # 现在,dest_picking就是current_picking的下一步
|
||||
current_picking = record.picking_id
|
||||
if not current_picking:
|
||||
record.current_location_id = False
|
||||
continue
|
||||
|
||||
# 获取当前picking对应的lot_location映射
|
||||
lot_dest_map = origin_location_map.get(current_picking.id, {})
|
||||
|
||||
# 查找匹配的lot_id
|
||||
for move_line in current_picking.move_line_ids:
|
||||
if move_line.lot_id and move_line.lot_id.id in lot_dest_map:
|
||||
record.current_location_id = lot_dest_map[move_line.lot_id.id]
|
||||
break
|
||||
else:
|
||||
record.current_location_id = False
|
||||
|
||||
# 是一张单据一张单据往下走的,所以这里的目标货位是上一张单据的当前货位,且这样去计算是可以的。
|
||||
@api.depends('location_dest_id')
|
||||
|
||||
Reference in New Issue
Block a user