Get the stock on each line at the fly

Hi everyone,
I am working on gnuhealth and I need to make some customizations on the prescriptions order form.
The idea is to have the remaining stock on the same line that the medicament prescription at the time the new line is created.

So I have something like this:

class PatientPrescriptionOrder(metaclass=PoolMeta):
       (......)
    prescription_line = fields.One2Many(
        'gnuhealth.prescription.line', 'name', 'Prescription line',
        states = STATES)
    pharmacy = fields.Many2One(
        'party.party', 'Pharmacy', domain=[('is_pharmacy', '=', True)],
        states={
            'readonly': (Eval('state') != 'draft') & Bool(Eval('pharmacy')),
            },
        depends=['state'])
     (....)

class PrescriptionLine(metaclass=PoolMeta):
    (....)
    stock = fields.Function(fields.Char('Stock on pharmacy'),
        'on_change_with_stock')
    (....)

   @fields.depends('quantity', 'name', 'medicament')
    def on_change_with_stock(self, name=None):
        pool = Pool()
        Product = pool.get('product.product')
               
        if self.name.pharmacy and self.name.pharmacy.warehouse:
            warehouse_id = self.name.pharmacy.warehouse.id
            products = Product.search([('template.id','=',self.medicament.name.template.id)])
            products_by_location = Product.products_by_location(
                location_ids = [warehouse_id],
                with_childs=True)
            stock = sum([products_by_location[(warehouse_id,x.id)] for x in products])
            if stock > 0:
                return str(stock)
        return '-------'

This way only works when the PatientPrescriptionOrder is saved.

Any help will be really appreciated. Thanks

I think this behaviour is done on health_service module, using the service line and description. Please take a look.

If you have a product and a warehouse you can just browse it using the proper context:

Product = pool.get('product.product')
with Trsansaction().set_context(locations=[location_id]):
    product = Product(product_id)
    return product.quantity

Where product_id is the id of the product to get the stock and location_id is the id of location where to compute the stock. It can be a warehouse or any storage location.

Hope this helps!

1 Like

It is a fancy solution, but it doesn’t work on my case. It only shows the quantity once the form is saved. I need to show quantities when the medicament is set.
Thanks anyway :+1:!

You should use an function field which is computed when the medicament is changed (using on_change_with).

This will show the values when the form is saved but also update them when the medicament is changed.

1 Like

Indeed I am using an on_change function_with.

Thanks anyway!

Finally I got to some kind of solution for it.
Just add a new field on the prescription model related to a medicament, a function field to show up the stock, and a button to add a new line to the prescription lines.
It would be something like:

    (....)
    medicament_to_prescribe = fields.Many2One('gnuhealth.medicament','Medicament to prescribe',
        states={'readonly': Eval('state') != 'draft'},depends=['state'])
    medicament_to_prescribe_qty_in_pharmacy = fields.Function(
        fields.Char('Quantity', help='Quantity of medicament on pharmacy'),
        'on_change_with_medicament_to_prescribe_qty_in_pharmacy')
    (....)

    @fields.depends('pharmacy','medicament_to_prescribe')
    def on_change_with_medicament_to_prescribe_qty_in_pharmacy(self, name=None):
        pool = Pool()
        Product = pool.get('product.product')
        if self.pharmacy and self.medicament_to_prescribe:
            location_id = self.pharmacy.warehouse.id
            with Transaction().set_context(locations=[location_id]):
                quantity = 0
                for product in [x for x in self.medicament_to_prescribe.name.template.products]:
                    product = Product(product.id)
                    quantity += product.quantity
                return str(quantity)
        return '0.0'

    @classmethod
    @ModelView.button
    def prescribe(cls, prescriptions):
        pool = Pool()
        PrescriptionLine = pool.get('gnuhealth.prescription.line')
        prescription = prescriptions[0]
        if prescription.medicament_to_prescribe_qty_in_pharmacy == '0.0':
            cls.raise_user_warning(str(prescription.id),'medicament_qty_unknown',{},'There is no stock registered of this medicament')
            PrescriptionLine.create([{
                'name': prescription.id,
                'medicament': prescription.medicament_to_prescribe.id,
                'quantity': prescription.medicament_to_prescribe.name.qty_out,
                'duration': prescription.delivery_duration,
                }])

This way the health professional can check on the fly the quantity and create or not a new line.

Thanks for all. Kind regards.
Francisco

Can you drop the full code here please i need to have a look at it, for helping me understand how the stock work