this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add reverse invoicing

+122
+31
care/emr/api/viewsets/inventory/delivery_order.py
··· 1 + from django.db import transaction 1 2 from django.db.models import Q 2 3 from django.shortcuts import get_object_or_404 3 4 from django_filters import rest_framework as filters 5 + from pydantic import ValidationError 4 6 from rest_framework.exceptions import PermissionDenied 5 7 from rest_framework.filters import OrderingFilter 6 8 ··· 18 20 from care.emr.resources.inventory.supply_delivery.delivery_order import ( 19 21 BaseSupplyDeliveryOrderSpec, 20 22 SupplyDeliveryOrderReadSpec, 23 + SupplyDeliveryOrderStatusOptions, 21 24 SupplyDeliveryOrderWriteSpec, 25 + ) 26 + from care.emr.resources.invoice.return_items_invoice import ( 27 + cancel_return_invoice, 28 + generate_return_invoice, 22 29 ) 23 30 from care.emr.resources.tag.config_spec import TagResource 24 31 from care.emr.tagging.filters import SingleFacilityTagFilter ··· 92 99 "Origin and destination must be in the same facility" 93 100 ) 94 101 return super().perform_create(instance) 102 + 103 + def perform_update(self, instance): 104 + with transaction.atomic(): 105 + old_instance = DeliveryOrder.objects.get(id=instance.id) 106 + if old_instance.status != instance.status: 107 + if old_instance.status in [ 108 + SupplyDeliveryOrderStatusOptions.abandoned.value, 109 + SupplyDeliveryOrderStatusOptions.entered_in_error.value, 110 + ]: 111 + raise ValidationError( 112 + "Delivery order already abandoned or entered in error" 113 + ) 114 + if ( 115 + instance.patient 116 + and instance.status 117 + == SupplyDeliveryOrderStatusOptions.completed.value 118 + ): 119 + generate_return_invoice(instance) 120 + if instance.patient and instance.status in [ 121 + SupplyDeliveryOrderStatusOptions.abandoned.value, 122 + SupplyDeliveryOrderStatusOptions.entered_in_error.value, 123 + ]: 124 + cancel_return_invoice(instance) 125 + return super().perform_update(instance) 95 126 96 127 def authorize_create(self, instance): 97 128 """
+10
care/emr/resources/charge_item/apply_charge_item_definition.py
··· 6 6 from care.utils.evaluators.interpretation_evaluator import InterpretationEvaluator 7 7 8 8 9 + def generate_negative_charge_item_definition(components): 10 + for component in components: 11 + if component.get("amount"): 12 + component["amount"] = -component["amount"] 13 + return components 14 + 15 + 9 16 def apply_charge_item_definition( 10 17 charge_item_definition, 11 18 patient, ··· 13 20 encounter=None, 14 21 account=None, 15 22 quantity=None, 23 + reverse=None, 16 24 ): 17 25 if not account: 18 26 account = get_default_account(patient, facility) ··· 40 48 if not conditions_met: 41 49 continue 42 50 selected_components.append(component) 51 + if reverse: 52 + price_components = generate_negative_charge_item_definition(price_components) 43 53 charge_item = ChargeItem( 44 54 facility=facility, 45 55 title=charge_item_definition.title,
+5
care/emr/resources/inventory/supply_delivery/delivery_order.py
··· 74 74 ) 75 75 if self.patient and self.origin: 76 76 raise ValidationError("Patient and origin cannot be provided together") 77 + if self.status.value not in [ 78 + SupplyDeliveryOrderStatusOptions.draft.value, 79 + SupplyDeliveryOrderStatusOptions.pending.value, 80 + ]: 81 + raise ValidationError("Status must be draft or pending on create") 77 82 return obj 78 83 79 84
+76
care/emr/resources/invoice/return_items_invoice.py
··· 1 + """ 2 + Utilities to create a return invoice for items based on delivery order 3 + """ 4 + 5 + from django.db import transaction 6 + 7 + from care.emr.models.charge_item import ChargeItem 8 + from care.emr.models.invoice import Invoice 9 + from care.emr.models.supply_delivery import DeliveryOrder, SupplyDelivery 10 + from care.emr.resources.account.sync_items import rebalance_account_task 11 + from care.emr.resources.charge_item.apply_charge_item_definition import ( 12 + apply_charge_item_definition, 13 + ) 14 + from care.emr.resources.charge_item.spec import ChargeItemStatusOptions 15 + from care.emr.resources.invoice.default_expression_evaluator import ( 16 + evaluate_invoice_identifier_default_expression, 17 + ) 18 + from care.emr.resources.invoice.spec import InvoiceStatusOptions 19 + from care.emr.resources.invoice.sync_items import sync_invoice_items 20 + 21 + 22 + def generate_return_invoice(delivery_order: DeliveryOrder): 23 + """ 24 + Generate a return invoice for items based on delivery order 25 + """ 26 + 27 + with transaction.atomic(): 28 + charge_items = [] 29 + invoice_obj = Invoice() 30 + invoice_obj.status = InvoiceStatusOptions.draft.value 31 + invoice_obj.facility = delivery_order.destination.facility 32 + invoice_obj.number = evaluate_invoice_identifier_default_expression( 33 + invoice_obj.facility 34 + ) 35 + invoice_obj.save() 36 + for supply_delivery in SupplyDelivery.objects.filter(order=delivery_order): 37 + product = supply_delivery.supplied_item 38 + charge_item_definition = product.charge_item_definition 39 + if not charge_item_definition: 40 + continue 41 + charge_item = apply_charge_item_definition( 42 + charge_item_definition, 43 + delivery_order.patient, 44 + delivery_order.destination.facility, 45 + reverse=True, 46 + ) 47 + charge_item.status = ChargeItemStatusOptions.billed.value 48 + charge_item.save() 49 + charge_items.append(charge_item.id) 50 + invoice_obj.charge_items = charge_items 51 + sync_invoice_items(invoice_obj) 52 + invoice_obj.status = InvoiceStatusOptions.issued.value 53 + invoice_obj.save() 54 + delivery_order.patient_invoice = invoice_obj 55 + delivery_order.save(update_fields=["patient_invoice"]) 56 + rebalance_account_task.delay(invoice_obj.account.id) 57 + return invoice_obj 58 + 59 + 60 + def cancel_return_invoice(delivery_order: DeliveryOrder): 61 + """ 62 + Cancel the return invoice for items based on delivery order 63 + """ 64 + if not delivery_order.patient_invoice: 65 + return 66 + with transaction.atomic(): 67 + delivery_order.patient_invoice.status = InvoiceStatusOptions.cancelled.value 68 + delivery_order.patient_invoice.save(update_fields=["status"]) 69 + ChargeItem.objects.filter( 70 + id__in=delivery_order.patient_invoice.charge_items, 71 + ).update( 72 + status=ChargeItemStatusOptions.entered_in_error.value, 73 + paid_invoice=None, 74 + paid_on=None, 75 + ) 76 + rebalance_account_task.delay(delivery_order.patient_invoice.account.id)