Adapt to Tryton 5.2

This commit is contained in:
Albert Cervera i Areny 2019-06-11 00:42:59 +02:00
parent ead83e32c1
commit dd2a59829f
21 changed files with 256 additions and 313 deletions

View File

@ -1,28 +1,32 @@
# The COPYRIGHT file at the top level of this repository contains the full # The COPYRIGHT file at the top level of this repository contains the full
# copyright notices and license terms. # copyright notices and license terms.
from trytond.pool import Pool from trytond.pool import Pool
from .prescription import * from . import prescription
from .specie import * from . import medication_event
from .medication_event import * from . import specie
__all__ = ['Party', 'ProductTemplate', 'Product', 'Move', 'Template',
'TemplateLine', 'Prescription', 'PrescriptionLine', 'PrescriptionAnimal',
'PrescriptionAnimalGroup', 'Location', 'CreateInternalShipmentStart',
'CreateInternalShipment']
def register(): def register():
Pool.register( Pool.register(
Template, prescription.Template,
TemplateLine, prescription.TemplateLine,
Prescription, prescription.Prescription,
PrescriptionLine, prescription.PrescriptionLine,
PrescriptionAnimal, prescription.PrescriptionAnimal,
PrescriptionAnimalGroup, prescription.PrescriptionAnimalGroup,
CreateInternalShipmentStart, prescription.CreateInternalShipmentStart,
Location, prescription.Location,
Move, prescription.Move,
MedicationEvent, medication_event.MedicationEvent,
Party, prescription.Party,
Product, prescription.Product,
ProductTemplate, prescription.ProductTemplate,
Specie, specie.Specie,
module='farm_prescription', type_='model') module='farm_prescription', type_='model')
Pool.register( Pool.register(
CreateInternalShipment, prescription.CreateInternalShipment,
module='farm_prescription', type_='wizard') module='farm_prescription', type_='wizard')

View File

@ -8,10 +8,9 @@ from trytond.modules.farm.events.abstract_event import (
_STATES_WRITE_DRAFT_VALIDATED, _DEPENDS_WRITE_DRAFT_VALIDATED) _STATES_WRITE_DRAFT_VALIDATED, _DEPENDS_WRITE_DRAFT_VALIDATED)
__all__ = ['MedicationEvent'] __all__ = ['MedicationEvent']
__metaclass__ = PoolMeta
class MedicationEvent: class MedicationEvent(metaclass=PoolMeta):
__name__ = 'farm.medication.event' __name__ = 'farm.medication.event'
prescription = fields.Many2One('farm.prescription', 'Prescription', prescription = fields.Many2One('farm.prescription', 'Prescription',
select=True, domain=[ select=True, domain=[

41
message.xml Normal file
View File

@ -0,0 +1,41 @@
<?xml version="1.0"?>
<tryton>
<data group="1">
<record model="ir.message" id="msg_template_related_to_product_or_prescription">
<field name="text">You can not change the Feed Product of Prescription Template "%(template)s" because there are products or prescriptions already related to this template.\nPlease, create a new template.</field>
</record>
<record model="ir.message" id="msg_lines_will_be_replaced">
<field name="text">Current values of prescription "%(prescription)s" will be replaced.</field>
</record>
<record model="ir.message" id="msg_lot_required_done">
<field name="text">Lot is required to set done the prescription "%(prescription)s".</field>
</record>
<record model="ir.message" id="msg_lot_expired">
<field name="text">The lot "%(lot)s" used in prescription "%(prescription)s" has expired.</field>
</record>
<record model="ir.message" id="msg_veterinarian_required_confirmed">
<field name="text">Veterinarian is requried to confirm the prescription "%(prescription)s".</field>
</record>
<record model="ir.message" id="msg_lines_required_confirmed">
<field name="text">The prescription "%(prescription)s" must have at least one line in order to be confirmed.</field>
</record>
<record model="ir.message" id="msg_from_prescription_line_invalid_prescription">
<field name="text">The Stock Move "%(move)s" has the Prescription Line "%(origin)s" as origin, but it isn't related to a Prescription or it isn't the origin's prescription.</field>
</record>
<record model="ir.message" id="msg_from_prescription_line_invalid_product_quantity">
<field name="text">The Stock Move "%(move)s" has the Prescription Line "%(origin)s" as origin, but the product and/or quantity are not the same.</field>
</record>
<record model="ir.message" id="msg_prescription_invalid_product_quantity">
<field name="text">The Stock Move "%(move)s" is related to Prescription "%(prescription)s", but the product and/or quantity are not the same.</field>
</record>
<record model="ir.message" id="msg_need_prescription">
<field name="text">Move "%(move)s" needs a confirmed prescription.</field>
</record>
<record model="ir.message" id="msg_unconfirmed_prescription">
<field name="text">Prescription "%(prescription)s" of move "%(move)s" must be confirmed before assigning the move.</field>
</record>
<record model="ir.message" id="msg_prescription_used">
<field name="text">The prescription "%(prescription)s" is used in internal shipment "%(shipment)s".</field>
</record>
</data>
</tryton>

View File

@ -10,12 +10,13 @@ from trytond.transaction import Transaction
from trytond.wizard import Wizard, StateView, StateAction, Button from trytond.wizard import Wizard, StateView, StateAction, Button
from trytond.pyson import Bool, Date, Equal, Eval, If, Or from trytond.pyson import Bool, Date, Equal, Eval, If, Or
from trytond import backend from trytond import backend
from trytond.exceptions import UserError, UserWarning
from trytond.i18n import gettext
__all__ = ['Party', 'ProductTemplate', 'Product', 'Move', 'Template', __all__ = ['Party', 'ProductTemplate', 'Product', 'Move', 'Template',
'TemplateLine', 'Prescription', 'PrescriptionLine', 'PrescriptionAnimal', 'TemplateLine', 'Prescription', 'PrescriptionLine', 'PrescriptionAnimal',
'PrescriptionAnimalGroup', 'Location', 'CreateInternalShipmentStart', 'PrescriptionAnimalGroup', 'Location', 'CreateInternalShipmentStart',
'CreateInternalShipment'] 'CreateInternalShipment']
__metaclass__ = PoolMeta
_STATES = { _STATES = {
'readonly': Eval('state') != 'draft', 'readonly': Eval('state') != 'draft',
@ -27,7 +28,7 @@ _STATES_REQUIRED = {
_DEPENDS = ['state'] _DEPENDS = ['state']
class Party: class Party(metaclass=PoolMeta):
__name__ = 'party.party' __name__ = 'party.party'
veterinarian = fields.Boolean('Veterinarian') veterinarian = fields.Boolean('Veterinarian')
@ -37,13 +38,13 @@ class Party:
}, depends=['veterinarian']) }, depends=['veterinarian'])
class ProductTemplate: class ProductTemplate(metaclass=PoolMeta):
__name__ = 'product.template' __name__ = 'product.template'
prescription_required = fields.Boolean('Prescription required') prescription_required = fields.Boolean('Prescription required')
class Product: class Product(metaclass=PoolMeta):
__name__ = 'product.product' __name__ = 'product.product'
prescription_required = fields.Function(fields.Boolean( prescription_required = fields.Function(fields.Boolean(
@ -224,21 +225,10 @@ class Template(ModelSQL, ModelView, PrescriptionMixin):
}, },
depends=['type']) depends=['type'])
@classmethod
def __setup__(cls):
super(Template, cls).__setup__()
cls._error_messages.update({
'template_related_to_product_or_prescription': (
'You can not change the Feed Product of Prescription '
'Template "%s" because there are products or '
'rescriptions already related to this template.\n'
'Please, create a new template.'),
})
@classmethod @classmethod
def __register__(cls, module_name): def __register__(cls, module_name):
TableHandler = backend.get('TableHandler') TableHandler = backend.get('TableHandler')
cursor = Transaction().connection.cursor cursor = Transaction().connection.cursor()
table = TableHandler(cls, module_name) table = TableHandler(cls, module_name)
sql_table = cls.__table__() sql_table = cls.__table__()
product = Table('product_product') product = Table('product_product')
@ -266,10 +256,8 @@ class Template(ModelSQL, ModelView, PrescriptionMixin):
@fields.depends('product', 'name') @fields.depends('product', 'name')
def on_change_product(self): def on_change_product(self):
changes = {}
if self.product and not self.name: if self.product and not self.name:
changes['name'] = self.product.rec_name self.name = self.product.rec_name
return changes
@classmethod @classmethod
def write(cls, *args): def write(cls, *args):
@ -288,9 +276,9 @@ class Template(ModelSQL, ModelView, PrescriptionMixin):
('template', '=', template.id), ('template', '=', template.id),
]) ])
if n_template_products or n_template_prescriptions: if n_template_products or n_template_prescriptions:
cls.raise_user_error( raise UserError(gettext('farm.prescription.msg_'
'template_related_to_product_or_prescription', 'template_related_to_product_or_prescription',
(template.rec_name,)) template=template.rec_name))
super(Template, cls).write(*args) super(Template, cls).write(*args)
@ -426,7 +414,7 @@ class Prescription(Workflow, ModelSQL, ModelView, PrescriptionMixin):
cls.product.depends = ['template'] cls.product.depends = ['template']
cls.unit.on_change_with.add('template') cls.unit.on_change_with.add('template')
if hasattr(Lot, 'expiry_date'): if hasattr(Lot, 'expiration_date'):
cls.lot.domain.append( cls.lot.domain.append(
If(Eval('state') != 'done', If(Eval('state') != 'done',
('expired', '=', False), ('expired', '=', False),
@ -438,18 +426,6 @@ class Prescription(Workflow, ModelSQL, ModelView, PrescriptionMixin):
cls.lot.context['stock_move_date'] = Eval('delivery_date', Date()) cls.lot.context['stock_move_date'] = Eval('delivery_date', Date())
cls.lot.depends += ['delivery_date'] cls.lot.depends += ['delivery_date']
cls._error_messages.update({
'lines_will_be_replaced': (
'Current values of prescription "%s" will be replaced.'),
'lot_required_done': ('Lot is required to set done the '
'prescription "%s".'),
'lot_expired': ('The lot "%(lot)s" used in prescription '
'"%(prescription)s" has expired.'),
'veterinarian_required_confirmed': ('Veterinarian is requried '
'to confirm the prescription "%s".'),
'lines_required_confirmed': ('The prescription "%s" must have '
'at least one line in order to be confirmed.'),
})
cls._transitions |= set(( cls._transitions |= set((
('draft', 'confirmed'), ('draft', 'confirmed'),
('confirmed', 'done'), ('confirmed', 'done'),
@ -476,20 +452,18 @@ class Prescription(Workflow, ModelSQL, ModelView, PrescriptionMixin):
return 'draft' return 'draft'
def get_rec_name(self, name): def get_rec_name(self, name):
return u'%s - %s (%s)' % (self.reference, return '%s - %s (%s)' % (self.reference,
self.product.rec_name, str(self.date)) self.product.rec_name, str(self.date))
@fields.depends('template') @fields.depends('template')
def on_change_template(self): def on_change_template(self):
changes = {}
if self.template: if self.template:
self.product = self.template.product self.product = self.template.product
return changes
@fields.depends('animals', 'animals_groups') @fields.depends('animals', 'animal_groups')
def on_change_with_number_of_animals(self): def on_change_with_number_of_animals(self):
animals = len(self.animals) animals = len(self.animals or [])
for group in self.animal_groups: for group in (self.animal_groups or []):
animals += group.quantity animals += group.quantity
return animals return animals
@ -532,11 +506,13 @@ class Prescription(Workflow, ModelSQL, ModelView, PrescriptionMixin):
def confirm(cls, prescriptions): def confirm(cls, prescriptions):
for prescription in prescriptions: for prescription in prescriptions:
if not prescription.veterinarian: if not prescription.veterinarian:
cls.raise_user_error('veterinarian_required_confirmed', raise UserError(gettext('farm_prescription.'
prescription.rec_name) 'msg_veterinarian_required_confirmed',
prescription=prescription.rec_name))
if prescription.type != 'medical' and not prescription.lines: if prescription.type != 'medical' and not prescription.lines:
cls.raise_user_error('lines_required_confirmed', raise UserError(gettext(
prescription.rec_name) 'farm_prescription.msg_lines_required_confirmed',
prescription=prescription.rec_name))
@classmethod @classmethod
@ModelView.button @ModelView.button
@ -548,19 +524,20 @@ class Prescription(Workflow, ModelSQL, ModelView, PrescriptionMixin):
stock_move_date = Transaction().context.get('stock_move_date') stock_move_date = Transaction().context.get('stock_move_date')
for prescription in prescriptions: for prescription in prescriptions:
if not prescription.lot: if not prescription.lot:
cls.raise_user_error('lot_required_done', raise UserError(gettext('farm_prescription.'
prescription.rec_name) 'msg_lot_required_done',
if hasattr(prescription.lot, 'expiry_date'): prescription=prescription.rec_name))
if hasattr(prescription.lot, 'expiration_date'):
prescription_date = prescription.delivery_date prescription_date = prescription.delivery_date
if stock_move_date: if stock_move_date:
prescription_date = max(prescription_date, stock_move_date) prescription_date = max(prescription_date, stock_move_date)
with Transaction().set_context( with Transaction().set_context(
stock_move_date=prescription_date): stock_move_date=prescription_date):
if Lot(prescription.lot.id).expired: if Lot(prescription.lot.id).expired:
cls.raise_user_error('lot_expired', { raise UserError(gettext('msg_lot_expired',
'lot': prescription.lot.rec_name, lot=prescription.lot.rec_name,
'prescription': prescription.rec_name, prescription=prescription.rec_name,
}) ))
@classmethod @classmethod
@ModelView.button @ModelView.button
@ -568,10 +545,9 @@ class Prescription(Workflow, ModelSQL, ModelView, PrescriptionMixin):
for prescription in prescriptions: for prescription in prescriptions:
if not prescription.template: if not prescription.template:
continue continue
raise UserWarning(gettext('replace_lines',
cls.raise_user_warning('replace_lines', 'lines_will_be_replaced', 'farm_prescription.msg_lines_will_be_replaced',
prescription.rec_name) prescription=prescription.rec_name))
prescription.set_template_vals() prescription.set_template_vals()
prescription.save() prescription.save()
@ -588,7 +564,7 @@ class Prescription(Workflow, ModelSQL, ModelView, PrescriptionMixin):
self.afection = self.template.afection self.afection = self.template.afection
self.dosage = self.template.dosage self.dosage = self.template.dosage
self.waiting_period = self.template.waiting_period self.waiting_period = self.template.waiting_period
self.expiry_period = self.template.expiry_period self.expiration_period = self.template.expiration_time
rate = self.get_factor_change_quantity_unit(self.template.quantity, rate = self.get_factor_change_quantity_unit(self.template.quantity,
self.template.unit) self.template.unit)
@ -672,33 +648,10 @@ class PrescriptionLine(ModelSQL, ModelView, PrescriptionLineMixin):
self.quantity = Uom.round(quantity, self.unit.rounding) self.quantity = Uom.round(quantity, self.unit.rounding)
class Move: class Move(metaclass=PoolMeta):
__name__ = 'stock.move' __name__ = 'stock.move'
prescription = fields.Many2One('farm.prescription', 'Prescription') prescription = fields.Many2One('farm.prescription', 'Prescription')
@classmethod
def __setup__(cls):
super(Move, cls).__setup__()
cls._error_messages.update({
'from_prescription_line_invalid_prescription': (
'The Stock Move "%(move)s" has the Prescription Line '
'"%(origin)s" as origin, but it isn\'t related to a '
'Prescription or it isn\'t the origin\'s prescription.'),
'from_prescription_line_invalid_product_quantity': (
'The Stock Move "%(move)s" has the Prescription Line '
'"%(origin)s" as origin, but the product and/or quantity '
'are not the same.'),
'prescription_invalid_product_quantity': (
'The Stock Move "%(move)s" is related to Prescription '
'"%(prescription)s", but the product and/or quantity are '
'not the same.'),
'need_prescription': ('Move "%s" needs a confirmed '
'prescription'),
'unconfirmed_prescription': ('Prescription "%s" of move "%s" '
'must be confirmed before assigning the move'),
})
@classmethod @classmethod
def _get_origin(cls): def _get_origin(cls):
models = super(Move, cls)._get_origin() models = super(Move, cls)._get_origin()
@ -724,30 +677,30 @@ class Move:
if self.origin and isinstance(self.origin, PrescriptionLine): if self.origin and isinstance(self.origin, PrescriptionLine):
if (not self.prescription or if (not self.prescription or
self.origin.prescription != self.prescription): self.origin.prescription != self.prescription):
self.raise_user_error( raise UserError(gettext('farm_prescription.'
'from_prescription_line_invalid_prescription', { 'msg_from_prescription_line_invalid_prescription',
'move': self.rec_name, move=self.rec_name,
'origin': self.origin.rec_name, origin=self.origin.rec_name,
}) ))
if (self.product != self.origin.product or if (self.product != self.origin.product or
self.quantity != Uom.compute_qty(self.origin.unit, self.quantity != Uom.compute_qty(self.origin.unit,
self.origin.quantity, self.uom)): self.origin.quantity, self.uom)):
self.raise_user_error( raise UserError(gettext('farm_prescription.'
'from_prescription_line_invalid_product_quantity', { 'msg_from_prescription_line_invalid_product_quantity',
'move': self.rec_name, move=self.rec_name,
'origin': self.origin.rec_name, origin=self.origin.rec_name,
}) ))
elif self.prescription: elif self.prescription:
quantity = Uom.compute_qty(self.prescription.unit, quantity = Uom.compute_qty(self.prescription.unit,
self.prescription.quantity + self.prescription.drug_quantity, self.prescription.quantity + self.prescription.drug_quantity,
self.uom) self.uom)
if (self.product != self.prescription.product or if (self.product != self.prescription.product or
self.quantity != quantity): self.quantity != quantity):
self.raise_user_error( raise UserError(gettext('farm_prescription.'
'prescription_invalid_product_quantity', { 'msg_prescription_invalid_product_quantity',
'move': self.rec_name, move=self.rec_name,
'prescription': self.prescription.rec_name, prescription=self.prescription.rec_name,
}) ))
@classmethod @classmethod
def assign(cls, moves): def assign(cls, moves):
@ -771,14 +724,17 @@ class Move:
and not isinstance(self.shipment, ShipmentIn) and not isinstance(self.shipment, ShipmentIn)
and not isinstance(self.origin, FeedEvent)): and not isinstance(self.origin, FeedEvent)):
# Purchases don't require prescription because are made to stock # Purchases don't require prescription because are made to stock
self.raise_user_error('need_prescription', self.rec_name) raise UserError(gettext('farm_prescription.msg_need_prescription',
move=self.rec_name))
if self.prescription: if self.prescription:
if self.prescription.state == 'draft': if self.prescription.state == 'draft':
self.raise_user_error('unconfirmed_prescription', raise UserError(gettext('farm_prescription.'
(self.prescription.rec_name, self.rec_name)) 'msg_unconfirmed_prescription',
prescription=self.prescription.rec_name,
move=self.rec_name))
class Location: class Location(metaclass=PoolMeta):
__name__ = 'stock.location' __name__ = 'stock.location'
prescription_required = fields.Boolean('Prescription required') prescription_required = fields.Boolean('Prescription required')
@ -817,14 +773,6 @@ class CreateInternalShipment(Wizard):
]) ])
create_ = StateAction('stock.act_shipment_internal_form') create_ = StateAction('stock.act_shipment_internal_form')
@classmethod
def __setup__(cls):
super(CreateInternalShipment, cls).__setup__()
cls._error_messages.update({
'prescription_used': (
'The prescription %s is used in internal shipment %s.'),
})
def default_start(self, fields): def default_start(self, fields):
pool = Pool() pool = Pool()
Move = pool.get('stock.move') Move = pool.get('stock.move')
@ -837,9 +785,11 @@ class CreateInternalShipment(Wizard):
move = Move.search([ move = Move.search([
('prescription', '=', prescription)]) ('prescription', '=', prescription)])
if move: if move:
self.raise_user_error('prescription_used', ( raise UserError(gettext('farm_prescription.'
prescription.reference, move[0].shipment and \ 'msg_prescription_used',
move[0].shipment.code or move[0].id)) prescription=prescription.reference,
shipment=(move[0].shipment and move[0].shipment.code
or move[0].id)))
return { return {
'from_location': None, 'from_location': None,
'farm': farm.id, 'farm': farm.id,
@ -849,7 +799,6 @@ class CreateInternalShipment(Wizard):
pool = Pool() pool = Pool()
Prescription = Pool().get('farm.prescription') Prescription = Pool().get('farm.prescription')
Shipment = pool.get('stock.shipment.internal') Shipment = pool.get('stock.shipment.internal')
Move = pool.get('stock.move')
Company = pool.get('company.company') Company = pool.get('company.company')
prescriptions = Prescription.browse( prescriptions = Prescription.browse(

View File

@ -161,45 +161,32 @@
<record model="ir.action.act_window" id="act_medical_prescription"> <record model="ir.action.act_window" id="act_medical_prescription">
<field name="name">Medical Prescription</field> <field name="name">Medical Prescription</field>
<field name="res_model">farm.prescription</field> <field name="res_model">farm.prescription</field>
<field name="domain" <field name="domain" eval="[('type', '=', 'medical')]" pyson="1"/>
eval="[('type', '=', 'medical')]" <field name="context" eval="{'type': 'medical'}" pyson="1"/>
pyson="1"/>
<field name="context"
eval="{'type': 'medical'}"
pyson="1"/>
</record> </record>
<record model="ir.action.act_window.view" <record model="ir.action.act_window.view" id="act_medical_prescription_view1">
id="act_medical_prescription_view1">
<field name="sequence" eval="10"/> <field name="sequence" eval="10"/>
<field name="view" ref="prescription_view_list"/> <field name="view" ref="prescription_view_list"/>
<field name="act_window" ref="act_medical_prescription"/> <field name="act_window" ref="act_medical_prescription"/>
</record> </record>
<record model="ir.action.act_window.view" <record model="ir.action.act_window.view" id="act_medical_prescription_view2">
id="act_medical_prescription_view2">
<field name="sequence" eval="20"/> <field name="sequence" eval="20"/>
<field name="view" ref="prescription_view_form"/> <field name="view" ref="prescription_view_form"/>
<field name="act_window" ref="act_medical_prescription"/> <field name="act_window" ref="act_medical_prescription"/>
</record> </record>
<record model="ir.action.act_window.domain" <record model="ir.action.act_window.domain" id="act_medical_prescription_draft">
id="act_medical_prescription_draft">
<field name="name">Draft</field> <field name="name">Draft</field>
<field name="sequence" eval="10"/> <field name="sequence" eval="10"/>
<field name="domain" <field name="domain" eval="[('state', '=', 'draft')]" pyson="1"/>
eval="[('state', '=', 'draft')]"
pyson="1"/>
<field name="act_window" ref="act_medical_prescription"/> <field name="act_window" ref="act_medical_prescription"/>
</record> </record>
<record model="ir.action.act_window.domain" <record model="ir.action.act_window.domain" id="act_medical_prescription_confirmed">
id="act_medical_prescription_confirmed">
<field name="name">Confirmed</field> <field name="name">Confirmed</field>
<field name="sequence" eval="20"/> <field name="sequence" eval="20"/>
<field name="domain" <field name="domain" eval="[('state', '=', 'confirmed')]" pyson="1"/>
eval="[('state', '=', 'confirmed')]"
pyson="1"/>
<field name="act_window" ref="act_medical_prescription"/> <field name="act_window" ref="act_medical_prescription"/>
</record> </record>
<record model="ir.action.act_window.domain" <record model="ir.action.act_window.domain" id="act_medical_prescription_all">
id="act_medical_prescription_all">
<field name="name">All</field> <field name="name">All</field>
<field name="sequence" eval="9999"/> <field name="sequence" eval="9999"/>
<field name="act_window" ref="act_medical_prescription"/> <field name="act_window" ref="act_medical_prescription"/>
@ -207,62 +194,46 @@
<record model="ir.action.act_window" id="act_feed_prescription"> <record model="ir.action.act_window" id="act_feed_prescription">
<field name="name">Feed Prescription</field> <field name="name">Feed Prescription</field>
<field name="res_model">farm.prescription</field> <field name="res_model">farm.prescription</field>
<field name="domain" <field name="domain" eval="[('type', '=', 'feed')]" pyson="1"/>
eval="[('type', '=', 'feed')]" <field name="context" eval="{'type': 'feed'}" pyson="1"/>
pyson="1"/>
<field name="context"
eval="{'type': 'feed'}"
pyson="1"/>
</record> </record>
<record model="ir.action.act_window.view" <record model="ir.action.act_window.view" id="act_feed_prescription_view1">
id="act_feed_prescription_view1">
<field name="sequence" eval="10"/> <field name="sequence" eval="10"/>
<field name="view" ref="prescription_view_list"/> <field name="view" ref="prescription_view_list"/>
<field name="act_window" ref="act_feed_prescription"/> <field name="act_window" ref="act_feed_prescription"/>
</record> </record>
<record model="ir.action.act_window.view" <record model="ir.action.act_window.view" id="act_feed_prescription_view2">
id="act_feed_prescription_view2">
<field name="sequence" eval="20"/> <field name="sequence" eval="20"/>
<field name="view" ref="prescription_view_form"/> <field name="view" ref="prescription_view_form"/>
<field name="act_window" ref="act_feed_prescription"/> <field name="act_window" ref="act_feed_prescription"/>
</record> </record>
<record model="ir.action.act_window.domain" <record model="ir.action.act_window.domain" id="act_feed_prescription_draft">
id="act_feed_prescription_draft">
<field name="name">Draft</field> <field name="name">Draft</field>
<field name="sequence" eval="10"/> <field name="sequence" eval="10"/>
<field name="domain" <field name="domain" eval="[('state', '=', 'draft')]" pyson="1"/>
eval="[('state', '=', 'draft')]"
pyson="1"/>
<field name="act_window" ref="act_feed_prescription"/> <field name="act_window" ref="act_feed_prescription"/>
</record> </record>
<record model="ir.action.act_window.domain" <record model="ir.action.act_window.domain" id="act_feed_prescription_confirmed">
id="act_feed_prescription_confirmed">
<field name="name">Confirmed</field> <field name="name">Confirmed</field>
<field name="sequence" eval="20"/> <field name="sequence" eval="20"/>
<field name="domain" <field name="domain" eval="[('state', '=', 'confirmed')]" pyson="1"/>
eval="[('state', '=', 'confirmed')]"
pyson="1"/>
<field name="act_window" ref="act_feed_prescription"/> <field name="act_window" ref="act_feed_prescription"/>
</record> </record>
<record model="ir.action.act_window.domain" <record model="ir.action.act_window.domain" id="act_feed_prescription_all">
id="act_feed_prescription_all">
<field name="name">All</field> <field name="name">All</field>
<field name="sequence" eval="9999"/> <field name="sequence" eval="9999"/>
<field name="act_window" ref="act_feed_prescription"/> <field name="act_window" ref="act_feed_prescription"/>
</record> </record>
<record model="ir.model.access" id="access_prescription"> <record model="ir.model.access" id="access_prescription">
<field name="model" <field name="model" search="[('model', '=', 'farm.prescription')]"/>
search="[('model', '=', 'farm.prescription')]"/>
<field name="perm_read" eval="True"/> <field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/> <field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/> <field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/> <field name="perm_delete" eval="False"/>
</record> </record>
<record model="ir.model.access" <record model="ir.model.access" id="access_prescription_group_prescription">
id="access_prescription_group_prescription"> <field name="model" search="[('model', '=', 'farm.prescription')]"/>
<field name="model"
search="[('model', '=', 'farm.prescription')]"/>
<field name="group" ref="group_prescription"/> <field name="group" ref="group_prescription"/>
<field name="perm_read" eval="True"/> <field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/> <field name="perm_write" eval="True"/>
@ -272,15 +243,31 @@
<record model="ir.model.button" id="prescription_confirm_button"> <record model="ir.model.button" id="prescription_confirm_button">
<field name="name">confirm</field> <field name="name">confirm</field>
<field name="model" <field name="model" search="[('model', '=', 'farm.prescription')]"/>
search="[('model', '=', 'farm.prescription')]"/>
</record> </record>
<record model="ir.model.button-res.group" <record model="ir.model.button-res.group" id="prescription_confirm_button_group_veterinarian">
id="prescription_confirm_button_group_veterinarian">
<field name="button" ref="prescription_confirm_button"/> <field name="button" ref="prescription_confirm_button"/>
<field name="group" ref="group_veterinarian"/> <field name="group" ref="group_veterinarian"/>
</record> </record>
<record model="ir.model.button" id="prescription_set_template_button">
<field name="name">set_template</field>
<field name="model" search="[('model', '=', 'farm.prescription')]"/>
</record>
<record model="ir.model.button-res.group" id="prescription_set_template_button_group_veterinarian">
<field name="button" ref="prescription_set_template_button"/>
<field name="group" ref="group_veterinarian"/>
</record>
<record model="ir.model.button" id="prescription_done_button">
<field name="name">done</field>
<field name="model" search="[('model', '=', 'farm.prescription')]"/>
</record>
<record model="ir.model.button-res.group" id="prescription_done_button_group_veterinarian">
<field name="button" ref="prescription_done_button"/>
<field name="group" ref="group_veterinarian"/>
</record>
<!-- farm.prescription.line --> <!-- farm.prescription.line -->
<record model="ir.ui.view" id="prescription_line_view_form"> <record model="ir.ui.view" id="prescription_line_view_form">
<field name="model">farm.prescription.line</field> <field name="model">farm.prescription.line</field>
@ -333,14 +320,12 @@
<!-- party.party --> <!-- party.party -->
<record model="ir.ui.view" id="party_view_form"> <record model="ir.ui.view" id="party_view_form">
<field name="model">party.party</field> <field name="model">party.party</field>
<field name="type" eval="None"/>
<field name="inherit" ref="party.party_view_form"/> <field name="inherit" ref="party.party_view_form"/>
<field name="name">party_form</field> <field name="name">party_form</field>
</record> </record>
<record model="ir.ui.view" id="party_view_list"> <record model="ir.ui.view" id="party_view_list">
<field name="model">party.party</field> <field name="model">party.party</field>
<field name="type" eval="None"/>
<field name="inherit" ref="party.party_view_tree"/> <field name="inherit" ref="party.party_view_tree"/>
<field name="name">party_list</field> <field name="name">party_list</field>
</record> </record>
@ -348,7 +333,6 @@
<!-- product.template --> <!-- product.template -->
<record model="ir.ui.view" id="product_template_view_form"> <record model="ir.ui.view" id="product_template_view_form">
<field name="model">product.template</field> <field name="model">product.template</field>
<field name="type" eval="None"/>
<field name="inherit" ref="product.template_view_form"/> <field name="inherit" ref="product.template_view_form"/>
<field name="name">product_template_form</field> <field name="name">product_template_form</field>
</record> </record>
@ -424,13 +408,11 @@
<record model="ir.ui.view" id="location_view_form"> <record model="ir.ui.view" id="location_view_form">
<field name="model">stock.location</field> <field name="model">stock.location</field>
<field name="type">form</field>
<field name="inherit" ref="stock.location_view_form"/> <field name="inherit" ref="stock.location_view_form"/>
<field name="name">location_form</field> <field name="name">location_form</field>
</record> </record>
<record model="ir.ui.view" id="location_view_list"> <record model="ir.ui.view" id="location_view_list">
<field name="model">stock.location</field> <field name="model">stock.location</field>
<field name="type">tree</field>
<field name="inherit" ref="stock.location_view_list"/> <field name="inherit" ref="stock.location_view_list"/>
<field name="name">location_list</field> <field name="name">location_list</field>
</record> </record>

View File

@ -4,7 +4,7 @@
from setuptools import setup from setuptools import setup
import re import re
import os import os
import ConfigParser import configparser
MODULE = 'recipts' MODULE = 'recipts'
PREFIX = 'nantic' PREFIX = 'nantic'
@ -14,7 +14,7 @@ MODULE2PREFIX = {}
def read(fname): def read(fname):
return open(os.path.join(os.path.dirname(__file__), fname)).read() return open(os.path.join(os.path.dirname(__file__), fname)).read()
config = ConfigParser.ConfigParser() config = configparser.ConfigParser()
config.readfp(open('tryton.cfg')) config.readfp(open('tryton.cfg'))
info = dict(config.items('tryton')) info = dict(config.items('tryton'))
for key in ('depends', 'extras_depend', 'xml'): for key in ('depends', 'extras_depend', 'xml'):

View File

@ -5,12 +5,11 @@ from trytond.pool import Pool, PoolMeta
from trytond.pyson import Bool, Eval, Not from trytond.pyson import Bool, Eval, Not
__all__ = ['Specie'] __all__ = ['Specie']
__metaclass__ = PoolMeta
MODULE_NAME = "farm_prescription" MODULE_NAME = "farm_prescription"
class Specie: class Specie(metaclass=PoolMeta):
__name__ = 'farm.specie' __name__ = 'farm.specie'
prescription_enabled = fields.Boolean('Prescriptions Enabled', prescription_enabled = fields.Boolean('Prescriptions Enabled',

View File

@ -9,59 +9,28 @@ Imports::
>>> from decimal import Decimal >>> from decimal import Decimal
>>> from operator import attrgetter >>> from operator import attrgetter
>>> from proteus import config, Model, Wizard >>> from proteus import config, Model, Wizard
>>> from trytond.tests.tools import activate_modules
>>> from trytond.modules.company.tests.tools import create_company, \
... get_company
>>> today = datetime.date.today() >>> today = datetime.date.today()
Create config:: Activate module::
>>> config = config.set_trytond() >>> config = activate_modules('farm_prescription')
>>> config.pool.test = True
Install Prescriptions::
>>> Module = Model.get('ir.module.module')
>>> module, = Module.find([('name', '=', 'farm_prescription')])
>>> Module.install ([module.id], config.context)
>>> Wizard('ir.module.module.install_upgrade').execute('upgrade')
Create company:: Create company::
>>> Currency = Model.get('currency.currency') >>> _ = create_company()
>>> CurrencyRate = Model.get('currency.currency.rate') >>> company = get_company()
>>> Company = Model.get('company.company')
>>> Party = Model.get('party.party')
>>> company_config = Wizard('company.company.config')
>>> company_config.execute('company')
>>> company = company_config.form
>>> party = Party(name='Dunder Mifflin')
>>> party.save()
>>> company.party = party
>>> currencies = Currency.find([('code', '=', 'USD')])
>>> if not currencies:
... currency = Currency(name='U.S. Dollar', symbol='$', code='USD',
... rounding=Decimal('0.01'), mon_grouping='[3, 3, 0]',
... mon_decimal_point='.', mon_thousands_sep=',')
... currency.save()
... CurrencyRate(date=today + relativedelta(month=1, day=1),
... rate=Decimal('1.0'), currency=currency).save()
... else:
... currency, = currencies
>>> company.currency = currency
>>> company_config.execute('add')
>>> company, = Company.find()
Reload the context::
>>> User = Model.get('res.user')
>>> config._context = User.get_preferences(True, config.context)
Create inner location:: Create inner location::
>>> Location = Model.get('stock.location') >>> Location = Model.get('stock.location')
>>> inner_farm = Location() >>> inner_farm = Location()
>>> inner_farm.name = "Test Farm/Inner Farm" >>> inner_farm.name = "Test Farm/Inner Farm"
>>> inner_farm.code = "TFARMI" >>> inner_farm.code = "TFARMI"
>>> inner_farm.type = "storage" >>> inner_farm.type = "storage"
>>> inner_farm.save() >>> inner_farm.save()
Check location has 'requires prescription' checked:: Check location has 'requires prescription' checked::
@ -70,30 +39,30 @@ Check location has 'requires prescription' checked::
Create production location:: Create production location::
>>> production_farm = Location() >>> production_farm = Location()
>>> production_farm.name = "Test Farm/Production Farm" >>> production_farm.name = "Test Farm/Production Farm"
>>> production_farm.code = "TFARMP" >>> production_farm.code = "TFARMP"
>>> production_farm.type = "production" >>> production_farm.type = "production"
>>> production_farm.save() >>> production_farm.save()
Create lost and found:: Create lost and found::
>>> lost_n_found = Location() >>> lost_n_found = Location()
>>> lost_n_found.name = "Test Lost and Found" >>> lost_n_found.name = "Test Lost and Found"
>>> lost_n_found.code = "TLNF" >>> lost_n_found.code = "TLNF"
>>> lost_n_found.type = "lost_found" >>> lost_n_found.type = "lost_found"
>>> lost_n_found.save() >>> lost_n_found.save()
Create farm:: Create farm::
>>> farm = Location() >>> farm = Location()
>>> farm.name = "Test Farm" >>> farm.name = "Test Farm"
>>> farm.code = "TFARM" >>> farm.code = "TFARM"
>>> farm.input_location = inner_farm >>> farm.input_location = inner_farm
>>> farm.output_location = inner_farm >>> farm.output_location = inner_farm
>>> farm.storage_location = inner_farm >>> farm.storage_location = inner_farm
>>> farm.production_location = production_farm >>> farm.production_location = production_farm
>>> farm.save() >>> farm.save()
Create products:: Create products::
@ -147,7 +116,7 @@ Create sequence::
Create species:: Create species::
>>> Specie = Model.get('farm.specie') >>> Specie = Model.get('farm.specie')
>>> SpecieBreed = Model.get('farm.specie.breed') >>> SpecieBreed = Model.get('farm.specie.breed')
>>> SpecieFarmLine = Model.get('farm.specie.farm_line') >>> SpecieFarmLine = Model.get('farm.specie.farm_line')
>>> warehouse, = Location.find([('type', '=', 'warehouse')]) >>> warehouse, = Location.find([('type', '=', 'warehouse')])
@ -159,8 +128,8 @@ Create species::
... individual_product=individual_product, ... individual_product=individual_product,
... group_enabled=True, ... group_enabled=True,
... group_product=group_product, ... group_product=group_product,
... prescription_enabled=True, ... prescription_enabled=True,
... prescription_sequence=prescription_sequence, ... prescription_sequence=prescription_sequence,
... removed_location=lost_n_found, ... removed_location=lost_n_found,
... foster_location=lost_n_found, ... foster_location=lost_n_found,
... lost_found_location=lost_n_found, ... lost_found_location=lost_n_found,
@ -182,39 +151,41 @@ Create species::
Create medicine product:: Create medicine product::
>>> ProductTemplate = Model.get('product.template') >>> ProductTemplate = Model.get('product.template')
>>> ProductUOM = Model.get('product.uom') >>> ProductUOM = Model.get('product.uom')
>>> product_template = ProductTemplate() >>> product_template = ProductTemplate()
>>> product_template.name = "Template product test" >>> product_template.name = "Template product test"
>>> product_template.type = 'goods' >>> product_template.type = 'goods'
>>> product_template.unique_variant = True >>> product_template.unique_variant = True
>>> product_template.prescription_required = True >>> product_template.prescription_required = True
>>> product_template.cost_price = Decimal('00.00') >>> product_template.cost_price = Decimal('00.00')
>>> product_template.list_price = Decimal('00.00') >>> product_template.list_price = Decimal('00.00')
>>> uom, = ProductUOM.find([('name', '=', 'Unit')]) >>> uom, = ProductUOM.find([('name', '=', 'Unit')])
>>> product_template.default_uom = uom >>> product_template.default_uom = uom
>>> product_template.save() >>> product_template.save()
Create prescription template:: Create prescription template::
>>> PrescriptionTemplate = Model.get('farm.prescription.template') >>> PrescriptionTemplate = Model.get('farm.prescription.template')
>>> Product = Model.get('product.product') >>> Product = Model.get('product.product')
>>> product, = Product.find([('name', '=', 'Template product test')]) >>> product, = Product.find([('name', '=', 'Template product test')])
>>> product.prescription_required = True >>> product.prescription_required = True
>>> product.save() >>> product.save()
>>> prescription_template = PrescriptionTemplate() >>> prescription_template = PrescriptionTemplate()
>>> prescription_template.product = product >>> prescription_template.product = product
>>> prescription_template.quantity = Decimal('01.00') >>> prescription_template.quantity = Decimal('01.00')
>>> #prescription_template.specie = pigs_specie >>> #prescription_template.specie = pigs_specie
>>> prescription_template.save() >>> prescription_template.save()
Create vet:: Create vet::
>>> vet = Party(name="Veterinary") >>> Party = Model.get('party.party')
>>> vet.save() >>> vet = Party(name="Veterinary")
>>> vet.save()
Create account farm user:: Create account farm user::
>>> User = Model.get('res.user')
>>> farm_user = User() >>> farm_user = User()
>>> farm_user.name = 'Farm User' >>> farm_user.name = 'Farm User'
>>> farm_user.login = 'farm_user' >>> farm_user.login = 'farm_user'
@ -222,37 +193,34 @@ Create account farm user::
>>> Group = Model.get('res.group') >>> Group = Model.get('res.group')
>>> groups = Group.find([ >>> groups = Group.find([
... ('name', 'in', ['Stock Administration', 'Stock', ... ('name', 'in', ['Stock Administration', 'Stock',
... 'Product Administration']), ... 'Product Administration', 'Farm / Prescriptions', 'Farm']),
... ]) ... ])
>>> farm_user.groups.extend(groups) >>> farm_user.groups.extend(groups)
>>> farm_user.save() >>> farm_user.save()
>>> config.user = farm_user.id >>> config.user = farm_user.id
Create prescription:: Create prescription::
>>> Prescription = Model.get('farm.prescription') >>> Prescription = Model.get('farm.prescription')
>>> prescription = Prescription() >>> prescription = Prescription()
>>> prescription.reference = "Test prescription" >>> prescription.reference = "Test prescription"
>>> prescription.farm = warehouse >>> prescription.farm = warehouse
>>> prescription.quantity = Decimal('01.00') >>> prescription.quantity = Decimal('01.00')
>>> prescription.delivery_date = today >>> prescription.delivery_date = today
>>> prescription.template = prescription_template >>> prescription.template = prescription_template
>>> prescription_template.product = product >>> prescription_template.product = product
>>> prescription_template.quantity = Decimal('01.00') >>> prescription_template.quantity = Decimal('01.00')
>>> prescription_template.delivery_date = today >>> prescription_template.delivery_date = today
>>> prescription_template.number_of_animals = 1 >>> prescription_template.number_of_animals = 1
>>> prescription_template.save() >>> prescription_template.save()
>>> prescription.save() >>> prescription.save()
Create internal shipment:: Create internal shipment::
>>> create_internal_shipment = Wizard('farm.prescription.internal.shipment', models=[prescription])
>>> create_internal_shipment = Wizard('farm.prescription.internal.shipment', models=[prescription])
>>> invoice_wizard = create_internal_shipment.form >>> invoice_wizard = create_internal_shipment.form
>>> invoice_wizard.from_location = inner_farm >>> invoice_wizard.from_location = inner_farm
>>> create_internal_shipment.execute('create_') >>> create_internal_shipment.execute('create_')
Check internal shipment:: Check internal shipment::
@ -305,7 +273,7 @@ Create internal shipment::
>>> no_prescription_shipment.click('assign_try') >>> no_prescription_shipment.click('assign_try')
False False
>>> no_prescription_shipment.state >>> no_prescription_shipment.state
u'waiting' 'waiting'
Create movement with no prescription:: Create movement with no prescription::
@ -352,7 +320,7 @@ Create internal shipment::
>>> shipment.click('done') >>> shipment.click('done')
>>> shipment.reload() >>> shipment.reload()
>>> shipment.state >>> shipment.state
u'done' 'done'
>>> shipments = ShipmentInternal.find([]) >>> shipments = ShipmentInternal.find([])
>>> len(shipments) >>> len(shipments)
3 3

View File

@ -1,10 +1,11 @@
[tryton] [tryton]
version=4.1.0 version=5.2.0
depends: depends:
farm farm
extras_depend: extras_depend:
stock_lot_expiry stock_lot_sled
xml: xml:
prescription.xml prescription.xml
specie.xml specie.xml
medication_event.xml medication_event.xml
message.xml

View File

@ -1,7 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<!-- 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. -->
<form string="Create Internal Shipment" col="2"> <form col="2">
<label name="from_location"/> <label name="from_location"/>
<field name="from_location"/> <field name="from_location"/>
<label name="farm"/> <label name="farm"/>

View File

@ -2,7 +2,7 @@
<!-- The COPYRIGHT file at the top level of this repository contains the full <!-- The COPYRIGHT file at the top level of this repository contains the full
copyright notices and license terms. --> copyright notices and license terms. -->
<data> <data>
<xpath expr="/tree/field[@name='active']" position="after"> <xpath expr="/tree" position="inside">
<field name="veterinarian"/> <field name="veterinarian"/>
<field name="collegiate_number"/> <field name="collegiate_number"/>
</xpath> </xpath>

View File

@ -1,7 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full <!-- The COPYRIGHT file at the top level of this repository contains the full
copyright notices and license terms. --> copyright notices and license terms. -->
<form string="Prescription"> <form>
<label name="reference"/> <label name="reference"/>
<field name="reference"/> <field name="reference"/>
<label name="date"/> <label name="date"/>

View File

@ -1,7 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full <!-- The COPYRIGHT file at the top level of this repository contains the full
copyright notices and license terms. --> copyright notices and license terms. -->
<form string="Prescription Line"> <form>
<label name="product"/> <label name="product"/>
<field name="product"/> <field name="product"/>
<label name="prescription"/> <label name="prescription"/>

View File

@ -1,7 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full <!-- The COPYRIGHT file at the top level of this repository contains the full
copyright notices and license terms. --> copyright notices and license terms. -->
<tree string="Prescription Line"> <tree>
<field name="prescription"/> <field name="prescription"/>
<field name="product"/> <field name="product"/>
<field name="quantity"/> <field name="quantity"/>

View File

@ -1,7 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full <!-- The COPYRIGHT file at the top level of this repository contains the full
copyright notices and license terms. --> copyright notices and license terms. -->
<tree string="Prescriptions"> <tree>
<field name="reference"/> <field name="reference"/>
<field name="date"/> <field name="date"/>
<field name="farm"/> <field name="farm"/>

View File

@ -1,7 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full <!-- The COPYRIGHT file at the top level of this repository contains the full
copyright notices and license terms. --> copyright notices and license terms. -->
<form string="Prescription Template"> <form>
<label name="name"/> <label name="name"/>
<field name="name" colspan="3"/> <field name="name" colspan="3"/>
<newline/> <newline/>

View File

@ -1,7 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full <!-- The COPYRIGHT file at the top level of this repository contains the full
copyright notices and license terms. --> copyright notices and license terms. -->
<form string="Prescription Template Line"> <form>
<label name="product"/> <label name="product"/>
<field name="product"/> <field name="product"/>
<label name="prescription"/> <label name="prescription"/>

View File

@ -1,7 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full <!-- The COPYRIGHT file at the top level of this repository contains the full
copyright notices and license terms. --> copyright notices and license terms. -->
<tree string="Prescription Template Line"> <tree>
<field name="prescription"/> <field name="prescription"/>
<field name="product"/> <field name="product"/>
<field name="quantity"/> <field name="quantity"/>

View File

@ -1,7 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<!-- The COPYRIGHT file at the top level of this repository contains the full <!-- The COPYRIGHT file at the top level of this repository contains the full
copyright notices and license terms. --> copyright notices and license terms. -->
<tree string="Prescription Templates"> <tree>
<field name="name"/> <field name="name"/>
<field name="product"/> <field name="product"/>
<field name="quantity"/> <field name="quantity"/>