Add lines to return sale wizard.

This commit refs #16127
This commit is contained in:
Sergio Morillo 2020-11-23 19:57:31 +01:00
parent e438c3e36f
commit 65aca0926d
8 changed files with 172 additions and 48 deletions

View File

@ -14,6 +14,7 @@ def register():
UnitLoad,
sale_reporting.Product,
sale.ReturnSaleStart,
sale.ReturnSaleStartLine,
module='sale_unit_load', type_='model')
Pool.register(
sale.ReturnSale,

View File

@ -168,4 +168,24 @@ msgstr "Unidades de carga"
msgctxt "model:ir.action,name:act_unit_loads_sale"
msgid "Sales"
msgstr "Ventas"
msgstr "Ventas"
msgctxt "field:sale.return_sale.start,lines:"
msgid "Lines"
msgstr "Líneas"
msgctxt "view:sale.return_sale.start:"
msgid "Please select the sale lines to return:"
msgstr "Marque las líneas de venta a devolver:"
msgctxt "field:sale.return_sale.start.line,sale_line:"
msgid "Sale line"
msgstr "Línea de venta"
msgctxt "field:sale.return_sale.start.line,ul_quantity:"
msgid "ULs"
msgstr "UdCs"
msgctxt "field:sale.return_sale.start.line,return_ul_quantity:"
msgid "Return ULs"
msgstr "UdCs a devolver"

160
sale.py
View File

@ -2,18 +2,19 @@
# this repository contains the full copyright notices and license terms.
import math
from decimal import Decimal
from trytond.model import fields
from trytond.model import fields, ModelSQL, ModelView, Model
from trytond.pool import PoolMeta, Pool
from trytond.pyson import Eval, Bool, Not
from trytond.pyson import Eval, Bool, Not, If
from trytond.modules.product import price_digits
from trytond.transaction import Transaction
from trytond.tools import reduce_ids
from sql import Null
from sql import Null, Literal
from sql.conditionals import Coalesce
from sql.aggregate import Sum
__all__ = ['Sale', 'SaleLine', 'SaleLineQuickAction',
'SaleLineQuickActionSplit', 'ReturnSaleStart', 'ReturnSale']
'SaleLineQuickActionSplit', 'ReturnSaleStart', 'ReturnSale',
'ReturnSaleStartLine']
class Sale(metaclass=PoolMeta):
@ -274,13 +275,13 @@ class ReturnSaleStart(metaclass=PoolMeta):
__name__ = 'sale.return_sale.start'
unit_loads = fields.One2Many('stock.unit_load', None, 'Unit Loads',
domain=[('sale', 'in', Eval('context', {}).get('active_ids'))],
domain=[('sale_line', 'in', Eval('available_lines'))],
states={
'invisible': Not(Bool(Eval('ul_required'))),
'required': Bool(Eval('ul_required')),
},
context={'ul_extended_rec_name': True},
depends=['ul_required'])
depends=['ul_required', 'available_lines'])
date = fields.Date('Return date', states={
'invisible': (Not(Bool(Eval('ul_required'))) &
Not(Bool(Eval('new_customer')))),
@ -295,6 +296,28 @@ class ReturnSaleStart(metaclass=PoolMeta):
'invisible': Not(Bool(Eval('new_customer')))
},
depends=['new_customer'])
lines = fields.One2Many('sale.return_sale.start.line', None,
'Lines', required=True, readonly=True,
domain=[('sale_line', 'in', Eval('available_lines'))],
states={
'invisible': Bool(Eval('ul_required'))
},
depends=['available_lines'])
available_lines = fields.Many2Many('sale.line', None, None,
'Available Lines')
@fields.depends('unit_loads', 'lines')
def on_change_unit_loads(self):
if self.unit_loads:
uls2line = {}
for ul in self.unit_loads:
uls2line.setdefault(ul.sale_line, 0)
uls2line[ul.sale_line] += 1
for sline, qty in uls2line.items():
for line in self.lines:
if line.sale_line != sline:
continue
line.return_ul_quantity = min(sline.ul_quantity, qty)
@fields.depends('new_customer')
def on_change_new_customer(self):
@ -304,6 +327,28 @@ class ReturnSaleStart(metaclass=PoolMeta):
type='delivery')
class ReturnSaleStartLine(ModelView):
"""Start Return Sale line"""
__name__ = 'sale.return_sale.start.line'
sale_line = fields.Many2One('sale.line', 'Sale line', required=True,
readonly=True)
ul_quantity = fields.Float('ULs', digits=(16, 0), readonly=True)
return_ul_quantity = fields.Float('Return ULs', digits=(16, 0),
domain=[If((Eval('ul_quantity', None) != None),
[
('return_ul_quantity', '>=', 0),
('return_ul_quantity', '<=', Eval('ul_quantity'))
], [])
], states={
'readonly': Bool(Eval('has_unit_loads')),
'required': (Eval('ul_quantity', None) != None),
}, depends=['ul_quantity'])
unit = fields.Many2One('product.uom', 'Unit', readonly=True)
unit_digits = fields.Integer('Unit digits', readonly=True)
has_unit_loads = fields.Boolean('Has unit loads', readonly=True)
class ReturnSale(metaclass=PoolMeta):
__name__ = 'sale.return_sale'
@ -312,14 +357,28 @@ class ReturnSale(metaclass=PoolMeta):
Date = pool.get('ir.date')
sales = self._get_sales()
lines = [line for s in sales for line in s.lines]
res = {
'date': Date.today(),
'ul_required': any(
line.unit_loads for sale in sales for line in sale.lines),
'available_lines': list(map(int, lines)),
'lines': [self._get_start_line(l) for l in lines]
}
return res
def _get_start_line(self, sale_line):
return {
'sale_line': sale_line.id,
'ul_quantity': sale_line.ul_quantity,
'return_ul_quantity': 0.0,
'unit': sale_line.unit and sale_line.unit.id or None,
'unit_digits': sale_line.unit and sale_line.unit.digits or 2,
'has_unit_loads': bool(sale_line.unit_loads)
}
def do_return_(self, action):
"""Override method and not call super"""
pool = Pool()
Sale = pool.get('sale.sale')
SaleLine = pool.get('sale.line')
@ -342,15 +401,6 @@ class ReturnSale(metaclass=PoolMeta):
'lines': None,
})
if not self.start.ul_required and not saleline2uls:
action, data = super().do_return_(action)
if new_sale:
if len(data['res_id']) == 1:
# re-reverse again
action['views'].reverse()
data['res_id'].append(new_sale.id)
return action, data
return_sales = []
for sale in sales:
return_sale = None
@ -361,6 +411,9 @@ class ReturnSale(metaclass=PoolMeta):
# todo: copy lines of other types (comment, subtotal)
if return_sale is None:
return_sale = self._create_return_sale(sale)
if not return_sale:
# method "_create_return_sale" can return none
continue
return_line = SaleLine.copy([line], {
'sale': return_sale.id
})
@ -370,9 +423,11 @@ class ReturnSale(metaclass=PoolMeta):
return_line, = return_line
return_uls = saleline2uls[line.id]
# store uls for current return sale line
ul2returnlines.update({
ul.id: return_line for ul in return_uls
})
if isinstance(return_uls, list):
ul2returnlines.update({
ul.id: return_line for ul in return_uls
})
self._update_return_line_values(return_line, line, return_uls)
return_lines.append(return_line)
@ -421,29 +476,35 @@ class ReturnSale(metaclass=PoolMeta):
return action, data
def _get_sale_line_uls(self):
UnitLoad = Pool().get('stock.unit_load')
res = {}
for ul in self.start.unit_loads:
for line in self.start.lines:
if line.has_unit_loads or not line.return_ul_quantity:
continue
res.setdefault(line.sale_line.id, line.return_ul_quantity)
for ul in UnitLoad.browse(list(map(int, self.start.unit_loads))):
res.setdefault(ul.sale_line.id, []).append(ul)
return res
def _update_return_line_values(self, return_line, original_line, uls):
if not uls:
return_line.ul_quantity *= -1
return_line.quantity *= -1
return_line.cases_quantity *= -1
return
return_line.ul_quantity = - float(len(uls))
uom = uls and uls[0].uom or return_line.unit
# change uom to get precision due to return quantity normally would be
# lower than original sale line quantity
return_line.unit_price = uom.compute_price(return_line.unit,
return_line.unit_price, uom)
return_line.unit = uom
return_line.quantity = - sum(return_line.unit.compute_qty(
ul.uom, ul.quantity, return_line.unit) for ul in uls
)
return_line.cases_quantity = - sum(ul.cases_quantity for ul in uls)
if isinstance(uls, float):
return_line.ul_quantity = -uls
return_line.quantity = - return_line.unit.round(
original_line.quantity_per_ul * uls)
return_line.cases_quantity = - round(
original_line.ul_cases_quantity * uls)
elif isinstance(uls, list) and uls:
return_line.ul_quantity = - float(len(uls))
uom = uls and uls[0].uom or return_line.unit
# change uom to get precision due to return quantity normally would be
# lower than original sale line quantity
return_line.unit_price = uom.compute_price(return_line.unit,
return_line.unit_price, uom)
return_line.unit = uom
return_line.quantity = - sum(return_line.unit.compute_qty(
ul.uom, ul.quantity, return_line.unit) for ul in uls
)
return_line.cases_quantity = - sum(ul.cases_quantity for ul in uls)
def _create_return_sale(self, original_sale):
pool = Pool()
@ -496,17 +557,22 @@ class ReturnSale(metaclass=PoolMeta):
taxes.extend(tax_ids)
new_line.taxes = taxes
if not uls:
return
new_line.ul_quantity = float(len(uls))
uom = uls[0].uom
new_line.unit_price = uom.compute_price(new_line.unit,
new_line.unit_price, uom)
new_line.unit = uom
new_line.quantity = sum(new_line.unit.compute_qty(
ul.uom, ul.quantity, new_line.unit) for ul in uls
)
new_line.cases_quantity = sum(ul.cases_quantity for ul in uls)
if isinstance(uls, float):
new_line.ul_quantity = uls
new_line.quantity = new_line.unit.round(
original_line.quantity_per_ul * uls)
new_line.cases_quantity = round(
original_line.ul_cases_quantity * uls)
elif isinstance(uls, list) and uls:
new_line.ul_quantity = float(len(uls))
uom = uls[0].uom
new_line.unit_price = uom.compute_price(new_line.unit,
new_line.unit_price, uom)
new_line.unit = uom
new_line.quantity = sum(new_line.unit.compute_qty(
ul.uom, ul.quantity, new_line.unit) for ul in uls
)
new_line.cases_quantity = sum(ul.cases_quantity for ul in uls)
def _get_sales(self):
pool = Pool()

View File

@ -24,6 +24,16 @@ this repository contains the full copyright notices and license terms. -->
<field name="inherit" ref="sale.return_sale_start_view_form"/>
<field name="name">return_sale_start_form</field>
</record>
<record model="ir.ui.view" id="return_sale_start_line_view_tree">
<field name="model">sale.return_sale.start.line</field>
<field name="type">tree</field>
<field name="name">return_sale_start_line_tree</field>
</record>
<record model="ir.ui.view" id="return_sale_start_line_view_form">
<field name="model">sale.return_sale.start.line</field>
<field name="type">form</field>
<field name="name">return_sale_start_line_form</field>
</record>
</data>
<data depends="sale_line_quick_actions">
<record model="ir.ui.view" id="sale_line_split_view_form">

View File

@ -237,7 +237,13 @@ Return UL with a sale::
>>> do_return.form.new_customer = customer2
>>> len(do_return.form.unit_loads)
0
>>> len(do_return.form.lines)
2
>>> sum(l.return_ul_quantity for l in do_return.form.lines)
0.0
>>> do_return.form.unit_loads.append(unit_load)
>>> sum(l.return_ul_quantity for l in do_return.form.lines)
1.0
>>> do_return.execute('return_')
>>> return_sale, = Sale.find([('id', '!=', sale.id), ('party', '=', customer.id)])
>>> return_line, = return_sale.lines

View File

@ -11,5 +11,7 @@
<field name="date"/>
<separator string="Please select the Unit loads to return:" name="unit_loads" colspan="4"/>
<field name="unit_loads" colspan="4" widget="multiselection"/>
<separator string="Please select the sale lines to return:" name="lines" colspan="4"/>
<field name="lines" colspan="4"/>
</xpath>
</data>

View File

@ -0,0 +1,11 @@
<?xml version="1.0"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full
copyright notices and license terms. -->
<form>
<label name="sale_line"/>
<field name="sale_line" colspan="2"/>
<label name="ul_quantity"/>
<field name="ul_quantity"/>
<label name="return_ul_quantity"/>
<field name="return_ul_quantity"/>
</form>

View File

@ -0,0 +1,8 @@
<?xml version="1.0"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full
copyright notices and license terms. -->
<tree editable="bottom">
<field name="sale_line" expand="1"/>
<field name="ul_quantity"/>
<field name="return_ul_quantity" width="100"/>
</tree>