diff --git a/connector_carepoint/README.rst b/connector_carepoint/README.rst index bb0d8f0..2221f60 100755 --- a/connector_carepoint/README.rst +++ b/connector_carepoint/README.rst @@ -8,15 +8,22 @@ CarePoint Connector This module provides CarePoint connector functionality. +Note that record creation will take place on the current user's company's +default Carepoint backend. + +Records imported from other backends will maintain their relation with that +backend when exporting updates. + The following two-way sync logic is implemented: * Odoo Patient / CarePoint Patient +* Odoo Physician / CarePoint Doctor +* Odoo Pharmacy / Careoint Organization +* Odoo Prescription & Line / CarePoint Prescription The following logic is impented on a one-way (CarePoint to Odoo) basis: -* Odoo Pharmacy / CarePoint Store -* Odoo Physician / CarePoint Doctor -* Odoo Prescription & Line / CarePoint Prescription +* Odoo Pharmacy Warehouse / CarePoint Store * Odoo Order / CarePoint Order * Odoo Order Line / CarePoint Order Line * Odoo NDC / FDB NDC @@ -26,7 +33,6 @@ The following logic is impented on a one-way (CarePoint to Odoo) basis: * Odoo Unit of Measure / FDB Strength * Odoo Drug Route / FDB Route - Installation ============ @@ -59,13 +65,14 @@ To use this module, you need to: Known Issues / Roadmap ====================== -* More intelligent PK handling, and allowance of searches without +* Automatic failed connection renegotiation +* Add more retryable errors (such as in event of temp db d/c) * Multiple DB connections not currently supported (namespace isolation required) * Have to reboot server after reinstall to kill dup namespaces * Medicament creation in NDC is bad & should use medicament importer instead * Medicament category setting is not enforced - also need Rx/OTC delineation * Add Rx/OTC Tax delineation -* ``import_dependency`` usage in ``_after_import`` should be replaced for delay +* ``_import_dependency`` usage in ``_after_import`` should be replaced for delay * Needs to be split into multiple modules to isolate dependencies * Carepoint organizations import as pharmacies, but might be other entities diff --git a/connector_carepoint/consumer.py b/connector_carepoint/consumer.py index 3102d5e..815182f 100644 --- a/connector_carepoint/consumer.py +++ b/connector_carepoint/consumer.py @@ -31,7 +31,8 @@ def delay_export(session, model_name, record_id, vals): export_record.delay(session, model_name, record_id, fields=fields) -@on_record_write(model_names=['medical.patient', +@on_record_write(model_names=['medical.prescription.order.line', + 'medical.patient', 'carepoint.address', 'carepoint.address.patient', 'carepoint.organization', @@ -51,7 +52,8 @@ def delay_export_all_bindings(session, model_name, record_id, vals): fields=fields) -@on_record_create(model_names=['medical.patient', +@on_record_create(model_names=['medical.prescription.order.line', + 'medical.patient', 'carepoint.address', 'carepoint.address.patient', 'carepoint.organization', diff --git a/connector_carepoint/models/medical_prescription_order.py b/connector_carepoint/models/medical_prescription_order.py index bb375ad..a31f5d9 100644 --- a/connector_carepoint/models/medical_prescription_order.py +++ b/connector_carepoint/models/medical_prescription_order.py @@ -109,29 +109,29 @@ def _import_dependencies(self): # """ Import the addresses """ # book = self.unit_for(PartnerAddressBook, model='carepoint.address') # book.import_addresses(self.carepoint_id, partner_binding.id) - - -@carepoint -class MedicalPrescriptionOrderExportMapper(ExportMapper): - _model_name = 'carepoint.medical.prescription.order' - - direct = [ - ('date_start_treatment', 'start_date'), - ('date_stop_treatment', 'expire_date'), - ('qty', 'written_qty'), - ('frequency', 'freq_of_admin'), - ('quantity', 'units_per_dose'), - # Note that the col naming seems to be reversed *shrug* - # ('refill_qty_original', 'refills_left'), - # ('refill_qty_remain', 'refills_orig'), - ] - - @mapping - def pat_id(self, record): - return {'pat_id': record.carepoint_id} - - -@carepoint -class MedicalPrescriptionOrderExporter(CarepointExporter): - _model_name = ['carepoint.medical.prescription.order'] - _base_mapper = MedicalPrescriptionOrderExportMapper +# +# +# @carepoint +# class MedicalPrescriptionOrderExportMapper(ExportMapper): +# _model_name = 'carepoint.medical.prescription.order' +# +# direct = [ +# ('date_start_treatment', 'start_date'), +# ('date_stop_treatment', 'expire_date'), +# ('qty', 'written_qty'), +# ('frequency', 'freq_of_admin'), +# ('quantity', 'units_per_dose'), +# # Note that the col naming seems to be reversed *shrug* +# # ('refill_qty_original', 'refills_left'), +# # ('refill_qty_remain', 'refills_orig'), +# ] +# +# @mapping +# def pat_id(self, record): +# return {'pat_id': record.carepoint_id} +# +# +# @carepoint +# class MedicalPrescriptionOrderExporter(CarepointExporter): +# _model_name = ['carepoint.medical.prescription.order'] +# _base_mapper = MedicalPrescriptionOrderExportMapper diff --git a/connector_carepoint/models/medical_prescription_order_line.py b/connector_carepoint/models/medical_prescription_order_line.py index 6c9b71e..4ea44dd 100644 --- a/connector_carepoint/models/medical_prescription_order_line.py +++ b/connector_carepoint/models/medical_prescription_order_line.py @@ -7,6 +7,8 @@ from openerp import models from openerp.addons.connector.unit.mapper import (mapping, only_create, + changed_by, + ExportMapper, ) from ..unit.backend_adapter import CarepointCRUDAdapter from ..unit.mapper import CarepointImportMapper @@ -14,9 +16,15 @@ from ..unit.import_synchronizer import (DelayedBatchImporter, CarepointImporter, ) +from ..unit.export_synchronizer import CarepointExporter _logger = logging.getLogger(__name__) +try: + from sqlalchemy import text, bindparam +except ImportError: + _logger.debug('Unable to import SQLAlchemy resources') + class CarepointMedicalPrescriptionOrderLine(models.Model): """ Binding Model for the Carepoint Prescription """ @@ -52,6 +60,49 @@ class MedicalPrescriptionOrderLineAdapter(CarepointCRUDAdapter): """ Backend Adapter for the Carepoint Prescription """ _model_name = 'carepoint.medical.prescription.order.line' + def _get_next_script_no(self, store_id, dea, otc=False): + """ It generates and returns the next Rx ID in sequence + Params: + store_id (int): ID of the store in CarepPoint + dea (int): DEA code for medicament + otc (bool): True if medicament is OTC + Return: + (str) Newly generated script number + """ + conn = self.carepoint.dbs['cph'].connect() + trans = conn.begin() + try: + res = conn.execute( + text( + "SET NOCOUNT ON;" + "DECLARE @out VARCHAR(30);" + "EXEC CpGetScriptNo :store_id, :dea, @out output, :otc;" + "SELECT @out;" + "SET NOCOUNT OFF;", + bindparams=[ + bindparam('store_id'), + bindparam('dea'), + bindparam('otc'), + ], + ), + seq_name=sequence_name, + ) + id_int = res.fetchall()[0][0] + trans.commit() + except: + trans.rollback() + raise + finally: + conn.close() + return id_int + + def create(self, data): + """ It gets the next Rx sequence, appends to data, and calls super """ + data['script_no'] = self._get_next_script_no( + data['store_id'], data['drug_dea_class'], + ) + return super(MedicalPrescriptionOrderLineAdapter, self).create(data) + @carepoint class MedicalPrescriptionOrderLineBatchImporter(DelayedBatchImporter): @@ -185,3 +236,131 @@ def _import_dependencies(self): 'carepoint.medical.prescription.order') self._import_dependency(record['ndc'], 'carepoint.fdb.ndc') + + +@carepoint +class MedicalPrescriptionOrderLineExportMapper(ExportMapper): + _model_name = 'carepoint.medical.prescription.order.line' + + direct = [ + ('date_start_treatment', 'start_date'), + ('date_stop_treatment', 'expire_date'), + ('orig_expire_date', 'expire_date'), + ('qty', 'written_qty'), + ('frequency', 'freq_of_admin'), + ('quantity', 'units_entered'), + ('refill_qty_original', 'refills_orig'), + ('refill_qty_remain', 'refills_left'), + ] + + @mapping + def pat_id(self, record): + binder = self.binder_for('carepoint.medical.patient') + record_id = binder.to_backend(record.patient_id) + return {'pat_id': record_id} + + @mapping + @changed_by('prescription_order_id.partner_id') + def store_id(self, record): + binder = self.binder_for('carepoint.carepoint.store') + record_id = binder.to_backend( + record.prescription_order_id.partner_id + ) + return {'store_id': record_id} + + @mapping + @changed_by('physician_id') + def md_id(self, record): + binder = self.binder_for('carepoint.medical.physician') + record_id = binder.to_backend(record.physician_id) + return {'md_id': record_id} + + @mapping + @changed_by('ndc_id') + def ndc(self, record): + return {'ndc': record.ndc_id.name} + + @mapping + @changed_by('gcn_id') + def gcn(self, record): + binder = self.binder_for('carepoint.fdb.gcn') + record_id = binder.to_backend(record.gcn_id) + return {'gcn': record_id} + + @mapping + @changed_by('ndc_id') + def mfg(self, record): + binder = self.binder_for('carepoint.fdb.ndc') + ndc = binder.to_backend(record.ndc_id, browse=True) + return {'mfg': ndc.lbl_mfg_id.mfg} + + @mapping + @changed_by('medicament_id') + def medicament_meta(self, record): + binder = self.binder_for('carepoint.medical.medicament') + record_id = binder.to_backend(record.medicament_id, browse=True) + return {'drug_name': record_id.display_name, + 'gpi_rx': record_id.gpi, + } + + @mapping + @changed_by('medication_dosage_id') + def sig_code_and_text(self, record): + return {'sig_code': record.medication_dosage_id.code, + 'sig_text': record.medication_dosage_id.name, + 'sig_text_english': record.medication_dosage_id.name, + } + + @mapping + @changed_by('last_dispense_id') + def last_rxdisp_and_meta(self, record): + binder = self.binder_for('carepoint.procurement.order') + proc = binder.to_backend(record.last_dispense_id, browse=True) + return {'last_rxdisp_id': proc.carepoint_id, + 'last_refill_qty': proc.product_qty, + 'last_refill_date': proc.date_planned, + 'last_dispense_prod': proc.product_id.display_name, + } + + @mapping + @changed_by('prescription_id.transfer_pharmacy_id') + def src_org_id(self, record): + binder = self.binder_for('carepoint.carepoint.organization') + record_id = binder.to_backend( + record.prescription_order_id.transfer_pharmacy_id + ) + return {'src_org_id': record_id} + + @mapping + @changed_by('is_substitutable') + def daw_yn(self, record): + return {'daw_yn': not record.is_substitutable} + + @mapping + def static_defaults(self, record): + return { + 'df': 1, + 'uu': 0, + 'dosage_multiplier': 1, + 'app_flags': 0, + 'treatment_yn': 0, + 'workflow_status_cn': 0, + 'taxable': 0, + 'priority_cn': 0, + } + + +@carepoint +class MedicalPrescriptionOrderLineExporter(CarepointExporter): + _model_name = ['carepoint.medical.prescription.order.line'] + _base_mapper = MedicalPrescriptionOrderLineExportMapper + + def _export_dependencies(self): + self._export_dependency(self.binding_record.patient_id, + 'carepoint.medical.patient') + self._export_dependency(self.binding_record.physician_id, + 'carepoint.medical.physician') + self._export_dependency( + record.prescription_order_id.transfer_pharmacy_id, + 'carepoint.carepoint.organization', + )