[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Gnumed-bugs] GNUmed does not allow same-day substance discontinuati
From: |
Karsten Hilbert |
Subject: |
Re: [Gnumed-bugs] GNUmed does not allow same-day substance discontinuations |
Date: |
Thu, 11 Jul 2013 11:33:58 +0200 |
User-agent: |
Mutt/1.5.21 (2010-09-15) |
On Wed, Jul 10, 2013 at 07:33:08PM +0000, Jim Busser wrote:
> A patient began a drug today, and contacted me today, and I have instructed
> him to take no more.
That is the single most important motivation to keep
improving GNUmed.
> GNUmed however does not permit the date discontinued to be the same date as
> started.
>
> This should be changed, so that the date discontinued need not be
>
> > date started
>
> only
>
> > = date started
OK, let's see
# just for good measure:
$> cd .../server/bootstrap/
$> sudo ./fixup-db.sh 18
$> psql -d gnumed_v18 -U gm-dbo -c '\d clin.substance_intake'
Tabelle »clin.substance_intake«
Spalte | Typ |
Attribute
-----------------------+--------------------------+---------------------------------------------------------------------------
pk_audit | integer | not null Vorgabewert
nextval('audit.audit_fields_pk_audit_seq'::regclass)
row_version | integer | not null Vorgabewert 0
modified_when | timestamp with time zone | not null Vorgabewert now()
modified_by | name | not null Vorgabewert
"current_user"()
pk_item | integer | not null Vorgabewert
nextval('clin.clin_root_item_pk_item_seq'::regclass)
clin_when | timestamp with time zone | not null Vorgabewert now()
fk_encounter | integer | not null
fk_episode | integer |
narrative | text |
soap_cat | text | Vorgabewert 'p'::text
pk | integer | not null Vorgabewert
nextval('clin.substance_intake_pk_seq'::regclass)
fk_substance | integer |
preparation | text |
schedule | text |
aim | text |
duration | interval |
intake_is_approved_of | boolean | not null
is_long_term | boolean |
discontinued | timestamp with time zone |
discontinue_reason | text |
fk_drug_component | integer |
Indexe:
"substance_intake_pkey" PRIMARY KEY, btree (pk)
"idx_c_subst_int_fk_drug_comp" btree (fk_drug_component)
"idx_fk_substance_curr_med" btree (fk_substance)
Check-Constraints:
"clin_root_item_sane_soap_cat" CHECK (soap_cat IS NULL OR (lower(soap_cat)
= ANY (ARRAY['s'::text, 'o'::text, 'a'::text, 'p'::text, 'u'::text])))
"clin_subst_intake_either_drug_or_substance" CHECK (fk_drug_component IS
NULL AND fk_substance IS NOT NULL OR fk_drug_component IS NOT NULL AND
fk_substance IS NULL)
"clin_subst_intake_sane_prep" CHECK (fk_drug_component IS NULL AND
preparation IS NOT NULL OR fk_drug_component IS NOT NULL AND preparation IS
NULL)
---> There we go:
"discontinued_after_started" CHECK (clin_when IS NULL OR discontinued IS
NULL OR discontinued >= clin_when AND discontinued <= now())
So the database does allow it.
"medication_is_plan" CHECK (soap_cat = 'p'::text)
"sane_aim" CHECK (gm.is_null_or_non_empty_string(aim) IS TRUE)
"sane_discontinue_reason" CHECK (discontinued IS NULL AND
discontinue_reason IS NULL OR discontinued IS NOT NULL AND
gm.is_null_or_non_empty_string(discontinue_reason) IS TRUE)
"sane_fk_episode" CHECK (intake_is_approved_of IS FALSE OR
intake_is_approved_of IS TRUE AND fk_episode IS NOT NULL)
"sane_schedule" CHECK (gm.is_null_or_non_empty_string(schedule) IS TRUE)
Fremdschlüssel-Constraints:
"substance_intake_fk_drug_component_fkey" FOREIGN KEY (fk_drug_component)
REFERENCES ref.lnk_substance2brand(pk) ON UPDATE RESTRICT ON DELETE RESTRICT
"substance_intake_fk_substance_fkey" FOREIGN KEY (fk_substance) REFERENCES
ref.consumable_substance(pk) ON UPDATE CASCADE ON DELETE CASCADE
Fremdschlüsselverweise von:
TABLE "clin.lnk_substance2episode" CONSTRAINT
"lnk_substance2episode_fk_substance_fkey" FOREIGN KEY (fk_substance) REFERENCES
clin.substance_intake(pk) ON UPDATE CASCADE ON DELETE RESTRICT
Trigger:
tr_delete_intake_document_deleted BEFORE DELETE ON clin.substance_intake
FOR EACH ROW EXECUTE PROCEDURE clin.trf_delete_intake_document_deleted()
tr_delete_intake_turns_other_components_into_substances AFTER DELETE ON
clin.substance_intake FOR EACH ROW EXECUTE PROCEDURE
clin.trf_delete_intake_turns_other_components_into_substances()
tr_insert_intake_links_all_drug_components AFTER INSERT ON
clin.substance_intake FOR EACH ROW EXECUTE PROCEDURE
clin.trf_insert_intake_links_all_drug_components()
tr_insert_intake_prevent_duplicate_component_links BEFORE INSERT ON
clin.substance_intake FOR EACH ROW EXECUTE PROCEDURE
clin.trf_insert_intake_prevent_duplicate_component_links()
tr_insert_update_intake_prevent_duplicate_substance_links AFTER INSERT OR
UPDATE ON clin.substance_intake DEFERRABLE INITIALLY DEFERRED FOR EACH ROW
EXECUTE PROCEDURE
clin.trf_insert_update_intake_prevent_duplicate_substance_links()
tr_narrative_mod AFTER INSERT OR DELETE OR UPDATE ON clin.substance_intake
DEFERRABLE INITIALLY IMMEDIATE FOR EACH ROW EXECUTE PROCEDURE
clin.trf_announce_narrative_mod()
tr_sanity_check_enc_epi_insert BEFORE INSERT ON clin.substance_intake FOR
EACH ROW EXECUTE PROCEDURE clin.trf_sanity_check_enc_epi_insert()
tr_sanity_check_substance_episode BEFORE INSERT OR UPDATE ON
clin.substance_intake FOR EACH ROW EXECUTE PROCEDURE
clin.trf_sanity_check_substance_episode()
tr_substance_intake_mod AFTER INSERT OR DELETE OR UPDATE ON
clin.substance_intake DEFERRABLE INITIALLY IMMEDIATE FOR EACH ROW EXECUTE
PROCEDURE clin.trf_announce_substance_intake_mod()
tr_undiscontinue_unsets_reason BEFORE INSERT OR UPDATE ON
clin.substance_intake FOR EACH ROW EXECUTE PROCEDURE
clin.trf_undiscontinue_unsets_reason()
tr_update_intake_must_link_all_drug_components AFTER UPDATE ON
clin.substance_intake DEFERRABLE INITIALLY DEFERRED FOR EACH ROW EXECUTE
PROCEDURE clin.trf_update_intake_must_link_all_drug_components()
tr_update_intake_updates_all_drug_components AFTER UPDATE ON
clin.substance_intake DEFERRABLE INITIALLY DEFERRED FOR EACH ROW EXECUTE
PROCEDURE clin.trf_update_intake_updates_all_drug_components()
zt_del_substance_intake BEFORE DELETE ON clin.substance_intake FOR EACH ROW
EXECUTE PROCEDURE audit.ft_del_substance_intake()
zt_ins_substance_intake BEFORE INSERT ON clin.substance_intake FOR EACH ROW
EXECUTE PROCEDURE audit.ft_ins_substance_intake()
zt_upd_substance_intake BEFORE UPDATE ON clin.substance_intake FOR EACH ROW
EXECUTE PROCEDURE audit.ft_upd_substance_intake()
Erbt von: clin.clin_root_item
Citing from the CHANGELOG:
1.3.2
FIX: exception on substance-discontinued in the future [thanks
S.Hilbert]
The corresponding patch:
commit ce565e79efe12a8a5ea702ebe46c5a2ecf5da6c1
Author: Karsten Hilbert <address@hidden>
#Date: Tue Apr 2 15:21:45 2013 +0200
Fix exception on substance discontinuation in the future
GNUmed sticks to its current plan of recording "state of affair"
with regard to substance intake. Respectively, one cannot
document discontinuation before it has happened.
Reported by S.Hilbert
diff --git a/gnumed/CHANGELOG b/gnumed/CHANGELOG
index eafc780..9523bd3 100644
--- a/gnumed/CHANGELOG
+++ b/gnumed/CHANGELOG
@@ -11,6 +11,7 @@
FIX: failure to fully escape % in Xe(La)TeX engine [thanks V.Banait]
FIX: formatting error in current substance intake list
FIX: collision of placeholder replacement and text expansion filling
+FIX: exception on substance-discontinued in the future [thanks S.Hilbert]
IMPROVED: record deletion of inbox messages in EMR
IMPROVED: create recalls from vaccinations manager
diff --git a/gnumed/gnumed/client/wxpython/gmMedicationWidgets.py
b/gnumed/gnumed/client/wxpython/gmMedicationWidgets.py
index 46a87b3..aaab804 100644
--- a/gnumed/gnumed/client/wxpython/gmMedicationWidgets.py
+++ b/gnumed/gnumed/client/wxpython/gmMedicationWidgets.py
@@ -1493,17 +1493,21 @@ class
cSubstanceIntakeEAPnl(wxgCurrentMedicationEAPnl.wxgCurrentMedicationEAPnl,
else:
self._PRW_duration.display_as_valid(True)
- # end must be > start if at all
+ # end must be "< now()" AND "> start" if at all
end = self._DP_discontinued.GetData()
if end is not None:
- start = self._DP_started.GetData()
- if start > end:
- self._DP_started.display_as_valid(False)
+ if end > gmDateTime.pydt_now_here():
self._DP_discontinued.display_as_valid(False)
validity = False
else:
- self._DP_started.display_as_valid(True)
- self._DP_discontinued.display_as_valid(True)
+ start = self._DP_started.GetData()
+ if start > end:
+ self._DP_started.display_as_valid(False)
+
self._DP_discontinued.display_as_valid(False)
+ validity = False
+ else:
+ self._DP_started.display_as_valid(True)
+
self._DP_discontinued.display_as_valid(True)
if validity is False:
gmDispatcher.send(signal = 'statustext', msg = _('Input
incomplete/invalid for saving as substance intake.'))
The code thus reads:
# end must be "< now()" AND "> start" if at all
end = self._DP_discontinued.GetData()
if end is not None:
# not in the future:
if end > gmDateTime.pydt_now_here():
self._DP_discontinued.display_as_valid(False)
validity = False
else:
# and not before it started
if start > end:
self._DP_started.display_as_valid(False)
self._DP_discontinued.display_as_valid(False)
validity = False
else:
self._DP_started.display_as_valid(True)
self._DP_discontinued.display_as_valid(True)
So, this really should work. Going checking... OK, I can
reproduce it. So let's instrument the code a bit... GNUmed
seems to think that end is > than now(). Ah, there's the
rub. The started PRW is pre-filled with now() and will
include the time. The discontinued PRW is not pre-filled but
rather filled in by the user. The user chooses (or types the
date for) today. This will be without the time. GNUmed
assumes 11:11:11.111am. Which can trigger two bugs:
- start was after 11:11am which makes discontinued > start
- now is before 11:11am wich makes discontinued > now
I have now normalized the checks to behave properly and also
give a better hint (1.3.7).
Thanks for reporting.
Karsten
--
GPG key ID E4071346 @ gpg-keyserver.de
E167 67FD A291 2BEA 73BD 4537 78B9 A9F9 E407 1346
screenshot_001.png
Description: PNG image
screenshot_002.png
Description: PNG image