Skip to content

Commit

Permalink
restrict perms/codenames between site and central pharmacist
Browse files Browse the repository at this point in the history
  • Loading branch information
erikvw committed Nov 28, 2024
1 parent 792c84f commit ee736de
Show file tree
Hide file tree
Showing 25 changed files with 234 additions and 122 deletions.
10 changes: 2 additions & 8 deletions edc_pharmacy/admin/actions/process_repack_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.utils.html import format_html
from edc_utils.celery import celery_is_active, run_task_sync_or_async
from edc_utils.celery import run_task_sync_or_async

from ...tasks.process_repack_request import process_repack_request_queryset
from ...utils import process_repack_request_queryset


@admin.action(description="Process repack request")
Expand All @@ -20,12 +20,6 @@ def process_repack_request_action(modeladmin, request, queryset):
"""
repack_request_pks = [obj.pk for obj in queryset]

# if celery is not running, just keep the first pk
if not celery_is_active():
repack_request_pks = repack_request_pks[:1]

# run task / func and update or clear the task_id
task = run_task_sync_or_async(
process_repack_request_queryset,
repack_request_pks=repack_request_pks,
Expand Down
76 changes: 53 additions & 23 deletions edc_pharmacy/auth_objects.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from django.apps import apps as django_apps
from edc_pharmacy.utils import get_codenames

app_name = "edc_pharmacy"
# groups
DISPENSING = "DISPENSING"
DISPENSING_VIEW = "DISPENSING_VIEW"
Expand All @@ -16,30 +15,64 @@
PHARMACY_PRESCRIBER_ROLE = "PHARMACY_PRESCRIBER_ROLE"
SITE_PHARMACIST_ROLE = "SITE_PHARMACIST_ROLE"

pharmacy_codenames = ["edc_pharmacy.view_subject"]
prescriber_codenames = ["edc_pharmacy.view_subject"]


navbar_codenames = [
"edc_pharmacy.nav_pharmacy_section",
]

navbar_codenames = ["edc_pharmacy.nav_pharmacy_section"]
navbar_tuples = []
for codename in navbar_codenames:
navbar_tuples.append((codename, f"Can access {codename.split('.')[1]}"))


for app_config in django_apps.get_app_configs():
if app_config.name in [
"edc_pharmacy",
]:
for model_cls in app_config.get_models():
app_name, model_name = model_cls._meta.label_lower.split(".")
if model_name == "registeredsubjectproxy":
continue
for prefix in ["view_", "add_", "change_", "delete_"]:
pharmacy_codenames.append(f"{app_name}.{prefix}{model_name}")
# central pharmacist
view_only_models = [
"edc_pharmacy.allocation",
"edc_pharmacy.formulation",
"edc_pharmacy.formulationtype",
"edc_pharmacy.frequencyunits",
"edc_pharmacy.location",
"edc_pharmacy.medication",
"edc_pharmacy.stockrequest",
"edc_pharmacy.stockrequestitem",
"edc_pharmacy.stock",
"edc_pharmacy.assignment",
"edc_pharmacy.subject",
"edc_pharmacy.visitschedule",
]
pharmacy_codenames = get_codenames([], view_only_models=view_only_models)
pharmacy_codenames.extend(navbar_codenames)
pharmacy_codenames.sort()


# site pharmacist
exclude_models = ["edc_pharmacy.lot", "edc_pharmacy.assignment"]
view_only_models = [
"edc_pharmacy.order",
"edc_pharmacy.orderitem",
"edc_pharmacy.receive",
"edc_pharmacy.receiveitem",
"edc_pharmacy.repackrequest",
"edc_pharmacy.stocktransfer",
"edc_pharmacy.stocktransferitem",
"edc_pharmacy.allocation",
"edc_pharmacy.container",
"edc_pharmacy.containertype",
"edc_pharmacy.formulation",
"edc_pharmacy.formulationtype",
"edc_pharmacy.frequencyunits",
"edc_pharmacy.location",
"edc_pharmacy.medication",
"edc_pharmacy.product",
"edc_pharmacy.stock",
"edc_pharmacy.subject",
"edc_pharmacy.visitschedule",
]
pharmacy_site_codenames = get_codenames(
[], view_only_models=view_only_models, exclude_models=exclude_models
)
pharmacy_site_codenames.extend(navbar_codenames)
pharmacy_site_codenames.sort()

# prescriber
prescriber_codenames = []
for model_name in ["dosageguideline", "formulation", "medication", "rxrefill"]:
prescriber_codenames.extend(
[
Expand All @@ -50,8 +83,5 @@
)
for model_name in ["rx", "rxitem"]:
prescriber_codenames.extend([c for c in pharmacy_codenames if model_name in c])

pharmacy_codenames.extend(navbar_codenames)
prescriber_codenames.append("edc_pharmacy.view_subject")
prescriber_codenames.sort()
pharmacy_codenames.sort()
pharmacy_site_codenames = [c for c in pharmacy_codenames if not c.endswith("lot")]
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 5.1.2 on 2024-11-27 16:33

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("edc_pharmacy", "0053_alter_location_managers_alter_historicalstock_lot_and_more"),
]

operations = [
migrations.AddField(
model_name="historicalreceiveitem",
name="task_id",
field=models.UUIDField(null=True),
),
migrations.AddField(
model_name="receiveitem",
name="task_id",
field=models.UUIDField(null=True),
),
]
23 changes: 9 additions & 14 deletions edc_pharmacy/models/signals.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

from decimal import Decimal

from celery.states import PENDING
Expand All @@ -9,8 +11,11 @@

from ..exceptions import InsufficientStockError
from ..model_mixins import StudyMedicationCrfModelMixin
from ..tasks import process_repack_request
from ..utils import update_previous_refill_end_datetime
from ..utils import (
create_new_stock_on_receive,
process_repack_request,
update_previous_refill_end_datetime,
)
from .stock import (
Allocation,
DispenseItem,
Expand Down Expand Up @@ -98,19 +103,9 @@ def receive_item_on_post_save(sender, instance, raw, created, update_fields, **k
if unit_qty_received == unit_qty:
order.status = COMPLETE
order.save()

# add to stock
for i in range(0, int(instance.qty)):
Stock.objects.create(
receive_item_id=instance.id,
qty_in=1,
qty_out=0,
qty=1,
product_id=instance.order_item.product.id,
container_id=instance.container.id,
location_id=instance.receive.location.id,
confirmed=False,
lot_id=instance.lot.id,
)
create_new_stock_on_receive(receive_item_pk=instance.id)


@receiver(post_save, sender=StockRequest, dispatch_uid="stock_request_on_post_save")
Expand Down
2 changes: 2 additions & 0 deletions edc_pharmacy/models/stock/receive_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ class ReceiveItem(BaseUuidModel):
help_text="Quantity x Container.Quantity, e.g. 10 x Bottle of 128 = 1280",
)

task_id = models.UUIDField(null=True)

objects = Manager()

history = HistoricalRecords()
Expand Down
1 change: 0 additions & 1 deletion edc_pharmacy/tasks/__init__.py

This file was deleted.

24 changes: 0 additions & 24 deletions edc_pharmacy/tasks/process_repack_request.py

This file was deleted.

23 changes: 23 additions & 0 deletions edc_pharmacy/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,37 @@
from .blinded_user import blinded_user
from .confirm_stock import confirm_stock
from .confirm_stock_at_site import confirm_stock_at_site
from .create_new_stock_on_receive import create_new_stock_on_receive
from .dispense import dispense
from .format_qty import format_qty
from .get_codenames import get_codenames
from .get_random_code import get_random_code
from .miscellaneous import get_rx_model_cls, get_rxrefill_model_cls
from .process_repack_request import process_repack_request
from .process_repack_request_queryset import process_repack_request_queryset
from .stock_request import (
bulk_create_stock_request_items,
remove_subjects_where_stock_on_site,
)
from .transfer_stock import transfer_stock
from .update_previous_refill_end_datetime import update_previous_refill_end_datetime

__all__ = [
"allocate_stock",
"blinded_user",
"bulk_create_stock_request_items",
"confirm_stock",
"confirm_stock_at_site",
"create_new_stock_on_receive",
"dispense",
"format_qty",
"get_codenames",
"get_random_code",
"get_rx_model_cls",
"get_rxrefill_model_cls",
"process_repack_request",
"process_repack_request_queryset",
"remove_subjects_where_stock_on_site",
"transfer_stock",
"update_previous_refill_end_datetime",
]
3 changes: 3 additions & 0 deletions edc_pharmacy/utils/allocate_stock.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,6 @@ def allocate_stock(
obj.save()
allocated += 1
return allocated, unallocated


__all__ = ["allocate_stock"]
3 changes: 3 additions & 0 deletions edc_pharmacy/utils/blinded_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ def blinded_user(request) -> bool:
return True
# user is not blinded
return False


__all__ = ["blinded_user"]
3 changes: 3 additions & 0 deletions edc_pharmacy/utils/confirm_stock.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,6 @@ def confirm_stock(
else:
already_confirmed.append(stock.code)
return confirmed, already_confirmed, invalid


__all__ = ["confirm_stock"]
3 changes: 3 additions & 0 deletions edc_pharmacy/utils/confirm_stock_at_site.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,6 @@ def confirm_stock_at_site(
obj.save()
confirmed.append(stock_code)
return confirmed, already_confirmed, invalid


__all__ = ["confirm_stock_at_site"]
21 changes: 21 additions & 0 deletions edc_pharmacy/utils/create_new_stock_on_receive.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from uuid import UUID

from django.apps import apps as django_apps


def create_new_stock_on_receive(receive_item_pk: UUID = None):
receive_item_model_cls = django_apps.get_model("edc_pharmacy.receiveitem")
stock_model_cls = django_apps.get_model("edc_pharmacy.stock")
receive_item = receive_item_model_cls.objects.get(pk=receive_item_pk)
for i in range(0, int(receive_item.qty)):
stock_model_cls.objects.create(
receive_item_id=receive_item.id,
qty_in=1,
qty_out=0,
qty=1,
product_id=receive_item.order_item.product.id,
container_id=receive_item.container.id,
location_id=receive_item.receive.location.id,
confirmed=False,
lot_id=receive_item.lot.id,
)
3 changes: 3 additions & 0 deletions edc_pharmacy/utils/dispense.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,6 @@ def dispense(

return dispense_item_model_cls.objects.filter(dispense=dispense_obj)
return None


__all__ = ["dispense"]
3 changes: 3 additions & 0 deletions edc_pharmacy/utils/format_qty.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ def format_qty(qty: Decimal, container: Container):
elif container.qty_decimal_places == 1:
return "{:0.1f}".format(qty)
return "{:0.2f}".format(qty)


__all__ = ["format_qty"]
27 changes: 27 additions & 0 deletions edc_pharmacy/utils/get_codenames.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from django.apps import apps as django_apps


def get_codenames(
codenames: list[str],
view_only_models: list[str] | None = None,
exclude_models: list[str] | None = None,
) -> list[str]:
"""Return a list of all codenames for the role.
See auths.py
"""
view_only_models = view_only_models or []
exclude_models = exclude_models or []
for app_config in django_apps.get_app_configs():
if app_config.name in ["edc_pharmacy"]:
for model_cls in app_config.get_models():
label_lower = model_cls._meta.label_lower
app_name, model_name = label_lower.split(".")
if label_lower in exclude_models:
continue
elif label_lower in view_only_models:
codenames.append(f"{app_name}.view_{model_name}")
else:
for prefix in ["view_", "add_", "change_", "delete_"]:
codenames.append(f"{app_name}.{prefix}{model_name}")
return codenames
3 changes: 3 additions & 0 deletions edc_pharmacy/utils/get_random_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ def get_random_code(model_cls, length: int, tries: int | None = None) -> str:
if x == tries:
raise StopIteration()
return random_code


__all__ = ["get_random_code"]
Loading

0 comments on commit ee736de

Please sign in to comment.