Skip to content

Commit

Permalink
Merge pull request #18 from openimis/develop
Browse files Browse the repository at this point in the history
v1.3
  • Loading branch information
edarchis authored Oct 28, 2021
2 parents 1fdcd65 + 2f4acbb commit eb9a2bb
Show file tree
Hide file tree
Showing 7 changed files with 262 additions and 58 deletions.
100 changes: 100 additions & 0 deletions .github/workflows/openmis-module-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
name: Automated CI testing
# This workflow run automatically for every commit on github it checks the syntax and launch the tests.
# | grep . | uniq -c filters out empty lines and then groups consecutive lines together with the number of occurrences
on:
pull_request:
workflow_dispatch:
inputs:
comment:
description: Just a simple comment to know the purpose of the manual build
required: false

jobs:
run_test:
runs-on: ubuntu-latest
services:
mssql:
image: mcr.microsoft.com/mssql/server:2017-latest
env:
ACCEPT_EULA: Y
SA_PASSWORD: GitHub999
ports:
- 1433:1433
# needed because the mssql container does not provide a health check
options: --health-interval=10s --health-timeout=3s --health-start-period=10s --health-retries=10 --health-cmd="/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P ${SA_PASSWORD} -Q 'SELECT 1' || exit 1"

steps:
- name: Set up Python 3.8
uses: actions/setup-python@v2
with:
python-version: 3.8
- name: install linux packages
run: |
wget https://raw.githubusercontent.com/openimis/database_ms_sqlserver/main/Empty%20databases/openIMIS_ONLINE.sql -O openIMIS_ONLINE.sql
wget https://raw.githubusercontent.com/openimis/database_ms_sqlserver/main/Demo%20database/openIMIS_demo_ONLINE.sql -O openIMIS_demo_ONLINE.sql
curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add -
curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list | sudo tee /etc/apt/sources.list.d/msprod.list
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install -y mssql-tools build-essential dialog apt-utils unixodbc-dev -y
python -m pip install --upgrade pip
- name: pull openimis backend
run: |
rm ./openimis -rf
git clone --depth 1 --branch develop https://github.com/openimis/openimis-be_py.git ./openimis
- name: copy current branch
uses: actions/checkout@v2
with:
path: './current-module'
- name: Update the configuration
working-directory: ./openimis
run: |
export MODULE_NAME="$(echo $GITHUB_REPOSITORY | sed 's#^openimis/openimis-be-\(.*\)_py$#\1#')"
echo "the local module called $MODULE_NAME will be injected in openIMIS .json"
jq --arg name "$MODULE_NAME" 'if [.modules[].name == ($name)]| max then (.modules[] | select(.name == ($name)) | .pip)|="../current-module" else .modules |= .+ [{name:($name), pip:"../current-module"}] end' openimis.json
echo $(jq --arg name "$MODULE_NAME" 'if [.modules[].name == ($name)]| max then (.modules[] | select(.name == ($name)) | .pip)|="../current-module" else .modules |= .+ [{name:($name), pip:"../current-module"}] end' openimis.json) > openimis.json
- name: Install openIMIS Python dependencies
working-directory: ./openimis
run: |
pip install -r requirements.txt
python modules-requirements.py openimis.json > modules-requirements.txt
cat modules-requirements.txt
pip install -r modules-requirements.txt
- name: Environment info
working-directory: ./openimis
run: |
pip list
- name: Initialize DB
run: |
/opt/mssql-tools/bin/sqlcmd -S localhost,1433 -U SA -P $SA_PASSWORD -Q 'DROP DATABASE IF EXISTS imis'
/opt/mssql-tools/bin/sqlcmd -S localhost,1433 -U SA -P $SA_PASSWORD -Q 'CREATE DATABASE imis'
/opt/mssql-tools/bin/sqlcmd -S localhost,1433 -U SA -P $SA_PASSWORD -d imis -i openIMIS_ONLINE.sql | grep . | uniq -c
/opt/mssql-tools/bin/sqlcmd -S localhost,1433 -U SA -P $SA_PASSWORD -d imis -i openIMIS_demo_ONLINE.sql | grep . | uniq -c
env:
SA_PASSWORD: GitHub999
ACCEPT_EULA: Y

# - name: Check formatting with black
# run: |
# black --check .

- name: Django tests
working-directory: ./openimis/openIMIS
run: |
export MODULE_NAME="$(echo $GITHUB_REPOSITORY | sed 's#^openimis/openimis-be-\(.*\)_py$#\1#')"
python -V
ls -l
python manage.py migrate
python init_test_db.py | grep . | uniq -c
python manage.py test --keepdb $MODULE_NAME
env:
SECRET_KEY: secret
DEBUG: true
#DJANGO_SETTINGS_MODULE: hat.settings
DB_HOST: localhost
DB_PORT: 1433
DB_NAME: imis
DB_USER: sa
DB_PASSWORD: GitHub999
#DEV_SERVER: true
SITE_ROOT: api
REMOTE_USER_AUTHENTICATION: True
15 changes: 11 additions & 4 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: olegtarasov/[email protected]
id: tagName
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
Expand All @@ -21,11 +23,16 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
pip install setuptools wheel twine jq
- name: update setup.py
run: |
echo "tag to use $GIT_TAG_NAME"
sed -i "s/version='.*'/version='$GIT_TAG_NAME'/g" setup.py
- name: Build and publish
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{secrets.PYPI_TOKEN}}
run: |
python setup.py sdist bdist_wheel
twine upload dist/*
twine upload dist/*
26 changes: 22 additions & 4 deletions policy/schema.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
from core.schema import (
OrderedDjangoFilterConnectionField,
signal_mutation_module_validate,
)
import graphene
from django.core.exceptions import PermissionDenied
from django.db.models import Prefetch
Expand All @@ -9,7 +13,7 @@
from django.utils.translation import gettext as _
import graphene_django_optimizer as gql_optimizer
from graphene_django.filter import DjangoFilterConnectionField
from core.schema import signal_mutation_module_validate, OrderedDjangoFilterConnectionField
from core.models import Officer
from .models import PolicyMutation
from product.models import Product
from contribution.models import Premium
Expand Down Expand Up @@ -78,7 +82,9 @@ class Query(graphene.ObjectType):
chfId=graphene.String(required=True),
serviceCode=graphene.String(required=True),
)
policy_officers = DjangoFilterConnectionField(OfficerGQLType)
policy_officers = DjangoFilterConnectionField(
OfficerGQLType, search=graphene.String()
)

def resolve_policy_values(self, info, **kwargs):
product = Product.objects.get(id=kwargs.get('product_id'))
Expand Down Expand Up @@ -245,10 +251,22 @@ def resolve_policy_service_eligibility_by_insuree(self, info, **kwargs):
req=req
)

def resolve_policy_officers(self, info, **kwargs):
if not info.context.user.has_perms(PolicyConfig.gql_query_policy_officers_perms):
def resolve_policy_officers(self, info, search=None, **kwargs):
if not info.context.user.has_perms(
PolicyConfig.gql_query_policy_officers_perms
):
raise PermissionDenied(_("unauthorized"))

qs = Officer.objects
if search is not None:
qs = qs.filter(
Q(code__icontains=search)
| Q(last_name__icontains=search)
| Q(other_names__icontains=search)
)

return qs


class Mutation(graphene.ObjectType):
create_policy = CreatePolicyMutation.Field()
Expand Down
105 changes: 70 additions & 35 deletions policy/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,33 @@ def __init__(self, user):

@staticmethod
def _to_item(row):
ceiling = None
ceiling_ip = None
ceiling_op = None
if row.product.max_treatment:
ceiling = row.product.max_treatment
if row.product.max_ip_treatment:
ceiling_ip = row.product.max_ip_treatment
if row.product.max_op_treatment:
ceiling_op = row.product.max_ip_treatment
if row.product.max_insuree:
ceiling = row.product.max_insuree - (row.total_rem_g if row.total_rem_g else 0)
else:
if row.product.max_ip_insuree:
ceiling_ip = row.product.max_ip_insuree - (row.total_rem_ip if row.total_rem_ip else 0)
if row.product.max_op_insuree:
ceiling_op = row.product.max_op_insuree - (row.total_rem_op if row.total_rem_op else 0)
if row.product.max_policy:
ceiling = row.product.max_policy - (row.total_rem_g if row.total_rem_g else 0)
else:
if row.product.max_ip_policy:
ceiling_ip = row.product.max_ip_policy - (row.total_rem_ip if row.total_rem_ip else 0)
if row.product.max_op_policy:
ceiling_op = row.product.max_op_policy - (row.total_rem_op if row.total_rem_op else 0)
balance = row.value
if row.total_ded_g:
balance -= row.total_ded_g

return ByFamilyOrInsureeResponseItem(
policy_id=row.id,
policy_uuid=row.uuid,
Expand All @@ -121,10 +148,10 @@ def _to_item(row):
ded=row.total_ded_g,
ded_in_patient=row.total_ded_ip,
ded_out_patient=row.total_ded_op,
ceiling=0, # TODO: product.xxx
ceiling_in_patient=0, # TODO: product.xxx
ceiling_out_patient=0, # TODO: product.xxx
balance=0, # TODO: nullsafe calculation from value,...
ceiling=ceiling,
ceiling_in_patient=ceiling_ip,
ceiling_out_patient=ceiling_op,
balance=balance,
validity_from=row.validity_from,
validity_to=row.validity_to
)
Expand Down Expand Up @@ -318,6 +345,14 @@ def str_none(x):
self.is_item_ok == other.is_item_ok and
self.is_service_ok == other.is_service_ok)

def __str__(self):
return f"Eligibility for {self.eligibility_request} gave product {self.prod_id} " \
f"with item/svc ok {self.is_item_ok}/{self.is_service_ok} " \
f" left: {self.item_left}/{self.service_left}"

def __repr__(self):
return self.__str__()


signal_eligibility_service_before = dispatch.Signal(providing_args=["user", "request", "response"])
signal_eligibility_service_after = dispatch.Signal(providing_args=["user", "request", "response"])
Expand Down Expand Up @@ -396,21 +431,21 @@ def request(self, req, response):
return EligibilityResponse(
eligibility_request=req,
prod_id=prod_id or None,
total_admissions_left=total_admissions_left or 0,
total_visits_left=total_visits_left or 0,
total_consultations_left=total_consultations_left or 0,
total_surgeries_left=total_surgeries_left or 0,
total_deliveries_left=total_deliveries_left or 0,
total_antenatal_left=total_antenatal_left or 0,
consultation_amount_left=consultation_amount_left or 0.0,
surgery_amount_left=surgery_amount_left or 0.0,
delivery_amount_left=delivery_amount_left or 0.0,
hospitalization_amount_left=hospitalization_amount_left or 0.0,
antenatal_amount_left=antenatal_amount_left or 0.0,
total_admissions_left=total_admissions_left,
total_visits_left=total_visits_left,
total_consultations_left=total_consultations_left,
total_surgeries_left=total_surgeries_left,
total_deliveries_left=total_deliveries_left,
total_antenatal_left=total_antenatal_left,
consultation_amount_left=consultation_amount_left,
surgery_amount_left=surgery_amount_left,
delivery_amount_left=delivery_amount_left,
hospitalization_amount_left=hospitalization_amount_left,
antenatal_amount_left=antenatal_amount_left,
min_date_service=min_date_service,
min_date_item=min_date_item,
service_left=service_left or 0,
item_left=item_left or 0,
service_left=service_left,
item_left=item_left,
is_item_ok=is_item_ok is True,
is_service_ok=is_service_ok is True
)
Expand Down Expand Up @@ -456,9 +491,9 @@ def request(self, req, response):
"policy__product_id",
waiting_period=F(waiting_period_field),
limit_no=F(limit_field))\
.annotate(min_date=MonthsAdd(waiting_period_field, "effective_date"))\
.annotate(min_date=MonthsAdd(Coalesce(F(waiting_period_field), 0), "effective_date"))\
.annotate(services_count=Count("policy__product__products__service_id"))\
.annotate(services_left=Coalesce("limit_no", Value(0)) - F("services_count"))
.annotate(services_left=F("limit_no") - F("services_count"))

min_date_qs = queryset_svc.aggregate(
min_date_lte=Min("min_date", filter=Q(min_date__lte=now)),
Expand All @@ -480,7 +515,7 @@ def request(self, req, response):
services_left = None
min_date_service = None
eligibility.min_date_service = min_date_service
eligibility.service_left = services_left or 0
eligibility.service_left = services_left

# TODO remove code duplication between service and item
if req.item_code:
Expand All @@ -491,7 +526,7 @@ def request(self, req, response):
waiting_period_field = "policy__product__items__waiting_period_child"
limit_field = "policy__product__items__limit_no_child"

item = Item.get_queryset(None, self.user).get(code__iexact=req.item_code) # TODO validity is checked but should be optional in get_queryset
item = Item.get_queryset(None, self.user).get(code__iexact=req.item_code)

queryset_item = InsureePolicy.objects\
.filter(validity_to__isnull=True)\
Expand All @@ -510,9 +545,9 @@ def request(self, req, response):
"policy__product_id",
waiting_period=F(waiting_period_field),
limit_no=F(limit_field))\
.annotate(min_date=MonthsAdd(waiting_period_field, "effective_date"))\
.annotate(min_date=MonthsAdd(Coalesce(F(waiting_period_field), 0), "effective_date"))\
.annotate(items_count=Count("policy__product__items__item_id")) \
.annotate(items_left=Coalesce("limit_no", Value(0)) - F("items_count"))
.annotate(items_left=F("limit_no") - F("items_count"))

min_date_qs = queryset_item.aggregate(
min_date_lte=Min("min_date", filter=Q(min_date__lte=now)),
Expand All @@ -534,7 +569,7 @@ def request(self, req, response):
items_left = None
min_date_item = None
eligibility.min_date_item = min_date_item
eligibility.item_left = items_left or 0
eligibility.item_left = items_left

def get_total_filter(category):
return (
Expand Down Expand Up @@ -620,11 +655,11 @@ def get_total_filter(category):
total_visits_left = result["total_visits_left"] \
if result["total_visits_left"] is None or result["total_visits_left"] >= 0 else 0

eligibility.surgery_amount_left = result["policy__product__max_amount_surgery"] or 0.0
eligibility.consultation_amount_left = result["policy__product__max_amount_consultation"] or 0.0
eligibility.delivery_amount_left = result["policy__product__max_amount_delivery"] or 0.0
eligibility.antenatal_amount_left = result["policy__product__max_amount_antenatal"] or 0.0
eligibility.hospitalization_amount_left = result["policy__product__max_amount_hospitalization"] or 0.0
eligibility.surgery_amount_left = result["policy__product__max_amount_surgery"]
eligibility.consultation_amount_left = result["policy__product__max_amount_consultation"]
eligibility.delivery_amount_left = result["policy__product__max_amount_delivery"]
eligibility.antenatal_amount_left = result["policy__product__max_amount_antenatal"]
eligibility.hospitalization_amount_left = result["policy__product__max_amount_hospitalization"]

if service:
if service.category == Service.CATEGORY_SURGERY:
Expand Down Expand Up @@ -670,12 +705,12 @@ def get_total_filter(category):
eligibility.is_item_ok = True

# The process above uses the None type but the stored procedure service sets these to 0
eligibility.total_admissions_left = total_admissions_left or 0
eligibility.total_consultations_left = total_consultations_left or 0
eligibility.total_surgeries_left = total_surgeries_left or 0
eligibility.total_deliveries_left = total_deliveries_left or 0
eligibility.total_antenatal_left = total_antenatal_left or 0
eligibility.total_visits_left = total_visits_left or 0
eligibility.total_admissions_left = total_admissions_left
eligibility.total_consultations_left = total_consultations_left
eligibility.total_surgeries_left = total_surgeries_left
eligibility.total_deliveries_left = total_deliveries_left
eligibility.total_antenatal_left = total_antenatal_left
eligibility.total_visits_left = total_visits_left
return eligibility


Expand Down
5 changes: 5 additions & 0 deletions policy/signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from core.signals import Signal


_check_formal_sector_for_policy_signal_params = ["user", "policy_id"]
signal_check_formal_sector_for_policy = Signal(providing_args=_check_formal_sector_for_policy_signal_params)
Loading

0 comments on commit eb9a2bb

Please sign in to comment.