You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

198 lines
7.5 KiB

# -*- coding: utf-8 -*-
# Copyright 2016-2018 Sylvain LE GAL (https://twitter.com/legalsylvain)
# Copyright 2018 David Vidal <david.vidal@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
class PosOrder(models.Model):
_inherit = 'pos.order'
returned_order_id = fields.Many2one(
comodel_name='pos.order',
string='Returned Order',
readonly=True,
)
refund_order_ids = fields.One2many(
comodel_name='pos.order',
inverse_name='returned_order_id',
string='Refund Orders',
readonly=True,
)
refund_order_qty = fields.Integer(
compute='_compute_refund_order_qty',
string='Refund Orders Quantity',
)
def _compute_refund_order_qty(self):
order_data = self.env['pos.order'].read_group(
[('returned_order_id', 'in', self.ids)],
['returned_order_id'], ['returned_order_id']
)
mapped_data = dict(
[(order['returned_order_id'][0], order['returned_order_id_count'])
for order in order_data])
for order in self:
order.refund_order_qty = mapped_data.get(order.id, 0)
def _blank_refund(self, res):
self.ensure_one()
new_order = self.browse(res['res_id'])
new_order.returned_order_id = self
# Remove created lines and recreate and link Lines
new_order.lines.unlink()
return new_order
def _prepare_invoice(self):
res = super(PosOrder, self)._prepare_invoice()
if not self.returned_order_id:
return res
res.update({
'origin': self.name,
'type': 'out_refund',
'refund_invoice_id': self.returned_order_id.invoice_id.id,
})
return res
def _action_create_invoice_line(self, line=False, invoice_id=False):
line = super(PosOrder, self
)._action_create_invoice_line(line, invoice_id)
if not self.returned_order_id:
return line
# Goes to refund invoice thus it should be positive
line.quantity = -line.quantity
return line
def _action_pos_order_invoice(self):
"""Wrap common process"""
self.action_pos_order_invoice()
self.invoice_id.sudo().action_invoice_open()
self.account_move = self.invoice_id.move_id
def refund(self):
# Call super to use original refund algorithm (session management, ...)
ctx = dict(self.env.context, do_not_check_negative_qty=True)
res = super(PosOrder, self.with_context(ctx)).refund()
new_order = self._blank_refund(res)
for line in self.lines:
qty = - line.max_returnable_qty([])
if qty != 0:
copy_line = line.copy()
copy_line.write({
'order_id': new_order.id,
'returned_line_id': line.id,
'qty': qty,
})
return res
def partial_refund(self, partial_return_wizard):
ctx = dict(self.env.context, partial_refund=True)
res = self.with_context(ctx).refund()
new_order = self._blank_refund(res)
for wizard_line in partial_return_wizard.line_ids:
qty = -wizard_line.qty
if qty != 0:
copy_line = wizard_line.pos_order_line_id.copy()
copy_line.write({
'order_id': new_order.id,
'returned_line_id': wizard_line.pos_order_line_id.id,
'qty': qty,
})
return res
def action_pos_order_paid(self):
if self.returned_order_id and self.returned_order_id.invoice_id:
self._action_pos_order_invoice()
return super(PosOrder, self).action_pos_order_paid()
def _create_picking_return(self):
self.ensure_one()
picking = self.returned_order_id.picking_id
ctx = dict(self.env.context,
active_ids=picking.ids, active_id=picking.id)
wizard = self.env['stock.return.picking'].with_context(ctx).create({})
# Discard not returned lines
wizard.product_return_moves.filtered(
lambda x: x.product_id not in self.mapped(
'lines.product_id')).unlink()
to_return = {}
for product in self.lines.mapped('product_id'):
to_return[product] = -sum(
self.lines.filtered(
lambda x: x.product_id == product).mapped('qty'))
for move in wizard.product_return_moves:
if to_return[move.product_id] < move.quantity:
move.quantity = to_return[move.product_id]
to_return[move.product_id] -= move.quantity
return wizard
def create_picking(self):
"""Odoo bases return picking if the quantities are negative, but it's
not linked to the original one"""
res = super(PosOrder, self.filtered(lambda x: not x.returned_order_id)
).create_picking()
for order in self.filtered('returned_order_id'):
wizard = order._create_picking_return()
res = wizard.create_returns()
order.write({'picking_id': res['res_id']})
return res
class PosOrderLine(models.Model):
_inherit = 'pos.order.line'
returned_line_id = fields.Many2one(
comodel_name='pos.order.line',
string='Returned Order',
readonly=True,
)
refund_line_ids = fields.One2many(
comodel_name='pos.order.line',
inverse_name='returned_line_id',
string='Refund Lines',
readonly=True,
)
@api.model
def max_returnable_qty(self, ignored_line_ids):
qty = self.qty
for refund_line in self.refund_line_ids:
if refund_line.id not in ignored_line_ids:
qty += refund_line.qty
return qty
@api.constrains('returned_line_id', 'qty')
def _check_return_qty(self):
if self.env.context.get('do_not_check_negative_qty', False):
return True
for line in self:
if line.returned_line_id and -line.qty > line.returned_line_id.qty:
raise ValidationError(_(
"You can not return %d %s of %s because the original "
"Order line only mentions %d %s."
) % (-line.qty, line.product_id.uom_id.name,
line.product_id.name, line.returned_line_id.qty,
line.product_id.uom_id.name))
if (line.returned_line_id and
-line.qty >
line.returned_line_id.max_returnable_qty([line.id])):
raise ValidationError(_(
"You can not return %d %s of %s because some refunds"
" has been yet done.\n Maximum quantity allowed :"
" %d %s."
) % (-line.qty, line.product_id.uom_id.name,
line.product_id.name,
line.returned_line_id.max_returnable_qty([line.id]),
line.product_id.uom_id.name))
if (not line.returned_line_id and
line.qty < 0 and not
line.product_id.product_tmpl_id.pos_allow_negative_qty):
raise ValidationError(_(
"For legal and traceability reasons, you can not set a"
" negative quantity (%d %s of %s), without using "
"return wizard."
) % (line.qty, line.product_id.uom_id.name,
line.product_id.name))