コード例 #1
0
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()
コード例 #2
0
ファイル: hygTreatWizard.py プロジェクト: vomae/openmolar1
    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
コード例 #3
0
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)
コード例 #4
0
ファイル: exam_wizard.py プロジェクト: fuinha/openmolar1
    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
コード例 #5
0
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)
コード例 #6
0
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
コード例 #7
0
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)
コード例 #8
0
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()
コード例 #9
0
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)
コード例 #10
0
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()
コード例 #11
0
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())
コード例 #12
0
ファイル: manipulate_plan.py プロジェクト: fuinha/openmolar1
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
コード例 #13
0
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
コード例 #14
0
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()