changeset 4878:0af7f7ed8f6f

task #16043: Migration to GNU Health 4.0: Migrate and cleanup health_stock
author Luis Falcon <falcon@gnuhealth.org>
date Sat, 15 Jan 2022 11:11:19 +0000
parents f878697cc363
children 6acbbe8bcac4
files tryton/health_stock/__init__.py tryton/health_stock/data/messages/messages.xml tryton/health_stock/exceptions.py tryton/health_stock/health_stock.py tryton/health_stock/tryton.cfg tryton/health_stock/wizard/wizard_create_prescription_stock_move.py tryton/health_stock/wizard/wizard_create_vaccination_stock_move.py
diffstat 7 files changed, 164 insertions(+), 132 deletions(-) [+]
line wrap: on
line diff
--- a/tryton/health_stock/__init__.py
+++ b/tryton/health_stock/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 ##############################################################################
 #
 #    GNU Health: The Free Health and Hospital Information System
@@ -23,26 +22,31 @@
 ##############################################################################
 
 from trytond.pool import Pool
-from .health_stock import *
-from .wizard import *
+from . import health_stock
+from . import wizard
+
 
 def register():
     Pool.register(
-        Party,
-        Lot,
-        Move,
-        PatientAmbulatoryCare,
-        PatientAmbulatoryCareMedicament,
-        PatientAmbulatoryCareMedicalSupply,
-        PatientRounding,
-        PatientRoundingMedicament,
-        PatientRoundingMedicalSupply,
-        PatientPrescriptionOrder,
-        PatientVaccination,
+        health_stock.Party,
+        health_stock.Lot,
+        health_stock.Move,
+        health_stock.PatientAmbulatoryCare,
+        health_stock.PatientAmbulatoryCareMedicament,
+        health_stock.PatientAmbulatoryCareMedicalSupply,
+        health_stock.PatientRounding,
+        health_stock.PatientRoundingMedicament,
+        health_stock.PatientRoundingMedicalSupply,
+        health_stock.PatientPrescriptionOrder,
+        health_stock.PatientVaccination,
+        wizard.wizard_create_prescription_stock_move.
         CreatePrescriptionStockMoveInit,
+        wizard.wizard_create_vaccination_stock_move.
         CreateVaccinationStockMoveInit,
         module='health_stock', type_='model')
     Pool.register(
+        wizard.wizard_create_prescription_stock_move.
         CreatePrescriptionStockMove,
+        wizard.wizard_create_vaccination_stock_move.
         CreateVaccinationStockMove,
         module='health_stock', type_='wizard')
new file mode 100644
--- /dev/null
+++ b/tryton/health_stock/data/messages/messages.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<!-- This file is part of GNU Health.  The COPYRIGHT file at the top level of
+this repository contains the full copyright notices and license terms. -->
+<tryton>
+    <data grouped="1">
+        <record model="ir.message" id="msg_expired_vaccine">
+            <field name="text">EXPIRED VACCINE. PLEASE INFORM THE LOCAL HEALTH AUTHORITIES AND DO NOT USE IT !!!</field>
+        </record>
+        <record model="ir.message" id="msg_stock_move_exists">
+            <field name="text">Stock move already exists</field>
+        </record>
+        <record model="ir.message" id="msg_no_pharmacy">
+            <field name="text">You need to select a pharmacy</field>
+        </record>
+    </data>
+</tryton>
new file mode 100644
--- /dev/null
+++ b/tryton/health_stock/exceptions.py
@@ -0,0 +1,14 @@
+# This file is part of GNU Health.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
+from trytond.model.exceptions import ValidationError
+
+
+class ExpiredVaccine(ValidationError):
+    pass
+
+
+class StockMoveExists(ValidationError):
+    pass
+
+class NoPharmacy(ValidationError):
+    pass
--- a/tryton/health_stock/health_stock.py
+++ b/tryton/health_stock/health_stock.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 ##############################################################################
 #
 #    GNU Health: The Free Health and Hospital Information System
@@ -23,39 +22,31 @@
 ##############################################################################
 from datetime import datetime
 from trytond.model import Workflow, ModelView, ModelSQL, fields
-from trytond.wizard import Wizard, StateView, Button, StateTransition
 from trytond.pyson import If, Or, Eval, Not, Bool
 from trytond.exceptions import UserError
-from trytond.transaction import Transaction
 from trytond.pool import Pool, PoolMeta
-from functools import reduce
+from trytond.modules.health.core import get_health_professional
+from trytond.i18n import gettext
+
+from .exceptions import (ExpiredVaccine)
 
 __all__ = ['Party', 'Lot', 'Move',
-    'PatientAmbulatoryCare', 'PatientAmbulatoryCareMedicament',
-    'PatientAmbulatoryCareMedicalSupply',
-    'PatientRounding', 'PatientRoundingMedicament',
-    'PatientRoundingMedicalSupply',
-    'PatientPrescriptionOrder', 'PatientVaccination']
-    
+           'PatientAmbulatoryCare', 'PatientAmbulatoryCareMedicament',
+           'PatientAmbulatoryCareMedicalSupply',
+           'PatientRounding', 'PatientRoundingMedicament',
+           'PatientRoundingMedicalSupply',
+           'PatientPrescriptionOrder', 'PatientVaccination']
+
 _STATES = {
     'readonly': Eval('state') == 'done',
     }
 _DEPENDS = ['state']
 
 
-"""
-Deprecated : Using now the quantity related to the product
-class Medicament(metaclass=PoolMeta):
-    __name__ = 'gnuhealth.medicament'
-    quantity = fields.Function(fields.Float('Quantity'), 'get_quantity')
-
-    def get_quantity(self,name):
-        return self.name.quantity
-"""
-
 class Party(metaclass=PoolMeta):
     __name__ = 'party.party'
-    warehouse = fields.Many2One('stock.location', 'Warehouse',
+    warehouse = fields.Many2One(
+        'stock.location', 'Warehouse',
         domain=[('type', 'in', ['warehouse', 'storage'])],
         states={
             'invisible': Not(Bool(Eval('is_pharmacy'))),
@@ -74,7 +65,8 @@
 class Lot(metaclass=PoolMeta):
     __name__ = 'stock.lot'
     expiration_date = fields.Date('Expiration Date')
-   
+
+
 class Move(metaclass=PoolMeta):
     __name__ = 'stock.move'
 
@@ -92,11 +84,13 @@
     'Patient Ambulatory Care'
     __name__ = 'gnuhealth.patient.ambulatory_care'
 
-    care_location = fields.Many2One('stock.location', 'Care Location',
+    care_location = fields.Many2One(
+        'stock.location', 'Care Location',
         domain=[('type', '=', 'storage')],
         states={
-            'required': If(Or(Bool(Eval('medicaments')),
-                Bool(Eval('medical_supplies'))), True, False),
+            'required': If(
+                Or(Bool(Eval('medicaments')),
+                    Bool(Eval('medical_supplies'))), True, False),
             'readonly': Eval('state') == 'done',
         }, depends=['state', 'medicaments'])
     medicaments = fields.One2Many(
@@ -106,7 +100,8 @@
         'gnuhealth.patient.ambulatory_care.medical_supply', 'name',
         'Medical Supplies', states=_STATES, depends=_DEPENDS)
 
-    moves = fields.One2Many('stock.move', 'origin', 'Stock Moves',
+    moves = fields.One2Many(
+        'stock.move', 'origin', 'Stock Moves',
         readonly=True)
 
     @classmethod
@@ -134,7 +129,6 @@
     @Workflow.transition('done')
     def done(cls, ambulatory_cares):
         pool = Pool()
-        Patient = pool.get('gnuhealth.patient')
         HealthProfessional = pool.get('gnuhealth.healthprofessional')
 
         lines_to_ship = {}
@@ -144,7 +138,6 @@
         signing_hp = HealthProfessional.get_health_professional()
 
         for ambulatory in ambulatory_cares:
-            patient = Patient(ambulatory.patient.id)
             for medicament in ambulatory.medicaments:
                 medicaments_to_ship.append(medicament)
 
@@ -180,8 +173,8 @@
                 move_info['unit_price'] = \
                     medicament.medicament.name.list_price
                 if medicament.lot:
-                    if  medicament.lot.expiration_date \
-                    and medicament.lot.expiration_date < Date.today():
+                    if medicament.lot.expiration_date and \
+                            medicament.lot.expiration_date < Date.today():
                         raise UserError('Expired medicaments')
                     move_info['lot'] = medicament.lot.id
                 moves.append(move_info)
@@ -197,8 +190,9 @@
                     ambulatory.patient.name.customer_location.id
                 move_info['unit_price'] = medical_supply.product.list_price
                 if medical_supply.lot:
-                    if  medical_supply.lot.expiration_date \
-                    and medical_supply.lot.expiration_date < Date.today():
+                    if medical_supply.lot.expiration_date \
+                            and medical_supply.lot.expiration_date \
+                            < Date.today():
                         raise UserError('Expired supplies')
                     move_info['lot'] = medical_supply.lot.id
                 moves.append(move_info)
@@ -216,15 +210,19 @@
     'Patient Ambulatory Care Medicament'
     __name__ = 'gnuhealth.patient.ambulatory_care.medicament'
 
-    name = fields.Many2One('gnuhealth.patient.ambulatory_care',
+    name = fields.Many2One(
+        'gnuhealth.patient.ambulatory_care',
         'Ambulatory ID')
-    medicament = fields.Many2One('gnuhealth.medicament', 'Medicament',
+    medicament = fields.Many2One(
+        'gnuhealth.medicament', 'Medicament',
         required=True)
     product = fields.Many2One('product.product', 'Product')
     quantity = fields.Integer('Quantity')
-    short_comment = fields.Char('Comment',
+    short_comment = fields.Char(
+        'Comment',
         help='Short comment on the specific drug')
-    lot = fields.Many2One('stock.lot', 'Lot', depends=['product'],
+    lot = fields.Many2One(
+        'stock.lot', 'Lot', depends=['product'],
         domain=[('product', '=', Eval('product'))])
 
     @staticmethod
@@ -244,14 +242,18 @@
     'Patient Ambulatory Care Medical Supply'
     __name__ = 'gnuhealth.patient.ambulatory_care.medical_supply'
 
-    name = fields.Many2One('gnuhealth.patient.ambulatory_care',
+    name = fields.Many2One(
+        'gnuhealth.patient.ambulatory_care',
         'Ambulatory ID')
-    product = fields.Many2One('product.product', 'Medical Supply',
+    product = fields.Many2One(
+        'product.product', 'Medical Supply',
         domain=[('is_medical_supply', '=', True)], required=True)
     quantity = fields.Integer('Quantity')
-    short_comment = fields.Char('Comment',
+    short_comment = fields.Char(
+        'Comment',
         help='Short comment on the specific drug')
-    lot = fields.Many2One('stock.lot', 'Lot', depends=['product'],
+    lot = fields.Many2One(
+        'stock.lot', 'Lot', depends=['product'],
         domain=[
             ('product', '=', Eval('product')),
             ])
@@ -260,14 +262,17 @@
     def default_quantity():
         return 1
 
+
 class PatientRounding(Workflow, ModelSQL, ModelView):
     'Patient Ambulatory Care'
     __name__ = 'gnuhealth.patient.rounding'
 
-    hospitalization_location = fields.Many2One('stock.location',
+    hospitalization_location = fields.Many2One(
+        'stock.location',
         'Hospitalization Location', domain=[('type', '=', 'storage')],
         states={
-            'required': If(Or(Bool(Eval('medicaments')),
+            'required': If(Or(
+                Bool(Eval('medicaments')),
                 Bool(Eval('medical_supplies'))), True, False),
             'readonly': Eval('state') == 'done',
         }, depends=_DEPENDS)
@@ -275,20 +280,22 @@
         'gnuhealth.patient.rounding.medicament', 'name', 'Medicaments',
         states=_STATES, depends=_DEPENDS)
     medical_supplies = fields.One2Many(
-        'gnuhealth.patient.rounding.medical_supply', 'name', 'Medical Supplies',
+        'gnuhealth.patient.rounding.medical_supply',
+        'name', 'Medical Supplies',
         states=_STATES, depends=_DEPENDS)
-    moves = fields.One2Many('stock.move', 'origin', 'Stock Moves',
+    moves = fields.One2Many(
+        'stock.move', 'origin', 'Stock Moves',
         readonly=True)
 
     @classmethod
     def __setup__(cls):
         super(PatientRounding, cls).__setup__()
         cls._transitions |= set((
-        ('draft', 'done'),
+            ('draft', 'done'),
         ))
         cls._buttons.update({
             'done': {
-            'invisible': ~Eval('state').in_(['draft']),
+                'invisible': ~Eval('state').in_(['draft']),
             }})
 
     @classmethod
@@ -303,19 +310,13 @@
     @ModelView.button
     @Workflow.transition('done')
     def done(cls, roundings):
-        pool = Pool()
-        Patient = pool.get('gnuhealth.patient')
-        HealthProfessional = pool.get('gnuhealth.healthprofessional')
-
-        signing_hp = HealthProfessional.get_health_professional()
+        signing_hp = get_health_professional()
 
         lines_to_ship = {}
         medicaments_to_ship = []
         supplies_to_ship = []
 
         for rounding in roundings:
-            patient = Patient(rounding.name.patient.id)
-
             for medicament in rounding.medicaments:
                 medicaments_to_ship.append(medicament)
 
@@ -324,7 +325,6 @@
 
         lines_to_ship['medicaments'] = medicaments_to_ship
         lines_to_ship['supplies'] = supplies_to_ship
-        
 
         cls.create_stock_moves(roundings, lines_to_ship)
 
@@ -349,11 +349,11 @@
                 move_info['from_location'] = \
                     rounding.hospitalization_location.id
                 move_info['to_location'] = \
-                rounding.name.patient.name.customer_location.id
+                    rounding.name.patient.name.customer_location.id
                 move_info['unit_price'] = medicament.medicament.name.list_price
                 if medicament.lot:
-                    if  medicament.lot.expiration_date \
-                    and medicament.lot.expiration_date < Date.today():
+                    if medicament.lot.expiration_date \
+                            and medicament.lot.expiration_date < Date.today():
                         raise UserError('Expired medicaments')
                     move_info['lot'] = medicament.lot.id
                 moves.append(move_info)
@@ -366,11 +366,12 @@
                 move_info['from_location'] = \
                     rounding.hospitalization_location.id
                 move_info['to_location'] = \
-                rounding.name.patient.name.customer_location.id
+                    rounding.name.patient.name.customer_location.id
                 move_info['unit_price'] = medical_supply.product.list_price
                 if medical_supply.lot:
-                    if  medical_supply.lot.expiration_date \
-                    and medical_supply.lot.expiration_date < Date.today():
+                    if medical_supply.lot.expiration_date \
+                            and medical_supply.lot.expiration_date < \
+                            Date.today():
                         raise UserError('Expired supplies')
                     move_info['lot'] = medical_supply.lot.id
                 moves.append(move_info)
@@ -388,13 +389,16 @@
     __name__ = 'gnuhealth.patient.rounding.medicament'
 
     name = fields.Many2One('gnuhealth.patient.rounding', 'Ambulatory ID')
-    medicament = fields.Many2One('gnuhealth.medicament', 'Medicament',
+    medicament = fields.Many2One(
+        'gnuhealth.medicament', 'Medicament',
         required=True)
     product = fields.Many2One('product.product', 'Product')
     quantity = fields.Integer('Quantity')
-    short_comment = fields.Char('Comment',
+    short_comment = fields.Char(
+        'Comment',
         help='Short comment on the specific drug')
-    lot = fields.Many2One('stock.lot', 'Lot', depends=['product'],
+    lot = fields.Many2One(
+        'stock.lot', 'Lot', depends=['product'],
         domain=[('product', '=', Eval('product'))])
 
     @staticmethod
@@ -415,12 +419,15 @@
     __name__ = 'gnuhealth.patient.rounding.medical_supply'
 
     name = fields.Many2One('gnuhealth.patient.rounding', 'Ambulatory ID')
-    product = fields.Many2One('product.product', 'Medical Supply',
+    product = fields.Many2One(
+        'product.product', 'Medical Supply',
         domain=[('is_medical_supply', '=', True)], required=True)
     quantity = fields.Integer('Quantity')
-    short_comment = fields.Char('Comment',
+    short_comment = fields.Char(
+        'Comment',
         help='Short comment on the specific drug')
-    lot = fields.Many2One('stock.lot', 'Lot', depends=['product'],
+    lot = fields.Many2One(
+        'stock.lot', 'Lot', depends=['product'],
         domain=[
             ('product', '=', Eval('product')),
             ])
@@ -453,23 +460,27 @@
 class PatientVaccination(metaclass=PoolMeta):
     __name__ = 'gnuhealth.vaccination'
     moves = fields.One2Many('stock.move', 'origin', 'Moves', readonly=True)
-    location = fields.Many2One('stock.location',
+    location = fields.Many2One(
+        'stock.location',
         'Stock Location', domain=[('type', '=', 'storage')])
 
     product = fields.Many2One('product.product', 'Product')
 
-    lot = fields.Many2One('stock.lot', 'Lot', depends=['product'],
+    lot = fields.Many2One(
+        'stock.lot', 'Lot', depends=['product'],
         domain=[('product', '=', Eval('product'))],
         help="This field includes the lot number and expiration date")
 
-
     @fields.depends('lot')
     def on_change_lot(self):
         # Check expiration date on the vaccine lot
         if self.lot:
             if self.lot.expiration_date < datetime.date(self.date):
-                self.raise_user_error('expired_vaccine')
+                raise ExpiredVaccine(
+                    gettext('health_stock.msg_expired_vaccine')
+                    )
         return {}
+
     @classmethod
     def copy(cls, vaccinations, default=None):
         if default is None:
@@ -479,17 +490,9 @@
         return super(PatientVaccination, cls).copy(
             vaccinations, default=default)
 
-    @classmethod
-    def __setup__(cls):
-        super(PatientVaccination, cls).__setup__()
-        cls._error_messages.update({
-            'expired_vaccine': 'EXPIRED VACCINE. PLEASE INFORM  THE LOCAL '
-                'HEALTH AUTHORITIES AND DO NOT USE IT !!!',
-        })
-
     @fields.depends('vaccine')
     def on_change_vaccine(self):
         if self.vaccine:
             self.product = self.vaccine.name.id
         else:
-            self.product =  None
+            self.product = None
--- a/tryton/health_stock/tryton.cfg
+++ b/tryton/health_stock/tryton.cfg
@@ -1,5 +1,5 @@
 [tryton]
-version=3.8.0
+version=3.9.0
 depends:
     health_nursing
     stock_lot
@@ -7,3 +7,4 @@
     health_stock_view.xml
     wizard/create_prescription_stock_move.xml
     wizard/create_vaccination_stock_move.xml
+    data/messages/messages.xml
--- a/tryton/health_stock/wizard/wizard_create_prescription_stock_move.py
+++ b/tryton/health_stock/wizard/wizard_create_prescription_stock_move.py
@@ -26,8 +26,11 @@
 from trytond.model import ModelView
 from trytond.transaction import Transaction
 from trytond.pool import Pool
+from trytond.i18n import gettext
+from ..exceptions import (StockMoveExists, NoPharmacy)
 
-__all__ = ['CreatePrescriptionStockMoveInit','CreatePrescriptionStockMove']
+__all__ = ['CreatePrescriptionStockMoveInit', 'CreatePrescriptionStockMove']
+
 
 class CreatePrescriptionStockMoveInit(ModelView):
     'Create Prescription Stock Move Init'
@@ -38,12 +41,14 @@
     'Create Prescription Stock Move'
     __name__ = 'gnuhealth.prescription.stock.move.create'
 
-    start = StateView('gnuhealth.prescription.stock.move.init',
-            'health_stock.view_create_prescription_stock_move', [
+    start = StateView(
+        'gnuhealth.prescription.stock.move.init',
+        'health_stock.view_create_prescription_stock_move', [
             Button('Cancel', 'end', 'tryton-cancel'),
-            Button('Create Stock Move', 'create_stock_move',
+            Button(
+                'Create Stock Move', 'create_stock_move',
                 'tryton-ok', True),
-            ])
+        ])
     create_stock_move = StateTransition()
 
     def transition_create_stock_move(self):
@@ -57,10 +62,14 @@
         for prescription in prescriptions:
 
             if prescription.moves:
-                self.raise_user_error('stock_move_exists')
+                raise StockMoveExists(
+                    gettext('health_stock.msg_stock_move_exists')
+                    )
 
             if not prescription.pharmacy:
-                self.raise_user_error('no_pharmacy_selected')
+                raise NoPharmacy(
+                    gettext('health_stock.msg_no_pharmacy')
+                    )
 
             from_location = prescription.pharmacy.warehouse
             if from_location.type == 'warehouse':
@@ -80,14 +89,3 @@
         StockMove.save(moves)
         StockMove.do(moves)
         return 'end'
-
-    @classmethod
-    def __setup__(cls):
-        super(CreatePrescriptionStockMove, cls).__setup__()
-        cls._error_messages.update({
-            'stock_move_exists':
-                'Stock moves already exists!.',
-            'no_pharmacy_selected':
-                'You need to select a pharmacy.',
-            })
-
--- a/tryton/health_stock/wizard/wizard_create_vaccination_stock_move.py
+++ b/tryton/health_stock/wizard/wizard_create_vaccination_stock_move.py
@@ -25,8 +25,11 @@
 from trytond.model import ModelView
 from trytond.transaction import Transaction
 from trytond.pool import Pool
+from trytond.i18n import gettext
+from ..exceptions import (StockMoveExists)
 
-__all__ = ['CreateVaccinationStockMoveInit','CreateVaccinationStockMove']
+__all__ = ['CreateVaccinationStockMoveInit', 'CreateVaccinationStockMove']
+
 
 class CreateVaccinationStockMoveInit(ModelView):
     'Create Vaccination Stock Move Init'
@@ -37,12 +40,12 @@
     'Create Vaccination Stock Move'
     __name__ = 'gnuhealth.vaccination.stock.move.create'
 
-    start = StateView('gnuhealth.vaccination.stock.move.init',
-            'health_stock.view_create_vaccination_stock_move', [
+    start = StateView(
+        'gnuhealth.vaccination.stock.move.init',
+        'health_stock.view_create_vaccination_stock_move', [
             Button('Cancel', 'end', 'tryton-cancel'),
-            Button('Create Stock Move', 'create_stock_move',
-                'tryton-ok', True),
-            ])
+            Button('Create Stock Move', 'create_stock_move', 'tryton-ok', True)
+        ])
     create_stock_move = StateTransition()
 
     def transition_create_stock_move(self):
@@ -55,10 +58,12 @@
         for vaccination in vaccinations:
 
             if vaccination.moves:
-                self.raise_user_error('stock_move_exists')
-                 
+                raise StockMoveExists(
+                    gettext('health_stock.msg_stock_move_exists')
+                    )
+
             lines = []
-            
+
             line_data = {}
             line_data['origin'] = str(vaccination)
             line_data['from_location'] = \
@@ -74,19 +79,10 @@
                 vaccination.vaccine.name.default_uom.id
             line_data['state'] = 'draft'
             lines.append(line_data)
-            
+
             moves = StockMove.create(lines)
 
             StockMove.assign(moves)
             StockMove.do(moves)
-            
-            
+
         return 'end'
-
-    @classmethod
-    def __setup__(cls):
-        super(CreateVaccinationStockMove, cls).__setup__()
-        cls._error_messages.update({
-            'stock_move_exists':
-                'Stock moves already exists!.',})
-