parent
e438c3e36f
commit
65aca0926d
|
@ -14,6 +14,7 @@ def register():
|
|||
UnitLoad,
|
||||
sale_reporting.Product,
|
||||
sale.ReturnSaleStart,
|
||||
sale.ReturnSaleStartLine,
|
||||
module='sale_unit_load', type_='model')
|
||||
Pool.register(
|
||||
sale.ReturnSale,
|
||||
|
|
22
locale/es.po
22
locale/es.po
|
@ -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
160
sale.py
|
@ -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()
|
||||
|
|
10
sale.xml
10
sale.xml
|
@ -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">
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
Loading…
Reference in New Issue