Use similar design as for sale_promotion
- Add start/end date criteria - Remove required on price list - Change modification right to sale administrator group issue4678 review11131002
This commit is contained in:
1 parent
4f5c104bad
commit
900708e481
13 files changed
+140
-70
No files matched your search
@@ -1,2 +1,6 @@
|
||||
* Add start/end date criteria
|
||||
* Remove required on price list
|
||||
* Change modification right to sale administrator group
|
||||
|
||||
Version 3.6.0 - 2015-04-20
|
||||
* Initial release
|
||||
* Initial release
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
from trytond.pool import Pool
|
||||
from .sale import *
|
||||
from .price_list import *
|
||||
|
||||
|
||||
def register():
|
||||
@@ -12,5 +11,4 @@ def register():
|
||||
SaleExtraLine,
|
||||
Sale,
|
||||
SaleLine,
|
||||
PriceList,
|
||||
module='sale_extra', type_='model')
|
||||
+4
-2
@@ -11,9 +11,11 @@ The criteria are defined by the *Sale Extras* of the *Price List*.
|
||||
Sale Extra
|
||||
**********
|
||||
|
||||
Each matching *Sale Extra* of the *Price List* is evaluated to add an extra
|
||||
line. The criteria are the fields:
|
||||
Each matching *Sale Extra* is evaluated to add an extra line.
|
||||
The criteria are the fields:
|
||||
|
||||
- *Price List*
|
||||
- *Start/End Date*
|
||||
- *Sale Amount*: If untaxed sale amount is greater or equal
|
||||
(in the price list company currency).
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
from trytond.pool import PoolMeta
|
||||
from trytond.model import fields
|
||||
|
||||
__all__ = ['PriceList']
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
|
||||
class PriceList:
|
||||
__name__ = 'product.price_list'
|
||||
|
||||
sale_extras = fields.One2Many('sale.extra', 'price_list', 'Sale Extras')
|
||||
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data>
|
||||
<record model="ir.ui.view" id="price_list_view_form">
|
||||
<field name="model">product.price_list</field>
|
||||
<field name="inherit" ref="product_price_list.price_list_view_form"/>
|
||||
<field name="name">price_list_form</field>
|
||||
</record>
|
||||
</data>
|
||||
</tryton>
|
||||
@@ -1,10 +1,15 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
import datetime
|
||||
from decimal import Decimal
|
||||
|
||||
from sql import Null
|
||||
|
||||
from trytond.pool import PoolMeta, Pool
|
||||
from trytond.model import ModelSQL, ModelView, MatchMixin, Workflow, fields
|
||||
from trytond.pyson import Eval
|
||||
from trytond.pyson import Eval, If
|
||||
from trytond.transaction import Transaction
|
||||
from trytond import backend
|
||||
|
||||
__all__ = ['Sale', 'SaleLine',
|
||||
'SaleExtra', 'SaleExtraLine']
|
||||
@@ -55,9 +60,38 @@ class SaleExtra(ModelSQL, ModelView, MatchMixin):
|
||||
__name__ = 'sale.extra'
|
||||
|
||||
name = fields.Char('Name', translate=True, required=True)
|
||||
company = fields.Many2One('company.company', 'Company', required=True,
|
||||
states={
|
||||
'readonly': Eval('id', 0) > 0,
|
||||
},
|
||||
domain=[
|
||||
('id', If(Eval('context', {}).contains('company'), '=', '!='),
|
||||
Eval('context', {}).get('company', -1)),
|
||||
],
|
||||
select=True)
|
||||
active = fields.Boolean('Active')
|
||||
start_date = fields.Date('Start Date',
|
||||
domain=['OR',
|
||||
('start_date', '<=', If(~Eval('end_date', None),
|
||||
datetime.date.max,
|
||||
Eval('end_date', datetime.date.max))),
|
||||
('start_date', '=', None),
|
||||
],
|
||||
depends=['end_date'])
|
||||
end_date = fields.Date('End Date',
|
||||
domain=['OR',
|
||||
('end_date', '>=', If(~Eval('start_date', None),
|
||||
datetime.date.min,
|
||||
Eval('start_date', datetime.date.min))),
|
||||
('end_date', '=', None),
|
||||
],
|
||||
depends=['start_date'])
|
||||
price_list = fields.Many2One('product.price_list', 'Price List',
|
||||
required=True, ondelete='CASCADE')
|
||||
ondelete='CASCADE',
|
||||
domain=[
|
||||
('company', '=', Eval('company', -1)),
|
||||
],
|
||||
depends=['company'])
|
||||
sale_amount = fields.Numeric('Sale Amount',
|
||||
digits=(16, Eval('currency_digits', 2)),
|
||||
depends=['currency_digits'])
|
||||
@@ -65,38 +99,80 @@ class SaleExtra(ModelSQL, ModelView, MatchMixin):
|
||||
'on_change_with_currency_digits')
|
||||
lines = fields.One2Many('sale.extra.line', 'extra', 'Lines')
|
||||
|
||||
@classmethod
|
||||
def __register__(cls, module_name):
|
||||
pool = Pool()
|
||||
PriceList = pool.get('product.price_list')
|
||||
TableHandler = backend.get('TableHandler')
|
||||
cursor = Transaction().cursor
|
||||
sql_table = cls.__table__()
|
||||
price_list = PriceList.__table__()
|
||||
|
||||
super(SaleExtra, cls).__register__(module_name)
|
||||
|
||||
table = TableHandler(cursor, cls, module_name)
|
||||
# Migration from 3.6: price_list not required and new company
|
||||
table.not_null_action('price_list', 'remove')
|
||||
query = sql_table.join(price_list,
|
||||
condition=sql_table.price_list == price_list.id
|
||||
).select(sql_table.id, price_list.company,
|
||||
where=sql_table.company == Null)
|
||||
cursor.execute(*query)
|
||||
for extra_id, company_id in cursor.fetchall():
|
||||
query = sql_table.update([sql_table.company], [company_id],
|
||||
where=sql_table.id == extra_id)
|
||||
cursor.execute(*query)
|
||||
|
||||
@staticmethod
|
||||
def default_company():
|
||||
return Transaction().context.get('company')
|
||||
|
||||
@staticmethod
|
||||
def default_active():
|
||||
return True
|
||||
|
||||
@fields.depends('price_list')
|
||||
@fields.depends('company')
|
||||
def on_change_with_currency_digits(self, name=None):
|
||||
if self.price_list.company:
|
||||
return self.price_list.company.currency.digits
|
||||
if self.company:
|
||||
return self.company.currency.digits
|
||||
return 2
|
||||
|
||||
@classmethod
|
||||
def _extras_domain(cls, sale):
|
||||
return [
|
||||
['OR',
|
||||
('start_date', '<=', sale.sale_date),
|
||||
('start_date', '=', None),
|
||||
],
|
||||
['OR',
|
||||
('end_date', '=', None),
|
||||
('end_date', '>=', sale.sale_date),
|
||||
],
|
||||
['OR',
|
||||
('price_list', '=', None),
|
||||
('price_list', '=',
|
||||
sale.price_list.id if sale.price_list else None),
|
||||
],
|
||||
('company', '=', sale.company.id),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def get_lines(cls, sale, pattern=None):
|
||||
'Return extra sale lines'
|
||||
'Yield extra sale lines'
|
||||
pool = Pool()
|
||||
Currency = pool.get('currency.currency')
|
||||
|
||||
if not sale.price_list:
|
||||
return []
|
||||
|
||||
extras = cls.search(cls._extras_domain(sale))
|
||||
if pattern is None:
|
||||
pattern = {}
|
||||
pattern['sale_amount'] = Currency.compute(sale.currency,
|
||||
sale.untaxed_amount, sale.company.currency)
|
||||
|
||||
lines = []
|
||||
for extra in sale.price_list.sale_extras:
|
||||
for extra in extras:
|
||||
if extra.match(pattern):
|
||||
for line in extra.lines:
|
||||
if line.match(pattern):
|
||||
lines.append(line.get_line(sale))
|
||||
yield line.get_line(sale)
|
||||
break
|
||||
return lines
|
||||
|
||||
def match(self, pattern):
|
||||
pattern = pattern.copy()
|
||||
|
||||
@@ -16,10 +16,11 @@ this repository contains the full copyright notices and license terms. -->
|
||||
</record>
|
||||
|
||||
<record model="ir.action.act_window" id="act_extra_form">
|
||||
<field name="name">Sale Extras</field>
|
||||
<field name="name">Extras</field>
|
||||
<field name="res_model">sale.extra</field>
|
||||
<field name="domain"
|
||||
eval="[('price_list', 'in', Eval('active_ids'))]"
|
||||
<field name="domain"></field>
|
||||
<field name="search_value"
|
||||
eval="['OR', ('end_date', '>=', Date()), ('end_date', '=', None)]"
|
||||
pyson="1"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_extra_form_view1">
|
||||
@@ -32,10 +33,23 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<field name="view" ref="extra_view_form"/>
|
||||
<field name="act_window" ref="act_extra_form"/>
|
||||
</record>
|
||||
<record model="ir.action.keyword" id="act_extra_keyword1">
|
||||
<menuitem parent="sale.menu_configuration" action="act_extra_form"
|
||||
id="menu_extra"/>
|
||||
|
||||
<record model="ir.action.act_window" id="act_extra_relate">
|
||||
<field name="name">Sale Extras</field>
|
||||
<field name="res_model">sale.extra</field>
|
||||
<field name="domain"
|
||||
eval="[('price_list', 'in', Eval('active_ids', []))]"
|
||||
pyson="1"/>
|
||||
<field name="search_value"
|
||||
eval="['OR', ('end_date', '>=', Date()), ('end_date', '=', None)]"
|
||||
pyson="1"/>
|
||||
</record>
|
||||
<record model="ir.action.keyword" id="act_extra_relate_keyword1">
|
||||
<field name="keyword">form_relate</field>
|
||||
<field name="model">product.price_list,-1</field>
|
||||
<field name="action" ref="act_extra_form"/>
|
||||
<field name="action" ref="act_extra_relate"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.rule.group" id="rule_group_extra">
|
||||
@@ -44,7 +58,7 @@ this repository contains the full copyright notices and license terms. -->
|
||||
</record>
|
||||
<record model="ir.rule" id="rule_extra1">
|
||||
<field name="domain"
|
||||
eval="[('price_list.company', '=', Eval('user', {}).get('company', None))]"
|
||||
eval="[('company', '=', Eval('user', {}).get('company', None))]"
|
||||
pyson="1"/>
|
||||
<field name="rule_group" ref="rule_group_extra"/>
|
||||
</record>
|
||||
@@ -56,9 +70,9 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_delete" eval="False"/>
|
||||
</record>
|
||||
<record model="ir.model.access" id="access_extra_product_admin">
|
||||
<record model="ir.model.access" id="access_extra_sale_admin">
|
||||
<field name="model" search="[('model', '=', 'sale.extra')]"/>
|
||||
<field name="group" ref="product.group_product_admin"/>
|
||||
<field name="group" ref="sale.group_sale_admin"/>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="True"/>
|
||||
<field name="perm_create" eval="True"/>
|
||||
@@ -91,7 +105,7 @@ this repository contains the full copyright notices and license terms. -->
|
||||
</record>
|
||||
<record model="ir.rule" id="rule_extra_line1">
|
||||
<field name="domain"
|
||||
eval="[('extra.price_list.company', '=', Eval('user', {}).get('company', None))]"
|
||||
eval="[('extra.company', '=', Eval('user', {}).get('company', None))]"
|
||||
pyson="1"/>
|
||||
<field name="rule_group" ref="rule_group_extra_line"/>
|
||||
</record>
|
||||
@@ -103,9 +117,9 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_delete" eval="False"/>
|
||||
</record>
|
||||
<record model="ir.model.access" id="access_extra_line_product_admin">
|
||||
<record model="ir.model.access" id="access_extra_line_sale_admin">
|
||||
<field name="model" search="[('model', '=', 'sale.extra.line')]"/>
|
||||
<field name="group" ref="product.group_product_admin"/>
|
||||
<field name="group" ref="sale.group_sale_admin"/>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="True"/>
|
||||
<field name="perm_create" eval="True"/>
|
||||
|
||||
@@ -41,7 +41,7 @@ if minor_version % 2:
|
||||
'hg+http://hg.tryton.org/modules/%s#egg=%s-%s' % (
|
||||
name[8:], name, version))
|
||||
|
||||
requires = []
|
||||
requires = ['python-sql']
|
||||
for dep in info.get('depends', []):
|
||||
if not re.match(r'(ir|res|webdav)(\W|$)', dep):
|
||||
requires.append(get_require_version('trytond_%s' % dep))
|
||||
|
||||
@@ -94,8 +94,11 @@ Create payment term::
|
||||
Create Extra::
|
||||
|
||||
>>> PriceList = Model.get('product.price_list')
|
||||
>>> Extra = Model.get('sale.extra')
|
||||
>>> price_list = PriceList(name='Default')
|
||||
>>> extra = price_list.sale_extras.new(name='Free Extra')
|
||||
>>> price_list.save()
|
||||
>>> extra = Extra(name='Free Extra')
|
||||
>>> extra.price_list = price_list
|
||||
>>> line = extra.lines.new()
|
||||
>>> line.sale_amount = Decimal('100')
|
||||
>>> line.product = extra_product
|
||||
@@ -105,7 +108,7 @@ Create Extra::
|
||||
>>> line.sale_amount = Decimal('50')
|
||||
>>> line.product = extra_product
|
||||
>>> line.quantity = 1
|
||||
>>> price_list.save()
|
||||
>>> extra.save()
|
||||
|
||||
Sale for 100, 2 free extra added::
|
||||
|
||||
|
||||
@@ -10,4 +10,3 @@ depends:
|
||||
sale_price_list
|
||||
xml:
|
||||
sale.xml
|
||||
price_list.xml
|
||||
+7
-1
@@ -6,9 +6,15 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<field name="name"/>
|
||||
<label name="active"/>
|
||||
<field name="active"/>
|
||||
<label name="start_date"/>
|
||||
<field name="start_date"/>
|
||||
<label name="end_date"/>
|
||||
<field name="end_date"/>
|
||||
<label name="company"/>
|
||||
<field name="company"/>
|
||||
<label name="price_list"/>
|
||||
<field name="price_list"/>
|
||||
<newline/>
|
||||
<separator id="pattern" colspan="4"/>
|
||||
<label name="sale_amount"/>
|
||||
<field name="sale_amount"/>
|
||||
<field name="lines" colspan="4"
|
||||
|
||||
@@ -4,6 +4,9 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<tree string="Extras">
|
||||
<field name="price_list"/>
|
||||
<field name="name"/>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
<field name="company"/>
|
||||
<field name="sale_amount"/>
|
||||
<field name="active" tree_invisible="1"/>
|
||||
</tree>
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<data>
|
||||
<xpath expr="/form/notebook" position="inside">
|
||||
<page name="sale_extras">
|
||||
<field name="sale_extras" colspan="4"/>
|
||||
</page>
|
||||
</xpath>
|
||||
</data>
|
||||
Reference in new issue
Block a user