diff --git a/README.md b/README.md
index e2081ea..03bc92e 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@ Bika Health LIS
Bika Laboratory Information Management System customised for use in Health laboratories.
-Last stable version: **v3.1.6** · released: 2015-02-27
+Last stable version: **v3.1.7** · released: 2015-06-09
[**Naringenin**](http://en.wikipedia.org/wiki/Naringenin) is a flavanone, a typeof flavonoid, that is considered to have a bioactive effect on human health as antioxidant, free radical scavenger, anti-inflammatory, carbohydrate metabolism promoter, and immune system modulator. It is the predominant flavanone in grapefruit.
@@ -12,7 +12,7 @@ Installation and upgrades
Bika Health can be installed on Windows, Mac OS X, Linux, BSD and other platforms:
https://github.com/bikalabs/bika.health/wiki/Installing-Bika-Health-Extension
-**Bika Health LIS 3.1.6 is only compatible with Bika LIMS 3.1.7**. Follow the instructions [Installing Bika Health Extension](https://github.com/bikalabs/bika.health/wiki/Installing-Bika-Health-Extension).
+**Bika Health LIS 3.1.7 is only compatible with Bika LIMS 3.1.8**. Follow the instructions [Installing Bika Health Extension](https://github.com/bikalabs/bika.health/wiki/Installing-Bika-Health-Extension).
You might also find useful the following recipes:
- Installing Bika LIMS: https://github.com/bikalabs/Bika-LIMS/wiki/Bika-LIMS-Installation
diff --git a/bika/health/__init__.py b/bika/health/__init__.py
index 2acc32f..58dd9ba 100644
--- a/bika/health/__init__.py
+++ b/bika/health/__init__.py
@@ -35,6 +35,7 @@ def initialize(context):
from content.aetiologicagent import AetiologicAgent
from content.caseoutcome import CaseOutcome
from content.casestatus import CaseStatus
+ from content.ethnicity import Ethnicity
from content.casesyndromicclassification import CaseSyndromicClassification
from content.disease import Disease
from content.doctor import Doctor
@@ -64,6 +65,7 @@ def initialize(context):
from controlpanel.bika_immunizations import Immunizations
from controlpanel.bika_treatments import Treatments
from controlpanel.bika_insurancecompanies import InsuranceCompanies
+ from controlpanel.bika_ethnicities import Ethnicities
from controlpanel.bika_vaccinationcenters import VaccinationCenters
content_types, constructors, ftis = process_types(
diff --git a/bika/health/browser/admin.py b/bika/health/browser/admin.py
deleted file mode 100644
index 706c419..0000000
--- a/bika/health/browser/admin.py
+++ /dev/null
@@ -1,16 +0,0 @@
-from Products.CMFPlone.browser.admin import Overview as OverviewBase
-from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
-
-
-
-class Overview(OverviewBase):
- """ Customized plone overview. """
-
- index = ViewPageTemplateFile('plone-addsiteTemplates/plone-overview.pt')
-
- def __call__(self):
- """ Redirect to bika.health instance if single instance is found. """
- sites = self.sites()
- if len(sites) == 1 and not self.outdated(sites[0]):
- return self.request.response.redirect(sites[0].absolute_url())
- return self.index()
\ No newline at end of file
diff --git a/bika/health/browser/analysisrequest/add.py b/bika/health/browser/analysisrequest/add.py
new file mode 100644
index 0000000..fbf8c69
--- /dev/null
+++ b/bika/health/browser/analysisrequest/add.py
@@ -0,0 +1,78 @@
+from bika.lims.browser.analysisrequest.add import AnalysisRequestAddView as AnalysisRequestAddViewLIMS
+from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
+import json
+from Products.CMFCore.utils import getToolByName
+from bika.lims.browser.widgets import AddressWidget
+
+
+class AnalysisRequestAddView(AnalysisRequestAddViewLIMS):
+ """
+ The main AR Add form adapted for health usage
+ """
+ health_template = ViewPageTemplateFile("templates/ar_add_health_standard.pt")
+ patient_template = ViewPageTemplateFile("templates/ar_addpatient.pt")
+ doctor_referrer_template = ViewPageTemplateFile("templates/ar_add_doctor_referrer.pt")
+ insurance_template = ViewPageTemplateFile("templates/ar_insurance.pt")
+ analyses_template = ViewPageTemplateFile("templates/ar_analyses.pt")
+ prices_template = ViewPageTemplateFile("templates/ar_prices.pt")
+
+ def __init__(self, context, request):
+ AnalysisRequestAddViewLIMS.__init__(self, context, request)
+ self.templatename = self.request.get('tpl','')
+ self.w = AddressWidget()
+
+ def __call__(self):
+ if self.templatename == 'classic':
+ return AnalysisRequestAddViewLIMS.__call__(self)
+
+ # Getting the checkbox value
+ enable_bika_request_field = self.context.bika_setup.Schema().getField('EnableBikaAnalysisRequestRequestForm')
+ enable_bika_request = enable_bika_request_field.get(self.context.bika_setup)
+ if enable_bika_request:
+ # Use the template defined on BikaLIMS
+ return AnalysisRequestAddViewLIMS.__call__(self)
+ else:
+ # Use the Health's template
+ self.col_count = 1
+ self.request.set('disable_border', 1)
+ return self.health_template()
+
+ def get_json_format(self, d):
+ """
+ Given some data, it gets its json format.
+ :param d: Data to be formatted.
+ :return: The formatted data in JSON.
+ """
+ return json.dumps(d)
+
+ def getDepartments(self):
+ """
+ It obtains the different departments
+ :return: A list with the department names and UID's [(UID,Name),....]
+ """
+ dep = getToolByName(self.context, 'bika_setup_catalog')(portal_type='Department')
+ l = []
+ for i in dep:
+ l.append((i.UID, i.Title))
+ return l
+
+ def categoryInDepartment(self, category, department):
+ """
+ It checks if the category belongs to the department
+ :param category: The category UID
+ :param department: The department UID
+ :return: True or False
+ """
+ return getToolByName(self.context, 'bika_setup_catalog')(UID=category)[0]\
+ .getObject().getDepartment().UID() == department
+
+ def getAvailableServices(self, categoryuid):
+ """ Return a list of services brains
+ """
+ bsc = getToolByName(self.context, 'bika_setup_catalog')
+ services = bsc(portal_type="AnalysisService",
+ sort_on='sortable_title',
+ inactive_state='active',
+ getCategoryUID=categoryuid)
+ return services
+
diff --git a/bika/health/browser/analysisrequest/overrides.zcml b/bika/health/browser/analysisrequest/overrides.zcml
index b50de0f..5e9ee18 100644
--- a/bika/health/browser/analysisrequest/overrides.zcml
+++ b/bika/health/browser/analysisrequest/overrides.zcml
@@ -76,4 +76,12 @@
permission="bika.lims.ManageInvoices"
layer="bika.lims.interfaces.IBikaLIMS"
/>
+
+
diff --git a/bika/health/browser/analysisrequest/templates/ar_add_doctor_referrer.pt b/bika/health/browser/analysisrequest/templates/ar_add_doctor_referrer.pt
new file mode 100644
index 0000000..2b71e5b
--- /dev/null
+++ b/bika/health/browser/analysisrequest/templates/ar_add_doctor_referrer.pt
@@ -0,0 +1,67 @@
+
+
+
Doctor and Referral Institution
+
+
+
+
+ Doctor's Code
+
+
+
+
+
+
+
+
+
diff --git a/bika/health/browser/analysisrequest/templates/ar_add_health_standard.pt b/bika/health/browser/analysisrequest/templates/ar_add_health_standard.pt
new file mode 100644
index 0000000..55f155d
--- /dev/null
+++ b/bika/health/browser/analysisrequest/templates/ar_add_health_standard.pt
@@ -0,0 +1,337 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bika/health/browser/analysisrequest/templates/ar_addpatient.pt b/bika/health/browser/analysisrequest/templates/ar_addpatient.pt
new file mode 100644
index 0000000..de9ed48
--- /dev/null
+++ b/bika/health/browser/analysisrequest/templates/ar_addpatient.pt
@@ -0,0 +1,194 @@
+
+
Patient Details
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Birth date is estimated
+
+
+
+
+
+
+
+ Gender
+
+ Male
+ Female
+ Don't Know
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bika/health/browser/analysisrequest/templates/ar_analyses.pt b/bika/health/browser/analysisrequest/templates/ar_analyses.pt
new file mode 100644
index 0000000..43c8043
--- /dev/null
+++ b/bika/health/browser/analysisrequest/templates/ar_analyses.pt
@@ -0,0 +1,63 @@
+
diff --git a/bika/health/browser/analysisrequest/templates/ar_insurance.pt b/bika/health/browser/analysisrequest/templates/ar_insurance.pt
new file mode 100644
index 0000000..de7d0ec
--- /dev/null
+++ b/bika/health/browser/analysisrequest/templates/ar_insurance.pt
@@ -0,0 +1,174 @@
+
+
Account to
+
+
+
+
+ Patient as guarantor
+
+
+
+
+
+
+
+
+
+ Guarantor ID Number
+ The ID number (Insurance Number) from the person whose contract cover the current patient.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Country
+
+
+
+
+
+
+
+
+
+
+ State
+
+
+
+
+
+
+
+
+
+
+ District
+
+
+
+
+
+
+
+
+
+
+ City
+
+
+
+ Postal Code
+
+
+
+ Address
+
+
+
+
+
+
+
diff --git a/bika/health/browser/analysisrequest/templates/ar_prices.pt b/bika/health/browser/analysisrequest/templates/ar_prices.pt
new file mode 100644
index 0000000..bbb79d7
--- /dev/null
+++ b/bika/health/browser/analysisrequest/templates/ar_prices.pt
@@ -0,0 +1,79 @@
+
\ No newline at end of file
diff --git a/bika/health/browser/overrides.zcml b/bika/health/browser/overrides.zcml
deleted file mode 100644
index 37d955a..0000000
--- a/bika/health/browser/overrides.zcml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/bika/health/browser/plone-addsiteTemplates/plone-addsite.pt b/bika/health/browser/plone-addsiteTemplates/plone-addsite.pt
deleted file mode 100644
index a4f38ee..0000000
--- a/bika/health/browser/plone-addsiteTemplates/plone-addsite.pt
+++ /dev/null
@@ -1,212 +0,0 @@
-
-
-
-
-
-
- Install Bika Health
-
-
-
-
-
-
-
-
-
-
- Install Bika health
-
-
-
-
\ No newline at end of file
diff --git a/bika/health/browser/plone-addsiteTemplates/plone-overview.pt b/bika/health/browser/plone-addsiteTemplates/plone-overview.pt
deleted file mode 100644
index a6bdb70..0000000
--- a/bika/health/browser/plone-addsiteTemplates/plone-overview.pt
+++ /dev/null
@@ -1,163 +0,0 @@
-
-
-
-
-
-
- Bika health - Professional Open Source LIMS for Health Labs
-
-
-
-
-
-
-
-
-
-
-
- Professional Open Source LIMS for Health Labs
-
-
-
-
-
-
diff --git a/bika/health/config.py b/bika/health/config.py
index 361e020..2152689 100644
--- a/bika/health/config.py
+++ b/bika/health/config.py
@@ -6,6 +6,12 @@
PROJECTNAME = "bika.health"
+GENDERS = DisplayList((
+ ('male', _('Male')),
+ ('female', _('Female')),
+ ('dk', _("Don't Know")),
+ ))
+
ETHNICITIES = DisplayList((
('Native American', _('Native American')),
('Asian', _('Asian')),
@@ -15,12 +21,6 @@
('Hispanic or Latino', _('Hispanic or Latino')),
))
-GENDERS = DisplayList((
- ('male', _('Male')),
- ('female', _('Female')),
- ('dk', _("Don't Know")),
- ))
-
GENDERS_APPLY = DisplayList((
('male', _('Male')),
('female', _('Female')),
diff --git a/bika/health/content/bikasetup.py b/bika/health/content/bikasetup.py
index 789bc4f..7edf992 100644
--- a/bika/health/content/bikasetup.py
+++ b/bika/health/content/bikasetup.py
@@ -95,6 +95,17 @@ class BikaSetupSchemaExtender(object):
"preferences' tab.")
)
),
+ ExtBooleanField('EnableBikaAnalysisRequestRequestForm',
+ schemata="Analyses",
+ default=False,
+ widget=BooleanWidget(
+ label=_("Enable Bika's analysis request form."),
+ description=_("It enables the secondary analysis request form. This request has some characteristic "
+ "features as allowing you to register more than one analysis request at the same time. "
+ "It's useful if you are supposed to register a big amount of analysis request at the same "
+ "time.")
+ )
+ ),
]
def __init__(self, context):
diff --git a/bika/health/content/ethnicity.py b/bika/health/content/ethnicity.py
new file mode 100644
index 0000000..97d0c4f
--- /dev/null
+++ b/bika/health/content/ethnicity.py
@@ -0,0 +1,23 @@
+from zope.interface import implements
+from Products.Archetypes import atapi
+from Products.Archetypes.public import BaseContent
+from bika.health.interfaces import IEthnicity
+from bika.lims.content.bikaschema import BikaSchema
+from bika.health import config
+
+
+schema = BikaSchema.copy() + atapi.Schema((
+
+))
+
+schema['description'].widget.visible = True
+schema['description'].schemata = 'default'
+
+
+class Ethnicity(BaseContent):
+ # It implements the IEthnicity interface
+ implements(IEthnicity)
+ schema = schema
+
+# Activating the content type in Archetypes' internal types registry
+atapi.registerType(Ethnicity, config.PROJECTNAME)
diff --git a/bika/health/content/patient.py b/bika/health/content/patient.py
index ea7a0fc..1f719ca 100644
--- a/bika/health/content/patient.py
+++ b/bika/health/content/patient.py
@@ -20,6 +20,7 @@
from bika.health.widgets import ReadonlyStringWidget
from datetime import datetime
from zope.interface import implements
+from Products.Archetypes.references import HoldingReference
from bika.health.widgets.patientmenstrualstatuswidget import PatientMenstrualStatusWidget
schema = Person.schema.copy() + Schema((
@@ -304,10 +305,24 @@
label=_('Birth place'),
),
),
+ # TODO This field will be removed on release 319. We maintain this field on release 318
+ # because of the transference between string field and content type data.
StringField('Ethnicity', schemata='Personal',
- index='FieldIndex',
- vocabulary=ETHNICITIES,
- widget=ReferenceWidget(
+ index='FieldIndex',
+ vocabulary=ETHNICITIES,
+ widget=ReferenceWidget(
+ label=_('Ethnicity'),
+ description=_("Ethnicity eg. Asian, African, etc."),
+ visible=False,
+ ),
+ ),
+ # TODO This field will change its name on v319 and it'll be called Ethnicity
+ ReferenceField('Ethnicity_Obj', schemata='Personal',
+ vocabulary='getEthnicitiesVocabulary',
+ allowed_types = ('Ethnicity',),
+ relationship = 'PatientEthnicity',
+ widget=SelectionWidget(
+ format='select',
label=_('Ethnicity'),
description=_("Ethnicity eg. Asian, African, etc."),
),
@@ -322,6 +337,11 @@
label=_('Mothers name'),
),
),
+ StringField('FathersName', schemata='Personal',
+ widget=StringWidget(
+ label=_('Fathers name'),
+ ),
+ ),
StringField('CivilStatus', schemata='Personal',
widget=StringWidget(
label=_('Civil status'),
@@ -415,6 +435,64 @@
description=_("If it is checked the invoices will be send to the insurance company."
" In this case the insurance number will be mandatory."))
),
+ BooleanField('PatientAsGuarantor',
+ schemata = 'Insurance',
+ default=True,
+ widget=BooleanWidget(
+ label=_("The patient is the guarantor."),
+ description=_("The patient and the guarantor are the same."))
+ ),
+ StringField('GuarantorID',
+ searchable=1,
+ schemata = 'Insurance',
+ required=0,
+ widget=StringWidget(
+ label=_('Guarantor ID'),
+ description=_("The ID number (Insurance Number) from the person whose contract cover the current patient.")
+ ),
+ ),
+ StringField('GuarantorSurname',
+ searchable=1,
+ schemata = 'Insurance',
+ required=0,
+ widget=StringWidget(
+ label=_("Guarantor's Surname"),
+ ),
+ ),
+ StringField('GuarantorFirstname',
+ searchable=1,
+ schemata = 'Insurance',
+ required=0,
+ widget=StringWidget(
+ label=_("Guarantor's First Name"),
+ ),
+ ),
+ StringField('GuarantorPostalAddress',
+ searchable=1,
+ schemata = 'Insurance',
+ required=0,
+ widget=AddressWidget(
+ label=_("Guarantor's postal address"),
+ ),
+ ),
+ StringField('GuarantorBusinessPhone',
+ schemata = 'Insurance',
+ widget = StringWidget(
+ label=_("Guarantor's Phone (business)"),
+ ),
+ ),
+ StringField('GuarantorHomePhone',
+ schemata = 'Insurance',
+ widget = StringWidget(
+ label=_("Guarantor's Phone (home)"),
+ ),
+ ),
+ StringField('GuarantorMobilePhone',
+ schemata = 'Insurance',
+ widget = StringWidget(
+ label=_("Guarantor's Phone (mobile)"),
+ ),
+ ),
))
schema['JobTitle'].widget.visible = False
@@ -591,5 +669,89 @@ def getCountryState(self):
if self.getField('CountryState').get(self) \
else self.getPhysicalAddress()
+ def getGuarantorID(self):
+ """
+ If the patient is the guarantor, all the fields related with the guarantor are going to have the same value as
+ the current patient fields.
+ :return: The guarantor ID (insurance number) from
+ """
+ return self.getInsuranceNumber() if self.getPatientAsGuarantor() else self.getField('GuarantorID').get(self)
+
+ def getGuarantorSurname(self):
+ """
+ If the patient is the guarantor, all the fields related with the guarantor are going to have the same value as
+ the current patient fields.
+ """
+ return self.getSurname() if self.getPatientAsGuarantor() else self.getField('GuarantorSurname').get(self)
+
+ def getGuarantorFirstname(self):
+ """
+ If the patient is the guarantor, all the fields related with the guarantor are going to have the same value as
+ the current patient fields.
+ """
+ return self.getFirstname() if self.getPatientAsGuarantor() else self.getField('GuarantorFirstname').get(self)
+
+ def getGuarantorPostalAddress(self):
+ """
+ If the patient is the guarantor, all the fields related with the guarantor are going to have the same value as
+ the current patient fields.
+ """
+ return self.getPostalAddress() \
+ if self.getPatientAsGuarantor() \
+ else self.getField('GuarantorPostalAddress').get(self)
+
+ def getGuarantorBusinessPhone(self):
+ """
+ If the patient is the guarantor, all the fields related with the guarantor are going to have the same value as
+ the current patient fields.
+ """
+ return self.getBusinessPhone() \
+ if self.getPatientAsGuarantor() \
+ else self.getField('GuarantorBusinessPhone').get(self)
+
+ def getGuarantorHomePhone(self):
+ """
+ If the patient is the guarantor, all the fields related with the guarantor are going to have the same value as
+ the current patient fields.
+ """
+ return self.getHomePhone() if self.getPatientAsGuarantor() else self.getField('GuarantorHomePhone').get(self)
+
+ def getGuarantorMobilePhone(self):
+ """
+ If the patient is the guarantor, all the fields related with the guarantor are going to have the same value as
+ the current patient fields.
+ """
+ return self.getMobilePhone() \
+ if self.getPatientAsGuarantor() \
+ else self.getField('GuarantorMobilePhone').get(self)
+
+ def getEthnicitiesVocabulary(self, instance=None):
+ """
+ Obtain all the ethnicities registered in the system and returns them as a list
+ """
+ bsc = getToolByName(self, 'bika_setup_catalog')
+ items = [(c.UID, c.Title) \
+ for c in bsc(portal_type='Ethnicity',
+ inactive_state = 'active')]
+ items.sort(lambda x,y:cmp(x[1], y[1]))
+ items.insert(0, ('', t(_(''))))
+ return DisplayList(items)
+
+ # TODO This function will will be removed on v319
+ def getEthnicity(self):
+ """
+ This function exists because we are changing the construction of ethnicities. Until now, ethnicities options were
+ hand-coded but now they are a new content type. So we need to pass all patient's ethnicity values, but to do
+ such thing, we need to create new ethnicity types on upgrade step and edit patient ethnicity field to relate them
+ with its corresponding ethnicity content type.
+ :return:
+ """
+ return self.getEthnicity_Obj()
+
+ # TODO This function will be removed on v319
+ def setEthnicity(self, value):
+ self.setEthnicity_Obj(value)
+
+
# schemata.finalizeATCTSchema(schema, folderish=True, moveDiscussion=False)
atapi.registerType(Patient, PROJECTNAME)
diff --git a/bika/health/controlpanel/bika_ethnicities.py b/bika/health/controlpanel/bika_ethnicities.py
new file mode 100644
index 0000000..15e9af8
--- /dev/null
+++ b/bika/health/controlpanel/bika_ethnicities.py
@@ -0,0 +1,81 @@
+from Products.ATContentTypes.content import schemata
+from Products.Archetypes import atapi
+from bika.lims.browser.bika_listing import BikaListingView
+from bika.health.config import PROJECTNAME
+from bika.health import bikaMessageFactory as _
+from bika.health.interfaces import IEthnicities
+from plone.app.layout.globals.interfaces import IViewView
+from plone.app.content.browser.interfaces import IFolderContentsView
+from plone.app.folder.folder import ATFolder, ATFolderSchema
+from zope.interface.declarations import implements
+
+
+class EthnicitiesView(BikaListingView):
+ implements(IFolderContentsView, IViewView)
+
+ def __init__(self, context, request):
+ super(EthnicitiesView, self).__init__(context, request)
+ self.catalog = 'bika_setup_catalog'
+ self.contentFilter = {'portal_type': 'Ethnicity',
+ 'sort_on': 'sortable_title'}
+ self.context_actions = {_('Add'):
+ {'url': 'createObject?type_name=Ethnicity',
+ 'icon': '++resource++bika.lims.images/add.png'}}
+ self.title = self.context.translate(_("Ethnicities"))
+ self.icon = self.portal_url + "/++resource++bika.health.images/patient.png"
+ self.description = ""
+ self.show_sort_column = False
+ self.show_select_row = False
+ self.show_select_column = True
+ self.pagesize = 25
+
+ self.columns = {
+ 'Title': {'title': _('Ethnicity Name'),
+ 'index': 'sortable_title'},
+
+ 'Description': {'title': _('Description'),
+ 'index': 'description',
+ 'toggle': False},
+ }
+
+ self.review_states = [
+ {'id': 'default',
+ 'title': _('Active'),
+ 'contentFilter': {'inactive_state': 'active'},
+ 'transitions': [{'id': 'deactivate'}, ],
+ 'columns': ['Title',
+ 'Description']},
+ {'id': 'inactive',
+ 'title': _('Dormant'),
+ 'contentFilter': {'inactive_state': 'inactive'},
+ 'transitions': [{'id': 'activate'}, ],
+ 'columns': ['Title',
+ 'Description']},
+ {'id': 'all',
+ 'title': _('All'),
+ 'contentFilter': {},
+ 'columns': ['Title',
+ 'Description']},
+ ]
+
+ def folderitems(self):
+ items = BikaListingView.folderitems(self)
+ for x in range(len(items)):
+ if not items[x].has_key('obj'): continue
+ obj = items[x]['obj']
+ items[x]['Description'] = obj.Description()
+ items[x]['replace']['Title'] = "%s " % \
+ (items[x]['url'], items[x]['Title'])
+
+ return items
+
+schema = ATFolderSchema.copy()
+
+
+class Ethnicities(ATFolder):
+ implements(IEthnicities)
+ displayContentsTab = False
+ schema = schema
+
+schemata.finalizeATCTSchema(schema, folderish=True, moveDiscussion=False)
+atapi.registerType(Ethnicities, PROJECTNAME)
diff --git a/bika/health/controlpanel/configure.zcml b/bika/health/controlpanel/configure.zcml
index 50dbbf6..23fb7ac 100644
--- a/bika/health/controlpanel/configure.zcml
+++ b/bika/health/controlpanel/configure.zcml
@@ -116,4 +116,12 @@
layer="bika.lims.interfaces.IBikaLIMS"
/>
+
+
diff --git a/bika/health/interfaces.py b/bika/health/interfaces.py
index 38ace79..6cc507f 100644
--- a/bika/health/interfaces.py
+++ b/bika/health/interfaces.py
@@ -59,3 +59,14 @@ class IInsuranceCompany(Interface):
class IInsuranceCompanies(Interface):
""
+
+class IEthnicity(Interface):
+ """
+ Ethnicity content type marker
+ """
+
+
+class IEthnicities(Interface):
+ """
+ Ethnicities content folder marker
+ """
diff --git a/bika/health/overrides.zcml b/bika/health/overrides.zcml
index 9569040..6a19d5f 100644
--- a/bika/health/overrides.zcml
+++ b/bika/health/overrides.zcml
@@ -11,7 +11,6 @@
-
diff --git a/bika/health/permissions.py b/bika/health/permissions.py
index a2cfc7d..7169637 100644
--- a/bika/health/permissions.py
+++ b/bika/health/permissions.py
@@ -20,6 +20,7 @@
AddSymptom = 'BIKA: Add Symptom'
AddDrugProhibition = 'BIKA: Add DrugProhibition'
AddInsuranceCompany = 'BIKA: Add InsuranceCompany'
+AddEthnicity = 'BIKA: Add Ethnicity'
# Add Permissions for specific types, if required
ADD_CONTENT_PERMISSIONS = {
@@ -32,7 +33,8 @@
'VaccinationCenter': AddVaccinationCenter,
'Symptom': AddSymptom,
'DrugProhibition': AddDrugProhibition,
- 'InsuranceCompany': AddInsuranceCompany
+ 'InsuranceCompany': AddInsuranceCompany,
+ 'Ethnicity': AddEthnicity
}
ManageDoctors = "BIKA: Manage Doctors"
@@ -41,6 +43,7 @@
ViewSamples = "BIKA: View Samples"
ViewAnalysisRequests = "BIKA: View AnalysisRequests"
ViewInsuranceCompanies = "BIKA: View InsuranceCompanies"
+ViewEthnicities = "BIKA: View Ethnicities"
# Patient permissions
ViewPatients = 'BIKA: View Patients'
diff --git a/bika/health/permissions.zcml b/bika/health/permissions.zcml
index 443a5b2..12b961a 100644
--- a/bika/health/permissions.zcml
+++ b/bika/health/permissions.zcml
@@ -23,7 +23,8 @@
-
+ +
+
@@ -32,6 +33,7 @@
+
# Patient permissions
diff --git a/bika/health/profiles/default/controlpanel.xml b/bika/health/profiles/default/controlpanel.xml
index 6ec1221..4adb252 100644
--- a/bika/health/profiles/default/controlpanel.xml
+++ b/bika/health/profiles/default/controlpanel.xml
@@ -130,4 +130,13 @@
BIKA: Manage Bika
+
+ BIKA: Manage Bika
+
+
diff --git a/bika/health/profiles/default/cssregistry.xml b/bika/health/profiles/default/cssregistry.xml
index 93cd30e..55b399b 100644
--- a/bika/health/profiles/default/cssregistry.xml
+++ b/bika/health/profiles/default/cssregistry.xml
@@ -24,4 +24,11 @@
rendering="link"
insert-after="*"/>
+
+
diff --git a/bika/health/profiles/default/factorytool.xml b/bika/health/profiles/default/factorytool.xml
index 45fa6a5..4734910 100644
--- a/bika/health/profiles/default/factorytool.xml
+++ b/bika/health/profiles/default/factorytool.xml
@@ -17,5 +17,6 @@
+
diff --git a/bika/health/profiles/default/jsregistry.xml b/bika/health/profiles/default/jsregistry.xml
index 493ea23..40cd028 100644
--- a/bika/health/profiles/default/jsregistry.xml
+++ b/bika/health/profiles/default/jsregistry.xml
@@ -78,6 +78,17 @@
inline="False"
insert-after="*"/>
+
+
- 316
+ 317
profile-bika.lims:default
diff --git a/bika/health/profiles/default/structure/bika_setup/.objects b/bika/health/profiles/default/structure/bika_setup/.objects
index ec5b25d..08170c3 100644
--- a/bika/health/profiles/default/structure/bika_setup/.objects
+++ b/bika/health/profiles/default/structure/bika_setup/.objects
@@ -12,3 +12,4 @@ bika_symptoms,Symptoms
bika_treatments,Treatments
bika_vaccinationcenters,VaccinationCenters
bika_insurancecompanies,InsuranceCompanies
+bika_ethnicities,Ethnicities
diff --git a/bika/health/profiles/default/structure/bika_setup/.preserve b/bika/health/profiles/default/structure/bika_setup/.preserve
index 70241b9..dc8b558 100644
--- a/bika/health/profiles/default/structure/bika_setup/.preserve
+++ b/bika/health/profiles/default/structure/bika_setup/.preserve
@@ -12,4 +12,4 @@ bika_insurancecompanies
bika_symptoms
bika_treatments
bika_vaccinationcenters
-
+bika_ethnicities
diff --git a/bika/health/profiles/default/structure/bika_setup/bika_ethnicities/.properties b/bika/health/profiles/default/structure/bika_setup/bika_ethnicities/.properties
new file mode 100644
index 0000000..a1f37e1
--- /dev/null
+++ b/bika/health/profiles/default/structure/bika_setup/bika_ethnicities/.properties
@@ -0,0 +1,3 @@
+[DEFAULT]
+description =
+title = Ethnicities
\ No newline at end of file
diff --git a/bika/health/profiles/default/types.xml b/bika/health/profiles/default/types.xml
index c1d4cfa..3e2a673 100644
--- a/bika/health/profiles/default/types.xml
+++ b/bika/health/profiles/default/types.xml
@@ -17,6 +17,8 @@
+
+
diff --git a/bika/health/profiles/default/types/Ethnicities.xml b/bika/health/profiles/default/types/Ethnicities.xml
new file mode 100644
index 0000000..45fb921
--- /dev/null
+++ b/bika/health/profiles/default/types/Ethnicities.xml
@@ -0,0 +1,26 @@
+
+
+ Ethnicities
+
+ ++resource++bika.health.images/patient_big.png
+ Ethnicities
+ bika.health
+ addEthnicities
+
+
+ False
+ True
+
+
+
+ False
+ False
+
+
+
+
+
+
diff --git a/bika/health/profiles/default/types/Ethnicity.xml b/bika/health/profiles/default/types/Ethnicity.xml
new file mode 100644
index 0000000..3bc7ac9
--- /dev/null
+++ b/bika/health/profiles/default/types/Ethnicity.xml
@@ -0,0 +1,41 @@
+
+
+ Ethnicity
+ The ethnicity of the patient
+ Ethnicity
+ ++resource++bika.health.images/patient.png
+ bika.health
+ addEthnicity
+ True
+ True
+ False
+ False
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bika/health/profiles/default/workflows.xml b/bika/health/profiles/default/workflows.xml
index cc963d1..caadb41 100644
--- a/bika/health/profiles/default/workflows.xml
+++ b/bika/health/profiles/default/workflows.xml
@@ -117,5 +117,11 @@
+
+
+
+
+
+
diff --git a/bika/health/setupdata/__init__.py b/bika/health/setupdata/__init__.py
index 9ee9a0a..5ea8b91 100644
--- a/bika/health/setupdata/__init__.py
+++ b/bika/health/setupdata/__init__.py
@@ -1,6 +1,7 @@
from Products.CMFCore.utils import getToolByName
from Products.CMFPlone.utils import safe_unicode, _createObjectByType
from bika.lims import logger
+from Products.CMFCore.utils import getToolByName
from bika.lims.exportimport.dataimport import SetupDataSetList as SDL
from bika.lims.exportimport.setupdata import WorksheetImporter
from bika.lims.idserver import renameAfterCreation
@@ -8,6 +9,7 @@
from bika.lims.utils import tmpID
from pkg_resources import resource_filename
from zope.interface import implements
+import transaction
class SetupDataSetList(SDL):
@@ -261,6 +263,21 @@ def Import(self):
renameAfterCreation(obj)
+class Ethnicities(WorksheetImporter):
+
+ def Import(self):
+ folder = self.context.bika_setup.bika_ethnicities
+ rows = self.get_rows(3)
+ for row in rows:
+ _id = folder.invokeFactory('Ethnicity', id=tmpID())
+ obj = folder[_id]
+ if row.get('Title', None):
+ obj.edit(title=row['Title'],
+ description=row.get('Description', ''))
+ obj.unmarkCreationFlag()
+ renameAfterCreation(obj)
+
+
class Patients(WorksheetImporter):
def Import(self):
@@ -275,12 +292,21 @@ def Import(self):
raise IndexError("Primary referrer invalid: '%s'" % row['PrimaryReferrer'])
client = client[0].getObject()
+
+ # Getting an existing ethnicity
+ bsc = getToolByName(self.context, 'bika_setup_catalog')
+ ethnicity = bsc(portal_type='Ethnicity', Title=row.get('Ethnicity', ''))
+ if len(ethnicity) == 0:
+ raise IndexError("Invalid ethnicity: '%s'" % row['Ethnicity'])
+ ethnicity = ethnicity[0].getObject()
+
_id = folder.invokeFactory('Patient', id=tmpID())
obj = folder[_id]
obj.unmarkCreationFlag()
renameAfterCreation(obj)
Fullname = (row['Firstname'] + " " + row.get('Surname', '')).strip()
- obj.edit(title=Fullname,
+ obj.edit(PatientID=row.get('PatientID'),
+ title=Fullname,
ClientPatientID = row.get('ClientPatientID', ''),
Salutation = row.get('Salutation', ''),
Firstname = row.get('Firstname', ''),
@@ -291,7 +317,8 @@ def Import(self):
BirthDate = row.get('BirthDate', ''),
BirthDateEstimated =self.to_bool(row.get('BirthDateEstimated','False')),
BirthPlace = row.get('BirthPlace', ''),
- Ethnicity = row.get('Ethnicity', ''),
+ # TODO Ethnicity_Obj -> Ethnicity on health v319
+ Ethnicity_Obj=ethnicity.UID(),
Citizenship =row.get('Citizenship', ''),
MothersName = row.get('MothersName', ''),
CivilStatus =row.get('CivilStatus', ''),
@@ -320,7 +347,13 @@ def Import(self):
logger.error("Unable to load Feature %s"%row['Feature'])
obj.unmarkCreationFlag()
- renameAfterCreation(obj)
+ transaction.savepoint(optimistic=True)
+ if row.get('PatientID'):
+ # To maintain the patient spreadsheet's IDs, we cannot do a 'renameaftercreation()'
+ obj.aq_inner.aq_parent.manage_renameObject(obj.id, row.get('PatientID'))
+ else:
+ renameAfterCreation(obj)
+
class Analysis_Specifications(WorksheetImporter):
@@ -347,8 +380,8 @@ def Import(self):
'keyword': service.getKeyword(),
'min': row['min'] if row['min'] else '0',
'max': row['max'] if row['max'] else '0',
- 'minpanic': row['min'] if row['min'] else '0',
- 'maxpanic': row['max'] if row['max'] else '0',
+ 'minpanic': row['minpanic'] if row['minpanic'] else '0',
+ 'maxpanic': row['maxpanic'] if row['maxpanic'] else '0',
'error': row['error'] if row['error'] else '0'
})
# write objects.
@@ -369,10 +402,33 @@ def Import(self):
obj.unmarkCreationFlag()
renameAfterCreation(obj)
-
+class Insurance_Companies(WorksheetImporter):
+
+ def Import(self):
+ folder = self.context.bika_setup.bika_insurancecompanies
+ for row in self.get_rows(3):
+ obj = _createObjectByType("InsuranceCompany", folder, tmpID())
+ if row.get('Name', None):
+ obj.edit(
+ Name=row.get('Name', ''),
+ EmailAddress=row.get('EmailAddress', ''),
+ Phone=row.get('Phone', ''),
+ Fax=row.get('Fax', ''),
+ TaxNumber=row.get('TaxNumber', ''),
+ AccountType=row.get('AccountType', {}),
+ AccountName=row.get('AccountName', {}),
+ AccountNumber=row.get('AccountNumber', ''),
+ BankName=row.get('BankName', ''),
+ BankBranch=row.get('BankBranch', ''),
+ )
+ self.fill_contactfields(row, obj)
+ self.fill_addressfields(row, obj)
+ obj.unmarkCreationFlag()
+ renameAfterCreation(obj)
from bika.lims.exportimport.setupdata import Setup as BaseSetup
+
class Setup(BaseSetup):
def Import(self):
@@ -387,3 +443,4 @@ def Import(self):
EnablePanicAlert=self.to_bool(values.get('EnablePanicAlert', True)),
EnableAnalysisRemarks=self.to_bool(values.get('EnableAnalysisRemarks', True))
)
+
diff --git a/bika/health/setupdata/configure.zcml b/bika/health/setupdata/configure.zcml
index 812583c..3759f1e 100644
--- a/bika/health/setupdata/configure.zcml
+++ b/bika/health/setupdata/configure.zcml
@@ -86,10 +86,22 @@
provides="bika.lims.interfaces.ISetupDataImporter"
for="Products.CMFPlone.interfaces.IPloneSiteRoot"/>
+
+
+
+
diff --git a/bika/health/setupdata/test/test.xlsx b/bika/health/setupdata/test/test.xlsx
index 42b1594..bd7a2eb 100644
Binary files a/bika/health/setupdata/test/test.xlsx and b/bika/health/setupdata/test/test.xlsx differ
diff --git a/bika/health/setuphandlers.py b/bika/health/setuphandlers.py
index 993268a..8cbe943 100644
--- a/bika/health/setuphandlers.py
+++ b/bika/health/setuphandlers.py
@@ -6,6 +6,8 @@
from Products.CMFEditions.Permissions import ApplyVersionControl
from Products.CMFEditions.Permissions import SaveNewVersion
from bika.health import logger
+from bika.lims.utils import tmpID
+from bika.lims.idserver import renameAfterCreation
from bika.health.permissions import AddAetiologicAgent
from bika.health.permissions import ManageDoctors
from bika.health.permissions import ViewPatients
@@ -13,6 +15,7 @@
from bika.health.permissions import ViewSamples
from bika.health.permissions import ViewAnalysisRequests
from bika.health.permissions import ViewInsuranceCompanies
+from bika.health.permissions import ViewEthnicities
from bika.health.permissions import AddAetiologicAgent
from bika.health.permissions import AddDoctor
from bika.health.permissions import AddDrug
@@ -23,6 +26,7 @@
from bika.health.permissions import AddTreatment
from bika.health.permissions import AddVaccinationCenter
from bika.health.permissions import AddInsuranceCompany
+from bika.health.permissions import AddEthnicity
from bika.health.permissions import EditPatient
from bika.health.permissions import ManageDoctors
from bika.lims.permissions import AddAnalysisRequest
@@ -38,6 +42,25 @@ class Empty:
pass
+def setupEthnicities(bika_setup):
+ """
+ Creates standard ethnicities
+ """
+ ethnicities = ['Native American', 'Asian', 'Black', 'Native Hawaiian or Other Pacific Islander', 'White',
+ 'Hispanic or Latino']
+ for ethnicityName in ethnicities:
+ folder = bika_setup.bika_ethnicities
+ # Generating a temporal object
+ _id = folder.invokeFactory('Ethnicity', id=tmpID())
+ obj = folder[_id]
+ # Setting its values
+ obj.edit(title=ethnicityName,
+ description='')
+ obj.unmarkCreationFlag()
+ renameAfterCreation(obj)
+ logger.info("Standard ethnicities enabled")
+
+
def setupHealthVarious(context):
""" Setup Bika site structure """
@@ -71,6 +94,7 @@ def setupHealthVarious(context):
'bika_identifiertypes',
'bika_casesyndromicclassifications',
'bika_insurancecompanies',
+ 'bika_ethnicities',
):
obj = bika_setup._getOb(obj_id)
obj.unmarkCreationFlag()
@@ -106,6 +130,8 @@ def setupHealthVarious(context):
description="",
condition="")
+ setupEthnicities(bika_setup)
+
def setupHealthGroupsAndRoles(context):
@@ -158,6 +184,7 @@ def setupHealthPermissions(context):
mp(AddInsuranceCompany, ['Manager', 'Owner', 'LabManager', 'LabClerk'], 1)
mp(AddSymptom, ['Manager', 'Owner', 'LabManager', 'LabClerk'], 1)
mp(AddDrugProhibition, ['Manager', 'Owner', 'LabManager', 'LabClerk'], 1)
+ mp(AddEthnicity, ['Manager', 'Owner', 'LabManager', 'LabClerk'], 1)
mp(ApplyVersionControl, ['Manager', 'LabManager', 'LabClerk', 'Doctor', 'Analyst', 'Owner', 'RegulatoryInspector'], 1)
mp(SaveNewVersion, ['Manager', 'LabManager', 'LabClerk', 'Doctor', 'Analyst', 'Owner', 'RegulatoryInspector'], 1)
@@ -170,6 +197,7 @@ def setupHealthPermissions(context):
mp(ViewSamples, ['Manager', 'LabManager', 'Owner', 'LabClerk', 'Doctor', 'RegulatoryInspector'], 1)
mp(ViewAnalysisRequests, ['Manager', 'LabManager', 'Owner', 'LabClerk', 'Doctor', 'RegulatoryInspector'], 1)
mp(ViewInsuranceCompanies, ['Manager', 'LabManager', 'Owner', 'LabClerk', 'Doctor', 'RegulatoryInspector'], 1)
+ mp(ViewEthnicities, ['Manager', 'LabManager', 'Owner', 'LabClerk', 'Doctor', 'RegulatoryInspector'], 1)
# /clients folder permissions
# Member role must have view permission on /clients, to see the list.
@@ -316,6 +344,7 @@ def addColumn(cat, col):
at.setCatalogsByType('EpidemiologicalYear', ['bika_setup_catalog', ])
at.setCatalogsByType('IdentifierType', ['bika_setup_catalog', ])
at.setCatalogsByType('CaseSyndromicClassification', ['bika_setup_catalog', ])
+ at.setCatalogsByType('Ethnicity', ['bika_setup_catalog', ])
addIndex(bsc,'getGender', 'FieldIndex')
addColumn(bsc,'getGender')
diff --git a/bika/health/skins/bika_health/bika_health.css.dtml b/bika/health/skins/bika_health/bika_health.css.dtml
index 621b655..a1ede78 100644
--- a/bika/health/skins/bika_health/bika_health.css.dtml
+++ b/bika/health/skins/bika_health/bika_health.css.dtml
@@ -44,53 +44,53 @@
}
div.template-symptoms td input[type="text"] {
- width:100%;
+ width:100%;
}
div.template-symptoms td,
div.template-symptoms th {
- padding: 0 5px 0px 5px;
+ padding: 0 5px 0px 5px;
}
div.template-symptoms td.Code,
div.template-symptoms td.Onset {
- width:10%;
+ width:10%;
}
div.template-symptoms td.Title {
- width:30%;
+ width:30%;
}
div.template-symptoms td.Description {
- width:45%;
+ width:45%;
}
div.template-caseprovisionaldiagnosis td input[type="text"] {
- width:100%;
+ width:100%;
}
div.template-caseprovisionaldiagnosis td,
div.template-caseprovisionaldiagnosis th {
- padding: 0 5px 0px 5px;
+ padding: 0 5px 0px 5px;
}
div.template-caseprovisionaldiagnosis td.Code,
div.template-caseprovisionaldiagnosis td.Onset {
- width:10%;
+ width:10%;
}
div.template-caseprovisionaldiagnosis td.Title {
- width:30%;
+ width:30%;
}
div.template-caseprovisionaldiagnosis td.Description {
- width:45%;
+ width:45%;
}
.readonly-emphasize {
- background: none repeat scroll 0 0 transparent;
- border: medium none;
- font-size: 1.8em;
- font-weight: bold;
+ background: none repeat scroll 0 0 transparent;
+ border: medium none;
+ font-size: 1.8em;
+ font-weight: bold;
}
div.cg-comboItem :not(.template-ar_add) {
- height:100%;
+ height:100%;
}
div.cg-DivItem {
- height:auto;
- text-align:left;
+ height:auto;
+ text-align:left;
}
/* OVERWRITE FROM bika.lims/bika_listing.css */
diff --git a/bika/health/skins/bika_health/bika_health_standard_analysis_request.css.dtml b/bika/health/skins/bika_health/bika_health_standard_analysis_request.css.dtml
new file mode 100644
index 0000000..506d9fa
--- /dev/null
+++ b/bika/health/skins/bika_health/bika_health_standard_analysis_request.css.dtml
@@ -0,0 +1,213 @@
+/* Health-standard AR add form */
+#content-core #health-standard-ar-add-form div.documentDescription {
+ border-top: 1px solid #ccc;
+ color: #333;
+ font-size: 1.8em;
+ font-weight: normal;
+ margin-top: 15px;
+ padding: 15px 0 8px;
+}
+#content-core #health-standard-ar-add-form div.content-block {
+ border: 1px solid #ccc;
+}
+#content-core #health-standard-ar-add-form div.content-block div.field {
+ border-bottom: 1px solid #aaa;
+ padding: 5px;
+ min-height:16px;
+ margin-top:-2px;
+}
+#content-core #health-standard-ar-add-form div.content-block div.field label {
+ float:left;
+ padding-top:2px;
+}
+#content-core #health-standard-ar-add-form div.content-block div.field input,
+#content-core #health-standard-ar-add-form div.content-block div.field select,
+#content-core #health-standard-ar-add-form div.content-block div.field div.readonly {
+ float: right;
+}
+#content-core #health-standard-ar-add-form div.content-block div.field select {
+ border-style: none none none solid;
+ border-width: medium medium medium 1px;
+ margin-top: -3px;
+ padding: 3px 0 4px 5px;
+ width: 61%;
+ background-color: #dfdfdf;
+}
+#content-core #health-standard-ar-add-form div.content-block div.field input:after,
+#content-core #health-standard-ar-add-form div.content-block div.field select:after,
+#content-core #health-standard-ar-add-form div.content-block div.field div.readonly:after{
+ visibility: hidden;
+ display: block;
+ font-size: 0;
+ content: " ";
+ clear: both;
+ height: 0;
+}
+#content-core #health-standard-ar-add-form div.content-block div.field input[type="text"],
+#content-core #health-standard-ar-add-form div.content-block div.field div.readonly {
+ background-color: #dfdfdf;
+ border: medium none;
+ margin: 0 -2px 0 0;
+ padding: 1px 0 2px 10px;
+ width: 60%;
+}
+#content-core #health-standard-ar-add-form div.content-block div.field textarea {
+ background-color: #dedede;
+ border: medium none;
+ height: 32px;
+ margin: 5px -5px -5px;
+ padding: 5px;
+ color:#333;
+}
+#content-core #health-standard-ar-add-form div.content-block div.field textarea:disabled {
+ background-color:#fff;
+ color:#555;
+}
+#content-core #health-standard-ar-add-form div.content-block span.formHelp {
+ display:none;
+ visibility:hidden;
+}
+#content-core #health-standard-ar-add-form div.content-block div.field input[type="text"]:disabled,
+#content-core #health-standard-ar-add-form div.content-block div.field div.readonly,
+#content-core #health-standard-ar-add-form div.content-block div.field select:disabled {
+ background-color:#fff;
+ color: #555;
+ background-image:none;
+}
+#content-core #health-standard-ar-add-form div.content-block div.field input[type="checkbox"] {
+ margin-right: 59%;
+}
+#content-core #health-standard-ar-add-form div.content-block div.fieldErrorBox {
+ color: red;
+ font-size: 0.9em;
+ font-weight: bold;
+}
+#content-core #health-standard-ar-add-form div.content-block h2 {
+ background-color: #436976;
+ border: 1px solid #436976;
+ color: #fff;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin: -1px -1px 0;
+ padding-left: 5px;
+ text-transform: uppercase;
+}
+#content-core #health-standard-ar-add-form div.content-block h3 {
+ background-color: #888;
+ color: #fff;
+ font-size: 1em;
+ padding-left: 5px;
+}
+#content-core #health-standard-ar-add-form div.content-block.patient-block,
+#content-core #health-standard-ar-add-form div.content-block.insurance-block {
+ width: 49.5%;
+}
+
+#content-core #health-standard-ar-add-form div.content-block.patient-block {
+ float:left;
+ max-height: 432px;
+ min-height: 432px;
+}
+#content-core #health-standard-ar-add-form div.content-block.insurance-block {
+ float: right;
+}
+#content-core #health-standard-ar-add-form div.content-block.patient-block div#section-signatures {
+ border-bottom:none;
+}
+#content-core #health-standard-ar-add-form div.content-block.analyses-block {
+ border:1px solid #fff;
+}
+#content-core #health-standard-ar-add-form div.content-block.analyses-block div.department-block {
+ display: inline-block;
+ width: 24.6%;
+ vertical-align:top;
+}
+#content-core #health-standard-ar-add-form div.content-block.analyses-block div.department-block h2 {
+ margin:0px;
+}
+#content-core #health-standard-ar-add-form div.content-block.analyses-block div.department-block ul {
+ border: 1px solid #888;
+ list-style: none outside none;
+ margin: 0;
+ padding: 5px;
+}
+#content-core #health-standard-ar-add-form div.content-block.analyses-block div.department-block ul li {
+ line-height:100%;
+}
+#content-core #health-standard-ar-add-form div.content-block.analyses-block div.department-block ul li span.keyword {
+ color: #888;
+ font-size: 0.7em;
+ vertical-align: top;
+}
+#content-core #health-standard-ar-add-form div.content-block.analyses-block div.department-block ul li span.title {
+ font-size: 0.85em;
+ line-height: 100%;
+ padding-left: 5px;
+ vertical-align: top;
+}
+#content-core #health-standard-ar-add-form div.clearfix {
+ clear: both;
+ padding-bottom: 10px;
+}
+
+#content-core #health-standard-ar-add-form div.content-block.analyses-block div.department-block ul li .specs {
+ float:right;
+ display:none;
+}
+#content-core #health-standard-ar-add-form div.content-block.analyses-block div.department-block ul li .spec_bit {
+ border: 1px solid #888;
+ font-size: 0.8em;
+ margin-right: 3px;
+ padding-right: 1px;
+ text-align: right;
+ width: 20px;
+}
+#content div.ar-add-template-classic-button {
+ float:right;
+}
+#content div.ar-add-template-classic-button a {
+ background-color:#fff;
+ border: 1px solid #cdcdcd;
+ padding: 4px 10px;
+}
+#content div.ar-add-template-classic-button input {
+ background-color:#fff;
+ border: 1px solid #cdcdcd;
+ padding: 2px 10px 2px;
+ margin-top: -5.5px;
+}
+#content div.ar-add-template-classic-button a:hover,
+#content div.ar-add-template-classic-button input:hover{
+ background-color: #ddd;
+ color:#fff;
+}
+@media print {
+ body {
+ font-size: 9px;
+ }
+ #content div.ar-add-template-classic-button,
+ div#portal-theme{
+ display: none;
+ }
+ #content-core #health-standard-ar-add-form div.content-block div.field {
+ border-bottom: 1px solid #aaa;
+ padding: 5px;
+ min-height:16px;
+ margin-top:-2px;
+ }
+ #content-core #health-standard-ar-add-form div.content-block div.field input {
+ font-size: 9px;
+ }
+ #content-core #health-standard-ar-add-form div.content-block div.field select {
+ font-size: 9px;
+ outline: 0;
+ padding-left: 1px;
+ }
+ #content-core #health-standard-ar-add-form div.content-block div.field textarea {
+ font-size: 8px;
+ }
+ #content-core #health-standard-ar-add-form div.analyses-block {
+ page-break-after: always;
+ }
+
+}
\ No newline at end of file
diff --git a/bika/health/static/js/bika.health.analysisrequest.add.js b/bika/health/static/js/bika.health.analysisrequest.add.js
index 6897bcd..d575000 100644
--- a/bika/health/static/js/bika.health.analysisrequest.add.js
+++ b/bika/health/static/js/bika.health.analysisrequest.add.js
@@ -42,12 +42,18 @@ function HealthAnalysisRequestAddView() {
// ClientPatientID fields change.
$('[id$="_ClientPatientID"]').bind("selected paste blur change", function () {
colposition = $(this).closest('td').attr('column');
+ if (colposition == undefined){
+ // we are on the specific health template
+ colposition = 0}
loadPatient($(this).val(), colposition);
checkClientContacts();
});
$('[id$="_Patient"]').bind("selected paste blur change", function () {
colposition = $(this).closest('td').attr('column');
+ if (colposition == undefined){
+ // we are on the specific health template
+ colposition = 0}
uid = $("#" + this.id + "_uid").val();
loadClientPatientID(uid, colposition);
checkClientContacts();
@@ -59,6 +65,9 @@ function HealthAnalysisRequestAddView() {
// See https://github.com/bikalabs/bika.health/issues/100
$('[id$="_Sample"]').bind("selected paste blur", function () {
colposition = $(this).closest('td').attr('column');
+ if (colposition == undefined){
+ // we are on the specific health template
+ colposition = 0}
uid = $("#" + this.id + "_uid").val();
loadPatientFromSample(uid, colposition);
checkClientContacts();
@@ -250,46 +259,64 @@ function HealthAnalysisRequestAddView() {
clientuid = $("#ar_" + col + "_Client_uid").val();
// Batch searches
- element = $("#ar_" + col + "_Batch")
- base_query = $.parseJSON($(element).attr("base_query"));
- base_query['getClientUID'] = clientuid;
- applyComboFilter(element, base_query);
+ element = $("#ar_" + col + "_Batch");
+ if (element.length > 0){
+ base_query = $.parseJSON($(element).attr("base_query"));
+ if (base_query != null) {
+ base_query['getClientUID'] = clientuid;
+ applyComboFilter(element, base_query);
+ }
+ }
// Patient searches
- element = $("#ar_" + col + "_Patient")
- base_query = $.parseJSON($(element).attr("base_query"));
- base_query['getPrimaryReferrerUID'] = clientuid;
- applyComboFilter(element, base_query);
+ element = $("#ar_" + col + "_Patient");
+ if (element.length > 0) {
+ base_query = $.parseJSON($(element).attr("base_query"));
+ if (base_query != null) {
+ base_query['getPrimaryReferrerUID'] = clientuid;
+ applyComboFilter(element, base_query);
+ }
+ }
// CPID searches
element = $("#ar_" + col + "_ClientPatientID")
- base_query = $.parseJSON($(element).attr("base_query"));
- base_query['getPrimaryReferrerUID'] = clientuid;
- applyComboFilter(element, base_query);
+ if (element.length > 0) {
+ base_query = $.parseJSON($(element).attr("base_query"));
+ if (base_query != null) {
+ base_query['getPrimaryReferrerUID'] = clientuid;
+ applyComboFilter(element, base_query);
+ }
+ }
// Contact searches
element = $("#ar_" + col + "_Contact")
- base_query = $.parseJSON($(element).attr("base_query"));
- base_query['getParentUID'] = clientuid;
- applyComboFilter(element, base_query);
+ if (element.length > 0) {
+ base_query = $.parseJSON($(element).attr("base_query"));
+ if (base_query != null) {
+ base_query['getParentUID'] = clientuid;
+ applyComboFilter(element, base_query);
+ }
+ }
}
}
function applyComboFilter(element, base_query) {
- $(element).attr("base_query", $.toJSON(base_query));
- options = $.parseJSON($(element).attr("combogrid_options"));
- options.url = window.location.href.split("/ar_add")[0] + "/" + options.url
- options.url = options.url + '?_authenticator=' + $('input[name="_authenticator"]').val();
- options.url = options.url + '&catalog_name=' + $(element).attr('catalog_name');
- options.url = options.url + '&base_query=' + $.toJSON(base_query);
- options.url = options.url + '&search_query=' + $(element).attr('search_query');
- options.url = options.url + '&colModel=' + $.toJSON($.parseJSON($(element).attr('combogrid_options'))["colModel"]);
- options.url = options.url + '&search_fields=' + $.toJSON($.parseJSON($(element).attr('combogrid_options'))["search_fields"]);
- options.url = options.url + '&discard_empty=' + $.toJSON($.parseJSON($(element).attr('combogrid_options'))["discard_empty"]);
- options['force_all'] = 'false';
- $(element).combogrid(options);
- $(element).addClass("has_combogrid_widget");
- $(element).attr('search_query', '{}');
+ if (element.length > 0) {
+ $(element).attr("base_query", $.toJSON(base_query));
+ options = $.parseJSON($(element).attr("combogrid_options"));
+ options.url = window.location.href.split("/ar_add")[0] + "/" + options.url
+ options.url = options.url + '?_authenticator=' + $('input[name="_authenticator"]').val();
+ options.url = options.url + '&catalog_name=' + $(element).attr('catalog_name');
+ options.url = options.url + '&base_query=' + $.toJSON(base_query);
+ options.url = options.url + '&search_query=' + $(element).attr('search_query');
+ options.url = options.url + '&colModel=' + $.toJSON($.parseJSON($(element).attr('combogrid_options'))["colModel"]);
+ options.url = options.url + '&search_fields=' + $.toJSON($.parseJSON($(element).attr('combogrid_options'))["search_fields"]);
+ options.url = options.url + '&discard_empty=' + $.toJSON($.parseJSON($(element).attr('combogrid_options'))["discard_empty"]);
+ options['force_all'] = 'false';
+ $(element).combogrid(options);
+ $(element).addClass("has_combogrid_widget");
+ $(element).attr('search_query', '{}');
+ }
}
/**
@@ -386,14 +413,17 @@ function HealthAnalysisRequestAddView() {
// Only allow the selection of batches from this patient
element = $("#ar_" + col + "_Batch")
base_query = $.parseJSON($(element).attr("base_query"));
- base_query['getPatientUID'] = data['PatientUID'];
- applyComboFilter(element, base_query);
-
+ if (base_query != null) {
+ base_query['getPatientUID'] = data['PatientUID'];
+ applyComboFilter(element, base_query);
+ }
// Contact searches
element = $("#ar_" + col + "_Contact")
base_query = $.parseJSON($(element).attr("base_query"));
- base_query['getParentUID'] = data['ClientUID'];
- applyComboFilter(element, base_query);
+ if (base_query != null) {
+ base_query['getParentUID'] = data['ClientUID'];
+ applyComboFilter(element, base_query);
+ }
}
function resetPatientData(col) {
diff --git a/bika/health/static/js/bika.health.analysisrequest.ar_add_health_standard.js b/bika/health/static/js/bika.health.analysisrequest.ar_add_health_standard.js
new file mode 100644
index 0000000..88444f5
--- /dev/null
+++ b/bika/health/static/js/bika.health.analysisrequest.ar_add_health_standard.js
@@ -0,0 +1,659 @@
+/**
+ * Controller class for AnalysisRequest add view for health standard template
+ */
+function HealthStandardAnalysisRequestAddView() {
+ /**
+ * Correct functionality:
+ * ======================
+ *
+ * AR coming from batch:
+ * ---------------------
+ * - Patient -> From batch. Fields blocked.
+ * - Guarantor and insurance -> From batch's patient. Fields blocked.
+ * - The save button is going to crate -> an AR
+ *
+ * AR coming from patient:
+ * -----------------------
+ * - Patient -> From patient. Fields blocked.
+ * - Guarantor and insurance -> From the current patient. Fields blocked
+ * - The save button is going to crate -> a case if the checkbox is selected, an AR (related with the case.)
+ *
+ * AR coming from client:
+ * ----------------------
+ * - Patient -> Must be chosen first!
+ * -- If a new patient is being created (NewPatientCheckbox == selected) ->
+ * - Guarantor's + insurance ready to be edited. Fields unblocked.
+ * - Patient fields unblocked.
+ * --- The save button is going to create -> a patient, a case related with the created patient if required, an AR (inside the case)
+ *
+ * -- If an old patient is selected (NewPatientCheckbox == unselected) ->
+ * - Guarantor + insurance from selected patient. Fields blocked.
+ * - Patient fields blocked.
+ * --- The save button is going to create -> a case if required, an AR.
+ *
+ * How it works?
+ * =============
+ * We can came from three different positions: from a batch, from a patient or from a client.
+ * If we come from a batch, all the client, patient, insurance and doctor's fields will be filled out.
+ * If we come from a patient, the client, patient and insurance will be filled out. We can decide if we want to
+ * create a new batch related with the new analysis request.
+ * If we come from a client(insurance company), we will be able to select an existent patient or create a new one.
+ * In the case we've selected an existing patient, all patient and insurance's fields will be blocked and filled out.
+ * If the checkbox "new patient" is selected all fields will be enabled.
+ *
+ * The "GLOBAL" SAVE BUTTON: When the user has filled out all the required fields, he clicks on the save button.
+ * This is NOT the form's button! So after clicking this button, the JS will check if a new patient and a new case
+ * should be created and related each other.
+ * Once these objects' creation (or not) have finished, the data from the patient and the case is copied inside
+ * the analysis request's html form. Then, the javascript clicks on the hidden save button from the form.
+ * Consequently the ajaxForm is gonna create the new Analysis Request.
+ *
+ */
+
+ var that = this;
+
+ // ------------------------------------------------------------------------
+ // PUBLIC FUNCTIONS
+ // ------------------------------------------------------------------------
+
+ /**
+ * Entry-point method for StandardAnalysisRequestAddView
+ */
+ this.load = function () {
+
+ var datafilled = false;
+ var frombatch = window.location.href.search('/batches/') >= 0;
+ var frompatient = document.referrer.search('/patients/') >= 0;
+
+ if (frombatch) {
+ // The current AR add View comes from a batch. Automatically fill
+ // the Client, Patient and Doctor fields and set them as readonly.
+ // Deactivate the option and fields to create a new patient
+ datafilled = true;
+ var batchid = window.location.href.split("/batches/")[1].split("/")[0];
+ cancelPatientCreationCheckBox();
+ // The fields with data should be fill out and set them as readonly.
+ setDataFromBatch(batchid);
+ // Hide and clear the CreateNewCase checkbox
+ $('input#CreateNewCase').prop('checked',false).prop('disabled', true)
+ }
+ else if (frompatient) {
+ // The current AR add View comes from a patient's AR folder view.
+ // Automatically fill the Client and Patient fields and set them
+ // as readonly.
+ datafilled = true;
+ cancelPatientCreationCheckBox();
+ setDataFromPatient()
+ }
+
+ if (!datafilled) {
+ // The current AR Add View doesn't come from a batch nor patient.
+ // Handle event firing when Patient or ClientPatientID fields change.
+
+ // ClientPatientID changed
+ $('[id$="_ClientPatientID"]').bind("selected paste blur change", function () {
+ // Load the new patients data
+ $('input[id$="_Patient"]').trigger("change");
+ });
+
+ // PatientFullName changed
+ $('[id$="_Patient"]').bind("selected paste blur change", function () {
+ // Set the new patient data
+ var patientUID = $(this).attr('uid');
+ setPatientData(patientUID);
+ // Set the new insurance's patient. We can call the function used to fill the insurance data when the
+ // AR comes from a batch
+ setInsuranceDataFromBatch(patientUID);
+ });
+
+ // NewPatient checkbox change
+ var np = $('input#NewPatient');
+ np.bind("click change", function () {
+ // The old patient's data should be uploaded/cleaned
+ hideShowFirstnameSurname();
+ if (np.prop('checked')) {
+ // If we are creating a new patient we should allow to fill the insurance stuff
+ cleanAndEnableDisableInsuranceData(false);
+ }
+ else{
+ cleanAndEnableDisableInsuranceData(true);
+ }
+ });
+ }
+
+ // Binding the triggers used on all cases
+ $('[id$="_Doctor"]').bind("selected paste blur change", function () {
+ setDoctorCode();
+ });
+ $('input#PatientAsGuarantor').bind("click", function() {
+ var cb = $('input#PatientAsGuarantor');
+ if (cb.prop('checked')) {
+ cleanAndEnableDisableInsuranceData(true);
+ cb.prop('disabled', false);
+ cb.prop('checked', true);
+ }
+ else{
+ cleanAndEnableDisableInsuranceData(false)
+ }
+ });
+
+ // Functions to execute at page load
+ hideShowFirstnameSurname();
+ disableInsuranceData();
+ // Unbind previous (from lims) loadAjaxSubmitHandler on submit button.
+ $("#analysisrequest_edit_form").ajaxFormUnbind();
+ // Bind the new handler
+ loadAjaxSubmitHealthHandler();
+ $('input#print').bind('click', function(){
+ printAnalysisRequest()
+ });
+
+ };
+ // ------------------------------------------------------------------------
+ // PRIVATE FUNCTIONS
+ // ------------------------------------------------------------------------
+
+ function setDataFromBatch(batchid){
+ /**
+ * It obtains the patient's data when the AR comes from the batch (case) view.
+ */
+ $('#archetypes-fieldname-Batch').remove();
+ $.ajaxSetup({async:false});
+ // Get batch data
+ window.bika.lims.jsonapi_read({
+ catalog_name:'bika_catalog',
+ id:batchid
+ }, function(data){
+ // Set patient data
+ setPatientData(data.objects[0]['getPatientUID']);
+ // Set the doctor's code
+ $('input#DoctorsCode').val(data.objects[0]['getDoctorID']).prop('disabled', true);
+ // Set the insurance company and block the insurance fields if it's necessary
+ setInsuranceDataFromBatch(data.objects[0]['getPatientUID']);
+ });
+ $.ajaxSetup({async:true});
+ }
+
+ function setDataFromPatient(){
+ /**
+ * It obtains the patient data when the AR comes from the patient view.
+ */
+ var pid = document.referrer.split("/patients/")[1].split("/")[0];
+ $.ajaxSetup({async:false});
+ // Get patient data
+ window.bika.lims.jsonapi_read({
+ catalog_name:'bika_patient_catalog',
+ id:pid
+ }, function(data){
+ setPatientData(data.objects[0]['UID']);
+ setInsuranceDataFromPatient(data.objects[0])
+ });
+ $.ajaxSetup({async:true});
+ }
+
+ // Patient template controller ----------------------------------------------------
+
+ function cancelPatientCreationCheckBox() {
+ /**
+ * If the "create a new patient" actions should be canceled, this function clear the checkbox to create
+ * a new patient and deactivates the possibility of interact with the checkbox.
+ */
+ var cb = $('input#NewPatient');
+ cb.prop('disabled', true).prop('checked', false);
+ }
+
+ function cleanPatientData(){
+ /**
+ * Clean all fields used by patient
+ */
+ $('[id$="_Patient"]').val('').attr('uid','');
+ $('input#Surname').val('');
+ $('input#Firstname').val('');
+ $("input#BirthDate").val('');
+ $('input#BirthDateEstimated').prop('checked', false);
+ $('select#Gender').val('dk');
+ $('input#BusinessPhone').val('').attr('uid','');
+ $('input#HomePhone').val('');
+ $('input#MobilePhone').val('');
+ $('input#EmailAddress').val('');
+ $('input#ar_0_ClientPatientID').val('').attr('uid','');
+ $('input#PatientID').val('')
+ }
+
+ function hideShowFirstnameSurname(){
+ /**
+ * Hide/show the fields surname, first name and patient depending on the "New patient"'s checkbox state.
+ * This function clear all patient data too.
+ */
+ var cb = $('input#NewPatient');
+ if (cb.prop('checked')) {
+ $('div#archetypes-fieldname-Patient').hide();
+ $('div#PatientID').hide();
+ $('div#archetypes-fieldname-Surname').show();
+ $('div#archetypes-fieldname-Firstname').show();
+ // Hiding the client-patient reference input and showing the simple one used when creating a patient
+ $('input#ar_0_ClientPatientID').hide();
+ $('input#ClientPatientID').show();
+
+ // Enable and clear all the fields
+ $('input#Surname').prop('disabled', false);
+ $('input#Firstname').prop('disabled', false);
+ $("input#BirthDate").prop('disabled', false);
+ $('input#BirthDateEstimated').prop('disabled', false).prop('checked', false);
+ $('select#Gender').prop('disabled', false).val('dk');
+ $('input#BusinessPhone').prop('disabled', false);
+ $('input#HomePhone').prop('disabled', false);
+ $('input#MobilePhone').prop('disabled', false);
+ $('input#EmailAddress').prop('disabled', false);
+ // We should clean the old data
+ cleanPatientData()
+ }
+ else {
+
+ $('div#archetypes-fieldname-Patient').show();
+ $('div#PatientID').show();
+ $('div#archetypes-fieldname-Surname').hide();
+ $('div#archetypes-fieldname-Firstname').hide();
+ // Showing the client-patient reference input and hiding the simple one
+ $('input#ar_0_ClientPatientID').show();
+ $('input#ClientPatientID').hide().val('');
+
+ // Disable and clear all the fields
+ $("input#BirthDate").prop('disabled', true);
+ $('input#BirthDateEstimated').prop('disabled', true);
+ $('select#Gender').prop('disabled', true);
+ $('input#BusinessPhone').prop('disabled', true);
+ $('input#HomePhone').prop('disabled', true);
+ $('input#MobilePhone').prop('disabled', true);
+ $('input#EmailAddress').prop('disabled', true);
+ //$('input#ar_0_ClientPatientID').prop('disabled', true);
+ }
+ }
+
+ function setPatientData(patientuid){
+ /**
+ * It fills out the patient data that remains from the bika.analysisrequest.add.js and blocks it.
+ * @patientuid The patient's uid
+ */
+ if (patientuid == ''){
+ // All data patient should be cleaned because no patient has been selected
+ cleanPatientData();
+ // Disabling the reference input client-patient uid to allow to introduce a patient from here
+ $('input#ar_0_ClientPatientID').prop('disabled', false);
+ }
+ $.ajaxSetup({async:false});
+ window.bika.lims.jsonapi_read({
+ catalog_name: 'bika_patient_catalog',
+ UID: patientuid
+ },function(dataobj){
+ if (dataobj.objects.length > 0) {
+ var data = dataobj.objects[0];
+ $("input#BirthDate").val(data['BirthDate']).prop('disabled', true);
+ $('input#BirthDateEstimated').prop('checked', data['BirthDateEstimated']).prop('disabled', true);
+ $('select#Gender').val(data['Gender']).prop('disabled', true);
+ $('input#BusinessPhone').val(data['BusinessPhone']).prop('disabled', true);
+ $('input#HomePhone').val(data['HomePhone']).prop('disabled', true);
+ $('input#MobilePhone').val(data['MobilePhone']).prop('disabled', true);
+ $('input#EmailAddress').val(data['EmailAddress']).prop('disabled', true);
+ $('input#ar_0_ClientPatientID').val(data['ClientPatientID']).prop('disabled', true);
+ $('input#PatientID').val(data['getPatientID'])
+ }
+ });
+ $.ajaxSetup({async:true});
+ }
+
+ // Doctor's template controller ------------------------------------------------
+
+ function setDoctorCode(){
+ /**
+ * Set the Doctor's code from the selected Referring Doctor.
+ */
+ var doctoruid = $('[id$="_Doctor"]').attr('uid');
+ $.ajaxSetup({async:false});
+ window.bika.lims.jsonapi_read({
+ catalog_name:'portal_catalog',
+ portal_type: 'Doctor',
+ UID:doctoruid
+ }, function(data){
+ $('input#DoctorsCode').val(data.objects[0]['DoctorID']);
+ });
+ $.ajaxSetup({async:true});
+ }
+
+ // Insurance's template controller --------------------------------------------------
+
+ function setInsuranceDataFromBatch(patientuid){
+ /**
+ * The function checks if the patient is related with an insurance company. In the affirmative case,
+ * the insurance fields will be filled out and blocked
+ * @patientuid The patient's uid where the function will look for the insurance company.
+ */
+ if (patientuid == ''){
+ // It means that the patient fields have been cleaned of data.
+ cleanAndEnableDisableInsuranceData(true);
+ }
+ else {
+ $.ajaxSetup({async: false});
+ window.bika.lims.jsonapi_read({
+ catalog_name: 'bika_patient_catalog',
+ UID: patientuid
+ }, function (data) {
+ if (data.objects[0]['InsuranceCompany_uid'] != '') {
+ setInsurance(data.objects[0]['InsuranceCompany_uid']);
+ }
+ // Since data variable stores the patient fields, we can set all guarantor stuff.
+ setGuarantor(data.objects[0]);
+ });
+ $.ajaxSetup({async: true});
+ }
+ }
+
+ function disableInsuranceData(){
+ /**
+ * Disable all the fields related with the insurance
+ */
+ $('input#ar_0_InsuranceCompany').prop('disabled', true);
+ $('input#PatientAsGuarantor').prop('disabled', true);
+ $('input#GuarantorID').prop('disabled', true);
+ $('input#GuarantorSurname').prop('disabled', true);
+ $('input#GuarantorFirstname').prop('disabled', true);
+ $('select[id="PostalAddress.country"]').prop('disabled', true);
+ $('select[id="PostalAddress.state"]').prop('disabled', true);
+ $('select[id="PostalAddress.district"]').prop('disabled', true);
+ $('input[id="PostalAddress.city"]').prop('disabled', true);
+ $('input[id="PostalAddress.zip"]').prop('disabled', true);
+ $('textarea[id="PostalAddress.address"]').prop('disabled', true);
+ $('input#GuarantorBusinessPhone').prop('disabled', true);
+ $('input#GuarantorHomePhone').prop('disabled', true);
+ $('input#GuarantorMobilePhone').prop('disabled', true);
+ }
+
+ function cleanAndEnableDisableInsuranceData(state){
+ /**
+ * Clean and enable/disable all the fields related with the insurance
+ * @state True/False depending on the disable state
+ */
+ $('input#ar_0_InsuranceCompany').val('').attr('uid','').prop('disabled', state);
+ $('input#PatientAsGuarantor').prop('checked', false).prop('disabled', state);
+ $('input#GuarantorID').val('').prop('disabled', state);
+ $('input#GuarantorSurname').val('').prop('disabled', state);
+ $('input#GuarantorFirstname').val('').prop('disabled', state);
+ $('select[id="PostalAddress.country"]')
+ .val($('[id="PostalAddress.country"] option[selected="selected"]').val()).prop('disabled', state);
+ $('select[id="PostalAddress.state"]').val('').prop('disabled', state);
+ $('select[id="PostalAddress.district"]').val('').prop('disabled', state);
+ $('input[id="PostalAddress.city"]').val('').prop('disabled', state);
+ $('input[id="PostalAddress.zip"]').val('').prop('disabled', state);
+ $('textarea[id="PostalAddress.address"]').val('').prop('disabled', state);
+ $('input#GuarantorBusinessPhone').val('').prop('disabled', state);
+ $('input#GuarantorHomePhone').val('').prop('disabled', state);
+ $('input#GuarantorMobilePhone').val('').prop('disabled', state);
+ }
+
+ function setInsuranceDataFromPatient(patientdata){
+ /**
+ * The function checks if the patient is related with an insurance company. In the affirmative case,
+ * the insurance fields will be filled out and blocked.
+ * @patientuid A dictionary with the patient's data where the function will look for the insurance company.
+ */
+ // Check if patient is related with an insurance company
+ if (patientdata['InsuranceCompany_uid'] != ''){
+ setInsurance(patientdata['InsuranceCompany_uid']);
+ }
+ // Fill out guarantor's fields
+ setGuarantor(patientdata);
+ }
+
+ function setInsurance(insuranceuid){
+ /**
+ * This function fill out the insurance field and block it.
+ * @insuranceuid The insurance company UID
+ */
+ if (insuranceuid != undefined) {
+ $.ajaxSetup({async: false});
+ window.bika.lims.jsonapi_read({
+ catalog_name: 'bika_setup_catalog',
+ content_type: 'InsuranceCompany',
+ UID: insuranceuid
+ }, function (dataobj) {
+ var data = dataobj.objects[0];
+ $('input#ar_0_InsuranceCompany').val(data['Title']).attr('uid', data['UID']).prop('disabled', true);
+ });
+ $.ajaxSetup({async: true});
+ }
+ }
+
+ function setGuarantor(patientdata) {
+ /**
+ * It fills out all guarantor's fields.
+ * @patientdata It's a dictionary with the patient's data
+ */
+ // The AR comes from batch or patients view
+ $('input#PatientAsGuarantor').prop('checked', patientdata['PatientAsGuarantor']).prop('disabled', true);
+ $('input#GuarantorID').val(patientdata['GuarantorID']).prop('disabled', true);
+ $('input#GuarantorSurname').val(patientdata['GuarantorSurname']).prop('disabled', true);
+ $('input#GuarantorFirstname').val(patientdata['GuarantorFirstname']).prop('disabled', true);
+ $('select[id="PostalAddress.country"]').val(patientdata['PostalAddress']['country']).prop('disabled', true);
+ $('select[id="PostalAddress.state"]').val(patientdata['PostalAddress']['state']).prop('disabled', true);
+ $('select[id="PostalAddress.district"]').val(patientdata['PostalAddress']['district']).prop('disabled', true);
+ $('input[id="PostalAddress.city"]').val(patientdata['PostalAddress']['city']).prop('disabled', true);
+ $('input[id="PostalAddress.zip"]').val(patientdata['PostalAddress']['zip']).prop('disabled', true);
+ $('textarea[id="PostalAddress.address"]').val(patientdata['PostalAddress']['address']).prop('disabled', true);
+ $('input#GuarantorBusinessPhone').val(patientdata['GuarantorBusinessPhone']).prop('disabled', true);
+ $('input#GuarantorHomePhone').val(patientdata['GuarantorHomePhone']).prop('disabled', true);
+ $('input#GuarantorMobilePhone').val(patientdata['GuarantorMobilePhone']).prop('disabled', true);
+ }
+
+ // Defining the health submit handler -----------------------------------------------------
+
+ function loadAjaxSubmitHealthHandler(){
+ /**
+ * This functions builds the options to create the objects and binds the needed functions to create the objects
+ * after submit.
+ * Since the different objects definitions are split into different forms, on the form's submit we have to create
+ * every object (if it's necessary) from every form, and copy its data into the analysis request's form to create
+ * the analysis request with all the recently created objects.
+ */
+ $('input#global_save_button').bind('click', function(){
+ // If the Analysis Request comes form a case (batch), the fields ClientPatientID, Doctor and Patient should
+ // be copied from their forms to the Analysis Request form.
+ if ($('input#NewPatient').prop('checked')){
+ // A patient should be created
+ createPatient();
+ }
+ if ($('input#CreateNewCase').prop('checked')){
+ // Creating a case
+ createCase();
+ }
+ // Coping the patient from the patient's creation form to the analysis request's creation form
+ $("form#analysisrequest_patient_edit_form #archetypes-fieldname-Patient")
+ .clone().appendTo("form#analysisrequest_edit_form").hide();
+ // Coping the doctor
+ $("div#archetypes-fieldname-Doctor")
+ .clone().appendTo("form#analysisrequest_edit_form").hide();
+ // Coping the Client-Patient-ID
+ $("form#analysisrequest_patient_edit_form #archetypes-fieldname-ClientPatientID")
+ .clone().appendTo("form#analysisrequest_edit_form").hide();
+
+ var options = createAR();
+ $("#analysisrequest_edit_form").ajaxForm(options);
+ // Click on analysis request form to trigger the AR creation
+ $('form#analysisrequest_edit_form input[name="save_button"]').click();
+ });
+ }
+
+ // Creating an AR ---------------------------------------------------------------------
+
+ function createAR(){
+ /**
+ * This function creates an Analysis Request.
+ */
+ var options = {
+ url: window.location.href.split("/portal_factory")[0] + "/analysisrequest_submit",
+ dataType: "json",
+ data: {"_authenticator": $("input[name='_authenticator']").val()},
+ beforeSubmit: function() {
+ $("input[class~='context']").prop("disabled",true);
+ },
+ success: function(responseText) {
+ var destination;
+ if(responseText.success !== undefined){
+ if(responseText.stickers !== undefined){
+ destination = window.location.href
+ .split("/portal_factory")[0];
+ var ars = responseText.stickers;
+ var template = responseText.stickertemplate;
+ var q = "/sticker?template="+template+"&items=";
+ q = q + ars.join(",");
+ window.location.replace(destination+q);
+ } else {
+ destination = window.location.href
+ .split("/portal_factory")[0];
+ window.location.replace(destination);
+ }
+ } else {
+ var msg = "";
+ for(var error in responseText.errors){
+ var x = error.split(".");
+ var e;
+ if (x.length == 2){
+ e = x[1] + ", Column " + (+x[0]) + ": ";
+ } else {
+ e = "";
+ }
+ msg = msg + e + responseText.errors[error] + " ";
+ }
+ window.bika.lims.portalMessage(msg);
+ window.scroll(0,0);
+ $("input[class~='context']").prop("disabled", false);
+ }
+ },
+ error: function(XMLHttpRequest, statusText) {
+ window.bika.lims.portalMessage(statusText);
+ window.scroll(0,0);
+ $("input[class~='context']").prop("disabled", false);
+ }
+ };
+ return options;
+ }
+ // Creating a Patient ----------------------------------------------------------------
+
+ function createPatient(){
+ /**
+ * This function creates a patient via ajax and jsonapi from the data introduced in the form.
+ */
+ var request_data = {
+ obj_path: '/Plone/patients',
+ obj_type: 'Patient',
+ ClientPatientID: $('input#ClientPatientID').val(),
+ Surname: $('#Surname').val(),
+ Firstname: $('#Firstname').val(),
+ BirthDate: $('#BirthDate').val(),
+ BirthDateEstimated: $('#BirthDateEstimated').prop('checked'),
+ Gender: $('#Gender').val(),
+ HomePhone: $('#HomePhone').val(),
+ MobilePhone: $('#MobilePhone').val(),
+ BusinessPhone: $('#BusinessPhone').val(),
+ EmailAddress: $('#EmailAddress').val(),
+ PatientAsGuarantor: $('#PatientAsGuarantor').prop('checked'),
+ PrimaryReferrer: "portal_type:Client|UID:" + $('input#ar_0_Client_uid').val()
+ };
+ if (!request_data['PatientAsGuarantor']){
+ var request_data_ext = {
+ GuarantorID: $('#GuarantorID').val(),
+ GuarantorFirstname: $('#GuarantorFirstname').val(),
+ GuarantorSurname: $('#GuarantorSurname').val(),
+ PostalAddress: $.toJSON({country:$('[id="PostalAddress.country"]').val(), state:$('[id="PostalAddress.state"]').val(),
+ city:$('[id="PostalAddress.city"]').val(), address:$('[id="PostalAddress.address"]').val(),
+ zip:$('[id="PostalAddress.zip"]').val()}),
+ GuarantorHomePhone: $('#GuarantorHomePhone').val(),
+ GuarantorMobilePhone: $('#GuarantorMobilePhone').val(),
+ GuarantorBusinessPhone: $('#GuarantorBusinessPhone').val()
+ };
+ $.extend(request_data,request_data_ext)
+ }
+ $.ajaxSetup({async: false});
+ $.ajax({
+ type: "POST",
+ dataType: "json",
+ url: window.portal_url + "/@@API/create",
+ data: request_data,
+ success: function(data){
+ // Getting the case's uid
+ window.bika.lims.jsonapi_read({
+ catalog_name: 'bika_patient_catalog',
+ content_type: 'Patient',
+ id: data['obj_id']
+ }, function (dataobj) {
+ // After creating the new patient, we should fill the "existing patient"'s input. When we are
+ // creating the analysis request, this input is going to be cloned to the analysis request form, and
+ // consequently, the AR and the patient will be related.
+ $('input#ar_0_Patient').attr('uid', dataobj.objects[0]['UID']);
+ $('input#ar_0_Patient_uid').val(dataobj.objects[0]['UID']);
+ $('input#ar_0_Patient').val(dataobj.objects[0]['title'])
+ });
+ },
+ error: function(XMLHttpRequest, statusText) {
+ window.bika.lims.portalMessage(statusText);
+ window.scroll(0,0);
+ $("input[class~='context']").prop("disabled", false);
+ }
+ });
+ $.ajaxSetup({async: true});
+ }
+
+ // Creating a batch (case) ------------------------------------------------------------
+
+ function createCase(){
+ /**
+ * This function reads the data from the doctor and the patient, and consequently creates a case.
+ * Finally it fills the case's input inside the analysis request form.
+ */
+ var patientuid = $('input#ar_0_Patient').attr('uid');
+ var doctoruid = $('input#ar_0_Doctor').attr('uid');
+ var clientuid = $('input#ar_0_Client_uid').val();
+ var request_data = {
+ obj_path: '/Plone/batches',
+ obj_type: 'Batch',
+ Patient: "catalog_name:bika_patient_catalog|portal_type:Patient|UID:" + patientuid,
+ Doctor:"portal_type:Doctor|UID:" + doctoruid,
+ Client:"portal_type:Client|UID:" + clientuid
+ };
+ $.ajaxSetup({async: false});
+ $.ajax({
+ type: "POST",
+ dataType: "json",
+ url: window.portal_url + "/@@API/create",
+ data: request_data,
+ success: function(data){
+ // To obtain the case's uid
+ window.bika.lims.jsonapi_read({
+ catalog_name: 'bika_catalog',
+ content_type: 'Batch',
+ id: data['obj_id']
+ }, function (dataobj) {
+ // Writing the case's uid inside the analysis request creation's form. Thus when the analysis
+ // request form submits, it will catch the case's uid and create it.
+ $('form#analysisrequest_edit_form input#ar_0_Batch').attr('uid', dataobj.objects[0]['UID']);
+ $('form#analysisrequest_edit_form input#ar_0_Batch_uid').val(dataobj.objects[0]['UID']);
+ });
+ // The case's input also needs their id.
+ $('form#analysisrequest_edit_form input#ar_0_Batch').val(data['obj_id']);
+ },
+ error: function(XMLHttpRequest, statusText) {
+ window.bika.lims.portalMessage(statusText);
+ window.scroll(0,0);
+ $("input[class~='context']").prop("disabled", false);
+ }
+ });
+ $.ajaxSetup({async: true});
+ }
+
+
+ function printAnalysisRequest(){
+ /**
+ * This function triggers the browser's print-page option.
+ */
+ window.print()
+ }
+}
diff --git a/bika/health/static/js/bika.health.loader.js b/bika/health/static/js/bika.health.loader.js
index 420ac93..96660f0 100644
--- a/bika/health/static/js/bika.health.loader.js
+++ b/bika/health/static/js/bika.health.loader.js
@@ -30,7 +30,10 @@ window.bika.health.controllers = {
'HealthPatientPublicationPrefsEditView'],
".template-ar_add #analysisrequest_edit_form":
- ['HealthAnalysisRequestAddView', ],
+ ['HealthAnalysisRequestAddView'],
+
+ ".template-ar_add #health-standard-ar-add-form":
+ ['HealthStandardAnalysisRequestAddView'],
".template-base_edit.portaltype-bikasetup":
['HealthBikaSetupEditView'],
diff --git a/bika/health/static/js/bika.health.patient.js b/bika/health/static/js/bika.health.patient.js
index 2bf17ba..109141b 100644
--- a/bika/health/static/js/bika.health.patient.js
+++ b/bika/health/static/js/bika.health.patient.js
@@ -144,6 +144,10 @@ function HealthPatientEditView() {
$("input#InvoiceToInsuranceCompany").live('change',function() {
checkInvoiceToInsuranceCompany(this);
});
+ $("#PatientAsGuarantor").live('change',function() {
+ hide_show_guarantor_fields();
+ });
+ hide_show_guarantor_fields();
}
/**
@@ -316,6 +320,23 @@ function HealthPatientEditView() {
$(item).prop('checked', false).unbind("click");
}
}
+
+ function hide_show_guarantor_fields(){
+ /**
+ * If the "Patient is the guarantor" checkbox is set, the guarantor's fields are going to be hidden.
+ * In the opposite situation, the opposite action is going to happen.
+ */
+ var fields = $('[data-fieldname*="Guarantor"]').not('#archetypes-fieldname-PatientAsGuarantor');
+ var address_widget = $('[id*="GuarantorPostalAddress"]').closest('fieldset');
+ if ($("#PatientAsGuarantor").attr('checked')?true:false){
+ fields.hide();
+ address_widget.hide();
+ }
+ else {
+ fields.show();
+ address_widget.show();
+ }
+ }
}
diff --git a/bika/health/upgrade/configure.zcml b/bika/health/upgrade/configure.zcml
index 24addee..103309d 100644
--- a/bika/health/upgrade/configure.zcml
+++ b/bika/health/upgrade/configure.zcml
@@ -65,4 +65,13 @@
handler="bika.health.upgrade.to316.upgrade"
sortkey="1"
profile="bika.health:default"/>
+
+
diff --git a/bika/health/upgrade/to317.py b/bika/health/upgrade/to317.py
new file mode 100644
index 0000000..68a32f8
--- /dev/null
+++ b/bika/health/upgrade/to317.py
@@ -0,0 +1,113 @@
+from Acquisition import aq_inner
+from Acquisition import aq_parent
+from Products.CMFCore.utils import getToolByName
+from bika.lims.utils import tmpID
+from bika.lims.idserver import renameAfterCreation
+from bika.health.permissions import AddEthnicity, ViewEthnicities
+from bika.lims import logger
+
+
+def upgrade(tool):
+
+ # Adding bika.health.analysisrequest.ar_add_health_standard.js
+ portal = aq_parent(aq_inner(tool))
+ setup = portal.portal_setup
+ typestool = getToolByName(portal, 'portal_types')
+
+ # Since this new version changes the hard-coded ethnicity to a new content type ethnicity, we need to save all
+ # patients' ethnicities to create and load them later. Otherwise, all patient with an ethnicity defined will lost
+ # its ethnicity value.
+
+ # Getting all patients brains
+ bpc = getToolByName(tool, 'bika_patient_catalog')
+ all_patients = bpc(portal_type='Patient')
+ # Initializing the list that will contain tuples with the actual (patientUID,ethnicity)
+ patient_list = []
+ for patient in all_patients:
+ # Obtaining patient object
+ patient_obj = patient.getObject()
+ # Obtaining patient's ethnicity name and uid
+ pa_ethnicity = patient_obj.Schema()['Ethnicity'].get(patient_obj)
+ pa_uid = patient_obj.UID()
+ if pa_ethnicity != '':
+ # If the patient contains an ethnicity, it should be saved in the list
+ patient_list.append((pa_uid, pa_ethnicity))
+ # reread jsregistry with the new data
+ setup.runImportStepFromProfile('profile-bika.health:default', 'jsregistry')
+ # Reread cssregistry to update the changes
+ setup.runImportStepFromProfile('profile-bika.health:default', 'cssregistry')
+ # Reread typeinfo to update/add the modified/added types
+ setup.runImportStepFromProfile('profile-bika.health:default', 'typeinfo')
+ # Reread factorytool to add the the new ethnicity type
+ setup.runImportStepFromProfile('profile-bika.health:default', 'factorytool')
+ # Reread workflow to add the the new ethnicity type
+ setup.runImportStepFromProfile('profile-bika.health:default', 'workflow')
+ # Reread controlpanel to add the the new ethnicity type
+ setup.runImportStepFromProfile('profile-bika.health:default', 'controlpanel')
+
+ # Adding Ethnicity roles
+ workflow = getToolByName(portal, 'portal_workflow')
+ workflow.updateRoleMappings()
+
+ # Adding Ethnicity content type
+ at = getToolByName(portal, 'archetype_tool')
+ at.setCatalogsByType('Ethnicity', ['bika_setup_catalog', ])
+ # If the type is not created yet, we should create it
+ if not portal['bika_setup'].get('bika_ethnicities'):
+ typestool.constructContent(type_name="Ethnicities",
+ container=portal['bika_setup'],
+ id='bika_ethnicities',
+ title='Ethnicity')
+ obj = portal['bika_setup']['bika_ethnicities']
+ obj.unmarkCreationFlag()
+ obj.reindexObject()
+ if not portal['bika_setup'].get('bika_ethnicities'):
+ logger.info("Ethnicities not created")
+
+ # Define permissions for ethnicity
+ mp = portal.manage_permission
+ mp(AddEthnicity, ['Manager', 'Owner', 'LabManager', 'LabClerk'], 1)
+ mp(ViewEthnicities, ['Manager', 'LabManager', 'Owner', 'LabClerk', 'Doctor', 'RegulatoryInspector'], 1)
+
+ # Creating all standard ethnicities
+ createEthnicities(tool)
+ # Relating new ethnicity contents types with patients
+ addPatientEthnicity(tool, patient_list)
+
+ return True
+
+
+def createEthnicities(context):
+ """
+ This function creates al the standard ethnicities
+ :return: a list of tuples with the created ethnicities contents as: [(ethnicity_name, ethnicity_uid), (), ...]
+ """
+ ethnicities = ['Native American', 'Asian', 'Black', 'Native Hawaiian or Other Pacific Islander', 'White',
+ 'Hispanic or Latino']
+ for ethnicityname in ethnicities:
+ folder = context.bika_setup.bika_ethnicities
+ # Generating a temporal object
+ _id = folder.invokeFactory('Ethnicity', id=tmpID())
+ obj = folder[_id]
+ # Setting its values
+ obj.edit(title=ethnicityname,
+ description='')
+ obj.unmarkCreationFlag()
+ renameAfterCreation(obj)
+
+
+def addPatientEthnicity(context, patient_list):
+ """
+ This function adds to the patient, its ethnicity.
+ :Patient_list: is a list of tuples. Each tuple contains a patient UID and a string. This string is the name of the
+ ethnicity that used te be related in the patient. [(patientUID, ethnicityName),(),...]
+ :return: Ethnicity object
+ """
+ for patientUID,ethnicityname in patient_list:
+ # Getting the ethnicity uid
+ bsc = getToolByName(context, 'bika_setup_catalog')
+ bpc = getToolByName(context, 'bika_patient_catalog')
+ ethnicityUID= bsc(Portal_type='Ethnicity', Title=ethnicityname)[0].getObject().UID()
+ # Getting the patient object
+ patient = bpc(Portal_type='Patient', UID=patientUID)[0].getObject()
+ patient.setEthnicity(ethnicityUID)
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index c74a51a..c46ee92 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -1,4 +1,12 @@
-3.1.6 (unreleased)
+3.1.7 (2015-06-09)
+------------------
+HEALTH-245: Set-up data load. Patient ID conversion, alternatives
+HEALTH-227: Converting Patient IDs before import
+HEALTH-228: Load Setup data bugs
+HEALTH-140: AR Create per path lab standard form
+HEALTH-251: Add guarantor details in insurance companies
+
+3.1.6 (2015-02-27)
------------------
HEALTH-223: When you are adding a doctor through an overlay (add doctor button in cases), the address widgets don't work properly.
HEALTH-215: Correct Navigation tree order
diff --git a/setup.cfg b/setup.cfg
index ed2be0a..0cf29e1 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,5 +1,5 @@
[egg_info]
-tag_build =
+tag_build =
tag_date = false
-tag_svn_revision = true
+tag_svn_revision = false
diff --git a/setup.py b/setup.py
index 5dd8bf4..10cf7d7 100644
--- a/setup.py
+++ b/setup.py
@@ -1,7 +1,7 @@
from setuptools import setup, find_packages
import os
-version = '3.1.6'
+version = '3.1.7'
setup(name='bika.health',
version=version,
@@ -33,7 +33,7 @@
zip_safe=False,
install_requires=[
'setuptools',
- 'bika.lims==3.1.7',
+ 'bika.lims==3.1.8',
'archetypes.schemaextender',
'collective.wtf',
],