15.1.661. tablet_qt/tasks/cpftlpsreferral.cpp

/*
    Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
    Created by Rudolf Cardinal (rnc1001@cam.ac.uk).

    This file is part of CamCOPS.

    CamCOPS is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    CamCOPS is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.
*/

#include "cpftlpsreferral.h"

#include "common/textconst.h"
#include "common/uiconst.h"
#include "core/camcopsapp.h"
#include "lib/datetime.h"
#include "maths/mathfunc.h"
#include "questionnairelib/commonoptions.h"
#include "questionnairelib/quboolean.h"
#include "questionnairelib/qudatetime.h"
#include "questionnairelib/questionnaire.h"
#include "questionnairelib/questionnairefunc.h"
#include "questionnairelib/quflowcontainer.h"
#include "questionnairelib/quhorizontalline.h"
#include "questionnairelib/qulineedit.h"
#include "questionnairelib/qumcq.h"
#include "questionnairelib/qutext.h"
#include "questionnairelib/qutextedit.h"
#include "tasklib/taskfactory.h"
#include "tasklib/taskregistrar.h"
using mathfunc::noneNullOrEmpty;


const QString CPFTLPSReferral::CPFTLPSREFERRAL_TABLENAME("cpft_lps_referral");

const QString REFERRAL_DATE_TIME("referral_date_time");
const QString LPS_DIVISION("lps_division");
const QString REFERRAL_PRIORITY("referral_priority");
const QString REFERRAL_METHOD("referral_method");
const QString REFERRER_NAME("referrer_name");
const QString REFERRER_CONTACT_DETAILS("referrer_contact_details");
const QString REFERRING_CONSULTANT("referring_consultant");
const QString REFERRING_SPECIALTY("referring_specialty");
const QString REFERRING_SPECIALTY_OTHER("referring_specialty_other");

const QString PATIENT_LOCATION("patient_location");
const QString ADMISSION_DATE("admission_date");
const QString ESTIMATED_DISCHARGE_DATE("estimated_discharge_date");
const QString PATIENT_AWARE_OF_REFERRAL("patient_aware_of_referral");
const QString INTERPRETER_REQUIRED("interpreter_required");
const QString SENSORY_IMPAIRMENT("sensory_impairment");
const QString MARITAL_STATUS_CODE("marital_status_code");
const QString ETHNIC_CATEGORY_CODE("ethnic_category_code");

const QString ADMISSION_REASON_OVERDOSE("admission_reason_overdose");
const QString ADMISSION_REASON_SELF_HARM_NOT_OVERDOSE(
    "admission_reason_self_harm_not_overdose"
);
const QString ADMISSION_REASON_CONFUSION("admission_reason_confusion");
const QString ADMISSION_REASON_TRAUMA("admission_reason_trauma");
const QString ADMISSION_REASON_FALLS("admission_reason_falls");
const QString ADMISSION_REASON_INFECTION("admission_reason_infection");
const QString ADMISSION_REASON_POOR_ADHERENCE("admission_reason_poor_adherence"
);
const QString ADMISSION_REASON_OTHER("admission_reason_other");

const QString EXISTING_PSYCHIATRIC_TEAMS("existing_psychiatric_teams");
const QString CARE_COORDINATOR("care_coordinator");
const QString OTHER_CONTACT_DETAILS("other_contact_details");

const QString REFERRAL_REASON("referral_reason");

void initializeCPFTLPSReferral(TaskFactory& factory)
{
    static TaskRegistrar<CPFTLPSReferral> registered(factory);
}


CPFTLPSReferral::CPFTLPSReferral(
    CamcopsApp& app, DatabaseManager& db, const int load_pk
) :
    Task(app, db, CPFTLPSREFERRAL_TABLENAME, false, false, false)
// ... anon, clin, resp
{
    addField(REFERRAL_DATE_TIME, QMetaType::fromType<QDateTime>());
    addField(LPS_DIVISION, QMetaType::fromType<QString>());
    addField(REFERRAL_PRIORITY, QMetaType::fromType<QString>());
    addField(REFERRAL_METHOD, QMetaType::fromType<QString>());
    addField(REFERRER_NAME, QMetaType::fromType<QString>());
    addField(REFERRER_CONTACT_DETAILS, QMetaType::fromType<QString>());
    addField(REFERRING_CONSULTANT, QMetaType::fromType<QString>());
    addField(REFERRING_SPECIALTY, QMetaType::fromType<QString>());
    addField(REFERRING_SPECIALTY_OTHER, QMetaType::fromType<QString>());

    addField(PATIENT_LOCATION, QMetaType::fromType<QString>());
    addField(ADMISSION_DATE, QMetaType::fromType<QDate>());
    addField(ESTIMATED_DISCHARGE_DATE, QMetaType::fromType<QDate>());
    addField(PATIENT_AWARE_OF_REFERRAL, QMetaType::fromType<bool>());
    addField(INTERPRETER_REQUIRED, QMetaType::fromType<bool>());
    addField(SENSORY_IMPAIRMENT, QMetaType::fromType<bool>());
    addField(MARITAL_STATUS_CODE, QMetaType::fromType<QString>());
    addField(ETHNIC_CATEGORY_CODE, QMetaType::fromType<QString>());

    addField(ADMISSION_REASON_OVERDOSE, QMetaType::fromType<bool>());
    addField(
        ADMISSION_REASON_SELF_HARM_NOT_OVERDOSE, QMetaType::fromType<bool>()
    );
    addField(ADMISSION_REASON_CONFUSION, QMetaType::fromType<bool>());
    addField(ADMISSION_REASON_TRAUMA, QMetaType::fromType<bool>());
    addField(ADMISSION_REASON_FALLS, QMetaType::fromType<bool>());
    addField(ADMISSION_REASON_INFECTION, QMetaType::fromType<bool>());
    addField(ADMISSION_REASON_POOR_ADHERENCE, QMetaType::fromType<bool>());
    addField(ADMISSION_REASON_OTHER, QMetaType::fromType<bool>());

    addField(EXISTING_PSYCHIATRIC_TEAMS, QMetaType::fromType<QString>());
    addField(CARE_COORDINATOR, QMetaType::fromType<QString>());
    addField(OTHER_CONTACT_DETAILS, QMetaType::fromType<QString>());

    addField(REFERRAL_REASON, QMetaType::fromType<QString>());

    load(load_pk);  // MUST ALWAYS CALL from derived Task constructor.
}

// ============================================================================
// Class info
// ============================================================================

QString CPFTLPSReferral::shortname() const
{
    return "CPFT_LPS_Referral";
}

QString CPFTLPSReferral::longname() const
{
    return tr("CPFT LPS – referral");
}

QString CPFTLPSReferral::description() const
{
    return tr("Referral to CPFT’s Liaison Psychiatry Service.");
}

QString CPFTLPSReferral::infoFilenameStem() const
{
    return "clinical";
}

QString CPFTLPSReferral::xstringTaskname() const
{
    return "cpft_lps_referral";
}

// ============================================================================
// Instance info
// ============================================================================

bool CPFTLPSReferral::isComplete() const
{
    // The bare minimum:
    return noneNullOrEmpty(values(QStringList{
        REFERRAL_DATE_TIME, PATIENT_LOCATION, REFERRAL_REASON}));
}

QStringList CPFTLPSReferral::summary() const
{
    return QStringList{
        QString("%1: <b>%2</b>.")
            .arg(
                xstring("f_referral_date_time"),
                datetime::textDateTime(value(REFERRAL_DATE_TIME))
            ),
        QString("%1: <b>%2</b>.")
            .arg(xstring("f_patient_location"), prettyValue(PATIENT_LOCATION)),
        QString("%1: <b>%2</b>.")
            .arg(xstring("f_referral_reason"), prettyValue(REFERRAL_REASON)),
    };
}

QStringList CPFTLPSReferral::detail() const
{
    return completenessInfo() + summary()
        + QStringList{
            "",
            TextConst::seeFacsimileForMoreDetail(),
        };
}

OpenableWidget* CPFTLPSReferral::editor(const bool read_only)
{
    const NameValueOptions referral_pickup_options
        = CommonOptions::optionsCopyingDescriptions({
            "Direct",
            "Morning Report",
            "Ops centre",
            "Other",
        });
    const NameValueOptions specialty_options
        = CommonOptions::optionsCopyingDescriptions({
            "Acute medicine",
            "Cardiology",
            "DME",
            "ED",
            "Endocrinology",
            "Gastroenterology",
            "Hepatology",
            "Neurology",
            "Oncology",
            "Perinatal/obstetric",
            "Renal",
            "Respiratory",
            "Surgery",
            "Transplant",
            "Trauma",
            "Other",  // last (others are alphabetical)
        });
    const NameValueOptions priority_options{
        {xstring("priority_R"), "R"},
        {xstring("priority_U"), "U"},
        {xstring("priority_E"), "E"},
    };
    const NameValueOptions lps_division_options{
        {xstring("service_G"), "G"},
        {xstring("service_O"), "O"},
        {xstring("service_S"), "S"},
    };
    const NameValueOptions yesno_options = CommonOptions::noYesBoolean();
    const NameValueOptions marital_options
        = m_app.nhsPersonMaritalStatusCodeOptions();
    const NameValueOptions ethnic_options
        = m_app.nhsEthnicCategoryCodeOptions();

    auto boldtext = [this](const QString& xstringname) -> QuElement* {
        return (new QuText(xstring(xstringname)))->setBold();
    };
    auto text = [this](const QString& xstringname) -> QuElement* {
        return new QuText(xstring(xstringname));
    };
    auto yn = [this, &yesno_options](
                  const QString& fieldname, bool mandatory = false
              ) -> QuElement* {
        return (new QuMcq(fieldRef(fieldname, mandatory), yesno_options))
            ->setAsTextButton(true)
            ->setHorizontal(true);
    };
    auto mcq = [this](
                   const QString& fieldname,
                   const NameValueOptions& options,
                   bool mandatory = false
               ) -> QuElement* {
        return (new QuMcq(fieldRef(fieldname, mandatory), options))
            ->setAsTextButton(true)
            ->setHorizontal(true);
    };
    auto boolbutton = [this](
                          const QString& fieldname,
                          const QString& xstringname,
                          bool mandatory = false
                      ) -> QuElement* {
        return (new QuBoolean(
                    xstring(xstringname), fieldRef(fieldname, mandatory)
                ))
            ->setAsTextButton(true);
    };

    QuPagePtr page(
        (new QuPage{
             boldtext("t_about_referral"),
             text("f_referral_date_time"),
             (new QuDateTime(fieldRef(REFERRAL_DATE_TIME)))
                 ->setMode(QuDateTime::Mode::DefaultDateTime)
                 ->setOfferNowButton(true),
             text("f_lps_division"),
             mcq(LPS_DIVISION, lps_division_options, true),
             text("f_referral_priority"),
             mcq(REFERRAL_PRIORITY, priority_options, true),
             text("f_referral_method"),
             mcq(REFERRAL_METHOD, referral_pickup_options, true),
             questionnairefunc::defaultGridRawPointer(
                 {
                     {xstring("f_referrer_name"),
                      new QuLineEdit(fieldRef(REFERRER_NAME, true))},
                     {xstring("f_referrer_contact_details"),
                      new QuLineEdit(fieldRef(REFERRER_CONTACT_DETAILS, true)
                      )},
                     {xstring("f_referring_consultant"),
                      new QuLineEdit(fieldRef(REFERRING_CONSULTANT, true))},
                 },
                 uiconst::DEFAULT_COLSPAN_Q,
                 uiconst::DEFAULT_COLSPAN_A
             ),
             text("f_referring_specialty"),
             mcq(REFERRING_SPECIALTY, specialty_options, true),
             questionnairefunc::defaultGridRawPointer(
                 {
                     {xstring("f_referring_specialty_other"),
                      new QuTextEdit(fieldRef(REFERRING_SPECIALTY_OTHER, false)
                      )},
                 },
                 uiconst::DEFAULT_COLSPAN_Q,
                 uiconst::DEFAULT_COLSPAN_A
             ),

             // ---------------------------------------------------------------
             new QuHorizontalLine(),
             boldtext("t_patient"),
             questionnairefunc::defaultGridRawPointer(
                 {
                     {xstring("f_patient_location"),
                      new QuTextEdit(fieldRef(PATIENT_LOCATION, true))},
                     {xstring("f_admission_date"),
                      (new QuDateTime(fieldRef(ADMISSION_DATE, false)))
                          ->setMode(QuDateTime::Mode::DefaultDate)
                          ->setOfferNowButton(true)},
                     {xstring("f_estimated_discharge_date"),
                      (new QuDateTime(fieldRef(ESTIMATED_DISCHARGE_DATE, false)
                       ))
                          ->setMode(QuDateTime::Mode::DefaultDate)
                          ->setOfferNowButton(true)},
                     {xstring("f_patient_aware_of_referral"),
                      yn(PATIENT_AWARE_OF_REFERRAL)},
                     {xstring("f_interpreter_required"),
                      yn(INTERPRETER_REQUIRED)},
                     {xstring("f_sensory_impairment"), yn(SENSORY_IMPAIRMENT)},
                     {xstring("f_marital_status"),
                      mcq(MARITAL_STATUS_CODE, marital_options)},
                     {xstring("f_ethnic_category"),
                      mcq(ETHNIC_CATEGORY_CODE, ethnic_options)},
                 },
                 uiconst::DEFAULT_COLSPAN_Q,
                 uiconst::DEFAULT_COLSPAN_A
             ),

             // ---------------------------------------------------------------
             new QuHorizontalLine(),
             boldtext("t_referral_reason"),
             new QuFlowContainer{
                 boolbutton(
                     ADMISSION_REASON_OVERDOSE, "f_admission_reason_overdose"
                 ),
                 boolbutton(
                     ADMISSION_REASON_SELF_HARM_NOT_OVERDOSE,
                     "f_admission_reason_self_harm_not_overdose"
                 ),
                 boolbutton(
                     ADMISSION_REASON_CONFUSION, "f_admission_reason_confusion"
                 ),
                 boolbutton(
                     ADMISSION_REASON_TRAUMA, "f_admission_reason_trauma"
                 ),
                 boolbutton(
                     ADMISSION_REASON_FALLS, "f_admission_reason_falls"
                 ),
                 boolbutton(
                     ADMISSION_REASON_INFECTION, "f_admission_reason_infection"
                 ),
                 boolbutton(
                     ADMISSION_REASON_POOR_ADHERENCE,
                     "f_admission_reason_poor_adherence"
                 ),
                 boolbutton(
                     ADMISSION_REASON_OTHER, "f_admission_reason_other"
                 ),
             },

             // ---------------------------------------------------------------
             new QuHorizontalLine(),
             boldtext("t_other_people"),
             questionnairefunc::defaultGridRawPointer(
                 {
                     {xstring("f_existing_psychiatric_teams"),
                      new QuTextEdit(
                          fieldRef(EXISTING_PSYCHIATRIC_TEAMS, false)
                      )},
                     {xstring("f_care_coordinator"),
                      new QuTextEdit(fieldRef(CARE_COORDINATOR, false))},
                     {xstring("f_other_contact_details"),
                      new QuTextEdit(fieldRef(OTHER_CONTACT_DETAILS, false))},
                 },
                 uiconst::DEFAULT_COLSPAN_Q,
                 uiconst::DEFAULT_COLSPAN_A
             ),

             // ---------------------------------------------------------------
             new QuHorizontalLine(),
             boldtext("t_referral_reason"),
             questionnairefunc::defaultGridRawPointer(
                 {
                     {xstring("f_referral_reason"),
                      new QuTextEdit(fieldRef(REFERRAL_REASON, true))},
                 },
                 uiconst::DEFAULT_COLSPAN_Q,
                 uiconst::DEFAULT_COLSPAN_A
             ),

         })
            ->setTitle(longname())
    );

    auto questionnaire = new Questionnaire(m_app, {page});
    questionnaire->setType(QuPage::PageType::Clinician);
    questionnaire->setReadOnly(read_only);
    return questionnaire;
}

// ============================================================================
// Task-specific calculations
// ============================================================================