046624 | Add Reclassification event
This commit is contained in:
parent
4e13165de3
commit
a19eb45557
|
@ -20,6 +20,7 @@ def register():
|
|||
specie.UIMenu,
|
||||
specie.ActionActWindow,
|
||||
specie.ActionWizard,
|
||||
specie.SpecieProduct,
|
||||
animal.Tag,
|
||||
events.removal_event.RemovalType,
|
||||
events.removal_event.RemovalReason,
|
||||
|
@ -39,7 +40,6 @@ def register():
|
|||
animal_group.AnimalGroupWeight,
|
||||
stock.Location,
|
||||
stock.LocationSiloLocation,
|
||||
stock.LotAnimal,
|
||||
stock.LotAnimalGroup,
|
||||
stock.Lot,
|
||||
stock.LotCostLine,
|
||||
|
@ -72,6 +72,7 @@ def register():
|
|||
events.weaning_event.WeaningEvent,
|
||||
events.weaning_event.WeaningEventAnimal,
|
||||
events.weaning_event.WeaningEventFemaleCycle,
|
||||
events.reclassification_event.ReclassficationEvent,
|
||||
stock.Move,
|
||||
production.BOM,
|
||||
quality.QualityTest,
|
||||
|
|
40
animal.py
40
animal.py
|
@ -10,6 +10,8 @@ from trytond.pool import Pool, PoolMeta
|
|||
from trytond.wizard import Wizard, StateView, StateAction, Button, StateTransition
|
||||
from trytond.exceptions import UserError
|
||||
from trytond.i18n import gettext
|
||||
from trytond import backend
|
||||
from sql import Table
|
||||
|
||||
_STATES_MALE_FIELD = {
|
||||
'invisible': Not(Equal(Eval('type'), 'male')),
|
||||
|
@ -142,8 +144,8 @@ class Animal(ModelSQL, ModelView, AnimalMixin):
|
|||
})
|
||||
breed = fields.Many2One('farm.specie.breed', 'Breed', required=True,
|
||||
domain=[('specie', '=', Eval('specie'))], depends=['specie'])
|
||||
lot = fields.One2One('stock.lot-farm.animal', 'animal', 'lot',
|
||||
string='Lot', required=True, readonly=True, domain=[
|
||||
lot = fields.Many2One('stock.lot', 'Lot',
|
||||
readonly=True, domain=[
|
||||
('animal_type', '=', Eval('type')),
|
||||
], depends=['type'])
|
||||
number = fields.Function(fields.Char('Number'),
|
||||
|
@ -211,11 +213,34 @@ class Animal(ModelSQL, ModelView, AnimalMixin):
|
|||
], 'Purpose', states=_STATES_INDIVIDUAL_FIELD,
|
||||
depends=_DEPENDS_INDIVIDUAL_FIELD)
|
||||
active = fields.Boolean('Active')
|
||||
lots= fields.One2Many(
|
||||
'stock.lot', 'animal', 'Lots', readonly=True)
|
||||
|
||||
# We can't use the 'required' attribute in field because it's
|
||||
# checked on view before execute 'create()' function where this
|
||||
# field is filled in.
|
||||
|
||||
@classmethod
|
||||
def __register__(cls, module_name):
|
||||
TableHandler = backend.get('TableHandler')
|
||||
table = cls.__table_handler__(module_name)
|
||||
sql_table = cls.__table__()
|
||||
update_lot = False
|
||||
if not table.column_exist('lot'):
|
||||
update_lot = True
|
||||
super().__register__(module_name)
|
||||
table = cls.__table_handler__(module_name)
|
||||
if update_lot:
|
||||
sql_table_animal_lot = 'stock_lot-farm_animal'
|
||||
if TableHandler.table_exist(sql_table_animal_lot):
|
||||
sql_table_animal_lot = Table(sql_table_animal_lot)
|
||||
cursor = Transaction().connection.cursor()
|
||||
cursor.execute(*sql_table_animal_lot.select(
|
||||
sql_table_animal_lot.animal, sql_table_animal_lot.lot))
|
||||
for animal_id, lot_id in cursor.fetchall():
|
||||
cursor.execute(*sql_table.update(columns=[sql_table.lot],
|
||||
values=[lot_id], where=sql_table.id == animal_id))
|
||||
|
||||
@staticmethod
|
||||
def default_specie():
|
||||
return Transaction().context.get('specie')
|
||||
|
@ -388,13 +413,19 @@ class Animal(ModelSQL, ModelView, AnimalMixin):
|
|||
location = Location(vals['initial_location'])
|
||||
vals['number'] = cls._calc_number(vals['specie'],
|
||||
location.warehouse.id, vals['type'])
|
||||
|
||||
new_animals = super(Animal, cls).create(vlist)
|
||||
for animal, vals in zip(new_animals, vlist):
|
||||
vals['id'] = animal.id
|
||||
if vals.get('lot'):
|
||||
lot = Lot(vals['lot'])
|
||||
Lot.write([lot], cls._get_lot_values(vals, False))
|
||||
animal.lot = lot
|
||||
animal.save()
|
||||
else:
|
||||
new_lot, = Lot.create([cls._get_lot_values(vals, True)])
|
||||
vals['lot'] = new_lot.id
|
||||
new_animals = super(Animal, cls).create(vlist)
|
||||
animal.lot = new_lot
|
||||
animal.save()
|
||||
if not context.get('no_create_stock_move'):
|
||||
cls._create_and_done_first_stock_move(new_animals)
|
||||
return new_animals
|
||||
|
@ -455,6 +486,7 @@ class Animal(ModelSQL, ModelView, AnimalMixin):
|
|||
'number': animal_vals['number'],
|
||||
'product': product.id,
|
||||
'animal_type': animal_vals['type'],
|
||||
'animal': animal_vals['id']
|
||||
}
|
||||
if Transaction().context.get('create_cost_lines', True):
|
||||
cost_lines = lot_tmp._on_change_product_cost_lines().get('add')
|
||||
|
|
|
@ -15,6 +15,7 @@ from . import abort_event
|
|||
from . import farrowing_event
|
||||
from . import foster_event
|
||||
from . import weaning_event
|
||||
from . import reclassification_event
|
||||
|
||||
from . import event_order
|
||||
|
||||
|
@ -22,4 +23,4 @@ __all__ = ['abstract_event', 'move_event', 'feed_event', 'feed_inventory',
|
|||
'medication_event', 'transformation_event', 'removal_event',
|
||||
'semen_extraction_event', 'insemination_event',
|
||||
'pregnancy_diagnosis_event', 'abort_event', 'farrowing_event',
|
||||
'foster_event', 'weaning_event', 'event_order']
|
||||
'foster_event', 'weaning_event', 'reclassification_event', 'event_order']
|
||||
|
|
|
@ -17,6 +17,7 @@ _INVISIBLE_NOT_GROUP = {
|
|||
}
|
||||
|
||||
|
||||
|
||||
class FarrowingProblem(ModelSQL, ModelView):
|
||||
'''Farrowing Event Problem'''
|
||||
__name__ = 'farm.farrowing.problem'
|
||||
|
|
|
@ -0,0 +1,198 @@
|
|||
# The COPYRIGHT file at the top level of this repository contains the full
|
||||
# copyright notices and license terms.
|
||||
from trytond.exceptions import UserError
|
||||
from trytond.model import fields, ModelView, Workflow
|
||||
from trytond.pyson import Equal, Eval, If, Not
|
||||
from trytond.pool import Pool
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.i18n import gettext
|
||||
|
||||
from .abstract_event import AbstractEvent, _STATES_VALIDATED_ADMIN, \
|
||||
_DEPENDS_VALIDATED_ADMIN
|
||||
|
||||
|
||||
class ReclassficationEvent(AbstractEvent):
|
||||
'''Farm Reclassification Event'''
|
||||
__name__ = 'farm.reclassification.event'
|
||||
_table = 'farm_reclassification_event'
|
||||
|
||||
reclassification_product = fields.Many2One(
|
||||
'product.product', "Reclassification Product", required=True,
|
||||
domain=[('id', 'in', Eval('valid_products'))],
|
||||
states={
|
||||
'readonly': Not(Equal(Eval('state'), 'draft')),
|
||||
}, depends=['animal_type', 'state', 'valid_products'])
|
||||
valid_products = fields.Function(fields.Many2Many(
|
||||
'product.product', None, None, 'Valid Products'),
|
||||
'on_change_with_valid_products')
|
||||
in_move = fields.Many2One(
|
||||
'stock.move', 'Input Stock Move', readonly=True,
|
||||
states=_STATES_VALIDATED_ADMIN, depends=_DEPENDS_VALIDATED_ADMIN)
|
||||
out_move = fields.Many2One(
|
||||
'stock.move', 'Output Stock Move',
|
||||
readonly=True, states=_STATES_VALIDATED_ADMIN,
|
||||
depends=_DEPENDS_VALIDATED_ADMIN)
|
||||
to_location = fields.Many2One('stock.location', 'Destination',
|
||||
required=True, states={
|
||||
'readonly': Not(Equal(Eval('state'), 'draft')),
|
||||
}, domain=[
|
||||
('type', '=', 'storage'),
|
||||
('silo', '=', False),
|
||||
], depends=['state'])
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
cls.animal.domain += [
|
||||
('farm', '=', Eval('farm')),
|
||||
('location.type', '=', 'storage'),
|
||||
('type', '=', 'individual'),
|
||||
]
|
||||
if 'farm' not in cls.animal.depends:
|
||||
cls.animal.depends.append('farm')
|
||||
|
||||
cls._buttons.update({
|
||||
'draft': {
|
||||
'invisible': True,
|
||||
},
|
||||
})
|
||||
|
||||
@fields.depends('animal')
|
||||
def on_change_with_valid_products(self, name=None):
|
||||
if self.animal and self.animal.specie:
|
||||
return [p.id for p in self.animal.specie.reclassification_products]
|
||||
return []
|
||||
|
||||
@classmethod
|
||||
@ModelView.button
|
||||
@Workflow.transition('validated')
|
||||
def validate_event(cls, events):
|
||||
"""
|
||||
Create the input and output stock moves.
|
||||
"""
|
||||
pool = Pool()
|
||||
Move = pool.get('stock.move')
|
||||
|
||||
for reclass_event in events:
|
||||
if reclass_event.in_move and reclass_event.out_move:
|
||||
raise UserError(gettext(
|
||||
'farm.related_stock_moves',
|
||||
event=reclass_event.id,
|
||||
in_move=reclass_event.in_move.id,
|
||||
out_move=reclass_event.out_move.id
|
||||
))
|
||||
if (reclass_event.animal.lot.product ==
|
||||
reclass_event.reclassification_product):
|
||||
raise UserError(gettext(
|
||||
'farm.invalid_reclassification_product',
|
||||
event=reclass_event.id,
|
||||
product=reclass_event.reclassification_product
|
||||
))
|
||||
|
||||
new_in_move = reclass_event._get_event_input_move()
|
||||
new_in_move.save()
|
||||
Move.assign([new_in_move])
|
||||
Move.do([new_in_move])
|
||||
new_out_move = reclass_event._get_event_output_move()
|
||||
new_out_move.save()
|
||||
Move.assign([new_out_move])
|
||||
Move.do([new_out_move])
|
||||
reclass_event.in_move = new_in_move
|
||||
reclass_event.out_move = new_out_move
|
||||
reclass_event.save()
|
||||
|
||||
@fields.depends('animal', 'valid_products', 'to_location')
|
||||
def on_change_animal(self):
|
||||
super().on_change_animal()
|
||||
if not self.animal:
|
||||
return
|
||||
self.to_location = self.animal.location
|
||||
|
||||
def _get_new_lot_values(self):
|
||||
"""
|
||||
Prepare values to create the new stock.lot for the reclassificated
|
||||
animal. It returns a dictionary with values to create stock.lot
|
||||
"""
|
||||
pool = Pool()
|
||||
Lot = pool.get('stock.lot')
|
||||
if not self.animal:
|
||||
return {}
|
||||
product = self.reclassification_product
|
||||
lot_tmp = Lot(product=product)
|
||||
# TODO Improve the manage of animal/lot number, currently using
|
||||
# the animal number to create the new lot
|
||||
res = {
|
||||
'number': self.animal.number,
|
||||
'product': product.id,
|
||||
'animal_type': self.animal.type,
|
||||
'animal': self.animal,
|
||||
}
|
||||
if Transaction().context.get('create_cost_lines', True):
|
||||
cost_lines = lot_tmp._on_change_product_cost_lines().get('add')
|
||||
if cost_lines:
|
||||
res['cost_lines'] = [('create', [cl[1] for cl in cost_lines])]
|
||||
return res
|
||||
|
||||
def _get_event_input_move(self):
|
||||
pool = Pool()
|
||||
Move = pool.get('stock.move')
|
||||
context = Transaction().context
|
||||
|
||||
if self.animal_type == 'group':
|
||||
lot = self.animal_group.lot
|
||||
else:
|
||||
lot = self.animal.lot
|
||||
production_location = self.farm.production_location
|
||||
return Move(
|
||||
product=lot.product,
|
||||
uom=lot.product.default_uom,
|
||||
quantity=1,
|
||||
from_location=self.animal.location,
|
||||
to_location=production_location,
|
||||
planned_date=self.timestamp.date(),
|
||||
effective_date=self.timestamp.date(),
|
||||
company=context.get('company'),
|
||||
lot=lot,
|
||||
origin=self,
|
||||
)
|
||||
|
||||
def _get_event_output_move(self):
|
||||
pool = Pool()
|
||||
Move = pool.get('stock.move')
|
||||
Lot = pool.get('stock.lot')
|
||||
context = Transaction().context
|
||||
lots = Lot.create([self._get_new_lot_values()])
|
||||
if lots:
|
||||
lot, = lots
|
||||
lot.save()
|
||||
self.animal.lot = lot
|
||||
self.animal.save()
|
||||
production_location = self.farm.production_location
|
||||
|
||||
return Move(
|
||||
product=lot.product,
|
||||
uom=lot.product.default_uom,
|
||||
quantity=1,
|
||||
from_location=production_location,
|
||||
to_location=self.to_location,
|
||||
planned_date=self.timestamp.date(),
|
||||
effective_date=self.timestamp.date(),
|
||||
company=context.get('company'),
|
||||
lot=lot,
|
||||
unit_price=lot.product.cost_price,
|
||||
origin=self,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def copy(cls, records, default=None):
|
||||
if default is None:
|
||||
default = {}
|
||||
else:
|
||||
default = default.copy()
|
||||
default.update({
|
||||
'reclassification_product': None,
|
||||
'to_location': None,
|
||||
'in_move': None,
|
||||
'out_move': None,
|
||||
})
|
||||
return super().copy(records, default=default)
|
|
@ -0,0 +1,116 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- The COPYRIGHT file at the top level of this repository contains the full
|
||||
copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data>
|
||||
<!-- farm.reclassification.event -->
|
||||
<record model="ir.ui.view" id="farm_reclassification_event_form_view">
|
||||
<field name="model">farm.reclassification.event</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">farm_reclassification_event_form</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="farm_reclassification_event_list_view">
|
||||
<field name="model">farm.reclassification.event</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="name">farm_reclassification_event_list</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.model.button" id="draft_reclassification_event_button">
|
||||
<field name="string">Draft</field>
|
||||
<field name="name">draft</field>
|
||||
<field name="model" search="[('model', '=', 'farm.reclassification.event')]"/>
|
||||
</record>
|
||||
<record model="ir.model.button-res.group" id="draft_reclassification_event_button_group_farm_admin">
|
||||
<field name="button" ref="draft_reclassification_event_button"/>
|
||||
<field name="group" ref="group_farm_admin"/>
|
||||
</record>
|
||||
<record model="ir.model.button-res.group" id="draft_reclassification_event_button_group_farm_males">
|
||||
<field name="button" ref="draft_reclassification_event_button"/>
|
||||
<field name="group" ref="group_farm_males"/>
|
||||
</record>
|
||||
<record model="ir.model.button-res.group" id="draft_reclassification_event_button_group_farm_females">
|
||||
<field name="button" ref="draft_reclassification_event_button"/>
|
||||
<field name="group" ref="group_farm_females"/>
|
||||
</record>
|
||||
<record model="ir.model.button-res.group" id="draft_reclassification_event_button_group_farm_individuals">
|
||||
<field name="button" ref="draft_reclassification_event_button"/>
|
||||
<field name="group" ref="group_farm_individuals"/>
|
||||
</record>
|
||||
<record model="ir.model.button-res.group" id="draft_reclassification_event_button_group_farm_groups">
|
||||
<field name="button" ref="draft_reclassification_event_button"/>
|
||||
<field name="group" ref="group_farm_groups"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.model.button" id="validate_reclassification_event_button">
|
||||
<field name="string">Validate</field>
|
||||
<field name="name">validate_event</field>
|
||||
<field name="model" search="[('model', '=', 'farm.reclassification.event')]"/>
|
||||
<field name="confirm">Are you sure to validate this event?</field>
|
||||
</record>
|
||||
<record model="ir.model.button-res.group" id="validate_reclassification_event_button_group_farm_admin">
|
||||
<field name="button" ref="validate_reclassification_event_button"/>
|
||||
<field name="group" ref="group_farm_admin"/>
|
||||
</record>
|
||||
<record model="ir.model.button-res.group" id="validate_reclassification_event_button_group_farm_males">
|
||||
<field name="button" ref="validate_reclassification_event_button"/>
|
||||
<field name="group" ref="group_farm_males"/>
|
||||
</record>
|
||||
<record model="ir.model.button-res.group" id="validate_reclassification_event_button_group_farm_females">
|
||||
<field name="button" ref="validate_reclassification_event_button"/>
|
||||
<field name="group" ref="group_farm_females"/>
|
||||
</record>
|
||||
<record model="ir.model.button-res.group" id="validate_reclassification_event_button_group_farm_individuals">
|
||||
<field name="button" ref="validate_reclassification_event_button"/>
|
||||
<field name="group" ref="group_farm_individuals"/>
|
||||
</record>
|
||||
<record model="ir.model.button-res.group" id="validate_reclassification_event_button_group_farm_groups">
|
||||
<field name="button" ref="validate_reclassification_event_button"/>
|
||||
<field name="group" ref="group_farm_groups"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.action.act_window" id="act_farm_reclassification_event">
|
||||
<field name="name">Reclassification</field>
|
||||
<field name="res_model">farm.reclassification.event</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_farm_reclassification_event_view1">
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="view" ref="farm_reclassification_event_list_view"/>
|
||||
<field name="act_window" ref="act_farm_reclassification_event"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_farm_reclassification_event_view2">
|
||||
<field name="sequence" eval="20"/>
|
||||
<field name="view" ref="farm_reclassification_event_form_view"/>
|
||||
<field name="act_window" ref="act_farm_reclassification_event"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.domain" id="act_farm_reclassification_event_domain_draft">
|
||||
<field name="name">Draft</field>
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="domain" eval="[('state', '=', 'draft')]" pyson="1"/>
|
||||
<field name="count" eval="True"/>
|
||||
<field name="act_window" ref="act_farm_reclassification_event"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.domain" id="act_farm_reclassification_event_domain_all">
|
||||
<field name="name">All</field>
|
||||
<field name="sequence" eval="20"/>
|
||||
<field name="act_window" ref="act_farm_reclassification_event"/>
|
||||
</record>
|
||||
|
||||
<!-- Permissions -->
|
||||
<record model="ir.model.access" id="access_farm_reclassification_event">
|
||||
<field name="model" search="[('model', '=', 'farm.reclassification.event')]"/>
|
||||
<field name="perm_read" eval="False"/>
|
||||
<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_farm_reclassification_event_farm">
|
||||
<field name="model" search="[('model', '=', 'farm.reclassification.event')]"/>
|
||||
<field name="group" ref="group_farm"/>
|
||||
<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>
|
||||
</data>
|
||||
</tryton>
|
|
@ -26,6 +26,7 @@ __all__ = ['WeaningEvent', 'WeaningEventFemaleCycle']
|
|||
_INVISIBLE_NOT_GROUP = {
|
||||
'invisible': ~Equal(Eval('produced_animal_type'), 'group')
|
||||
}
|
||||
|
||||
_REQUIRED_IF_GROUP = {'required': Equal(Eval('produced_animal_type'), 'group')}
|
||||
|
||||
|
||||
|
@ -320,6 +321,7 @@ class WeaningEvent(AbstractEvent, ImportedEventMixin):
|
|||
|
||||
if weaning_event.produced_animal_type == 'individual':
|
||||
to_save = []
|
||||
|
||||
for animal in weaning_event.farrowing_animals:
|
||||
animalMove = AnimalMove()
|
||||
animalMove.event = weaning_event
|
||||
|
|
|
@ -301,5 +301,12 @@ this repository contains the full copyright notices and license terms. -->
|
|||
<field name="text">In Transformation Events, the quantity must be 1 for Animals (not Groups).</field>
|
||||
</record>
|
||||
|
||||
<!-- events/reclassification_event.py -->
|
||||
<record model="ir.message" id="invalid_reclassification_product">
|
||||
<field name="text">In reclassification event "%(event)s", the product "%(product)s" is already set to the animal</field>
|
||||
</record>
|
||||
<record model="ir.message" id="related_stock_moves">
|
||||
<field name="text">Reclassification Event "%(event)s" already has the related stock moves: IN: "%(in_move)s", OUT: "%(out_move)s"</field>
|
||||
</record>
|
||||
</data>
|
||||
</tryton>
|
||||
|
|
14
specie.py
14
specie.py
|
@ -97,6 +97,9 @@ class Specie(ModelSQL, ModelView):
|
|||
('individual', 'Individual'),
|
||||
('group', 'Group'),
|
||||
], 'Produced Animal Type')
|
||||
reclassification_products = fields.Many2Many(
|
||||
'farm.specie-product.product', 'specie', 'product',
|
||||
'Reclassification Products')
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
|
@ -403,6 +406,10 @@ class Specie(ModelSQL, ModelView):
|
|||
'farm.weaning.event': Menu(ModelData.get_id(MODULE_NAME,
|
||||
'menu_farm_weaning_event')),
|
||||
},
|
||||
'individual': {
|
||||
'farm.reclassification.event': Menu(ModelData.get_id(MODULE_NAME,
|
||||
'menu_farm_reclassification_event')),
|
||||
}
|
||||
}
|
||||
|
||||
def _duplicate_menu(self, original_menu, parent_menu, sequence,
|
||||
|
@ -644,3 +651,10 @@ class ActionActWindow(metaclass=PoolMeta):
|
|||
class ActionWizard(metaclass=PoolMeta):
|
||||
__name__ = 'ir.action.wizard'
|
||||
specie = fields.Many2One('farm.specie', 'Specie', ondelete='CASCADE')
|
||||
|
||||
class SpecieProduct(ModelSQL):
|
||||
'Specie - Product'
|
||||
__name__ = 'farm.specie-product.product'
|
||||
specie = fields.Many2One('farm.specie', 'Specie', ondelete='CASCADE',
|
||||
required=True)
|
||||
product = fields.Many2One('product.product', 'Product', required=True)
|
||||
|
|
|
@ -88,6 +88,10 @@
|
|||
<field name="group" ref="group_farm_individuals"/>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_farm_reclassification_event"
|
||||
action="act_farm_reclassification_event"
|
||||
parent="menu_farm_animal_individuals" sequence="20"/>
|
||||
|
||||
<!-- Groups -->
|
||||
<menuitem id="menu_farm_animal_groups"
|
||||
action="act_farm_animal_group"
|
||||
|
|
38
stock.py
38
stock.py
|
@ -8,6 +8,8 @@ from trytond.model import ModelView, ModelSQL, fields, Workflow
|
|||
from trytond.pyson import Equal, Eval, Not
|
||||
from trytond.pool import Pool, PoolMeta
|
||||
from trytond.transaction import Transaction
|
||||
from trytond import backend
|
||||
from sql import Table
|
||||
|
||||
|
||||
class Lot(metaclass=PoolMeta):
|
||||
|
@ -20,8 +22,7 @@ class Lot(metaclass=PoolMeta):
|
|||
('individual', 'Individual'),
|
||||
('group', 'Group'),
|
||||
], 'Animal Type', readonly=True)
|
||||
animal = fields.One2One('stock.lot-farm.animal', 'lot', 'animal',
|
||||
string='Animal', readonly=True,
|
||||
animal = fields.Many2One('farm.animal', 'Animal', readonly=True,
|
||||
states={'invisible': Equal(Eval('animal_type'), 'group')},
|
||||
depends=['animal_type'])
|
||||
animal_group = fields.One2One('stock.lot-farm.animal.group', 'lot',
|
||||
|
@ -42,6 +43,27 @@ class Lot(metaclass=PoolMeta):
|
|||
# Consider making configurable per specie if that constraint should
|
||||
# apply to 'group' too but with more than one unit.
|
||||
|
||||
@classmethod
|
||||
def __register__(cls, module_name):
|
||||
TableHandler = backend.get('TableHandler')
|
||||
table = cls.__table_handler__(module_name)
|
||||
sql_table = cls.__table__()
|
||||
update_animal = False
|
||||
if not table.column_exist('animal'):
|
||||
update_animal = True
|
||||
super().__register__(module_name)
|
||||
table = cls.__table_handler__(module_name)
|
||||
if update_animal:
|
||||
sql_table_animal_lot = 'stock_lot-farm_animal'
|
||||
if TableHandler.table_exist(sql_table_animal_lot):
|
||||
sql_table_animal_lot = Table(sql_table_animal_lot)
|
||||
cursor = Transaction().connection.cursor()
|
||||
cursor.execute(*sql_table_animal_lot.select(
|
||||
sql_table_animal_lot.animal, sql_table_animal_lot.lot))
|
||||
for animal_id, lot_id in cursor.fetchall():
|
||||
cursor.execute(*sql_table.update(columns=[sql_table.animal],
|
||||
values=[animal_id], where=sql_table.id == lot_id))
|
||||
|
||||
@staticmethod
|
||||
def default_animal_type():
|
||||
return ''
|
||||
|
@ -132,16 +154,6 @@ class Lot(metaclass=PoolMeta):
|
|||
return res
|
||||
|
||||
|
||||
class LotAnimal(ModelSQL):
|
||||
"Lot - Animal"
|
||||
__name__ = 'stock.lot-farm.animal'
|
||||
|
||||
lot = fields.Many2One('stock.lot', 'Lot', required=True,
|
||||
ondelete='RESTRICT', select=True)
|
||||
animal = fields.Many2One('farm.animal', 'Animal', required=True,
|
||||
ondelete='RESTRICT', select=True)
|
||||
|
||||
|
||||
class LotAnimalGroup(ModelSQL):
|
||||
"Lot - Animal Group"
|
||||
__name__ = 'stock.lot-farm.animal.group'
|
||||
|
@ -376,6 +388,7 @@ class Move(metaclass=PoolMeta):
|
|||
'farm.farrowing.event',
|
||||
'farm.foster.event',
|
||||
'farm.weaning.event',
|
||||
'farm.reclassification.event'
|
||||
]
|
||||
return models
|
||||
|
||||
|
@ -404,5 +417,6 @@ class LotCostLine(metaclass=PoolMeta):
|
|||
'farm.transformation.event',
|
||||
'farm.farrowing.event',
|
||||
'farm.weaning.event',
|
||||
'farm.reclassification.event'
|
||||
]
|
||||
return models
|
||||
|
|
|
@ -35,4 +35,5 @@ xml:
|
|||
events/weaning_event.xml
|
||||
events/feed_inventory.xml
|
||||
events/event_order.xml
|
||||
events/reclassification_event.xml
|
||||
specie_menu_template.xml
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
<field name="initial_location" colspan="3"/>
|
||||
<label name="location"/>
|
||||
<field name="location" colspan="3"/>
|
||||
<label name="lot"/>
|
||||
<field name="lot"/>
|
||||
<!--
|
||||
<label name="lot"/>
|
||||
<field name="lot"/>
|
||||
|
@ -76,6 +78,9 @@
|
|||
<label name="current_weight"/>
|
||||
<field name="current_weight"/>
|
||||
<field name="weights" colspan="4"/>
|
||||
</page>
|
||||
<page name="lots">
|
||||
<field name="lots" colspan="4"/>
|
||||
</page>
|
||||
<page string="Notes" id="notes">
|
||||
<field name="notes"/>
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- The COPYRIGHT file at the top level of this repository contains the full
|
||||
copyright notices and license terms. -->
|
||||
<form>
|
||||
<group id="header" colspan="4" col="6">
|
||||
<label name="farm"/>
|
||||
<field name="farm"/>
|
||||
<label name="timestamp"/>
|
||||
<group col="2" id="timestamp">
|
||||
<field name="timestamp" widget="date"/>
|
||||
<field name="timestamp" widget="time"/>
|
||||
</group>
|
||||
</group>
|
||||
<group id="animal_or_group" colspan="2" col="2">
|
||||
<label name="animal"/>
|
||||
<field name="animal"/>
|
||||
</group>
|
||||
<label name="employee"/>
|
||||
<field name="employee"/>
|
||||
<label name="reclassification_product"/>
|
||||
<field name="reclassification_product"/>
|
||||
<label name="to_location"/>
|
||||
<field name="to_location"/>
|
||||
<newline/>
|
||||
<label name="in_move"/>
|
||||
<field name="in_move"/>
|
||||
<label name="out_move"/>
|
||||
<field name="out_move"/>
|
||||
<separator name="notes" colspan="4"/>
|
||||
<field name="notes" colspan="4"/>
|
||||
<group id="state_and_buttons" colspan="4" col="12">
|
||||
<label name="state"/>
|
||||
<field name="state"/>
|
||||
<button name="draft"/>
|
||||
<button name="validate_event"/>
|
||||
</group>
|
||||
</form>
|
|
@ -0,0 +1,12 @@
|
|||
<?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="animal"/>
|
||||
<field name="animal_group"/>
|
||||
<field name="timestamp" widget="date"/>
|
||||
<field name="timestamp" widget="time"/>
|
||||
<field name="employee"/>
|
||||
<field name="farm"/>
|
||||
<field name="state"/>
|
||||
</tree>
|
|
@ -42,6 +42,7 @@
|
|||
<label name="feed_lost_found_location"/>
|
||||
<field name="feed_lost_found_location"/>
|
||||
</group>
|
||||
<field name="reclassification_products" colspan="4"/>
|
||||
<field name="farm_lines" colspan="4"/>
|
||||
</page>
|
||||
<page string="Menus & Actions" id="actions">
|
||||
|
|
Loading…
Reference in New Issue