Distinct readonly and editable states
This commit is contained in:
+3
-5
@@ -111,13 +111,11 @@ def setup(config, activated, company):
|
||||
if 'production_work' in activated:
|
||||
for work in production.works:
|
||||
for _ in range(0, random.randint(1, 2)):
|
||||
cycle = WorkCycle(
|
||||
work=work,
|
||||
duration=dt.timedelta(
|
||||
seconds=random.randint(60, 3600)),
|
||||
)
|
||||
cycle = WorkCycle(work=work)
|
||||
cycle.save()
|
||||
cycle.click('run')
|
||||
cycle.duration = dt.timedelta(
|
||||
seconds=random.randint(60, 3600))
|
||||
cycle.click('do')
|
||||
output, = production.outputs
|
||||
output.unit_price = (production.cost
|
||||
|
||||
+12
-13
@@ -629,8 +629,8 @@ def AccountMixin(template=False):
|
||||
if (not isinstance(field, fields.Field)
|
||||
or isinstance(field, fields.Function)):
|
||||
continue
|
||||
field.states['readonly'] = (
|
||||
Bool(Eval('template', -1)) & ~Eval('template_override', False))
|
||||
field.states['editable'] = (
|
||||
Eval('template', None) & ~Eval('template_override', False))
|
||||
return Mixin
|
||||
|
||||
|
||||
@@ -828,8 +828,7 @@ class Account(
|
||||
ModelSQL, ModelView):
|
||||
__name__ = 'account.account'
|
||||
_states = {
|
||||
'readonly': (Bool(Eval('template', -1))
|
||||
& ~Eval('template_override', False)),
|
||||
'editable': Eval('template', None) & ~Eval('template_override', False),
|
||||
}
|
||||
company = fields.Many2One('company.company', 'Company', required=True,
|
||||
ondelete="RESTRICT")
|
||||
@@ -842,14 +841,14 @@ class Account(
|
||||
('id', '!=', Eval('currency', -1)),
|
||||
],
|
||||
states={
|
||||
'readonly': _states['readonly'],
|
||||
'editable': _states['editable'],
|
||||
'invisible': ~Eval('deferral', False),
|
||||
},
|
||||
help="Force all moves for this account to have this second currency.")
|
||||
type = fields.Many2One(
|
||||
'account.account.type', "Type", ondelete='RESTRICT',
|
||||
states={
|
||||
'readonly': _states['readonly'],
|
||||
'editable': _states['editable'],
|
||||
},
|
||||
domain=[
|
||||
('company', '=', Eval('company', -1)),
|
||||
@@ -857,10 +856,10 @@ class Account(
|
||||
debit_type = fields.Many2One(
|
||||
'account.account.type', "Debit Type", ondelete='RESTRICT',
|
||||
states={
|
||||
'readonly': _states['readonly'],
|
||||
'editable': _states['editable'],
|
||||
'invisible': (
|
||||
~Eval('type') | Eval('credit_type')
|
||||
| (_states['readonly']) & ~Eval('debit_type')),
|
||||
| (_states['editable']) & ~Eval('debit_type')),
|
||||
},
|
||||
domain=[
|
||||
('company', '=', Eval('company', -1)),
|
||||
@@ -872,10 +871,10 @@ class Account(
|
||||
credit_type = fields.Many2One(
|
||||
'account.account.type', "Credit Type", ondelete='RESTRICT',
|
||||
states={
|
||||
'readonly': _states['readonly'],
|
||||
'editable': _states['editable'],
|
||||
'invisible': (
|
||||
~Eval('type') | Eval('debit_type')
|
||||
| (_states['readonly']) & ~Eval('credit_type')),
|
||||
| (_states['editable']) & ~Eval('credit_type')),
|
||||
},
|
||||
domain=[
|
||||
('company', '=', Eval('company', -1)),
|
||||
@@ -939,7 +938,7 @@ class Account(
|
||||
'account.account', "Replaced By",
|
||||
domain=[('company', '=', Eval('company', -1))],
|
||||
states={
|
||||
'readonly': _states['readonly'],
|
||||
'editable': _states['editable'],
|
||||
'invisible': ~Eval('end_date'),
|
||||
})
|
||||
template = fields.Many2One('account.account.template', 'Template')
|
||||
@@ -955,8 +954,8 @@ class Account(
|
||||
super().__setup__()
|
||||
for date in [cls.start_date, cls.end_date]:
|
||||
date.states = {
|
||||
'readonly': (Bool(Eval('template', -1))
|
||||
& ~Eval('template_override', False)),
|
||||
'editable': (
|
||||
Eval('template', -1) & ~Eval('template_override', False)),
|
||||
}
|
||||
cls._order.insert(0, ('code', 'ASC'))
|
||||
cls._order.insert(1, ('name', 'ASC'))
|
||||
|
||||
@@ -942,8 +942,9 @@ class Line(DescriptionOriginMixin, MoveLineMixin, ModelSQL, ModelView):
|
||||
ondelete='CASCADE',
|
||||
states={
|
||||
'required': False,
|
||||
'readonly': (((Eval('state') == 'valid') | _states['readonly'])
|
||||
& Bool(Eval('move'))),
|
||||
'readonly': (
|
||||
((Eval('state') == 'valid') | _states['readonly'])
|
||||
& (Eval('move') & (Eval('id', -1) >= 0))),
|
||||
})
|
||||
journal = fields.Function(fields.Many2One(
|
||||
'account.journal', 'Journal',
|
||||
@@ -1567,6 +1568,7 @@ class Line(DescriptionOriginMixin, MoveLineMixin, ModelSQL, ModelView):
|
||||
default = {}
|
||||
else:
|
||||
default = default.copy()
|
||||
default.setdefault('state', 'draft')
|
||||
default.setdefault('move', None)
|
||||
default.setdefault('reconciliation', None)
|
||||
default.setdefault('reconciliations_delegated', [])
|
||||
|
||||
@@ -15,7 +15,7 @@ from trytond.modules.account.exceptions import AccountMissing
|
||||
from trytond.modules.company import CompanyReport
|
||||
from trytond.modules.currency.fields import Monetary
|
||||
from trytond.pool import Pool
|
||||
from trytond.pyson import Bool, Eval, If
|
||||
from trytond.pyson import Eval, If
|
||||
from trytond.tools import cached_property
|
||||
from trytond.transaction import Transaction, check_access, without_check_access
|
||||
from trytond.wizard import (
|
||||
@@ -57,7 +57,8 @@ class Asset(Workflow, ModelSQL, ModelView):
|
||||
number = fields.Char("Number", readonly=True)
|
||||
product = fields.Many2One('product.product', 'Product', required=True,
|
||||
states={
|
||||
'readonly': (Eval('lines', [0]) | (Eval('state') != 'draft')),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0]),
|
||||
},
|
||||
context={
|
||||
'company': Eval('company', None),
|
||||
@@ -81,7 +82,8 @@ class Asset(Workflow, ModelSQL, ModelView):
|
||||
],
|
||||
],
|
||||
states={
|
||||
'readonly': (Eval('lines', [0]) | (Eval('state') != 'draft')),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0])
|
||||
})
|
||||
customer_invoice_line = fields.Function(fields.Many2One(
|
||||
'account.invoice.line', 'Customer Invoice Line'),
|
||||
@@ -102,19 +104,21 @@ class Asset(Workflow, ModelSQL, ModelView):
|
||||
quantity = fields.Float(
|
||||
"Quantity", digits='unit',
|
||||
states={
|
||||
'readonly': (Bool(Eval('supplier_invoice_line', 1))
|
||||
| Eval('lines', [0])
|
||||
| (Eval('state') != 'draft')),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(
|
||||
Eval('supplier_invoice_line', 1)
|
||||
| Eval('lines', [0])),
|
||||
})
|
||||
unit = fields.Many2One('product.uom', 'Unit',
|
||||
states={
|
||||
'readonly': (Bool(Eval('product'))
|
||||
| (Eval('state') != 'draft')),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('product'),
|
||||
})
|
||||
value = Monetary(
|
||||
"Value", currency='currency', digits='currency',
|
||||
states={
|
||||
'readonly': (Eval('lines', [0]) | (Eval('state') != 'draft')),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0]),
|
||||
},
|
||||
required=True,
|
||||
help="The value of the asset when purchased.")
|
||||
@@ -124,7 +128,8 @@ class Asset(Workflow, ModelSQL, ModelView):
|
||||
('depreciated_amount', '<=', Eval('value')),
|
||||
],
|
||||
states={
|
||||
'readonly': (Eval('lines', [0]) | (Eval('state') != 'draft')),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0]),
|
||||
},
|
||||
required=True,
|
||||
help="The amount already depreciated at the start date.")
|
||||
@@ -139,22 +144,26 @@ class Asset(Workflow, ModelSQL, ModelView):
|
||||
('residual_value', '<=', Eval('depreciating_value')),
|
||||
],
|
||||
states={
|
||||
'readonly': (Eval('lines', [0]) | (Eval('state') != 'draft')),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0]),
|
||||
})
|
||||
purchase_date = fields.Date('Purchase Date', states={
|
||||
'readonly': (Bool(Eval('supplier_invoice_line', 1))
|
||||
| Eval('lines', [0])
|
||||
| (Eval('state') != 'draft')),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(
|
||||
Eval('supplier_invoice_line', 1)
|
||||
| Eval('lines', [0])),
|
||||
},
|
||||
required=True)
|
||||
start_date = fields.Date('Start Date', states={
|
||||
'readonly': (Eval('lines', [0]) | (Eval('state') != 'draft')),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0]),
|
||||
},
|
||||
required=True,
|
||||
domain=[('start_date', '<=', Eval('end_date', None))])
|
||||
end_date = fields.Date('End Date',
|
||||
states={
|
||||
'readonly': (Eval('lines', [0]) | (Eval('state') != 'draft')),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0]),
|
||||
},
|
||||
required=True,
|
||||
domain=[('end_date', '>=', Eval('start_date', None))])
|
||||
@@ -162,7 +171,8 @@ class Asset(Workflow, ModelSQL, ModelView):
|
||||
('linear', 'Linear'),
|
||||
], 'Depreciation Method',
|
||||
states={
|
||||
'readonly': (Eval('lines', [0]) | (Eval('state') != 'draft')),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0]),
|
||||
},
|
||||
required=True)
|
||||
frequency = fields.Selection([
|
||||
@@ -171,7 +181,8 @@ class Asset(Workflow, ModelSQL, ModelView):
|
||||
], 'Frequency',
|
||||
required=True,
|
||||
states={
|
||||
'readonly': (Eval('lines', [0]) | (Eval('state') != 'draft')),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0]),
|
||||
})
|
||||
state = fields.Selection([
|
||||
('draft', 'Draft'),
|
||||
|
||||
@@ -93,7 +93,8 @@ class BudgetMixin(ChatMixin):
|
||||
company = fields.Many2One(
|
||||
'company.company', "Company", required=True,
|
||||
states={
|
||||
'readonly': Eval('company') & Eval('lines', [-1]),
|
||||
'readonly': Eval('id', -1) >= 0,
|
||||
'editable': ~Eval('lines', [-1]),
|
||||
},
|
||||
help="The company that the budget is associated with.")
|
||||
lines = None
|
||||
@@ -305,13 +306,13 @@ class Budget(BudgetMixin, ModelSQL, ModelView):
|
||||
lines = fields.One2Many(
|
||||
'account.budget.line', 'budget', "Lines",
|
||||
states={
|
||||
'readonly': Eval('id', -1) < 0,
|
||||
'editable': Eval('id', -1) < 0,
|
||||
},
|
||||
order=[('left', 'ASC'), ('id', 'ASC')])
|
||||
root_lines = fields.One2Many(
|
||||
'account.budget.line', 'budget', "Lines",
|
||||
states={
|
||||
'readonly': Eval('id', -1) < 0,
|
||||
'editable': Eval('id', -1) < 0,
|
||||
},
|
||||
filter=[
|
||||
('parent', '=', None),
|
||||
|
||||
@@ -75,9 +75,9 @@ class Invoice(
|
||||
company = fields.Many2One(
|
||||
'company.company', "Company", required=True,
|
||||
states={
|
||||
'readonly': (
|
||||
_states['readonly']
|
||||
| Eval('party', True)
|
||||
'readonly': _states['readonly'],
|
||||
'editable': ~(
|
||||
Eval('party', True)
|
||||
| Eval('lines', [0])),
|
||||
},
|
||||
context={
|
||||
@@ -100,8 +100,9 @@ class Invoice(
|
||||
('in', "Supplier"),
|
||||
], "Type", required=True,
|
||||
states={
|
||||
'readonly': ((Eval('state') != 'draft')
|
||||
| Eval('context', {}).get('type')
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(
|
||||
Eval('context', {}).get('type')
|
||||
| (Eval('lines', [0]) & Eval('type'))),
|
||||
})
|
||||
type_name = fields.Function(fields.Char('Type'), 'get_type_name')
|
||||
@@ -200,9 +201,8 @@ class Invoice(
|
||||
domain=[('party', '=', Eval('party', -1))])
|
||||
currency = fields.Many2One('currency.currency', 'Currency', required=True,
|
||||
states={
|
||||
'readonly': (
|
||||
_states['readonly']
|
||||
| (Eval('lines', [0]) & Eval('currency'))),
|
||||
'readonly': _states['readonly'],
|
||||
'editable': ~(Eval('lines', [0]) & Eval('currency')),
|
||||
})
|
||||
currency_date = fields.Function(fields.Date('Currency Date'),
|
||||
'on_change_with_currency_date')
|
||||
@@ -1692,6 +1692,7 @@ class Invoice(
|
||||
default.setdefault('supplier_payment_reference')
|
||||
default.setdefault('supplier_payment_reference_type')
|
||||
default.setdefault('sequence')
|
||||
default.setdefault('sequence_type_cache')
|
||||
default.setdefault('move', None)
|
||||
default.setdefault('additional_moves', None)
|
||||
default.setdefault('cancel_move', None)
|
||||
@@ -2459,7 +2460,8 @@ class InvoiceLine(sequence_ordered(), ModelSQL, ModelView, TaxableMixin):
|
||||
'required': (~Eval('invoice_type') & Eval('party')
|
||||
& Eval('currency') & Eval('company')),
|
||||
'invisible': Bool(Eval('context', {}).get('standalone')),
|
||||
'readonly': _states['readonly'] & Bool(Eval('invoice')),
|
||||
'readonly': _states['readonly'],
|
||||
'editable': ~Eval('invoice'),
|
||||
})
|
||||
invoice_party = fields.Function(
|
||||
fields.Many2One(
|
||||
@@ -2480,7 +2482,9 @@ class InvoiceLine(sequence_ordered(), ModelSQL, ModelView, TaxableMixin):
|
||||
invoice_type = fields.Selection(
|
||||
'get_invoice_types', "Invoice Type",
|
||||
states={
|
||||
'readonly': Eval('context', {}).get('type') | Eval('type'),
|
||||
'editable': (
|
||||
~Eval('context', {}).get('type')
|
||||
& ~Eval('invoice_type')),
|
||||
'required': ~Eval('invoice'),
|
||||
})
|
||||
party = fields.Many2One(
|
||||
@@ -3241,7 +3245,8 @@ class InvoiceTax(sequence_ordered(), ModelSQL, ModelView):
|
||||
invoice = fields.Many2One(
|
||||
'account.invoice', "Invoice", ondelete='CASCADE', required=True,
|
||||
states={
|
||||
'readonly': _states['readonly'] & Bool(Eval('invoice')),
|
||||
'readonly': _states['readonly'],
|
||||
'editable': ~Eval('invoice'),
|
||||
})
|
||||
invoice_state = fields.Function(
|
||||
fields.Selection('get_invoice_states', "Invoice State"),
|
||||
@@ -3287,18 +3292,18 @@ class InvoiceTax(sequence_ordered(), ModelSQL, ModelView):
|
||||
('company', '=', Eval('_parent_invoice', {}).get('company', 0)),
|
||||
],
|
||||
states={
|
||||
'readonly': (
|
||||
~Eval('manual', False) | ~Bool(Eval('invoice'))
|
||||
| _states['readonly']),
|
||||
'readonly': _states['readonly'],
|
||||
'editable': Eval('manual', False) & Bool(Eval('invoice')),
|
||||
},
|
||||
depends={'invoice'})
|
||||
legal_notice = fields.Text(
|
||||
"Legal Notice",
|
||||
states={
|
||||
'readonly': (_states['readonly']
|
||||
& ~Id('account', 'group_account_admin').in_(
|
||||
'readonly': _states['readonly'],
|
||||
'editable': (
|
||||
Id('account', 'group_account_admin').in_(
|
||||
Eval('context', {}).get('groups', []))
|
||||
& ~Eval('context', {}).get('administrator', False)),
|
||||
| Eval('context', {}).get('administrator', False)),
|
||||
})
|
||||
|
||||
del _states
|
||||
|
||||
@@ -58,7 +58,7 @@ Create invoice::
|
||||
... 'source_untaxed_amount': Decimal('100.00'),
|
||||
... 'source_tax_amount': Decimal('10.00'),
|
||||
... 'source_total_amount': Decimal('110.00'),
|
||||
... }, invoice._context)
|
||||
... }, {**invoice._context, '_check_access': False})
|
||||
|
||||
Try to validate::
|
||||
|
||||
|
||||
@@ -63,7 +63,8 @@ class InvoiceDeferred(Workflow, ModelSQL, ModelView):
|
||||
company = fields.Many2One(
|
||||
'company.company', "Company", required=True,
|
||||
states={
|
||||
'readonly': (Eval('state') != 'draft') & Eval('invoice_line'),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('invoice_line'),
|
||||
})
|
||||
type = fields.Selection([
|
||||
('out', "Customer"),
|
||||
|
||||
@@ -57,7 +57,7 @@ class Category(CompanyMultiValueMixin, metaclass=PoolMeta):
|
||||
accounting = fields.Boolean(
|
||||
"Accounting",
|
||||
states={
|
||||
'readonly': Bool(Eval('childs', [0])) | Bool(Eval('parent')),
|
||||
'editable': Bool(Eval('childs', [0])) | Bool(Eval('parent')),
|
||||
},
|
||||
help="Check to indicate the category is used for accounting.")
|
||||
account_parent = fields.Boolean('Use Parent\'s accounts',
|
||||
|
||||
@@ -79,7 +79,8 @@ class Statement(Workflow, ModelSQL, ModelView, ChatMixin):
|
||||
company = fields.Many2One(
|
||||
'company.company', "Company", required=True,
|
||||
states={
|
||||
'readonly': (Eval('state') != 'draft') | Eval('lines', [0]),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0]),
|
||||
})
|
||||
journal = fields.Many2One(
|
||||
'account.statement.journal', "Journal", required=True,
|
||||
@@ -87,7 +88,8 @@ class Statement(Workflow, ModelSQL, ModelView, ChatMixin):
|
||||
('company', '=', Eval('company', -1)),
|
||||
],
|
||||
states={
|
||||
'readonly': (Eval('state') != 'draft') | Eval('lines', [0]),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0]),
|
||||
})
|
||||
currency = fields.Function(fields.Many2One(
|
||||
'currency.currency', "Currency"), 'on_change_with_currency')
|
||||
@@ -786,10 +788,11 @@ class Line(origin_mixin(_states), sequence_ordered(), ModelSQL, ModelView):
|
||||
states=_states,
|
||||
context={'with_payment': False})
|
||||
origin = fields.Many2One(
|
||||
'account.statement.origin', 'Origin', readonly=True,
|
||||
'account.statement.origin', 'Origin',
|
||||
ondelete='RESTRICT',
|
||||
states={
|
||||
'invisible': ~Bool(Eval('origin')),
|
||||
'readonly': Eval('id', -1) >= 0,
|
||||
},
|
||||
domain=[
|
||||
('statement', '=', Eval('statement', -1)),
|
||||
@@ -802,9 +805,8 @@ class Line(origin_mixin(_states), sequence_ordered(), ModelSQL, ModelView):
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
table = cls.__table__()
|
||||
cls.date.states['readonly'] = (
|
||||
cls.date.states.get('readonly', False)
|
||||
| Bool(Eval('origin', 0)))
|
||||
cls.date.states['readonly'] = cls.date.states.get('readonly', False)
|
||||
cls.date.states['editable'] = ~Bool(Eval('origin', 0))
|
||||
cls.account.required = True
|
||||
cls.party.states['required'] = (
|
||||
cls.party.states.get('required', False)
|
||||
@@ -1184,7 +1186,8 @@ class LineGroup(ModelSQL, ModelView):
|
||||
|
||||
|
||||
_states = {
|
||||
'readonly': (Eval('statement_state') != 'draft') | Eval('lines', []),
|
||||
'readonly': Eval('statement_state') != 'draft',
|
||||
'editable': ~Eval('lines', []),
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
from trytond.model import DeactivableMixin, ModelSQL, ModelView, Unique, fields
|
||||
from trytond.pool import PoolMeta
|
||||
from trytond.pyson import Bool, Eval, If
|
||||
from trytond.pyson import Eval, If
|
||||
from trytond.transaction import Transaction
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ class Product_EUExciseTax(ModelSQL, ModelView):
|
||||
country = fields.Many2One(
|
||||
'country.country', "Country", required=True,
|
||||
states={
|
||||
'readonly': Bool(Eval('excise_tax')),
|
||||
'editable': ~Eval('excise_tax'),
|
||||
})
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -29,7 +29,8 @@ class Sale(metaclass=PoolMeta):
|
||||
],
|
||||
states={
|
||||
'invisible': ~Eval('warehouse_eu_excise_number'),
|
||||
'readonly': (Eval('state') != 'draft') | Eval('lines', [0]),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0]),
|
||||
})
|
||||
eu_excise_types = fields.Function(
|
||||
fields.MultiSelection(IDENTIFIER_TYPES, "Excise Types"),
|
||||
@@ -41,9 +42,11 @@ class Sale(metaclass=PoolMeta):
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
cls.warehouse.states['readonly'] = (
|
||||
cls.warehouse.states.get('readonly', False)
|
||||
| Eval('eu_excise_number'))
|
||||
editable = ~Eval('eu_excise_number')
|
||||
if cls.warehouse.states.get('editable'):
|
||||
cls.warehouse.states['editable'] &= editable
|
||||
else:
|
||||
cls.warehouse.states['editable'] = editable
|
||||
|
||||
@fields.depends(methods=['_clear_eu_excise_number'])
|
||||
def on_change_party(self):
|
||||
|
||||
@@ -448,9 +448,9 @@ class InvoiceLine(metaclass=PoolMeta):
|
||||
__name__ = 'account.invoice.line'
|
||||
shipment_cost = fields.Many2One(
|
||||
'account.shipment_cost', "Shipment Cost",
|
||||
readonly=True,
|
||||
states={
|
||||
'invisible': ~Eval('shipment_cost'),
|
||||
'editable': False,
|
||||
})
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -13,8 +13,11 @@ class Purchase(metaclass=PoolMeta):
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
for field in (cls.invoice_address, cls.warehouse):
|
||||
field.states['readonly'] |= (
|
||||
Eval('lines', [0]) & Eval('invoice_address'))
|
||||
editable = ~(Eval('lines', [0]) & Eval('invoice_address'))
|
||||
if field.states.get('editable'):
|
||||
field.states['editable'] &= editable
|
||||
else:
|
||||
field.states['editable'] = editable
|
||||
|
||||
|
||||
class Line(metaclass=PoolMeta):
|
||||
|
||||
@@ -13,8 +13,11 @@ class Sale(metaclass=PoolMeta):
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
for field in (cls.shipment_party, cls.shipment_address, cls.warehouse):
|
||||
field.states['readonly'] |= (
|
||||
Eval('lines', [0]) & Eval('shipment_address'))
|
||||
editable = ~(Eval('lines', [0]) & Eval('shipment_address'))
|
||||
if field.states.get('editable'):
|
||||
field.states['editable'] &= editable
|
||||
else:
|
||||
field.states['editable'] = editable
|
||||
|
||||
|
||||
class Line(metaclass=PoolMeta):
|
||||
|
||||
@@ -53,7 +53,7 @@ class Budget(BudgetMixin, ModelSQL, ModelView):
|
||||
('type', '=', 'root'),
|
||||
],
|
||||
states={
|
||||
'readonly': Eval('root') & Eval('lines', [-1]),
|
||||
'editable': ~(Eval('root') & Eval('lines', [-1])),
|
||||
})
|
||||
lines = fields.One2Many(
|
||||
'analytic_account.budget.line', 'budget', "Lines",
|
||||
|
||||
@@ -17,14 +17,14 @@ class Carrier(metaclass=PoolMeta):
|
||||
states={
|
||||
'invisible': Eval('carrier_cost_method') != 'weight',
|
||||
'required': Eval('carrier_cost_method') == 'weight',
|
||||
'readonly': Bool(Eval('weight_price_list', [])),
|
||||
'editable': Bool(Eval('weight_price_list', [])),
|
||||
},
|
||||
help="The Unit of Measure of weight criteria for the price list.")
|
||||
weight_currency = fields.Many2One('currency.currency', 'Currency',
|
||||
states={
|
||||
'invisible': Eval('carrier_cost_method') != 'weight',
|
||||
'required': Eval('carrier_cost_method') == 'weight',
|
||||
'readonly': Bool(Eval('weight_price_list', [])),
|
||||
'editable': Bool(Eval('weight_price_list', [])),
|
||||
},
|
||||
help="The currency of the price.")
|
||||
weight_price_list = fields.One2Many('carrier.weight_price_list', 'carrier',
|
||||
|
||||
@@ -47,7 +47,8 @@ class Party(
|
||||
code = fields.Char(
|
||||
"Code", required=True,
|
||||
states={
|
||||
'readonly': Eval('code_readonly', True),
|
||||
'readonly': Eval('id', -1) >= 0,
|
||||
'editable': ~Eval('code_readonly', True),
|
||||
},
|
||||
help="The unique identifier of the party.")
|
||||
code_readonly = fields.Function(fields.Boolean('Code Readonly'),
|
||||
|
||||
@@ -196,7 +196,8 @@ class RelationAll(Relation, ModelView):
|
||||
Relation = pool.get('party.relation')
|
||||
vlist = cls._before_create(vlist)
|
||||
relations = Relation.create(vlist)
|
||||
return cls.browse(cls._after_create([r.id * 2 for r in relations]))
|
||||
return cls.browse(cls._after_create(
|
||||
[r.id * 2 for r in relations], vlist))
|
||||
|
||||
@classmethod
|
||||
def write(cls, *args):
|
||||
|
||||
@@ -153,7 +153,7 @@ class Template(
|
||||
list_price = fields.MultiValue(fields.Numeric(
|
||||
"List Price", digits=price_digits,
|
||||
states={
|
||||
'readonly': ~Eval('context', {}).get('company'),
|
||||
'editable': ~Eval('context', {}).get('company'),
|
||||
},
|
||||
help="The standard price the product is sold at."))
|
||||
list_prices = fields.One2Many(
|
||||
@@ -515,7 +515,7 @@ class Product(
|
||||
list_price = fields.MultiValue(fields.Numeric(
|
||||
"List Price", digits=price_digits,
|
||||
states={
|
||||
'readonly': ~Eval('context', {}).get('company'),
|
||||
'editable': ~Eval('context', {}).get('company'),
|
||||
},
|
||||
help="The standard price the variant is sold at.\n"
|
||||
"Leave empty to use the list price of the product."))
|
||||
@@ -528,7 +528,7 @@ class Product(
|
||||
cost_price = fields.MultiValue(fields.Numeric(
|
||||
"Cost Price", digits=price_digits,
|
||||
states={
|
||||
'readonly': ~Eval('context', {}).get('company'),
|
||||
'editable': ~Eval('context', {}).get('company'),
|
||||
},
|
||||
help="The amount it costs to purchase or make the variant, "
|
||||
"or carry out the service."))
|
||||
@@ -633,6 +633,7 @@ class Product(
|
||||
setattr(cls, 'order_%s' % attr, order_method)
|
||||
if isinstance(tfield, fields.One2Many):
|
||||
getattr(cls, attr).setter = '_set_template_function'
|
||||
getattr(cls, attr)._field.readonly = False
|
||||
|
||||
@classmethod
|
||||
def _set_template_function(cls, products, name, value):
|
||||
|
||||
@@ -40,7 +40,7 @@ class Product(metaclass=PoolMeta):
|
||||
readonly = (
|
||||
Eval('context', {}).get('cost_price_warehouse', False)
|
||||
& ~Eval('context', {}).get('warehouse'))
|
||||
if cls.cost_price.states['readonly']:
|
||||
if cls.cost_price.states.get('readonly'):
|
||||
cls.cost_price.states['readonly'] |= readonly
|
||||
else:
|
||||
cls.cost_price.states['readonly'] = readonly
|
||||
|
||||
@@ -47,16 +47,20 @@ class Production(
|
||||
('type', '=', 'warehouse'),
|
||||
],
|
||||
states={
|
||||
'readonly': (~Eval('state').in_(['request', 'draft'])
|
||||
| Eval('inputs', [-1]) | Eval('outputs', [-1])),
|
||||
'readonly': ~Eval('state').in_(['request', 'draft']),
|
||||
'editable': ~(
|
||||
Eval('inputs', [-1])
|
||||
| Eval('outputs', [-1])),
|
||||
})
|
||||
location = fields.Many2One('stock.location', 'Location', required=True,
|
||||
domain=[
|
||||
('type', '=', 'production'),
|
||||
],
|
||||
states={
|
||||
'readonly': (~Eval('state').in_(['request', 'draft'])
|
||||
| Eval('inputs', [-1]) | Eval('outputs', [-1])),
|
||||
'readonly': ~Eval('state').in_(['request', 'draft']),
|
||||
'editable': ~(
|
||||
Eval('inputs', [-1])
|
||||
| Eval('outputs', [-1])),
|
||||
})
|
||||
type = fields.Selection([
|
||||
('assembly', "Assembly"),
|
||||
@@ -87,8 +91,8 @@ class Production(
|
||||
),
|
||||
],
|
||||
states={
|
||||
'readonly': (~Eval('state').in_(['request', 'draft'])
|
||||
| ~Eval('warehouse', 0) | ~Eval('location', 0)),
|
||||
'readonly': ~Eval('state').in_(['request', 'draft']),
|
||||
'editable': Eval('warehouse', None) & Eval('location', None),
|
||||
'invisible': ~Eval('product'),
|
||||
})
|
||||
uom_category = fields.Function(fields.Many2One(
|
||||
@@ -123,8 +127,8 @@ class Production(
|
||||
('company', '=', Eval('company', -1)),
|
||||
],
|
||||
states={
|
||||
'readonly': (~Eval('state').in_(['request', 'draft', 'waiting'])
|
||||
| ~Eval('warehouse') | ~Eval('location')),
|
||||
'readonly': ~Eval('state').in_(['request', 'draft', 'waiting']),
|
||||
'editable': Eval('warehouse', None) & Eval('location', None),
|
||||
})
|
||||
outputs = fields.One2Many(
|
||||
'stock.move', 'production_output', "Output Materials",
|
||||
@@ -138,8 +142,8 @@ class Production(
|
||||
('company', '=', Eval('company', -1)),
|
||||
],
|
||||
states={
|
||||
'readonly': (Eval('state').in_(['done', 'cancelled'])
|
||||
| ~Eval('warehouse') | ~Eval('location')),
|
||||
'readonly': Eval('state').in_(['done', 'cancelled']),
|
||||
'editable': Eval('warehouse', None) & Eval('location', None),
|
||||
})
|
||||
|
||||
assigned_by = employee_field("Assigned By")
|
||||
|
||||
@@ -46,7 +46,7 @@ class Location(metaclass=PoolMeta):
|
||||
class Move(metaclass=PoolMeta):
|
||||
__name__ = 'stock.move'
|
||||
production_input = fields.Many2One(
|
||||
'production', "Production Input", readonly=True, ondelete='CASCADE',
|
||||
'production', "Production Input", ondelete='CASCADE',
|
||||
domain=[
|
||||
('company', '=', Eval('company', -1)),
|
||||
If(Eval('production_output', None),
|
||||
@@ -55,9 +55,10 @@ class Move(metaclass=PoolMeta):
|
||||
],
|
||||
states={
|
||||
'invisible': ~Eval('production_input'),
|
||||
'readonly': Eval('id', -1) >= 0,
|
||||
})
|
||||
production_output = fields.Many2One(
|
||||
'production', "Production Output", readonly=True, ondelete='CASCADE',
|
||||
'production', "Production Output", ondelete='CASCADE',
|
||||
domain=[
|
||||
('company', '=', Eval('company', -1)),
|
||||
If(Eval('production_input', None),
|
||||
@@ -66,6 +67,7 @@ class Move(metaclass=PoolMeta):
|
||||
],
|
||||
states={
|
||||
'invisible': ~Eval('production_output'),
|
||||
'readonly': Eval('id', -1) >= 0,
|
||||
})
|
||||
production = fields.Function(fields.Many2One(
|
||||
'production', "Production",
|
||||
|
||||
@@ -82,7 +82,9 @@ Change cost of input::
|
||||
|
||||
>>> Move = Model.get('stock.move')
|
||||
>>> input, = production.inputs
|
||||
>>> Move.write([input], {'cost_price': Decimal(6)}, config.context)
|
||||
>>> Move.write(
|
||||
... [input], {'cost_price': Decimal(6)},
|
||||
... {**config.context, '_check_access': False})
|
||||
>>> input.reload()
|
||||
>>> bool(input.production_cost_price_updated)
|
||||
True
|
||||
|
||||
@@ -161,7 +161,7 @@ class Work(
|
||||
company = fields.Many2One(
|
||||
'company.company', "Company", required=True,
|
||||
states={
|
||||
'readonly': (
|
||||
'editable': ~(
|
||||
Eval('origin', None)
|
||||
| Eval('parent', None)
|
||||
| Eval('children', [])
|
||||
|
||||
@@ -85,9 +85,9 @@ class Purchase(
|
||||
company = fields.Many2One(
|
||||
'company.company', "Company", required=True,
|
||||
states={
|
||||
'readonly': (
|
||||
(Eval('state') != 'draft')
|
||||
| Eval('lines', [0])
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(
|
||||
Eval('lines', [0])
|
||||
| Eval('party', True)
|
||||
| Eval('invoice_party', True)),
|
||||
})
|
||||
@@ -112,8 +112,8 @@ class Purchase(
|
||||
})
|
||||
party = fields.Many2One('party.party', 'Party', required=True,
|
||||
states={
|
||||
'readonly': ((Eval('state') != 'draft')
|
||||
| (Eval('lines', [0]) & Eval('party'))),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(Eval('lines', [0]) & Eval('party')),
|
||||
},
|
||||
context={
|
||||
'company': Eval('company', -1),
|
||||
@@ -132,8 +132,8 @@ class Purchase(
|
||||
depends={'company'})
|
||||
invoice_party = fields.Many2One('party.party', "Invoice Party",
|
||||
states={
|
||||
'readonly': ((Eval('state') != 'draft')
|
||||
| Eval('lines', [0])),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0]),
|
||||
},
|
||||
context={
|
||||
'company': Eval('company', -1),
|
||||
@@ -157,16 +157,14 @@ class Purchase(
|
||||
domain=[('type', '=', 'warehouse')], states=_states)
|
||||
currency = fields.Many2One('currency.currency', 'Currency', required=True,
|
||||
states={
|
||||
'readonly': ((Eval('state') != 'draft')
|
||||
| (Eval('lines', [0]) & Eval('currency'))),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(Eval('lines', [0]) & Eval('currency')),
|
||||
})
|
||||
lines = fields.One2Many(
|
||||
'purchase.line', 'purchase', "Lines",
|
||||
states={
|
||||
'readonly': (
|
||||
(Eval('state') != 'draft')
|
||||
| ~Eval('company')
|
||||
| ~Eval('currency')),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': Eval('company', None) & Eval('currency', None),
|
||||
})
|
||||
line_lines = fields.One2Many(
|
||||
'purchase.line', 'purchase', "Line - Lines", readonly=True,
|
||||
@@ -1177,8 +1175,8 @@ class Line(sequence_ordered(), ModelSQL, ModelView):
|
||||
purchase = fields.Many2One(
|
||||
'purchase.purchase', "Purchase", ondelete='CASCADE', required=True,
|
||||
states={
|
||||
'readonly': ((Eval('purchase_state') != 'draft')
|
||||
& Bool(Eval('purchase'))),
|
||||
'readonly': Eval('purchase_state') != 'draft',
|
||||
'editable': ~Eval('purchase'),
|
||||
})
|
||||
type = fields.Selection([
|
||||
('line', 'Line'),
|
||||
@@ -1403,9 +1401,9 @@ class Line(sequence_ordered(), ModelSQL, ModelView):
|
||||
delivery_date = fields.Function(fields.Date('Delivery Date',
|
||||
states={
|
||||
'invisible': Eval('type') != 'line',
|
||||
'readonly': (Eval('purchase_state').in_(
|
||||
['processing', 'done', 'cancelled'])
|
||||
| ~Eval('delivery_date_edit', False)),
|
||||
'readonly': Eval('purchase_state').in_(
|
||||
['processing', 'done', 'cancelled']),
|
||||
'editable': Eval('delivery_date_edit', False),
|
||||
}),
|
||||
'on_change_with_delivery_date', setter='set_delivery_date')
|
||||
delivery_date_edit = fields.Boolean(
|
||||
@@ -1425,7 +1423,7 @@ class Line(sequence_ordered(), ModelSQL, ModelView):
|
||||
},
|
||||
help="Check to edit the delivery date.")
|
||||
delivery_date_store = fields.Date(
|
||||
"Delivery Date", readonly=True,
|
||||
"Delivery Date",
|
||||
domain=[
|
||||
If(Eval('type') != 'line',
|
||||
('delivery_date_store', '=', None),
|
||||
@@ -1433,6 +1431,7 @@ class Line(sequence_ordered(), ModelSQL, ModelView):
|
||||
],
|
||||
states={
|
||||
'invisible': Eval('type') != 'line',
|
||||
'editable': False
|
||||
})
|
||||
purchase_state = fields.Function(
|
||||
fields.Selection('get_purchase_states', 'Purchase State'),
|
||||
|
||||
@@ -42,7 +42,8 @@ class Amendment(Workflow, ModelSQL, ModelView):
|
||||
('state', 'in', ['processing', 'done']),
|
||||
],
|
||||
states={
|
||||
'readonly': (Eval('state') != 'draft') | Eval('lines', [0]),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0]),
|
||||
})
|
||||
date = fields.Date(
|
||||
"Date", required=True,
|
||||
@@ -248,9 +249,8 @@ class AmendmentLine(ModelSQL, ModelView):
|
||||
('default_uom_category', '=', Eval('product_uom_category', -1)),
|
||||
],
|
||||
states={
|
||||
'readonly': (
|
||||
(Eval('state') != 'draft')
|
||||
| ~Eval('product_uom_category', None)),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': Bool(Eval('product_uom_category', None)),
|
||||
'invisible': Eval('action') != 'line',
|
||||
})
|
||||
product_supplier = fields.Many2One(
|
||||
|
||||
@@ -115,9 +115,9 @@ class BlanketAgreement(Workflow, ModelSQL, ModelView, ChatMixin):
|
||||
company = fields.Many2One(
|
||||
'company.company', "Company", required=True,
|
||||
states={
|
||||
'readonly': (
|
||||
(Eval('state') != 'draft')
|
||||
| Eval('lines', [0])
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(
|
||||
Eval('lines', [0])
|
||||
| Eval('supplier', True)),
|
||||
})
|
||||
number = fields.Char("Number", readonly=True)
|
||||
@@ -130,9 +130,8 @@ class BlanketAgreement(Workflow, ModelSQL, ModelView, ChatMixin):
|
||||
supplier = fields.Many2One(
|
||||
'party.party', "Supplier", required=True,
|
||||
states={
|
||||
'readonly': (
|
||||
(Eval('state') != 'draft')
|
||||
| (Eval('lines', [0]) & Eval('supplier'))),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(Eval('lines', [0]) & Eval('supplier', None)),
|
||||
},
|
||||
context={
|
||||
'company': Eval('company', -1),
|
||||
@@ -163,16 +162,14 @@ class BlanketAgreement(Workflow, ModelSQL, ModelView, ChatMixin):
|
||||
currency = fields.Many2One(
|
||||
'currency.currency', "Currency", required=True,
|
||||
states={
|
||||
'readonly': (
|
||||
(Eval('state') != 'draft')
|
||||
| (Eval('lines', [0]) & Eval('currency', 0))),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(Eval('lines', [0]) & Eval('currency', 0)),
|
||||
})
|
||||
lines = fields.One2Many(
|
||||
'purchase.blanket_agreement.line', 'blanket_agreement', "Lines",
|
||||
states={
|
||||
'readonly': (
|
||||
(Eval('state') != 'draft')
|
||||
| ~Eval('supplier'))
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': Bool(Eval('supplier', None)),
|
||||
})
|
||||
|
||||
amount = fields.Function(Monetary(
|
||||
|
||||
@@ -10,10 +10,7 @@ class Purchase(metaclass=PoolMeta):
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
cls.party.states['readonly'] = (cls.party.states['readonly']
|
||||
| Eval('lines', [0]))
|
||||
cls.lines.states['readonly'] = (cls.lines.states['readonly']
|
||||
| ~Eval('party'))
|
||||
cls.lines.states['editable'] &= Eval('party', None)
|
||||
|
||||
|
||||
class Line(metaclass=PoolMeta):
|
||||
|
||||
@@ -111,7 +111,7 @@ class Quotation(Workflow, ModelSQL, ModelView, ChatMixin):
|
||||
supplier = fields.Many2One(
|
||||
'party.party', "Supplier", required=True,
|
||||
states={
|
||||
'readonly': Eval('lines', [0]) & Eval('supplier'),
|
||||
'editable': Eval('lines', [0]) & Eval('supplier'),
|
||||
},
|
||||
context={
|
||||
'company': Eval('company', -1),
|
||||
|
||||
@@ -78,7 +78,8 @@ class PurchaseRequisition(Workflow, ModelSQL, ModelView, ChatMixin):
|
||||
company = fields.Many2One(
|
||||
'company.company', "Company", required=True,
|
||||
states={
|
||||
'readonly': (Eval('state') != 'draft') | Eval('lines', [0]),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0]),
|
||||
})
|
||||
number = fields.Char('Number', readonly=True)
|
||||
description = fields.Char('Description', states=_states)
|
||||
@@ -99,8 +100,8 @@ class PurchaseRequisition(Workflow, ModelSQL, ModelView, ChatMixin):
|
||||
currency = fields.Many2One(
|
||||
'currency.currency', 'Currency',
|
||||
states={
|
||||
'readonly': (_states['readonly']
|
||||
| (Eval('lines', [0]) & Eval('currency'))),
|
||||
'readonly': _states['readonly'],
|
||||
'editable': ~(Eval('lines', [0]) & Eval('currency')),
|
||||
})
|
||||
total_amount = fields.Function(
|
||||
Monetary("Total", currency='currency', digits='currency'),
|
||||
|
||||
@@ -43,14 +43,16 @@ class Line(metaclass=PoolMeta):
|
||||
secondary_uom_factor = fields.Float(
|
||||
"Secondary UoM Factor",
|
||||
states={
|
||||
'readonly': True,
|
||||
'readonly': Eval('purchase_state') != 'draft',
|
||||
'editable': False,
|
||||
'required': (Eval('type') == 'line') & Eval('secondary_unit'),
|
||||
},
|
||||
help="The factor for the secondary Unit of Measure.")
|
||||
secondary_uom_rate = fields.Float(
|
||||
"Secondary UoM Rate",
|
||||
states={
|
||||
'readonly': True,
|
||||
'readonly': Eval('purchase_state') != 'draft',
|
||||
'editable': False,
|
||||
'required': (Eval('type') == 'line') & Eval('secondary_unit'),
|
||||
},
|
||||
help="The rate for the secondary Unit of Measure.")
|
||||
|
||||
+25
-20
@@ -81,9 +81,9 @@ class Sale(
|
||||
company = fields.Many2One(
|
||||
'company.company', "Company", required=True,
|
||||
states={
|
||||
'readonly': (
|
||||
(Eval('state') != 'draft')
|
||||
| Eval('lines', [0])
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(
|
||||
Eval('lines', [0])
|
||||
| Eval('party', True)
|
||||
| Eval('invoice_party', True)
|
||||
| Eval('shipment_party', True)),
|
||||
@@ -97,9 +97,8 @@ class Sale(
|
||||
quotation_date = fields.Date(
|
||||
"Quotation Date",
|
||||
states={
|
||||
'readonly': (
|
||||
(Eval('state') != 'draft')
|
||||
| (Eval('number') & Eval('lines'))),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(Eval('number') & Eval('lines', [0])),
|
||||
'invisible': ~Eval('state').in_(['draft', 'quotation']),
|
||||
},
|
||||
help="When the quotation was edited.")
|
||||
@@ -140,8 +139,8 @@ class Sale(
|
||||
party = fields.Many2One(
|
||||
'party.party', "Party", required=True,
|
||||
states={
|
||||
'readonly': ((Eval('state') != 'draft')
|
||||
| (Eval('lines', [0]) & Eval('party'))),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(Eval('lines', [0]) & Eval('party')),
|
||||
},
|
||||
context={
|
||||
'company': Eval('company', -1),
|
||||
@@ -160,8 +159,8 @@ class Sale(
|
||||
depends={'company'})
|
||||
invoice_party = fields.Many2One('party.party', "Invoice Party",
|
||||
states={
|
||||
'readonly': ((Eval('state') != 'draft')
|
||||
| Eval('lines', [0])),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0]),
|
||||
},
|
||||
context={
|
||||
'company': Eval('company', -1),
|
||||
@@ -213,16 +212,14 @@ class Sale(
|
||||
})
|
||||
currency = fields.Many2One('currency.currency', 'Currency', required=True,
|
||||
states={
|
||||
'readonly': ((Eval('state') != 'draft')
|
||||
| (Eval('lines', [0]) & Eval('currency', 0))),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(Eval('lines', [0]) & Eval('currency', 0)),
|
||||
})
|
||||
lines = fields.One2Many(
|
||||
'sale.line', 'sale', "Lines",
|
||||
states={
|
||||
'readonly': (
|
||||
(Eval('state') != 'draft')
|
||||
| ~Eval('company')
|
||||
| ~Eval('currency')),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': Eval('company', None) & Eval('currency', None),
|
||||
})
|
||||
line_lines = fields.One2Many(
|
||||
'sale.line', 'sale', "Line - Lines", readonly=True,
|
||||
@@ -556,6 +553,10 @@ class Sale(
|
||||
def default_invoice_state():
|
||||
return 'none'
|
||||
|
||||
@classmethod
|
||||
def default_to_invoice(cls):
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def default_shipment_method(cls, **pattern):
|
||||
Config = Pool().get('sale.configuration')
|
||||
@@ -566,6 +567,10 @@ class Sale(
|
||||
def default_shipment_state():
|
||||
return 'none'
|
||||
|
||||
@classmethod
|
||||
def default_to_ship(cls):
|
||||
return False
|
||||
|
||||
@fields.depends(
|
||||
'company', 'party', 'invoice_party', 'shipment_party', 'warehouse',
|
||||
'payment_term', 'lines')
|
||||
@@ -916,10 +921,10 @@ class Sale(
|
||||
default.setdefault('number', None)
|
||||
default.setdefault('reference')
|
||||
default.setdefault('invoice_state', 'none')
|
||||
default.setdefault('to_invoice')
|
||||
default.setdefault('to_invoice', cls.default_to_invoice())
|
||||
default.setdefault('invoices_ignored', None)
|
||||
default.setdefault('shipment_state', 'none')
|
||||
default.setdefault('to_ship')
|
||||
default.setdefault('to_ship', cls.default_to_ship())
|
||||
default.setdefault('quotation_date')
|
||||
default.setdefault('sale_date', None)
|
||||
default.setdefault('quoted_by')
|
||||
@@ -1389,8 +1394,8 @@ class SaleLine(TaxableMixin, sequence_ordered(), ModelSQL, ModelView):
|
||||
sale = fields.Many2One(
|
||||
'sale.sale', "Sale", ondelete='CASCADE', required=True,
|
||||
states={
|
||||
'readonly': ((Eval('sale_state') != 'draft')
|
||||
& Bool(Eval('sale'))),
|
||||
'readonly': Eval('sale_state') != 'draft',
|
||||
'editable': ~Eval('sale'),
|
||||
})
|
||||
type = fields.Selection([
|
||||
('line', 'Line'),
|
||||
|
||||
@@ -46,8 +46,9 @@ Create a quotation::
|
||||
|
||||
Expire quotation::
|
||||
|
||||
>>> sale.quotation_date = today - dt.timedelta(weeks=2)
|
||||
>>> sale.save()
|
||||
>>> Sale.write([sale.id], {
|
||||
... 'quotation_date': today - dt.timedelta(weeks=2)
|
||||
... }, {**config._context, '_check_access': False})
|
||||
|
||||
>>> cron, = Cron.find(
|
||||
... [('method', '=', 'sale.sale|cancel_expired_quotation')], limit=1)
|
||||
|
||||
@@ -42,7 +42,8 @@ class Amendment(Workflow, ModelSQL, ModelView):
|
||||
('state', 'in', ['processing', 'done']),
|
||||
],
|
||||
states={
|
||||
'readonly': (Eval('state') != 'draft') | Eval('lines', [0]),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0]),
|
||||
})
|
||||
date = fields.Date(
|
||||
"Date", required=True,
|
||||
@@ -286,9 +287,8 @@ class AmendmentLine(ModelSQL, ModelView):
|
||||
('default_uom_category', '=', Eval('product_uom_category', -1)),
|
||||
],
|
||||
states={
|
||||
'readonly': (
|
||||
(Eval('state') != 'draft')
|
||||
| ~Eval('product_uom_category', None)),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': Bool(Eval('product_uom_category', None)),
|
||||
'invisible': Eval('action') != 'line',
|
||||
})
|
||||
quantity = fields.Float(
|
||||
|
||||
@@ -115,9 +115,9 @@ class BlanketAgreement(Workflow, ModelSQL, ModelView, ChatMixin):
|
||||
company = fields.Many2One(
|
||||
'company.company', "Company", required=True,
|
||||
states={
|
||||
'readonly': (
|
||||
(Eval('state') != 'draft')
|
||||
| Eval('lines', [0])
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(
|
||||
Eval('lines', [0])
|
||||
| Eval('customer', True)),
|
||||
})
|
||||
number = fields.Char("Number", readonly=True)
|
||||
@@ -130,9 +130,8 @@ class BlanketAgreement(Workflow, ModelSQL, ModelView, ChatMixin):
|
||||
customer = fields.Many2One(
|
||||
'party.party', "Customer", required=True,
|
||||
states={
|
||||
'readonly': (
|
||||
(Eval('state') != 'draft')
|
||||
| (Eval('lines', [0]) & Eval('customer'))),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(Eval('lines', [0]) & Eval('customer', None)),
|
||||
},
|
||||
context={
|
||||
'company': Eval('company', -1),
|
||||
@@ -163,16 +162,14 @@ class BlanketAgreement(Workflow, ModelSQL, ModelView, ChatMixin):
|
||||
currency = fields.Many2One(
|
||||
'currency.currency', "Currency", required=True,
|
||||
states={
|
||||
'readonly': (
|
||||
(Eval('state') != 'draft')
|
||||
| (Eval('lines', [0]) & Eval('currency', 0))),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(Eval('lines', [0]) & Eval('currency', 0)),
|
||||
})
|
||||
lines = fields.One2Many(
|
||||
'sale.blanket_agreement.line', 'blanket_agreement', "Lines",
|
||||
states={
|
||||
'readonly': (
|
||||
(Eval('state') != 'draft')
|
||||
| ~Eval('customer'))
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': Bool(Eval('customer', None)),
|
||||
})
|
||||
|
||||
amount = fields.Function(Monetary(
|
||||
|
||||
@@ -56,7 +56,8 @@ class Complaint(Workflow, ModelSQL, ModelView, ChatMixin):
|
||||
company = fields.Many2One(
|
||||
'company.company', 'Company', required=True,
|
||||
states={
|
||||
'readonly': _states['readonly'] | Eval('origin'),
|
||||
'readonly': _states['readonly'],
|
||||
'editable': ~Eval('origin'),
|
||||
})
|
||||
type = fields.Many2One('sale.complaint.type', 'Type', required=True,
|
||||
states=_states)
|
||||
@@ -96,8 +97,8 @@ class Complaint(Workflow, ModelSQL, ModelView, ChatMixin):
|
||||
],
|
||||
},
|
||||
states={
|
||||
'readonly': ((Eval('state') != 'draft')
|
||||
| Bool(Eval('actions', [0]))),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('actions', [0]),
|
||||
'required': Bool(Eval('origin_model')),
|
||||
},
|
||||
depends={'origin_model'})
|
||||
@@ -108,8 +109,9 @@ class Complaint(Workflow, ModelSQL, ModelView, ChatMixin):
|
||||
description = fields.Text('Description', states=_states)
|
||||
actions = fields.One2Many('sale.complaint.action', 'complaint', 'Actions',
|
||||
states={
|
||||
'readonly': ((Eval('state') != 'draft')
|
||||
| (If(~Eval('origin_id', 0), 0, Eval('origin_id', 0)) <= 0)),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': (
|
||||
If(~Eval('origin_id', 0), -1, Eval('origin_id', -1)) < 0),
|
||||
},
|
||||
depends={'origin_model'})
|
||||
submitted_by = employee_field(
|
||||
|
||||
@@ -71,7 +71,7 @@ class Extra(DeactivableMixin, ModelSQL, ModelView, MatchMixin):
|
||||
company = fields.Many2One(
|
||||
'company.company', "Company", required=True,
|
||||
states={
|
||||
'readonly': Eval('id', 0) > 0,
|
||||
'readonly': Eval('id', -1) >= 0,
|
||||
})
|
||||
start_date = fields.Date('Start Date',
|
||||
domain=['OR',
|
||||
|
||||
@@ -11,7 +11,7 @@ from trytond.model import Exclude, ModelSQL, ModelView, Workflow, fields
|
||||
from trytond.modules.company.model import CompanyValueMixin
|
||||
from trytond.modules.currency.fields import Monetary
|
||||
from trytond.pool import Pool, PoolMeta
|
||||
from trytond.pyson import Bool, Eval, Id
|
||||
from trytond.pyson import Eval, Id
|
||||
from trytond.report import Report, get_email
|
||||
from trytond.sendmail import send_message_transactional
|
||||
from trytond.tools.email_ import (
|
||||
@@ -58,7 +58,9 @@ class GiftCard(ModelSQL, ModelView):
|
||||
_rec_name = 'number'
|
||||
|
||||
_states = {
|
||||
'readonly': Bool(Eval('origin')) | Bool(Eval('spent_on')),
|
||||
'readonly': (
|
||||
(Eval('origin', None) | Eval('spent_on', None))
|
||||
& (Eval('id', -1) >= 0)),
|
||||
}
|
||||
|
||||
number = fields.Char(
|
||||
@@ -80,9 +82,16 @@ class GiftCard(ModelSQL, ModelView):
|
||||
currency = fields.Many2One(
|
||||
'currency.currency', "Currency", required=True, states=_states)
|
||||
|
||||
origin = fields.Reference("Origin", selection='get_origin', readonly=True)
|
||||
origin = fields.Reference(
|
||||
"Origin", selection='get_origin',
|
||||
states={
|
||||
'editable': Eval('id', -1) >= 0,
|
||||
})
|
||||
spent_on = fields.Reference(
|
||||
"Spent On", selection='get_spent_on', readonly=True)
|
||||
"Spent On", selection='get_spent_on',
|
||||
states={
|
||||
'editable': Eval('id', -1) >= 0,
|
||||
})
|
||||
|
||||
del _states
|
||||
|
||||
|
||||
@@ -65,7 +65,8 @@ class SaleOpportunity(
|
||||
company = fields.Many2One(
|
||||
'company.company', "Company", required=True,
|
||||
states={
|
||||
'readonly': _states_stop['readonly'] | Eval('party', True),
|
||||
'readonly': _states_stop['readonly'],
|
||||
'editable': ~Eval('party', True),
|
||||
},
|
||||
domain=[
|
||||
('id', If(In('company', Eval('context', {})), '=', '!='),
|
||||
|
||||
@@ -111,9 +111,8 @@ class POSSale(Workflow, ModelSQL, ModelView, TaxableMixin, ChatMixin):
|
||||
point = fields.Many2One(
|
||||
'sale.point', "Point", required=True, ondelete='RESTRICT',
|
||||
states={
|
||||
'readonly': ((Eval('id', 0) > 0)
|
||||
| Bool(Eval('lines', [0]))
|
||||
| _states['readonly']),
|
||||
'readonly': (Eval('id', -1) >= 0) | _states['readonly'],
|
||||
'editable': ~Eval('lines', [0]),
|
||||
},
|
||||
domain=[
|
||||
('company', '=', Eval('company', -1)),
|
||||
@@ -482,12 +481,12 @@ class POSSaleLine(ModelSQL, ModelView, TaxableMixin):
|
||||
unit_list_price = fields.Numeric(
|
||||
"Unit List Price", digits=price_digits, required=True,
|
||||
states={
|
||||
'readonly': True, # Allow client to sent value
|
||||
'editable': False,
|
||||
})
|
||||
unit_gross_price = fields.Numeric(
|
||||
"Unit Gross Price", digits=price_digits, required=True,
|
||||
states={
|
||||
'readonly': True, # Allow client to sent value
|
||||
'editable': False,
|
||||
})
|
||||
unit_price = fields.Function(fields.Numeric(
|
||||
"Unit Price", digits=price_digits,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
from trytond.model import fields
|
||||
from trytond.pool import Pool, PoolMeta
|
||||
from trytond.pyson import Bool, Equal, Eval, Not, Or
|
||||
from trytond.pyson import Eval
|
||||
|
||||
|
||||
class Sale(metaclass=PoolMeta):
|
||||
@@ -11,17 +11,14 @@ class Sale(metaclass=PoolMeta):
|
||||
help="Use to compute the unit price of lines.",
|
||||
domain=[('company', '=', Eval('company', -1))],
|
||||
states={
|
||||
'readonly': Or(Not(Equal(Eval('state'), 'draft')),
|
||||
Bool(Eval('lines', [0]))),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0]),
|
||||
})
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
cls.party.states['readonly'] = (cls.party.states['readonly']
|
||||
| Eval('lines', [0]))
|
||||
cls.lines.states['readonly'] = (cls.lines.states['readonly']
|
||||
| ~Eval('party') | ~Eval('company'))
|
||||
cls.lines.states['editable'] &= Eval('party', None)
|
||||
|
||||
@fields.depends('company')
|
||||
def on_change_party(self):
|
||||
|
||||
@@ -184,7 +184,7 @@ class Promotion(
|
||||
company = fields.Many2One(
|
||||
'company.company', "Company", required=True,
|
||||
states={
|
||||
'readonly': Eval('id', 0) > 0,
|
||||
'readonly': Eval('id', -1) >= 0,
|
||||
})
|
||||
start_date = fields.Date('Start Date',
|
||||
domain=['OR',
|
||||
|
||||
@@ -130,7 +130,8 @@ class Rental(
|
||||
company = fields.Many2One(
|
||||
'company.company', "Company", required=True,
|
||||
states={
|
||||
'readonly': (Eval('state') != 'draft') | Eval('party', True),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('party', True),
|
||||
},
|
||||
help="Make the sale rental belong to the company.")
|
||||
|
||||
@@ -149,9 +150,8 @@ class Rental(
|
||||
party = fields.Many2One(
|
||||
'party.party', "Party", required=True,
|
||||
states={
|
||||
'readonly': (
|
||||
(Eval('state') != 'draft')
|
||||
| (Eval('lines', [0]) & Eval('party'))),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(Eval('lines', [0]) & Eval('party')),
|
||||
},
|
||||
context={
|
||||
'company': Eval('company', -1),
|
||||
@@ -169,8 +169,8 @@ class Rental(
|
||||
depends={'company', 'party'})
|
||||
invoice_party = fields.Many2One('party.party', "Invoice Party",
|
||||
states={
|
||||
'readonly': ((Eval('state') != 'draft')
|
||||
| Eval('lines', [0])),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0]),
|
||||
},
|
||||
context={
|
||||
'company': Eval('company', -1),
|
||||
@@ -207,8 +207,8 @@ class Rental(
|
||||
currency = fields.Many2One(
|
||||
'currency.currency', "Currency", required=True,
|
||||
states={
|
||||
'readonly': ((Eval('state') != 'draft')
|
||||
| (Eval('lines', [0]) & Eval('currency', 0))),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(Eval('lines', [0]) & Eval('currency', None)),
|
||||
})
|
||||
|
||||
start = fields.Function(
|
||||
|
||||
@@ -43,14 +43,16 @@ class Line(metaclass=PoolMeta):
|
||||
secondary_uom_factor = fields.Float(
|
||||
"Secondary UoM Factor",
|
||||
states={
|
||||
'readonly': True,
|
||||
'readonly': Eval('sale_state') != 'draft',
|
||||
'editable': False,
|
||||
'required': (Eval('type') == 'line') & Eval('secondary_unit'),
|
||||
},
|
||||
help="The factor for the secondary Unit of Measure.")
|
||||
secondary_uom_rate = fields.Float(
|
||||
"Secondary UoM Rate",
|
||||
states={
|
||||
'readonly': True,
|
||||
'readonly': Eval('sale_state') != 'draft',
|
||||
'editable': False,
|
||||
'required': (Eval('type') == 'line') & Eval('secondary_unit'),
|
||||
},
|
||||
help="The rate for the secondary Unit of Measure.")
|
||||
|
||||
@@ -17,9 +17,8 @@ class ShipmentCostSaleMixin:
|
||||
'currency.currency', "Cost Sale Currency",
|
||||
states={
|
||||
'invisible': Eval('cost_sale_method') != 'shipment',
|
||||
'readonly': (
|
||||
Eval('shipment_cost_sale_readonly', True)
|
||||
| ~Eval('cost_edit', False)),
|
||||
'readonly': Eval('shipment_cost_sale_readonly', True),
|
||||
'editable': Eval('cost_edit', False),
|
||||
}),
|
||||
'on_change_with_cost_sale_currency_used', setter='set_cost')
|
||||
cost_sale_currency = fields.Many2One(
|
||||
@@ -33,9 +32,8 @@ class ShipmentCostSaleMixin:
|
||||
"Cost Sale", digits=price_digits,
|
||||
states={
|
||||
'invisible': Eval('cost_sale_method') != 'shipment',
|
||||
'readonly': (
|
||||
Eval('shipment_cost_sale_readonly', True)
|
||||
| ~Eval('cost_edit', False)),
|
||||
'readonly': Eval('shipment_cost_sale_readonly', True),
|
||||
'editable': Eval('cost_edit', False),
|
||||
}),
|
||||
'on_change_with_cost_sale_used', setter='set_cost')
|
||||
cost_sale = fields.Numeric(
|
||||
|
||||
@@ -32,9 +32,9 @@ class Subscription(Workflow, ModelSQL, ModelView, ChatMixin):
|
||||
company = fields.Many2One(
|
||||
'company.company', "Company", required=True,
|
||||
states={
|
||||
'readonly': (
|
||||
(Eval('state') != 'draft')
|
||||
| Eval('lines', [0])
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(
|
||||
Eval('lines', [0])
|
||||
| Eval('party', True)
|
||||
| Eval('invoice_party', True)),
|
||||
},
|
||||
@@ -54,8 +54,8 @@ class Subscription(Workflow, ModelSQL, ModelView, ChatMixin):
|
||||
party = fields.Many2One(
|
||||
'party.party', "Party", required=True,
|
||||
states={
|
||||
'readonly': ((Eval('state') != 'draft')
|
||||
| (Eval('lines', [0]) & Eval('party'))),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(Eval('lines', [0]) & Eval('party', None)),
|
||||
},
|
||||
context={
|
||||
'company': Eval('company', -1),
|
||||
@@ -73,8 +73,8 @@ class Subscription(Workflow, ModelSQL, ModelView, ChatMixin):
|
||||
depends={'company', 'party'})
|
||||
invoice_party = fields.Many2One('party.party', "Invoice Party",
|
||||
states={
|
||||
'readonly': ((Eval('state') != 'draft')
|
||||
| Eval('lines', [0])),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0]),
|
||||
},
|
||||
context={
|
||||
'company': Eval('company', -1),
|
||||
@@ -102,8 +102,8 @@ class Subscription(Workflow, ModelSQL, ModelView, ChatMixin):
|
||||
currency = fields.Many2One(
|
||||
'currency.currency', "Currency", required=True,
|
||||
states={
|
||||
'readonly': ((Eval('state') != 'draft')
|
||||
| (Eval('lines', [0]) & Eval('currency', 0))),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(Eval('lines', [0]) & Eval('currency', 0)),
|
||||
})
|
||||
|
||||
start_date = fields.Date(
|
||||
|
||||
@@ -34,12 +34,15 @@ class Inventory(Workflow, ModelSQL, ModelView, ChatMixin):
|
||||
help="The main identifier for the inventory.")
|
||||
location = fields.Many2One(
|
||||
'stock.location', 'Location', required=True,
|
||||
domain=[('type', '=', 'storage')], states={
|
||||
'readonly': (Eval('state') != 'draft') | Eval('lines', [0]),
|
||||
domain=[('type', '=', 'storage')],
|
||||
states={
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0]),
|
||||
},
|
||||
help="The location inventoried.")
|
||||
date = fields.Date('Date', required=True, states={
|
||||
'readonly': (Eval('state') != 'draft') | Eval('lines', [0]),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0]),
|
||||
},
|
||||
help="The date of the stock count.")
|
||||
lines = fields.One2Many(
|
||||
@@ -56,7 +59,8 @@ class Inventory(Workflow, ModelSQL, ModelView, ChatMixin):
|
||||
help="How lines without a quantity are handled.")
|
||||
company = fields.Many2One('company.company', 'Company', required=True,
|
||||
states={
|
||||
'readonly': (Eval('state') != 'draft') | Eval('lines', [0]),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0]),
|
||||
},
|
||||
help="The company the inventory is associated with.")
|
||||
state = fields.Selection([
|
||||
|
||||
+23
-20
@@ -18,7 +18,7 @@ from trytond.model import (
|
||||
from trytond.model.exceptions import AccessError
|
||||
from trytond.modules.product import price_digits, round_price
|
||||
from trytond.pool import Pool
|
||||
from trytond.pyson import Bool, Equal, Eval, Id, If, TimeDelta
|
||||
from trytond.pyson import Bool, Eval, Id, If, TimeDelta
|
||||
from trytond.tools import cached_property
|
||||
from trytond.transaction import Transaction, without_check_access
|
||||
|
||||
@@ -214,8 +214,8 @@ class Move(Workflow, ModelSQL, ModelView):
|
||||
unit = fields.Many2One(
|
||||
'product.uom', "Unit", required=True,
|
||||
states={
|
||||
'readonly': (Eval('state').in_(['cancelled', 'assigned', 'done'])
|
||||
| Eval('unit_price')),
|
||||
'readonly': Eval('state').in_(['cancelled', 'assigned', 'done']),
|
||||
'editable': ~Eval('unit_price'),
|
||||
},
|
||||
domain=[
|
||||
If(~Eval('state').in_(['done', 'cancelled']),
|
||||
@@ -239,10 +239,10 @@ class Move(Workflow, ModelSQL, ModelView):
|
||||
'stock.location', "From Location",
|
||||
required=True,
|
||||
states={
|
||||
'readonly': (
|
||||
STATES['readonly']
|
||||
| (Eval('shipment')
|
||||
& Equal(Eval('_parent_shipment.id', None), None))),
|
||||
'readonly': STATES['readonly'],
|
||||
'editable': ~(
|
||||
Eval('shipment')
|
||||
| Eval('_parent_shipment', None)),
|
||||
},
|
||||
domain=[
|
||||
LOCATION_DOMAIN,
|
||||
@@ -264,10 +264,10 @@ class Move(Workflow, ModelSQL, ModelView):
|
||||
'stock.location', "To Location",
|
||||
required=True,
|
||||
states={
|
||||
'readonly': (
|
||||
STATES['readonly']
|
||||
| (Eval('shipment')
|
||||
& Equal(Eval('_parent_shipment.id', None), None))),
|
||||
'readonly': STATES['readonly'],
|
||||
'editable': ~(
|
||||
Eval('shipment')
|
||||
| Eval('_parent_shipment', None)),
|
||||
},
|
||||
domain=[
|
||||
LOCATION_DOMAIN,
|
||||
@@ -286,9 +286,10 @@ class Move(Workflow, ModelSQL, ModelView):
|
||||
"To Location"),
|
||||
'on_change_with_to_location_name')
|
||||
shipment = fields.Reference(
|
||||
"Shipment", selection='get_shipment', readonly=True,
|
||||
"Shipment", selection='get_shipment',
|
||||
states={
|
||||
'invisible': ~Eval('shipment'),
|
||||
'readonly': Eval('id', -1) >= 0,
|
||||
},
|
||||
help="Used to group several stock moves together.")
|
||||
origin = fields.Reference(
|
||||
@@ -305,20 +306,20 @@ class Move(Workflow, ModelSQL, ModelView):
|
||||
planned_date = fields.Date(
|
||||
"Planned Date",
|
||||
states={
|
||||
'readonly': (
|
||||
Eval('state').in_(['cancelled', 'assigned', 'done'])
|
||||
| Eval('shipment')
|
||||
| Eval('_parent_shipment'))
|
||||
'readonly': Eval('state').in_(['cancelled', 'assigned', 'done']),
|
||||
'editable': ~(
|
||||
Eval('shipment', None)
|
||||
| Eval('_parent_shipment', None)),
|
||||
},
|
||||
help="When the stock is expected to be moved.")
|
||||
effective_date = fields.Date(
|
||||
"Effective Date",
|
||||
states={
|
||||
'required': Eval('state') == 'done',
|
||||
'readonly': (
|
||||
Eval('state').in_(['cancelled', 'done'])
|
||||
| Eval('shipment')
|
||||
| Eval('_parent_shipment')),
|
||||
'readonly': Eval('state').in_(['cancelled', 'done']),
|
||||
'editable': ~(
|
||||
Eval('shipment', None)
|
||||
| Eval('_parent_shipment', None)),
|
||||
},
|
||||
help="When the stock was actually moved.")
|
||||
delay = fields.Function(
|
||||
@@ -1024,6 +1025,8 @@ class Move(Workflow, ModelSQL, ModelView):
|
||||
@classmethod
|
||||
def copy(cls, moves, default=None):
|
||||
default = default.copy() if default is not None else {}
|
||||
default.setdefault('internal_quantity', 0)
|
||||
default.setdefault('cost_price')
|
||||
default.setdefault('outcome_moves', None)
|
||||
return super().copy(moves, default=default)
|
||||
|
||||
|
||||
+50
-31
@@ -359,9 +359,10 @@ class ShipmentIn(
|
||||
help="The company the shipment is associated with.")
|
||||
supplier = fields.Many2One('party.party', 'Supplier',
|
||||
states={
|
||||
'readonly': (((Eval('state') != 'draft')
|
||||
| Eval('incoming_moves', [0]))
|
||||
& Eval('supplier')),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(
|
||||
Eval('incoming_moves', [0])
|
||||
& Eval('supplier', None)),
|
||||
}, required=True,
|
||||
context={
|
||||
'company': Eval('company', -1),
|
||||
@@ -381,8 +382,10 @@ class ShipmentIn(
|
||||
warehouse = fields.Many2One('stock.location', "Warehouse",
|
||||
required=True, domain=[('type', '=', 'warehouse')],
|
||||
states={
|
||||
'readonly': (Eval('state').in_(['cancelled', 'done'])
|
||||
| Eval('incoming_moves', [0]) | Eval('inventory_moves', [0])),
|
||||
'readonly': Eval('state').in_(['cancelled', 'done']),
|
||||
'editable': ~(
|
||||
Eval('incoming_moves', [0])
|
||||
| Eval('inventory_moves', [0])),
|
||||
},
|
||||
help="Where the stock is received.")
|
||||
warehouse_input = fields.Many2One(
|
||||
@@ -822,10 +825,12 @@ class ShipmentInReturn(
|
||||
help="The company the shipment is associated with.")
|
||||
supplier = fields.Many2One('party.party', 'Supplier',
|
||||
states={
|
||||
'readonly': (((Eval('state') != 'draft')
|
||||
| Eval('moves', [0]))
|
||||
& Eval('supplier', 0)),
|
||||
}, required=True,
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(
|
||||
Eval('moves', [0])
|
||||
& Eval('supplier', None)),
|
||||
},
|
||||
required=True,
|
||||
context={
|
||||
'company': Eval('company', -1),
|
||||
'party_contact_mechanism_usage': 'delivery',
|
||||
@@ -847,14 +852,20 @@ class ShipmentInReturn(
|
||||
],
|
||||
help="Where the stock is sent to.")
|
||||
from_location = fields.Many2One('stock.location', "From Location",
|
||||
required=True, states={
|
||||
'readonly': (Eval('state') != 'draft') | Eval('moves', [0]),
|
||||
}, domain=[('type', 'in', ['storage', 'view'])],
|
||||
required=True,
|
||||
states={
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('moves', [0]),
|
||||
},
|
||||
domain=[('type', 'in', ['storage', 'view'])],
|
||||
help="Where the stock is moved from.")
|
||||
to_location = fields.Many2One('stock.location', "To Location",
|
||||
required=True, states={
|
||||
'readonly': (Eval('state') != 'draft') | Eval('moves', [0]),
|
||||
}, domain=[('type', '=', 'supplier')],
|
||||
required=True,
|
||||
states={
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('moves', [0]),
|
||||
},
|
||||
domain=[('type', '=', 'supplier')],
|
||||
help="Where the stock is moved to.")
|
||||
warehouse = fields.Function(
|
||||
fields.Many2One('stock.location', "Warehouse"),
|
||||
@@ -1162,8 +1173,8 @@ class ShipmentOut(
|
||||
help="The company the shipment is associated with.")
|
||||
customer = fields.Many2One('party.party', 'Customer', required=True,
|
||||
states={
|
||||
'readonly': ((Eval('state') != 'draft')
|
||||
| Eval('outgoing_moves', [0])),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('outgoing_moves', [0]),
|
||||
},
|
||||
context={
|
||||
'company': Eval('company', -1),
|
||||
@@ -1190,9 +1201,12 @@ class ShipmentOut(
|
||||
help="Where the stock is sent to.")
|
||||
warehouse = fields.Many2One('stock.location', "Warehouse", required=True,
|
||||
states={
|
||||
'readonly': ((Eval('state') != 'draft')
|
||||
| Eval('outgoing_moves', [0]) | Eval('inventory_moves', [0])),
|
||||
}, domain=[('type', '=', 'warehouse')],
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(
|
||||
Eval('outgoing_moves', [0])
|
||||
| Eval('inventory_moves', [0])),
|
||||
},
|
||||
domain=[('type', '=', 'warehouse')],
|
||||
help="Where the stock is sent from.")
|
||||
warehouse_storage = fields.Many2One(
|
||||
'stock.location', "Warehouse Storage", required=True,
|
||||
@@ -1876,8 +1890,8 @@ class ShipmentOutReturn(
|
||||
help="The company the shipment is associated with.")
|
||||
customer = fields.Many2One('party.party', 'Customer', required=True,
|
||||
states={
|
||||
'readonly': ((Eval('state') != 'draft')
|
||||
| Eval('incoming_moves', [0])),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('incoming_moves', [0]),
|
||||
},
|
||||
context={
|
||||
'company': Eval('company', -1),
|
||||
@@ -1896,9 +1910,12 @@ class ShipmentOutReturn(
|
||||
help="The address the customer can be contacted at.")
|
||||
warehouse = fields.Many2One('stock.location', "Warehouse", required=True,
|
||||
states={
|
||||
'readonly': ((Eval('state') != 'draft')
|
||||
| Eval('incoming_moves', [0]) | Eval('inventory_moves', [0])),
|
||||
}, domain=[('type', '=', 'warehouse')],
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~(
|
||||
Eval('incoming_moves', [0])
|
||||
| Eval('inventory_moves', [0])),
|
||||
},
|
||||
domain=[('type', '=', 'warehouse')],
|
||||
help="Where the stock is returned.")
|
||||
warehouse_storage = fields.Many2One(
|
||||
'stock.location', "Warehouse Storage", required=True,
|
||||
@@ -2337,18 +2354,20 @@ class ShipmentInternal(
|
||||
help="The company the shipment is associated with.")
|
||||
from_location = fields.Many2One('stock.location', "From Location",
|
||||
required=True, states={
|
||||
'readonly': (~Eval('state').in_(['request', 'draft'])
|
||||
| Eval('moves', [0])),
|
||||
'readonly': ~Eval('state').in_(['request', 'draft']),
|
||||
'editable': ~Eval('moves', [0]),
|
||||
},
|
||||
domain=[
|
||||
('type', 'in', ['view', 'storage', 'lost_found']),
|
||||
],
|
||||
help="Where the stock is moved from.")
|
||||
to_location = fields.Many2One('stock.location', "To Location",
|
||||
required=True, states={
|
||||
'readonly': (~Eval('state').in_(['request', 'draft'])
|
||||
| Eval('moves', [0])),
|
||||
}, domain=[
|
||||
required=True,
|
||||
states={
|
||||
'readonly': ~Eval('state').in_(['request', 'draft']),
|
||||
'editable': ~Eval('moves', [0]),
|
||||
},
|
||||
domain=[
|
||||
('type', 'in', ['view', 'storage', 'lost_found']),
|
||||
],
|
||||
help="Where the stock is moved to.")
|
||||
|
||||
@@ -107,7 +107,10 @@ Reopen the period::
|
||||
|
||||
Create an assigned move::
|
||||
|
||||
>>> Move.write([move], {'state': 'assigned'}, config._context)
|
||||
>>> Move.write(
|
||||
... [move], {'state': 'assigned'},
|
||||
... {**config._context, '_check_access': False})
|
||||
>>> move.reload()
|
||||
>>> move.state
|
||||
'assigned'
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ Imports::
|
||||
|
||||
>>> from proteus import Model, Wizard
|
||||
>>> from trytond.modules.company.tests.tools import create_company, get_company
|
||||
>>> from trytond.modules.stock.move import Move
|
||||
>>> from trytond.modules.stock.move import Move as StockMove
|
||||
>>> from trytond.tests.tools import activate_modules, assertEqual, assertFalse
|
||||
|
||||
>>> today = dt.date.today()
|
||||
@@ -18,7 +18,7 @@ Imports::
|
||||
Patch on_change_with_assignation_required::
|
||||
|
||||
>>> _ = patch.object(
|
||||
... Move, 'on_change_with_assignation_required',
|
||||
... StockMove, 'on_change_with_assignation_required',
|
||||
... return_value=False).start()
|
||||
|
||||
Activate modules::
|
||||
@@ -29,6 +29,8 @@ Get company::
|
||||
|
||||
>>> company = get_company()
|
||||
|
||||
>>> Move = Model.get('stock.move')
|
||||
|
||||
Create product::
|
||||
|
||||
>>> ProductUom = Model.get('product.uom')
|
||||
@@ -129,8 +131,10 @@ Update unit price of a move::
|
||||
... ])
|
||||
>>> bool(move.unit_price_updated)
|
||||
False
|
||||
>>> move.unit_price = Decimal('130')
|
||||
>>> move.save()
|
||||
>>> Move.write(
|
||||
... [move], {'unit_price': Decimal('130')},
|
||||
... {**config._context, '_check_access': False})
|
||||
>>> move.reload()
|
||||
>>> bool(move.unit_price_updated)
|
||||
True
|
||||
|
||||
@@ -151,8 +155,10 @@ Update unit price of a move::
|
||||
|
||||
Launch cron task::
|
||||
|
||||
>>> move.unit_price = Decimal('120')
|
||||
>>> move.save()
|
||||
>>> Move.write(
|
||||
... [move], {'unit_price': Decimal('120')},
|
||||
... {**config._context, '_check_access': False})
|
||||
>>> move.reload()
|
||||
|
||||
>>> Cron = Model.get('ir.cron')
|
||||
>>> Company = Model.get('company.company')
|
||||
|
||||
@@ -32,7 +32,8 @@ class Forecast(Workflow, ModelSQL, ModelView, ChatMixin):
|
||||
warehouse = fields.Many2One(
|
||||
'stock.location', 'Location', required=True,
|
||||
domain=[('type', '=', 'warehouse')], states={
|
||||
'readonly': (Eval('state') != 'draft') | Eval('lines', [0]),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0]),
|
||||
})
|
||||
destination = fields.Many2One(
|
||||
'stock.location', 'Destination', required=True,
|
||||
@@ -49,7 +50,8 @@ class Forecast(Workflow, ModelSQL, ModelView, ChatMixin):
|
||||
'stock.forecast.line', 'forecast', 'Lines', states=_states)
|
||||
company = fields.Many2One(
|
||||
'company.company', 'Company', required=True, states={
|
||||
'readonly': (Eval('state') != 'draft') | Eval('lines', [0]),
|
||||
'readonly': Eval('state') != 'draft',
|
||||
'editable': ~Eval('lines', [0]),
|
||||
})
|
||||
state = fields.Selection([
|
||||
('draft', "Draft"),
|
||||
|
||||
@@ -70,7 +70,7 @@ class Move(metaclass=PoolMeta):
|
||||
__name__ = 'stock.move'
|
||||
|
||||
from_place = fields.Many2One(
|
||||
'stock.product.location.place', "From Place", readonly=True,
|
||||
'stock.product.location.place', "From Place",
|
||||
domain=[
|
||||
If(~Eval('state').in_(['done', 'cancelled']),
|
||||
['OR',
|
||||
@@ -79,9 +79,12 @@ class Move(metaclass=PoolMeta):
|
||||
],
|
||||
('location', '=', Eval('from_location', -1)),
|
||||
),
|
||||
])
|
||||
],
|
||||
states={
|
||||
'editable': False,
|
||||
})
|
||||
to_place = fields.Many2One(
|
||||
'stock.product.location.place', "To Place", readonly=True,
|
||||
'stock.product.location.place', "To Place",
|
||||
domain=[
|
||||
If(~Eval('state').in_(['done', 'cancelled']),
|
||||
['OR',
|
||||
@@ -90,7 +93,10 @@ class Move(metaclass=PoolMeta):
|
||||
],
|
||||
('location', '=', Eval('to_location', -1)),
|
||||
),
|
||||
])
|
||||
],
|
||||
states={
|
||||
'editable': False,
|
||||
})
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
|
||||
+4
-2
@@ -93,7 +93,8 @@ Request to ship to first warehouse in 2 and 3 weeks::
|
||||
>>> move.quantity = 10
|
||||
>>> shipment_int1.save()
|
||||
>>> ShipmentInternal.write(
|
||||
... [shipment_int1.id], {'state': 'request'}, shipment_int1._context)
|
||||
... [shipment_int1.id], {'state': 'request'},
|
||||
... {**shipment_int1._context, '_check_access': False})
|
||||
|
||||
>>> shipment_int2 = ShipmentInternal()
|
||||
>>> shipment_int2.planned_date = week2
|
||||
@@ -106,7 +107,8 @@ Request to ship to first warehouse in 2 and 3 weeks::
|
||||
>>> move.quantity = 5
|
||||
>>> shipment_int2.save()
|
||||
>>> ShipmentInternal.write(
|
||||
... [shipment_int2.id], {'state': 'request'}, shipment_int2._context)
|
||||
... [shipment_int2.id], {'state': 'request'},
|
||||
... {**shipment_int2._context, '_check_access': False})
|
||||
|
||||
Plan to ship in 3 weeks::
|
||||
|
||||
|
||||
@@ -26,6 +26,16 @@ class Move(metaclass=PoolMeta):
|
||||
super().__setup__()
|
||||
cls._allow_modify_closed_period.add('shipment_out_cost_price')
|
||||
|
||||
@classmethod
|
||||
def default_shipment_out_cost_price(cls):
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def copy(cls, moves, default=None):
|
||||
default = default.copy() if default is not None else {}
|
||||
default.setdefault('shipment_out_cost_price')
|
||||
return super().copy(moves, default=default)
|
||||
|
||||
|
||||
class ShipmentCostMixin:
|
||||
__slots__ = ()
|
||||
@@ -43,9 +53,8 @@ class ShipmentCostMixin:
|
||||
cost_currency_used = fields.Function(fields.Many2One(
|
||||
'currency.currency', "Cost Currency",
|
||||
states={
|
||||
'readonly': (
|
||||
Eval('shipment_cost_readonly', True)
|
||||
| ~Eval('cost_edit', False)),
|
||||
'readonly': Eval('shipment_cost_readonly', True),
|
||||
'editable': Eval('cost_edit', False),
|
||||
}),
|
||||
'on_change_with_cost_currency_used', setter='set_cost')
|
||||
cost_currency = fields.Many2One(
|
||||
@@ -58,12 +67,15 @@ class ShipmentCostMixin:
|
||||
cost_used = fields.Function(fields.Numeric(
|
||||
"Cost", digits=price_digits,
|
||||
states={
|
||||
'readonly': (
|
||||
Eval('shipment_cost_readonly', True)
|
||||
| ~Eval('cost_edit', False)),
|
||||
'readonly': Eval('shipment_cost_readonly', True),
|
||||
'editable': Eval('cost_edit', False),
|
||||
}),
|
||||
'on_change_with_cost_used', setter='set_cost')
|
||||
cost = fields.Numeric("Cost", digits=price_digits, readonly=True)
|
||||
cost = fields.Numeric(
|
||||
"Cost", digits=price_digits,
|
||||
states={
|
||||
'editable': False,
|
||||
})
|
||||
cost_edit = fields.Boolean(
|
||||
"Edit Cost",
|
||||
states={
|
||||
|
||||
@@ -83,6 +83,14 @@ class Move(metaclass=PoolMeta):
|
||||
"Internal Volume", readonly=True,
|
||||
help="The volume of the moved product in liter.")
|
||||
|
||||
@classmethod
|
||||
def default_internal_weight(cls):
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def default_internal_volume(cls):
|
||||
return None
|
||||
|
||||
@fields.depends(
|
||||
'quantity', 'unit', 'product',
|
||||
methods=['on_change_with_internal_quantity'])
|
||||
@@ -147,6 +155,13 @@ class Move(metaclass=PoolMeta):
|
||||
values['internal_volume'] = internal_volume
|
||||
return values
|
||||
|
||||
@classmethod
|
||||
def copy(cls, moves, default=None):
|
||||
default = default.copy() if default is not None else {}
|
||||
default.setdefault('internal_weight', cls.default_internal_weight())
|
||||
default.setdefault('internal_volume', cls.default_internal_volume())
|
||||
return super().copy(moves, default=default)
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
@Workflow.transition('cancelled')
|
||||
@@ -229,6 +244,14 @@ class MeasurementsMixin(object):
|
||||
if set_measurements:
|
||||
cls.set_measurements()
|
||||
|
||||
@classmethod
|
||||
def default_internal_weight(cls):
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def default_internal_volume(cls):
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def _measurements_states(cls):
|
||||
return []
|
||||
@@ -433,6 +456,13 @@ class MeasurementsMixin(object):
|
||||
def _measurements_location_condition(cls, table, move, location):
|
||||
raise NotImplementedError
|
||||
|
||||
@classmethod
|
||||
def copy(cls, records, default=None):
|
||||
default = default.copy() if default is not None else {}
|
||||
default.setdefault('internal_weight', cls.default_internal_weight())
|
||||
default.setdefault('internal_volume', cls.default_internal_volume())
|
||||
return super().copy(records, default=default)
|
||||
|
||||
|
||||
def set_measurements(func):
|
||||
@wraps(func)
|
||||
|
||||
@@ -36,7 +36,7 @@ def str2bigint(s):
|
||||
class Cron(DeactivableMixin, ModelSQL, ModelView):
|
||||
__name__ = "ir.cron"
|
||||
_states = {
|
||||
'readonly': Eval('running', False),
|
||||
'editable': Eval('running', False),
|
||||
}
|
||||
interval_number = fields.Integer(
|
||||
"Interval Number", required=True, states=_states)
|
||||
@@ -53,7 +53,7 @@ class Cron(DeactivableMixin, ModelSQL, ModelView):
|
||||
[('minute', '>=', 0), ('minute', '<=', 59)],
|
||||
],
|
||||
states={
|
||||
'readonly': _states['readonly'],
|
||||
'editable': _states['editable'],
|
||||
'invisible': Eval('interval_type').in_(['minutes']),
|
||||
},
|
||||
depends=['interval_type'])
|
||||
@@ -63,14 +63,14 @@ class Cron(DeactivableMixin, ModelSQL, ModelView):
|
||||
[('hour', '>=', 0), ('hour', '<=', 23)],
|
||||
],
|
||||
states={
|
||||
'readonly': _states['readonly'],
|
||||
'editable': _states['editable'],
|
||||
'invisible': Eval('interval_type').in_(['minutes', 'hours']),
|
||||
},
|
||||
depends=['interval_type'])
|
||||
weekday = fields.Many2One(
|
||||
'ir.calendar.day', "Day of Week",
|
||||
states={
|
||||
'readonly': _states['readonly'],
|
||||
'editable': _states['editable'],
|
||||
'invisible': Eval('interval_type').in_(
|
||||
['minutes', 'hours', 'days']),
|
||||
},
|
||||
@@ -81,7 +81,7 @@ class Cron(DeactivableMixin, ModelSQL, ModelView):
|
||||
('day', '>=', 0),
|
||||
],
|
||||
states={
|
||||
'readonly': _states['readonly'],
|
||||
'editable': _states['editable'],
|
||||
'invisible': Eval('interval_type').in_(
|
||||
['minutes', 'hours', 'days', 'weeks']),
|
||||
},
|
||||
|
||||
@@ -564,7 +564,10 @@ class ModelStorage(Model):
|
||||
|
||||
def test_readonly(records, field_name, override):
|
||||
field = cls._fields[field_name]
|
||||
if isinstance(field, (fields.One2Many, fields.Many2Many)):
|
||||
if (isinstance(field, (fields.One2Many, fields.Many2Many))
|
||||
or (isinstance(field, fields.Function)
|
||||
and isinstance(
|
||||
field._field, (fields.One2Many, fields.Many2Many)))):
|
||||
# Must be enforced on the target
|
||||
return
|
||||
if field.readonly:
|
||||
|
||||
Reference in New Issue
Block a user