mirror of
https://github.com/NaN-tic/trytond-agronomics.git
synced 2023-12-14 05:33:01 +01:00
add new model quality sample
This commit is contained in:
parent
ae01d2813b
commit
f2f3f29768
11 changed files with 300 additions and 45 deletions
|
@ -34,6 +34,9 @@ def register():
|
||||||
weighing.Weighing,
|
weighing.Weighing,
|
||||||
weighing.WeighingPlantation,
|
weighing.WeighingPlantation,
|
||||||
weighing.WeighingDo,
|
weighing.WeighingDo,
|
||||||
|
quality.Configuration,
|
||||||
|
quality.ConfigurationCompany,
|
||||||
|
quality.ProductQualitySample,
|
||||||
quality.QualitySample,
|
quality.QualitySample,
|
||||||
quality.QualityTest,
|
quality.QualityTest,
|
||||||
quality.QuantitativeTestLine,
|
quality.QuantitativeTestLine,
|
||||||
|
|
19
product.py
19
product.py
|
@ -32,6 +32,7 @@ class Container(ModelSQL, ModelView):
|
||||||
class Template(metaclass=PoolMeta):
|
class Template(metaclass=PoolMeta):
|
||||||
__name__ = 'product.template'
|
__name__ = 'product.template'
|
||||||
|
|
||||||
|
needs_sample = fields.Boolean('Needs Samples')
|
||||||
agronomic_type = fields.Selection([
|
agronomic_type = fields.Selection([
|
||||||
(None, ''),
|
(None, ''),
|
||||||
('grape', "Grape"),
|
('grape', "Grape"),
|
||||||
|
@ -89,13 +90,13 @@ class Product(WineMixin, metaclass=PoolMeta):
|
||||||
}, depends=['agronomic_type'])
|
}, depends=['agronomic_type'])
|
||||||
ecologicals = fields.Many2Many('product.product-agronomics.ecological',
|
ecologicals = fields.Many2Many('product.product-agronomics.ecological',
|
||||||
'product', 'ecological', 'Ecologicals')
|
'product', 'ecological', 'Ecologicals')
|
||||||
quality_sample = fields.Many2One('quality.sample', 'Quality Sample',
|
# quality_sample = fields.Many2One('quality.sample', 'Quality Sample',
|
||||||
states={
|
# states={
|
||||||
'invisible': ~ Eval('agronomic_type').in_(
|
# 'invisible': ~ Eval('agronomic_type').in_(
|
||||||
['wine', 'unfiltered-wine', 'filtered-wine', 'clarified-wine',
|
# ['wine', 'unfiltered-wine', 'filtered-wine', 'clarified-wine',
|
||||||
'bottled-wine']
|
# 'bottled-wine']
|
||||||
)
|
# )
|
||||||
}, depends=['agronomic_type'])
|
# }, depends=['agronomic_type'])
|
||||||
certification = fields.Many2One('agronomics.certification',
|
certification = fields.Many2One('agronomics.certification',
|
||||||
'Certification', states={
|
'Certification', states={
|
||||||
'invisible': ~ Eval('agronomic_type').in_(
|
'invisible': ~ Eval('agronomic_type').in_(
|
||||||
|
@ -109,8 +110,8 @@ class Product(WineMixin, metaclass=PoolMeta):
|
||||||
'bottled-wine']
|
'bottled-wine']
|
||||||
)}, depends=['agronomic_type']), 'get_alcohol_volume')
|
)}, depends=['agronomic_type']), 'get_alcohol_volume')
|
||||||
quality_tests = fields.One2Many('quality.test', 'document', 'Quality Tests')
|
quality_tests = fields.One2Many('quality.test', 'document', 'Quality Tests')
|
||||||
quality_samples = fields.One2Many('quality.sample', 'product',
|
quality_samples = fields.Many2Many('product.product-quality.sample',
|
||||||
'Quality Samples')
|
'product', 'sample', 'Quality Samples')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate(cls, products):
|
def validate(cls, products):
|
||||||
|
|
|
@ -366,18 +366,18 @@ class Production(metaclass=PoolMeta):
|
||||||
return new_product
|
return new_product
|
||||||
|
|
||||||
def copy_quality_samples(self, new_product):
|
def copy_quality_samples(self, new_product):
|
||||||
QualitySample = Pool().get('quality.sample')
|
ProductSample = Pool().get('product.product-quality.sample')
|
||||||
products = [x.product for x in self.inputs if x.product.quality_samples]
|
products = [x.product for x in self.inputs if x.product.quality_samples]
|
||||||
if not self.pass_quality_sample or len(products) != 1:
|
if not self.pass_quality_sample or len(products) != 1:
|
||||||
return new_product
|
return new_product
|
||||||
samples = products[0].quality_samples
|
samples = products[0].quality_samples
|
||||||
new_samples =[]
|
new_samples =[]
|
||||||
for sample in samples:
|
for sample in samples:
|
||||||
new_sample, = QualitySample.copy([sample], {'product':new_product})
|
product_sample = ProductSample()
|
||||||
new_sample.origin = sample
|
product_sample.product = new_product
|
||||||
new_samples.append(new_sample)
|
product_sample.sample = sample
|
||||||
QualitySample.save(new_samples)
|
new_samples.append(product_sample)
|
||||||
QualitySample.done(new_samples)
|
ProductSample.save(new_samples)
|
||||||
return new_product
|
return new_product
|
||||||
|
|
||||||
def copy_quality(self, new_product):
|
def copy_quality(self, new_product):
|
||||||
|
|
148
quality.py
148
quality.py
|
@ -1,31 +1,149 @@
|
||||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||||
# this repository contains the full copyright notices and license terms.
|
# this repository contains the full copyright notices and license terms.
|
||||||
|
import datetime
|
||||||
from trytond.pool import PoolMeta, Pool
|
from trytond.pool import PoolMeta, Pool
|
||||||
from trytond.model import fields, Model
|
from trytond.model import fields, Model, ModelSQL, ModelView, Workflow
|
||||||
from trytond.pyson import Eval
|
from trytond.pyson import Eval, Id
|
||||||
from trytond.modules.agronomics.wine import _WINE_DIGITS
|
from trytond.modules.agronomics.wine import _WINE_DIGITS
|
||||||
|
from trytond.transaction import Transaction
|
||||||
|
|
||||||
class QualitySample(metaclass=PoolMeta):
|
STATES = {
|
||||||
|
'readonly': Eval('state') == 'done',
|
||||||
|
}
|
||||||
|
DEPENDS = ['state']
|
||||||
|
|
||||||
|
class ConfigurationCompany(ModelSQL):
|
||||||
|
'Company Quality configuration'
|
||||||
|
__name__ = 'quality.configuration.company'
|
||||||
|
|
||||||
|
company = fields.Many2One('company.company', 'Company')
|
||||||
|
sample_sequence = fields.Many2One('ir.sequence',
|
||||||
|
'Sample Sequence', domain=[
|
||||||
|
('company', 'in',
|
||||||
|
[Eval('context', {}).get('company', -1), None]),
|
||||||
|
('sequence_type', '=', Id('agronomics',
|
||||||
|
'sequence_type_sample')),
|
||||||
|
])
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def default_company():
|
||||||
|
return Transaction().context.get('company')
|
||||||
|
|
||||||
|
|
||||||
|
class Configuration(metaclass=PoolMeta):
|
||||||
|
__name__ = 'quality.configuration'
|
||||||
|
|
||||||
|
sample_sequence = fields.Function(fields.Many2One('ir.sequence',
|
||||||
|
'Sample Sequence', domain=[
|
||||||
|
('company', 'in',
|
||||||
|
[Eval('context', {}).get('company', -1), None]),
|
||||||
|
('sequence_type', '=', Id('agronomics',
|
||||||
|
'sequence_type_sample')),
|
||||||
|
]),
|
||||||
|
'get_company_config', setter='set_company_config')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_company_config(cls, configs, names):
|
||||||
|
pool = Pool()
|
||||||
|
CompanyConfig = pool.get('quality.configuration.company')
|
||||||
|
res = dict.fromkeys(names, {configs[0].id: None})
|
||||||
|
company_configs = CompanyConfig.search([], limit=1)
|
||||||
|
if len(company_configs) == 1:
|
||||||
|
company_config, = company_configs
|
||||||
|
for field_name in set(names):
|
||||||
|
value = getattr(company_config, field_name, None)
|
||||||
|
if value:
|
||||||
|
res[field_name] = {configs[0].id: value.id}
|
||||||
|
return res
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def set_company_config(cls, configs, name, value):
|
||||||
|
pool = Pool()
|
||||||
|
CompanyConfig = pool.get('quality.configuration.company')
|
||||||
|
company_configs = CompanyConfig.search([], limit=1)
|
||||||
|
if len(company_configs) == 1:
|
||||||
|
company_config, = company_configs
|
||||||
|
else:
|
||||||
|
company_config = CompanyConfig()
|
||||||
|
setattr(company_config, name, value)
|
||||||
|
company_config.save()
|
||||||
|
|
||||||
|
|
||||||
|
class QualitySample(Workflow, ModelSQL, ModelView):
|
||||||
|
'Quality Sample'
|
||||||
__name__ = 'quality.sample'
|
__name__ = 'quality.sample'
|
||||||
|
|
||||||
|
code = fields.Char('Code', select=True, readonly=True)
|
||||||
|
state = fields.Selection([
|
||||||
|
('draft', 'Draft'),
|
||||||
|
('done', 'Done')],
|
||||||
|
'State', required=True, readonly=True)
|
||||||
reference = fields.Char('Reference')
|
reference = fields.Char('Reference')
|
||||||
origin = fields.Reference('Origin', selection='get_origin', select=True,
|
products = fields.Many2Many('product.product-quality.sample', 'sample',
|
||||||
states={
|
'product', 'Products')
|
||||||
'readonly': Eval('state') != 'draft',
|
collection_date = fields.DateTime('Collection Date', required=True,
|
||||||
|
states=STATES, depends=DEPENDS)
|
||||||
|
company = fields.Many2One('company.company', 'Company', required=True,
|
||||||
|
select=True, states=STATES, depends=DEPENDS)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def __setup__(cls):
|
||||||
|
super(QualitySample, cls).__setup__()
|
||||||
|
cls._transitions |= set((('draft', 'done'),))
|
||||||
|
cls._buttons.update({
|
||||||
|
'done': {
|
||||||
|
'invisible': Eval('state') != 'draft',
|
||||||
|
'icon': 'tryton-forward',
|
||||||
},
|
},
|
||||||
depends=['state'])
|
})
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _get_origin(cls):
|
@ModelView.button
|
||||||
'Return list of Model names for origin Reference'
|
@Workflow.transition('done')
|
||||||
return [cls.__name__, 'quality.sample']
|
def done(cls, samples):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def default_state():
|
||||||
|
return 'draft'
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def default_company():
|
||||||
|
return Transaction().context.get('company')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def default_collection_date():
|
||||||
|
return datetime.datetime.now()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_origin(cls):
|
def create(cls, vlist):
|
||||||
IrModel = Pool().get('ir.model')
|
pool = Pool()
|
||||||
get_name = IrModel.get_name
|
Config = pool.get('quality.configuration')
|
||||||
models = cls._get_origin()
|
|
||||||
return [(None, '')] + [(m, get_name(m)) for m in models]
|
sequence = Config(1).sample_sequence
|
||||||
|
for value in vlist:
|
||||||
|
if not value.get('code'):
|
||||||
|
value['code'] = sequence.get()
|
||||||
|
return super(QualitySample, cls).create(vlist)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def copy(cls, samples, default=None):
|
||||||
|
if default is None:
|
||||||
|
default = {}
|
||||||
|
else:
|
||||||
|
default = default.copy()
|
||||||
|
default['code'] = None
|
||||||
|
return super(QualitySample, cls).copy(samples, default=default)
|
||||||
|
|
||||||
|
class ProductQualitySample(ModelSQL):
|
||||||
|
'Product - Quality Sample'
|
||||||
|
__name__ = 'product.product-quality.sample'
|
||||||
|
|
||||||
|
product = fields.Many2One('product.product', 'Product', required=True,
|
||||||
|
ondelete='CASCADE', select=True)
|
||||||
|
sample = fields.Many2One('quality.sample', 'Sample', ondelete='CASCADE',
|
||||||
|
required=True, select=True)
|
||||||
|
|
||||||
|
|
||||||
class QualityTest(metaclass=PoolMeta):
|
class QualityTest(metaclass=PoolMeta):
|
||||||
__name__ = 'quality.test'
|
__name__ = 'quality.test'
|
||||||
|
|
116
quality.xml
116
quality.xml
|
@ -1,10 +1,122 @@
|
||||||
<tryton>
|
<tryton>
|
||||||
<data>
|
<data>
|
||||||
<!-- Quality Sample-->
|
<record model="ir.ui.view" id="quality_configuration_view_form">
|
||||||
|
<field name="model">quality.configuration</field>
|
||||||
|
<field name="inherit" ref="quality_control.quality_configuration_form_view"/>
|
||||||
|
<field name="name">quality_configuration_form</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="ir.rule.group" id="rule_group_quality_configuration_company">
|
||||||
|
<field name="name">Quality Configuration Company</field>
|
||||||
|
<field name="model" search="[('model', '=', 'quality.configuration.company')]"/>
|
||||||
|
<field name="global_p" eval="True"/>
|
||||||
|
</record>
|
||||||
|
<record model="ir.rule" id="rule_quality_configuration_company1">
|
||||||
|
<field name="rule_group" ref="rule_group_quality_configuration_company"/>
|
||||||
|
<field name="domain" eval="[('company', '=', Eval('user', {}).get('company', None))]" pyson="1"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="ir.sequence.type" id="sequence_type_sample">
|
||||||
|
<field name="name">Quality Sample</field>
|
||||||
|
</record>
|
||||||
|
<record model="ir.sequence.type-res.group" id="sequence_type_sample_group_admin">
|
||||||
|
<field name="sequence_type" ref="sequence_type_sample"/>
|
||||||
|
<field name="group" ref="res.group_admin"/>
|
||||||
|
</record>
|
||||||
|
<record model="ir.sequence.type-res.group" id="sequence_type_sample_group_sale_admin">
|
||||||
|
<field name="sequence_type" ref="sequence_type_sample"/>
|
||||||
|
<field name="group" ref="quality_control.group_quality_control_admin"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="ir.sequence" id="sequence_sample">
|
||||||
|
<field name="name">Sample</field>
|
||||||
|
<field name="sequence_type" ref="sequence_type_sample"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="res.group" id="group_quality_control_sample">
|
||||||
|
<field name="name">Quality Samples</field>
|
||||||
|
</record>
|
||||||
|
<record model="res.user-res.group"
|
||||||
|
id="user_admin_group_quality_control_sample">
|
||||||
|
<field name="user" ref="res.user_admin"/>
|
||||||
|
<field name="group" ref="group_quality_control_sample"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- quality.sample -->
|
||||||
<record model="ir.ui.view" id="quality_sample_view_form">
|
<record model="ir.ui.view" id="quality_sample_view_form">
|
||||||
<field name="model">quality.sample</field>
|
<field name="model">quality.sample</field>
|
||||||
|
<field name="type">form</field>
|
||||||
<field name="name">quality_sample_form</field>
|
<field name="name">quality_sample_form</field>
|
||||||
<field name="inherit" ref="quality_control_sample.quality_sample_view_form"/>
|
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<record model="ir.ui.view" id="quality_sample_view_list">
|
||||||
|
<field name="model">quality.sample</field>
|
||||||
|
<field name="type">tree</field>
|
||||||
|
<field name="name">quality_sample_list</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="ir.action.act_window" id="act_quality_sample">
|
||||||
|
<field name="name">Samples</field>
|
||||||
|
<field name="res_model">quality.sample</field>
|
||||||
|
</record>
|
||||||
|
<record model="ir.action.act_window.view" id="act_quality_sample_view1">
|
||||||
|
<field name="sequence" eval="10"/>
|
||||||
|
<field name="view" ref="quality_sample_view_list"/>
|
||||||
|
<field name="act_window" ref="act_quality_sample"/>
|
||||||
|
</record>
|
||||||
|
<record model="ir.action.act_window.view" id="act_quality_sample_view2">
|
||||||
|
<field name="sequence" eval="20"/>
|
||||||
|
<field name="view" ref="quality_sample_view_form"/>
|
||||||
|
<field name="act_window" ref="act_quality_sample"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="ir.model.access" id="access_quality_sample">
|
||||||
|
<field name="model" search="[('model', '=', 'quality.sample')]"/>
|
||||||
|
<field name="perm_read" eval="True"/>
|
||||||
|
<field name="perm_write" eval="False"/>
|
||||||
|
<field name="perm_create" eval="False"/>
|
||||||
|
<field name="perm_delete" eval="False"/>
|
||||||
|
</record>
|
||||||
|
<record model="ir.model.access" id="access_quality_sample_group_sample">
|
||||||
|
<field name="model" search="[('model', '=', 'quality.sample')]"/>
|
||||||
|
<field name="group" ref="group_quality_control_sample"/>
|
||||||
|
<field name="perm_read" eval="True"/>
|
||||||
|
<field name="perm_write" eval="True"/>
|
||||||
|
<field name="perm_create" eval="True"/>
|
||||||
|
<field name="perm_delete" eval="True"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
<record model="ir.rule.group" id="rule_group_quality_sample">
|
||||||
|
<field name="name">Quality Sample</field>
|
||||||
|
<field name="model" search="[('model', '=', 'quality.sample')]"/>
|
||||||
|
<field name="global_p" eval="True"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="ir.rule" id="rule_quality_sample1">
|
||||||
|
<field name="domain" eval="[('company', '=', Eval('user', {}).get('company', None))]" pyson="1"/>
|
||||||
|
<field name="rule_group" ref="rule_group_quality_sample"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- ir.model.button -->
|
||||||
|
<record model="ir.model.button" id="sample_done_button">
|
||||||
|
<field name="name">done</field>
|
||||||
|
<field name="string">Done</field>
|
||||||
|
<field name="model" search="[('model', '=', 'quality.sample')]"/>
|
||||||
|
</record>
|
||||||
|
<record model="ir.model.button-res.group" id="sample_done_button_group_sample">
|
||||||
|
<field name="button" ref="sample_done_button"/>
|
||||||
|
<field name="group" ref="group_quality_control_sample"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- menus -->
|
||||||
|
<menuitem action="act_quality_sample" id="menu_quality_sample"
|
||||||
|
parent="quality_control.menu_quality_control" sequence="30"/>
|
||||||
|
<record model="ir.ui.menu-res.group"
|
||||||
|
id="menu_quality_control_sample_group_quality_control_sample">
|
||||||
|
<field name="menu" ref="menu_quality_sample"/>
|
||||||
|
<field name="group" ref="group_quality_control_sample"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
</tryton>
|
</tryton>
|
|
@ -7,7 +7,7 @@ depends:
|
||||||
product_classification
|
product_classification
|
||||||
product_classification_taxonomic
|
product_classification_taxonomic
|
||||||
product_template_form_quantity
|
product_template_form_quantity
|
||||||
quality_control_sample
|
quality_control
|
||||||
purchase_contract
|
purchase_contract
|
||||||
production
|
production
|
||||||
xml:
|
xml:
|
||||||
|
|
|
@ -5,8 +5,6 @@
|
||||||
<field name="varieties" colspan="2"/>
|
<field name="varieties" colspan="2"/>
|
||||||
<field name="denominations_of_origin" colspan="2"/>
|
<field name="denominations_of_origin" colspan="2"/>
|
||||||
<field name="ecologicals" colspan="2"/>
|
<field name="ecologicals" colspan="2"/>
|
||||||
<label name="quality_sample"/>
|
|
||||||
<field name="quality_sample"/>
|
|
||||||
<label name="certification"/>
|
<label name="certification"/>
|
||||||
<field name="certification"/>
|
<field name="certification"/>
|
||||||
<label name="alcohol_volume"/>
|
<label name="alcohol_volume"/>
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
<field name="varieties" tree_invisible="1"/>
|
<field name="varieties" tree_invisible="1"/>
|
||||||
<field name="denominations_of_origin" tree_invisible="1"/>
|
<field name="denominations_of_origin" tree_invisible="1"/>
|
||||||
<field name="ecologicals" tree_invisible="1"/>
|
<field name="ecologicals" tree_invisible="1"/>
|
||||||
<field name="quality_sample" tree_invisible="1"/>
|
|
||||||
<field name="certification" tree_invisible="1"/>
|
<field name="certification" tree_invisible="1"/>
|
||||||
<field name="alcohol_volume" tree_invisible="1"/>
|
<field name="alcohol_volume" tree_invisible="1"/>
|
||||||
<field name="container" tree_invisible="1"/>
|
<field name="container" tree_invisible="1"/>
|
||||||
|
|
9
view/quality_configuration_form.xml
Normal file
9
view/quality_configuration_form.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!-- The COPYRIGHT file at the top level of this repository contains the full
|
||||||
|
copyright notices and license terms. -->
|
||||||
|
<data>
|
||||||
|
<xpath expr="/form/field[@name='allowed_documents']" position="before">
|
||||||
|
<label name="sample_sequence"/>
|
||||||
|
<field name="sample_sequence"/>
|
||||||
|
</xpath>
|
||||||
|
</data>
|
|
@ -1,9 +1,15 @@
|
||||||
<data>
|
<?xml version="1.0"?>
|
||||||
<xpath expr="/form/field[@name='lot']" position="after">
|
<!-- The COPYRIGHT file at the top level of this repository contains the full
|
||||||
<label name="reference"/>
|
copyright notices and license terms. -->
|
||||||
<field name="reference"/>
|
<form>
|
||||||
<newline/>
|
<label name="collection_date"/>
|
||||||
<label name="origin"/>
|
<field name="collection_date"/>
|
||||||
<field name="origin" colspan="3"/>
|
<label name="code"/>
|
||||||
</xpath>
|
<field name="code"/>
|
||||||
</data>
|
<field name="products" colspan="4"/>
|
||||||
|
<group colspan="4" id="buttons">
|
||||||
|
<label name="state"/>
|
||||||
|
<field name="state"/>
|
||||||
|
<button name="done"/>
|
||||||
|
</group>
|
||||||
|
</form>
|
||||||
|
|
9
view/quality_sample_list.xml
Normal file
9
view/quality_sample_list.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!-- The COPYRIGHT file at the top level of this repository contains the full
|
||||||
|
copyright notices and license terms. -->
|
||||||
|
<tree>
|
||||||
|
<field name="code"/>
|
||||||
|
<field name="collection_date" widget="date"/>
|
||||||
|
<field name="collection_date" widget="time"/>
|
||||||
|
<field name="state"/>
|
||||||
|
</tree>
|
Loading…
Reference in a new issue