2018-01-16 06:58:15 +01:00
|
|
|
# -*- coding: utf-8 -*-
|
2018-01-16 11:34:37 +01:00
|
|
|
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
|
2018-01-16 06:58:15 +01:00
|
|
|
|
2018-01-16 11:34:37 +01:00
|
|
|
from flectra import api, fields, models, _
|
|
|
|
from flectra.exceptions import UserError
|
2018-01-16 06:58:15 +01:00
|
|
|
|
|
|
|
|
|
|
|
class StockPicking(models.Model):
|
|
|
|
_inherit = 'stock.picking'
|
|
|
|
|
|
|
|
purchase_id = fields.Many2one('purchase.order', related='move_lines.purchase_line_id.order_id',
|
|
|
|
string="Purchase Orders", readonly=True)
|
|
|
|
|
|
|
|
@api.model
|
|
|
|
def _create_backorder(self, backorder_moves=[]):
|
|
|
|
res = super(StockPicking, self)._create_backorder(backorder_moves)
|
|
|
|
for picking in self:
|
|
|
|
if picking.picking_type_id.code == 'incoming':
|
|
|
|
for backorder in self.search([('backorder_id', '=', picking.id)]):
|
|
|
|
backorder.message_post_with_view('mail.message_origin_link',
|
|
|
|
values={'self': backorder, 'origin': backorder.purchase_id},
|
|
|
|
subtype_id=self.env.ref('mail.mt_note').id)
|
|
|
|
return res
|
|
|
|
|
|
|
|
|
|
|
|
class StockMove(models.Model):
|
|
|
|
_inherit = 'stock.move'
|
|
|
|
|
|
|
|
purchase_line_id = fields.Many2one('purchase.order.line',
|
2018-07-13 11:21:38 +02:00
|
|
|
'Purchase Order Line', ondelete='set null', index=True, readonly=True)
|
2018-01-16 06:58:15 +01:00
|
|
|
created_purchase_line_id = fields.Many2one('purchase.order.line',
|
|
|
|
'Created Purchase Order Line', ondelete='set null', readonly=True, copy=False)
|
|
|
|
|
|
|
|
@api.model
|
|
|
|
def _prepare_merge_moves_distinct_fields(self):
|
|
|
|
distinct_fields = super(StockMove, self)._prepare_merge_moves_distinct_fields()
|
2018-04-05 10:25:40 +02:00
|
|
|
distinct_fields += ['purchase_line_id', 'created_purchase_line_id']
|
2018-01-16 06:58:15 +01:00
|
|
|
return distinct_fields
|
|
|
|
|
|
|
|
@api.model
|
|
|
|
def _prepare_merge_move_sort_method(self, move):
|
|
|
|
move.ensure_one()
|
|
|
|
keys_sorted = super(StockMove, self)._prepare_merge_move_sort_method(move)
|
2018-04-05 10:25:40 +02:00
|
|
|
keys_sorted += [move.purchase_line_id.id, move.created_purchase_line_id.id]
|
2018-01-16 06:58:15 +01:00
|
|
|
return keys_sorted
|
|
|
|
|
|
|
|
@api.multi
|
|
|
|
def _get_price_unit(self):
|
|
|
|
""" Returns the unit price for the move"""
|
|
|
|
self.ensure_one()
|
|
|
|
if self.purchase_line_id and self.product_id.id == self.purchase_line_id.product_id.id:
|
|
|
|
line = self.purchase_line_id
|
|
|
|
order = line.order_id
|
|
|
|
price_unit = line.price_unit
|
|
|
|
if line.taxes_id:
|
|
|
|
price_unit = line.taxes_id.with_context(round=False).compute_all(price_unit, currency=line.order_id.currency_id, quantity=1.0)['total_excluded']
|
|
|
|
if line.product_uom.id != line.product_id.uom_id.id:
|
|
|
|
price_unit *= line.product_uom.factor / line.product_id.uom_id.factor
|
|
|
|
if order.currency_id != order.company_id.currency_id:
|
|
|
|
price_unit = order.currency_id.compute(price_unit, order.company_id.currency_id, round=False)
|
|
|
|
return price_unit
|
|
|
|
return super(StockMove, self)._get_price_unit()
|
|
|
|
|
|
|
|
def _prepare_extra_move_vals(self, qty):
|
|
|
|
vals = super(StockMove, self)._prepare_extra_move_vals(qty)
|
|
|
|
vals['purchase_line_id'] = self.purchase_line_id.id
|
|
|
|
return vals
|
|
|
|
|
|
|
|
def _prepare_move_split_vals(self, uom_qty):
|
|
|
|
vals = super(StockMove, self)._prepare_move_split_vals(uom_qty)
|
|
|
|
vals['purchase_line_id'] = self.purchase_line_id.id
|
|
|
|
return vals
|
|
|
|
|
|
|
|
def _action_cancel(self):
|
|
|
|
for move in self:
|
|
|
|
if move.created_purchase_line_id:
|
|
|
|
try:
|
|
|
|
activity_type_id = self.env.ref('mail.mail_activity_data_todo').id
|
|
|
|
except ValueError:
|
|
|
|
activity_type_id = False
|
|
|
|
self.env['mail.activity'].create({
|
|
|
|
'activity_type_id': activity_type_id,
|
|
|
|
'note': _('A sale order that generated this purchase order has been deleted. Check if an action is needed.'),
|
|
|
|
'user_id': move.created_purchase_line_id.product_id.responsible_id.id,
|
|
|
|
'res_id': move.created_purchase_line_id.order_id.id,
|
|
|
|
'res_model_id': self.env.ref('purchase.model_purchase_order').id,
|
|
|
|
})
|
|
|
|
return super(StockMove, self)._action_cancel()
|
|
|
|
|
|
|
|
|
|
|
|
class StockWarehouse(models.Model):
|
|
|
|
_inherit = 'stock.warehouse'
|
|
|
|
|
|
|
|
buy_to_resupply = fields.Boolean('Purchase to resupply this warehouse', default=True,
|
|
|
|
help="When products are bought, they can be delivered to this warehouse")
|
|
|
|
buy_pull_id = fields.Many2one('procurement.rule', 'Buy rule')
|
|
|
|
|
|
|
|
@api.multi
|
|
|
|
def _get_buy_pull_rule(self):
|
|
|
|
try:
|
|
|
|
buy_route_id = self.env['ir.model.data'].get_object_reference('purchase', 'route_warehouse0_buy')[1]
|
|
|
|
except:
|
|
|
|
buy_route_id = self.env['stock.location.route'].search([('name', 'like', _('Buy'))])
|
|
|
|
buy_route_id = buy_route_id[0].id if buy_route_id else False
|
|
|
|
if not buy_route_id:
|
|
|
|
raise UserError(_("Can't find any generic Buy route."))
|
|
|
|
|
|
|
|
return {
|
|
|
|
'name': self._format_routename(_(' Buy')),
|
|
|
|
'location_id': self.in_type_id.default_location_dest_id.id,
|
|
|
|
'route_id': buy_route_id,
|
|
|
|
'action': 'buy',
|
|
|
|
'picking_type_id': self.in_type_id.id,
|
|
|
|
'warehouse_id': self.id,
|
|
|
|
'group_propagation_option': 'none',
|
|
|
|
}
|
|
|
|
|
|
|
|
@api.multi
|
|
|
|
def create_routes(self):
|
|
|
|
res = super(StockWarehouse, self).create_routes() # super applies ensure_one()
|
|
|
|
if self.buy_to_resupply:
|
|
|
|
buy_pull_vals = self._get_buy_pull_rule()
|
|
|
|
buy_pull = self.env['procurement.rule'].create(buy_pull_vals)
|
|
|
|
res['buy_pull_id'] = buy_pull.id
|
|
|
|
return res
|
|
|
|
|
|
|
|
@api.multi
|
|
|
|
def write(self, vals):
|
|
|
|
if 'buy_to_resupply' in vals:
|
|
|
|
if vals.get("buy_to_resupply"):
|
|
|
|
for warehouse in self:
|
|
|
|
if not warehouse.buy_pull_id:
|
|
|
|
buy_pull_vals = self._get_buy_pull_rule()
|
|
|
|
buy_pull = self.env['procurement.rule'].create(buy_pull_vals)
|
|
|
|
vals['buy_pull_id'] = buy_pull.id
|
|
|
|
else:
|
|
|
|
for warehouse in self:
|
|
|
|
if warehouse.buy_pull_id:
|
|
|
|
warehouse.buy_pull_id.unlink()
|
|
|
|
return super(StockWarehouse, self).write(vals)
|
|
|
|
|
|
|
|
@api.multi
|
|
|
|
def _get_all_routes(self):
|
|
|
|
routes = super(StockWarehouse, self).get_all_routes_for_wh()
|
|
|
|
routes |= self.filtered(lambda self: self.buy_to_resupply and self.buy_pull_id and self.buy_pull_id.route_id).mapped('buy_pull_id').mapped('route_id')
|
|
|
|
return routes
|
|
|
|
|
|
|
|
@api.multi
|
|
|
|
def _update_name_and_code(self, name=False, code=False):
|
|
|
|
res = super(StockWarehouse, self)._update_name_and_code(name, code)
|
|
|
|
warehouse = self[0]
|
|
|
|
#change the buy procurement rule name
|
|
|
|
if warehouse.buy_pull_id and name:
|
|
|
|
warehouse.buy_pull_id.write({'name': warehouse.buy_pull_id.name.replace(warehouse.name, name, 1)})
|
|
|
|
return res
|
|
|
|
|
|
|
|
@api.multi
|
|
|
|
def _update_routes(self):
|
|
|
|
res = super(StockWarehouse, self)._update_routes()
|
|
|
|
for warehouse in self:
|
|
|
|
if warehouse.in_type_id.default_location_dest_id != warehouse.buy_pull_id.location_id:
|
|
|
|
warehouse.buy_pull_id.write({'location_id': warehouse.in_type_id.default_location_dest_id.id})
|
|
|
|
return res
|
|
|
|
|
|
|
|
class ReturnPicking(models.TransientModel):
|
|
|
|
_inherit = "stock.return.picking"
|
|
|
|
|
|
|
|
def _prepare_move_default_values(self, return_line, new_picking):
|
|
|
|
vals = super(ReturnPicking, self)._prepare_move_default_values(return_line, new_picking)
|
|
|
|
vals['purchase_line_id'] = return_line.move_id.purchase_line_id.id
|
|
|
|
return vals
|
|
|
|
|
|
|
|
|
|
|
|
class Orderpoint(models.Model):
|
|
|
|
_inherit = "stock.warehouse.orderpoint"
|
|
|
|
|
|
|
|
def _quantity_in_progress(self):
|
|
|
|
res = super(Orderpoint, self)._quantity_in_progress()
|
|
|
|
for poline in self.env['purchase.order.line'].search([('state','in',('draft','sent','to approve')),('orderpoint_id','in',self.ids)]):
|
|
|
|
res[poline.orderpoint_id.id] += poline.product_uom._compute_quantity(poline.product_qty, poline.orderpoint_id.product_uom, round=False)
|
|
|
|
return res
|
2018-04-05 10:25:40 +02:00
|
|
|
|
|
|
|
def action_view_purchase(self):
|
|
|
|
""" This function returns an action that display existing
|
|
|
|
purchase orders of given orderpoint.
|
|
|
|
"""
|
|
|
|
action = self.env.ref('purchase.purchase_rfq')
|
|
|
|
result = action.read()[0]
|
|
|
|
|
|
|
|
# Remvove the context since the action basically display RFQ and not PO.
|
|
|
|
result['context'] = {}
|
|
|
|
order_line_ids = self.env['purchase.order.line'].search([('orderpoint_id', '=', self.id)])
|
|
|
|
purchase_ids = order_line_ids.mapped('order_id')
|
|
|
|
|
|
|
|
result['domain'] = "[('id','in',%s)]" % (purchase_ids.ids)
|
|
|
|
|
|
|
|
return result
|