def remove_treatments_from_plan_and_est(om_gui, treatments, completed=False): ''' remove treatments from the treatment plan and estimate. treatments is in the form ((att, shortcut),) ''' LOGGER.debug((treatments, completed)) pt = om_gui.pt courseno = pt.treatment_course.courseno for att, shortcut in treatments: if completed: txs = pt.treatment_course.__dict__["%scmp" % att] n_txs = txs.split(" ").count(shortcut) hash_ = localsettings.hash_func( "%s%s%s%s" % (courseno, att, n_txs, shortcut)) tx_hash = TXHash(hash_, completed) tx_hash_reverse(om_gui, tx_hash) txs = "%s %s" % ( pt.treatment_course.__dict__["%scmp" % att], pt.treatment_course.__dict__["%spl" % att] ) n_txs = txs.split(" ").count(shortcut) hash_ = localsettings.hash_func( "%s%s%s%s" % (courseno, att, n_txs, shortcut)) tx_hash = TXHash(hash_, completed=False) p_att = "%spl" % att val = pt.treatment_course.__dict__[p_att] new_val = val.replace("%s " % shortcut, "", 1) if re.match("[ul][lr][1-8]", att): n_txs = None if not complex_shortcut_removal_handled(om_gui, att, shortcut, n_txs, tx_hash): affected_ests = list(om_gui.pt.ests_from_hash(tx_hash)) if not affected_ests: om_gui.advise(u"%s '%s' %s<hr />%s" % ( _("Couldn't find"), "%s%s%s%s" % (courseno, att, n_txs, shortcut), _("in the patient's estimate"), _("This Shouldn't Happen!")), 2) for est in affected_ests: LOGGER.debug("removing reference to %s in estimate %s" % ( tx_hash, est)) est.tx_hashes.remove(tx_hash) if est.tx_hashes == []: om_gui.pt.estimates.remove(est) pt.treatment_course.__dict__[p_att] = new_val if re.match("[ul][lr[1-8]", att): plan = pt.treatment_course.__dict__["%spl" % att] cmp = pt.treatment_course.__dict__["%scmp" % att] charts_gui.updateChartsAfterTreatment(om_gui, att, plan, cmp) om_gui.updateDetails()
def perform_tx(self): pt = self.om_gui.pt if pt.serialno == 0: self.om_gui.advise(_("no patient selected"), 1) return if "N" in pt.cset: self.db_radioButton.hide() self.extsp_radioButton.hide() else: self.extsp_radioButton.setChecked( "SP+" in pt.treatment_course.periopl) result = self.getInput() if result: courseno = pt.treatment_course.courseno if self.trt in pt.treatment_course.periopl: n_txs = pt.treatment_course.periocmp.split(" ").count( self.trt) + 1 hash_ = localsettings.hash_func("%sperio%s%s" % (courseno, n_txs, self.trt)) tx_hash = TXHash(hash_) manipulate_plan.tx_hash_complete(self.om_gui, tx_hash) else: trts = (("perio", "%s" % self.trt), ) manipulate_plan.add_treatments_to_plan(self.om_gui, trts, True) note = "%s %s %s\n" % (self.trt, _("performed by"), self.dent) self.om_gui.addNewNote(note) return True else: self.om_gui.advise("Hyg Treatment not applied", 2) return False
def reverse_txs(om_gui, treatments, confirm_multiples=True): LOGGER.debug(treatments) pt = om_gui.pt courseno = pt.treatment_course.courseno if len(treatments) > 1 and confirm_multiples: txs = [] for att, treat in treatments: txs.append((att, treat, True)) dl = CompleteTreatmentDialog(txs, om_gui) if not dl.exec_(): return treatments = dl.uncompleted_treatments deleted_treatments = dl.deleted_treatments else: deleted_treatments = iter([]) for att, treatment in treatments: completed = pt.treatment_course.__dict__["%scmp" % att] treat = treatment.strip(" ") count = completed.split(" ").count(treat) LOGGER.debug("creating tx_hash using %s %s %s", att, count, treat) hash_ = localsettings.hash_func("%s%s%s%s" % (courseno, att, count, treat)) tx_hash = TXHash(hash_) tx_hash_reverse(om_gui, tx_hash) for att, treat, completed in deleted_treatments: remove_treatments_from_plan_and_est(om_gui, ((att, treat.strip(" ")), ), completed)
def perform_exam(self): ''' perform an exam ''' if self.pt.serialno == 0: om_gui.advise("no patient selected", 1) return if self.pt.treatment_course.has_exam: message = u"<p>%s</p><hr /><p>%s</p>" % ( _('You already have a completed exam ' 'on this course of treatment'), _("Unable to perform exam")) self.om_gui.advise(message, 1) return APPLIED = False while not APPLIED: result = self.getInput() if not result: self.om_gui.advise(_("Examination not applied"), 2) return False examtype, examdent, examd = result APPLIED, examdent = self.check_dent(examdent) if APPLIED: courseno = self.pt.treatment_course.courseno self.pt.treatment_course.examt = examtype if self.pt.treatment_course.examt == "CE": self.pt.pd5 = examd if self.pt.treatment_course.examt == "ECE": self.pt.pd6 = examd if self.pt.treatment_course.examt == "FCA": self.pt.pd7 = examd self.pt.treatment_course.examd = examd self.update_recall_date() self.pt.addHiddenNote("exam", "%s " % examtype) dentid = localsettings.ops_reverse[examdent] hash_ = localsettings.hash_func( "%sexam1%s" % (courseno, examtype)) tx_hash = TXHash(hash_, True) manipulate_plan.add_treatment_to_estimate( self.om_gui, "exam", examtype, dentid, [tx_hash]) newnotes = unicode( self.om_gui.ui.notesEnter_textEdit.toPlainText().toUtf8()) if newnotes != "" and newnotes[-1] != "\n": newnotes += "\n" newnotes += "%s %s %s\n" % ( examtype, _("performed by"), examdent) self.om_gui.ui.notesEnter_textEdit.setText(newnotes) return APPLIED
def xrayAdd(om_gui, complete=False): ''' add xray items ''' mylist = ( ("xray", "S"), ("xray", "M"), ("xray", "P"), ) # offerTreatmentItems is a generator, so the list conversion here # is so that the dialog get raised before the # were these xrays taken today question chosen_treatments = list(offerTreatmentItems(om_gui, mylist, complete)) if not chosen_treatments: return if not complete: input = QtWidgets.QMessageBox.question( om_gui, _("question"), _("Were these xrays taken today?"), QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No) if input == QtWidgets.QMessageBox.Yes: complete = True completed_planned_warning_required = False # complete any xrays already planned. if complete: pt = om_gui.pt courseno = pt.treatment_course.courseno for xray, trt in chosen_treatments: if trt in pt.treatment_course.xraypl: n_txs = pt.treatment_course.xraycmp.split(" ").count(trt) + 1 hash_ = localsettings.hash_func("%sxray%s%s" % (courseno, n_txs, trt)) tx_hash = TXHash(hash_) tx_hash_complete(om_gui, tx_hash) completed_planned_warning_required = True else: add_treatments_to_plan(om_gui, ((xray, trt), ), True) else: add_treatments_to_plan(om_gui, chosen_treatments, False) if om_gui.ui.tabWidget.currentIndex() == 4: # clinical summary om_gui.load_clinicalSummaryPage() else: om_gui.ui.completed_listView.model().reset() if completed_planned_warning_required: om_gui.advise( _("Some of the xrays you completed were already planned."), 1)
def getEsts(sno): db = connect() cursor = db.cursor() cursor.execute(QUERY, (sno, )) rows = cursor.fetchall() cursor.close() estimates = [] for row in rows: hash_ = row[10] completed = bool(row[9]) tx_hash = TXHash(hash_, completed) ix = row[0] found = False # use existing est if one relates to multiple treatments for existing_est in estimates: if existing_est.ix == ix: existing_est.tx_hashes.append(tx_hash) found = True break if found: continue # initiate a custom data class est = Estimate() est.ix = ix est.courseno = row[11] est.number = row[1] est.itemcode = row[2] est.description = row[3] est.fee = row[4] est.ptfee = row[5] est.feescale = row[6] est.csetype = row[7] est.dent = row[8] # est.category = "TODO" # est.type_ = "TODO" est.tx_hashes = [tx_hash] estimates.append(est) cursor.close() return estimates
def cmp_viewer_context_menu(om_gui, att, values, point): ''' provides and handles a context menu for the ui.completed_listView and the ui.completedChartWidget ''' if len(values) == 0: return if len(values) > 1: treatments = [] for value in values: treatments.append((att, value)) reverse_txs(om_gui, treatments, confirm_multiples=True) return qmenu = QtWidgets.QMenu(om_gui) value = values[0] if att == "exam": hash_ = localsettings.hash_func("%sexam1%s" % (om_gui.pt.treatment_course.courseno, om_gui.pt.treatment_course.examt)) tx_hash = TXHash(hash_, True) rev_func = partial(tx_hash_reverse, om_gui, tx_hash) else: rev_func = partial(reverse_txs, om_gui, ((att, value), )) message = "%s %s %s" % (_("Reverse and Delete"), att, value) delete_action = QtWidgets.QAction(message, qmenu) delete_action.triggered.connect( partial(remove_treatments_from_plan_and_est, om_gui, ((att, value), ), True)) message = "%s %s %s" % (_("Reverse"), att, value) reverse_action = QtWidgets.QAction(message, qmenu) reverse_action.triggered.connect(rev_func) cancel_action = QtWidgets.QAction(_("Cancel"), qmenu) # not connected to anything.. f clicked menu will simply die! qmenu.addAction(reverse_action) qmenu.addSeparator() if att != "exam": qmenu.addAction(delete_action) qmenu.addAction(cancel_action) qmenu.setDefaultAction(qmenu.actions()[0]) qmenu.exec_(point)
def customAdd(om_gui, description=None): ''' add 'custom' items ''' if course_module.newCourseNeeded(om_gui): return pt = om_gui.pt courseno = pt.treatment_course.courseno Dialog = QtWidgets.QDialog(om_gui) dl = Ui_customTreatment.Ui_Dialog() dl.setupUi(Dialog) if description: dl.description_lineEdit.setText(description) if Dialog.exec_(): no = dl.number_spinBox.value() descr = dl.description_lineEdit.text() if descr == "": descr = "??" usercode = str(descr.replace(" ", "_"))[:20].upper() fee = localsettings.pencify(str(dl.fee_doubleSpinBox.value())) for i in range(no): pt.treatment_course.custompl += "%s " % usercode custom_txs = "%s %s" % (pt.treatment_course.customcmp, pt.treatment_course.custompl) n = custom_txs.split(" ").count(usercode) hash_ = localsettings.hash_func("%scustom%s%s" % (courseno, n, usercode)) tx_hash = TXHash(hash_) dentid = om_gui.pt.course_dentist add_treatment_to_estimate(om_gui, "custom", usercode, dentid, [tx_hash], itemcode="CUSTO", csetype="P", descr=descr, fee=fee, ptfee=fee) om_gui.update_plan_est()
def complete_txs(om_gui, treatments, confirm_multiples=True): ''' complete tooth treatment #args is a list - ["ul5","MOD","RT",] args is a list - [("ul5","MOD"),("ul5", "RT"), ("perio", "SP")] ''' if localsettings.clinicianNo == 0: om_gui.advise( _("You have no clinician login. " "Treatments cannot be completed by you!"), 2) return LOGGER.debug(treatments) pt = om_gui.pt courseno = pt.treatment_course.courseno if len(treatments) > 1 and confirm_multiples: txs = [] for att, treat in treatments: txs.append((att, treat, False)) dl = CompleteTreatmentDialog(txs, om_gui) dl.hide_reverse_all_but() if not dl.exec_(): return treatments = dl.completed_treatments deleted_treatments = dl.deleted_treatments else: deleted_treatments = iter([]) for att, treatment in treatments: existingcompleted = pt.treatment_course.__dict__["%scmp" % att] newcompleted = existingcompleted + treatment treat = treatment.strip(" ") count = newcompleted.split(" ").count(treat) LOGGER.debug("creating tx_hash using %s %s %s", att, count, treat) hash_ = localsettings.hash_func("%s%s%s%s" % (courseno, att, count, treat)) tx_hash = TXHash(hash_) tx_hash_complete(om_gui, tx_hash) for att, treat, completed in deleted_treatments: remove_treatments_from_plan_and_est(om_gui, ((att, treat.strip(" ")), ), completed)
def add_treatments_to_plan(om_gui, treatments, completed=False): LOGGER.debug(treatments) if course_module.newCourseNeeded(om_gui): return pt = om_gui.pt for att, shortcut in treatments: LOGGER.debug("adding %s %s to treatment plan" % (att, shortcut)) existing_txs = "%s %s" % (pt.treatment_course.__dict__["%scmp" % att], pt.treatment_course.__dict__["%spl" % att] ) # count the existing number and add 1 for the new shortcut n_txs = existing_txs.split(" ").count(shortcut) + 1 courseno = pt.treatment_course.courseno hash_ = localsettings.hash_func( "%s%s%s%s" % (courseno, att, n_txs, shortcut)) tx_hash = TXHash(hash_) dentid = pt.course_dentist pt.treatment_course.__dict__["%spl" % att] += "%s " % shortcut # check for deciduous tooth. if re.match("[ul][lr][1-8]", att): n_txs = None tooth_name = pt.chartgrid.get(att) if tooth_name != att: LOGGER.debug("Deciduous tooth treatment! on %s" % tooth_name) att = "%s%s" % (att[:2], tooth_name[2]) complex_addition_handled, shortcut = complex_shortcut_addition( om_gui, att, shortcut, n_txs, tx_hash) if complex_addition_handled == FULLY_HANDLED: LOGGER.debug("complex addition handled the estimate in entirety") elif complex_addition_handled == PARTIALLY_HANDLED: LOGGER.debug("complex addition handled the estimate in part") add_treatment_to_estimate(om_gui, att, shortcut, dentid, [tx_hash]) else: LOGGER.debug("adding only as a standard shortcut") add_treatment_to_estimate(om_gui, att, shortcut, dentid, [tx_hash]) if completed: tx_hash_complete(om_gui, tx_hash) om_gui.update_plan_est()
def getEsts(sno, courseno=None): db = connect() cursor = db.cursor() if courseno is None: cursor.execute(QUERY, (sno, )) else: cursor.execute(COURSE_QUERY, (sno, courseno)) rows = cursor.fetchall() cursor.close() estimates = OrderedDict() for row in rows: hash_ = row[10] completed = bool(row[9]) tx_hash = TXHash(hash_, completed) ix = row[0] est = estimates.get(ix, Estimate()) est.ix = ix est.courseno = row[11] est.number = row[1] est.itemcode = row[2] est.description = row[3] est.fee = row[4] est.ptfee = row[5] est.feescale = row[6] est.csetype = row[7] est.dent = row[8] try: est.tx_hashes.append(tx_hash) except AttributeError: est.tx_hashes = [tx_hash] estimates[ix] = est return list(estimates.values())
def recalculate_estimate(om_gui): ''' look up all the itemcodes in the patients feetable (which could have changed), and apply new fees ''' pt = om_gui.pt dentid = pt.course_dentist LOGGER.info("USER IS RECALCULATING ESTIMATE FOR PATIENT %s" % pt.serialno) # drop all existing estimates except custom items. # and reverse fee for completed items. cust_ests = [] for estimate in pt.estimates: if estimate.is_custom: cust_ests.append(estimate) for hash_, att, shortcut in pt.tx_hash_tups: if shortcut.strip(" ") == "!FEE": for est in pt.ests_from_hash(hash_): cust_ests.append(est) pt.estimates = cust_ests duplicate_txs = [] # recalculating the estimate has to be handled differently than when # adding treatment to a plan manually. # pt.new_hash_tups is a store of all treatments that are special cases # and need to ignore the rest of the treatment plan # an example is an extra fee for the first crown in an arch. pt.new_hash_tups = [] for hash_, att, shortcut in pt.tx_hash_tups: shortcut = shortcut.strip(" ") if shortcut == "!FEE" or att == "custom": continue tx_hash = TXHash(hash_) if re.match("[ul][lr][1-8A-E]", att): n_txs = None else: duplicate_txs.append("%s%s" % (att, shortcut)) n_txs = duplicate_txs.count("%s%s" % (att, shortcut)) complex_addition_handled, shortcut = complex_shortcut_addition( om_gui, att, shortcut, n_txs, tx_hash, recalculating=True) if complex_addition_handled == FULLY_HANDLED: LOGGER.debug("complex addition handled the estimate in entirety") elif complex_addition_handled == PARTIALLY_HANDLED: LOGGER.debug("complex addition handled the estimate in part") add_treatment_to_estimate(om_gui, att, shortcut, dentid, [tx_hash]) else: LOGGER.debug("adding only as a standard shortcut") add_treatment_to_estimate(om_gui, att, shortcut, dentid, [tx_hash]) LOGGER.debug("checking for completed items") for est in pt.estimates: for tx_hash in est.tx_hashes: if tx_hash in pt.completed_tx_hashes: tx_hash.completed = True om_gui.advise(_("Estimate recalculated"), 1) pt.new_hash_tups = None return True
def recalculate_estimate(om_gui): ''' look up all the itemcodes in the patients feetable (which could have changed), and apply new fees ''' pt = om_gui.pt dentid = pt.course_dentist LOGGER.info("USER IS RECALCULATING ESTIMATE FOR PATIENT %s" % pt.serialno) # drop all existing estimates except custom items. # and reverse fee for completed items. cust_ests = [] for estimate in pt.estimates: if estimate.is_custom: cust_ests.append(estimate) for hash_, att, shortcut in pt.tx_hash_tups: if shortcut.strip(" ") == "!FEE": for est in pt.ests_from_hash(hash_): cust_ests.append(est) pt.estimates = cust_ests duplicate_txs = [] # recalculating the estimate has to be handled differently than when # adding treatment to a plan manually. # pt.new_hash_tups is a store of all treatments that are special cases # and need to ignore the rest of the treatment plan # an example is an extra fee for the first crown in an arch. pt.new_hash_tups = [] for hash_, att, shortcut in pt.tx_hash_tups: shortcut = shortcut.strip(" ") if shortcut == "!FEE" or att == "custom": continue tx_hash = TXHash(hash_) if re.match("[ul][lr][1-8A-E]", att): n_txs = None else: duplicate_txs.append("%s%s" % (att, shortcut)) n_txs = duplicate_txs.count("%s%s" % (att, shortcut)) complex_addition_handled, shortcut = complex_shortcut_addition( om_gui, att, shortcut, n_txs, tx_hash, recalculating=True) if complex_addition_handled == FULLY_HANDLED: LOGGER.debug("complex addition handled the estimate in entirety") elif complex_addition_handled == PARTIALLY_HANDLED: LOGGER.debug("complex addition handled the estimate in part") add_treatment_to_estimate(om_gui, att, shortcut, dentid, [tx_hash]) else: LOGGER.debug("adding only as a standard shortcut") add_treatment_to_estimate(om_gui, att, shortcut, dentid, [tx_hash]) LOGGER.debug("checking for completed items") for est in pt.estimates: for tx_hash in est.tx_hashes: if tx_hash in pt.completed_tx_hashes: tx_hash.completed = True om_gui.advise(_("Estimate recalculated"), 1) pt.new_hash_tups = None return True
def fromFeeTable(om_gui, fee_item, sub_index): ''' add an item which has been selected from the fee table itself sub_index is when a child item has been added. ''' def show_help(): message = '''%s<ul> <li>%s %s %s %s <b>%s</b></li><li>%s %s</li><li>%s</li> </ul>''' % (_("Choose"), _("OK to add"), att_, _("to patient attribute"), shortcut, _("Recommended"), _("Use Feescale Method"), _("to overide this behaviour"), _("Cancel to abandon this addition entirely")) QtWidgets.QMessageBox.information(mb, _("Help"), message) def confirm_selected_table(): ''' check that the user is happy to use the suggested table, not the current one. returns the selected table, or None to keep the current. ''' table = pt.fee_table if fee_item.table == table: return table message = '%s<br /><b>%s</b>%s<hr />%s<br />%s' % ( _("Confirm you wish to use feescale"), fee_item.table.briefName, _("for this item"), _("The patient's default table is"), table.briefName) if QtWidgets.QMessageBox.question( om_gui, _("Confirm"), message, QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Ok) == QtWidgets.QMessageBox.Ok: return fee_item.table LOGGER.debug("fee_item %s, sub_index %s" % (fee_item, sub_index)) if course_module.newCourseNeeded(om_gui): return pt = om_gui.pt table = confirm_selected_table() if table is None: return att_ = fee_item.pt_attribute if att_ == "chart": atts = om_gui.chooseTooth() else: atts = [att_] if fee_item.shortcut is None or fee_item.is_regex: shortcut = "!FEE" else: shortcut = fee_item.shortcut if table == pt.fee_table and shortcut != "!FEE" and att_ != "exam": message = "%s %s<hr />%s" % (_( "You appear to be adding a relatively straightforward code to the" " patient's treatment plan using their default feescale" ), _("It is normally advisable to add this code conventionally."), _("Would you like to do this now?")) mb = QtWidgets.QMessageBox(None) mb.setWindowTitle(_("Confirm")) mb.setText(message) mb.setIcon(mb.Question) mb.addButton(_("Use Feescale Method"), mb.DestructiveRole) mb.addButton(mb.Cancel) mb.addButton(mb.Ok) mb.addButton(mb.Help) result = mb.exec_() while result == mb.Help: show_help() result = mb.exec_() if result == mb.Ok: LOGGER.warning("reverting to standard treatment adding methods") txs = [] message = "" for att in atts: txs.append((att, shortcut)) message += "<li>%s %s</li>" % (att, shortcut) add_treatments_to_plan(om_gui, txs) om_gui.advise( "%s <ul>%s</ul>%s" % (_("Treatments"), message, _("were added conventionally")), 1) return elif result == mb.Cancel: LOGGER.info("Feescale addition abandoned by user") return if not fee_item.allow_feescale_add: if att_ == "exam": reason = _("Exam items can never be added this way") else: reason = fee_item.forbid_reason message = "%s<hr /><em>%s</em>" % (_( "This item can not be added to the treatment plan " "using the feescale method, sorry"), reason) om_gui.advise(message, 1) return fee = fee_item.fees[sub_index] try: pt_fee = fee_item.ptFees[sub_index] except IndexError: pt_fee = fee dentid = pt.course_dentist cset = table.categories[0] for att in atts: if "%spl" % att not in pt.treatment_course.__dict__: att = "other" pt.treatment_course.__dict__[att + "pl"] += "%s " % shortcut new_plan = pt.treatment_course.__dict__[att + "pl"] descr = fee_item.description if re.match("[ul][lr][1-8]", att): om_gui.ui.planChartWidget.setToothProps(att, new_plan) tooth_name = pt.chartgrid.get(att).upper() descr = descr.replace("*", " %s" % tooth_name) existing_txs = "%s %s" % (pt.treatment_course.__dict__["%scmp" % att], new_plan) n_txs = existing_txs.split(" ").count(shortcut) courseno = pt.treatment_course.courseno hash_ = localsettings.hash_func("%s%s%s%s" % (courseno, att, n_txs, shortcut)) tx_hash = TXHash(hash_) add_treatment_to_estimate(om_gui, att, shortcut, dentid, [tx_hash], fee_item.itemcode, cset, descr, fee, pt_fee, table) om_gui.advise( "<b>%s</b> %s (%s)" % (fee_item.description, _("added to estimate"), _("from feescale")), 1) om_gui.update_plan_est()