Skip to content
Commits on Source (8)
gnumed-server (22.4-1) unstable; urgency=medium
* New upstream version
* debhelper 12
* Standards-Version: 4.3.0
* Secure URI in copyright format
* Add python3 as Depends since there are some Python3 scripts
-- Andreas Tille <tille@debian.org> Mon, 14 Jan 2019 14:46:24 +0100
gnumed-server (22.3-1) unstable; urgency=medium
* New upstream version
......
......@@ -4,10 +4,10 @@ Uploaders: Andreas Tille <tille@debian.org>,
Sebastian Hilbert <sebastian.hilbert@gmx.net>
Section: misc
Priority: optional
Build-Depends: debhelper (>= 11~),
Build-Depends: debhelper (>= 12~),
python
Build-Depends-Indep: po-debconf
Standards-Version: 4.2.0
Standards-Version: 4.3.0
Vcs-Browser: https://salsa.debian.org/med-team/gnumed-server
Vcs-Git: https://salsa.debian.org/med-team/gnumed-server.git
Homepage: http://www.gnumed.de
......@@ -18,6 +18,7 @@ Depends: ${misc:Depends},
postgresql (>= 9.2),
postgresql-client,
python,
python3,
debconf,
bsd-mailx | mail-reader,
openssl,
......
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: GNUmed
Upstream-Contact: Karsten Hilbert <Karsten.Hilbert@gmx.net>
Source: http://www.gnumed.de/downloads/server/
......
This diff is collapsed.
......@@ -27,6 +27,7 @@ database alias = gnumed_v22
minimum postgresql version = 9.2
schema base directory = ../sql/v21-v22/fixups/
schema = $schema$
v22-ref-paperwork_templates-fixups.sql
v22-release_notes-fixup.sql
$schema$
......@@ -57,6 +58,7 @@ $upgrade plausibility checks$
script base directory = ../sql/v21-v22/python/
data import scripts = $data import scripts$
v22-import-form-templates.py
v22-2-fixup-form-templates.py
$data import scripts$
......
"""Automatic GNUmed audit trail generation.
This module creates SQL DDL commands for the audit
trail triggers and functions to be created in the schema "audit".
Theory of operation:
Any table that needs to be audited (all modifications
logged) must be recorded in the table "audit.audited_tables".
This script creates the triggers, functions and tables
neccessary to establish the audit trail. Some or all
audit trail tables may have been created previously but
need not contain all columns of the audited table. Do not
put any constraints on the audit trail tables except for
"not null" on those columns that cannot be null in the
audited table.
"""
#==================================================================
__author__ = "Horst Herb, Karsten.Hilbert@gmx.net"
__license__ = "GPL v2 or later" # (details at http://www.gnu.org)
import sys, os.path, string, logging, io
from Gnumed.pycommon import gmPG2
_log = logging.getLogger('gm.bootstrapper')
LOG_TABLE_PREFIX = u'log_' # the audit trail tables start with this prefix
AUDIT_TRAIL_PARENT_TABLE = u'audit_trail' # and inherit from this table
AUDIT_FIELDS_TABLE = u'audit_fields' # audited tables inherit these fields
AUDIT_SCHEMA = u'audit' # audit stuff lives in this schema
#==================================================================
# SQL statements for auditing setup script
#------------------------------------------------------------------
# audit triggers are named "zt_*_*" to make
# reasonably sure they are executed last
# insert
SQL_TEMPLATE_INSERT = u"""DROP FUNCTION IF EXISTS audit.ft_ins_%(src_tbl)s() cascade;
CREATE FUNCTION audit.ft_ins_%(src_tbl)s()
RETURNS trigger
LANGUAGE 'plpgsql'
SECURITY DEFINER
AS '
DECLARE
_is_allowed_inserter boolean;
BEGIN
-- is the session user allowed to insert data ?
SELECT gm.account_is_dbowner_or_staff(SESSION_USER) INTO STRICT _is_allowed_inserter;
IF _is_allowed_inserter IS FALSE THEN
RAISE EXCEPTION
''INSERT: gm.account_is_dbowner_or_staff(NAME): <%%> is neither database owner, nor <postgres>, nor on staff'', SESSION_USER
USING ERRCODE = ''integrity_constraint_violation''
;
return NEW;
END IF;
NEW.row_version := 0;
NEW.modified_when := CURRENT_TIMESTAMP;
NEW.modified_by := SESSION_USER;
return NEW;
END;';
CREATE TRIGGER zt_ins_%(src_tbl)s
BEFORE INSERT ON %(src_schema)s.%(src_tbl)s
FOR EACH ROW EXECUTE PROCEDURE audit.ft_ins_%(src_tbl)s();
"""
SQL_TEMPLATE_INSERT_NO_INSERTER_CHECK = u"""DROP FUNCTION IF EXISTS audit.ft_ins_%(src_tbl)s() cascade;
CREATE FUNCTION audit.ft_ins_%(src_tbl)s()
RETURNS trigger
LANGUAGE 'plpgsql'
SECURITY DEFINER
AS '
BEGIN
NEW.row_version := 0;
NEW.modified_when := CURRENT_TIMESTAMP;
NEW.modified_by := SESSION_USER;
return NEW;
END;';
CREATE TRIGGER zt_ins_%(src_tbl)s
BEFORE INSERT ON %(src_schema)s.%(src_tbl)s
FOR EACH ROW EXECUTE PROCEDURE audit.ft_ins_%(src_tbl)s();
"""
# update
SQL_TEMPLATE_UPDATE = u"""DROP FUNCTION IF EXISTS audit.ft_upd_%(src_tbl)s() cascade;
CREATE FUNCTION audit.ft_upd_%(src_tbl)s()
RETURNS trigger
LANGUAGE 'plpgsql'
SECURITY DEFINER
AS '
DECLARE
_is_allowed_updater boolean;
BEGIN
-- is the session user allowed to update data ?
SELECT gm.account_is_dbowner_or_staff(SESSION_USER) INTO STRICT _is_allowed_updater;
IF _is_allowed_updater IS FALSE THEN
RAISE EXCEPTION
''UPDATE: gm.account_is_dbowner_or_staff(NAME): <%%> is neither database owner, nor <postgres>, nor on staff'', SESSION_USER
USING ERRCODE = ''integrity_constraint_violation''
;
return NEW;
END IF;
NEW.row_version := OLD.row_version + 1;
NEW.modified_when := CURRENT_TIMESTAMP;
NEW.modified_by := SESSION_USER;
INSERT INTO audit.%(log_tbl)s (
orig_version, orig_when, orig_by, orig_tableoid, audit_action,
%(cols_clause)s
) VALUES (
OLD.row_version, OLD.modified_when, OLD.modified_by, TG_RELID, TG_OP,
%(vals_clause)s
);
return NEW;
END;';
CREATE TRIGGER zt_upd_%(src_tbl)s
BEFORE UPDATE ON %(src_schema)s.%(src_tbl)s
FOR EACH ROW EXECUTE PROCEDURE audit.ft_upd_%(src_tbl)s();
"""
SQL_TEMPLATE_UPDATE_NO_UPDATER_CHECK = u"""DROP FUNCTION IF EXISTS audit.ft_upd_%(src_tbl)s() cascade;
CREATE FUNCTION audit.ft_upd_%(src_tbl)s()
RETURNS trigger
LANGUAGE 'plpgsql'
SECURITY DEFINER
AS '
BEGIN
NEW.row_version := OLD.row_version + 1;
NEW.modified_when := CURRENT_TIMESTAMP;
NEW.modified_by := SESSION_USER;
INSERT INTO audit.%(log_tbl)s (
orig_version, orig_when, orig_by, orig_tableoid, audit_action,
%(cols_clause)s
) VALUES (
OLD.row_version, OLD.modified_when, OLD.modified_by, TG_RELID, TG_OP,
%(vals_clause)s
);
return NEW;
END;';
CREATE TRIGGER zt_upd_%(src_tbl)s
BEFORE UPDATE ON %(src_schema)s.%(src_tbl)s
FOR EACH ROW EXECUTE PROCEDURE audit.ft_upd_%(src_tbl)s();
"""
# delete
SQL_TEMPLATE_DELETE = u"""DROP FUNCTION IF EXISTS audit.ft_del_%(src_tbl)s() cascade;
CREATE FUNCTION audit.ft_del_%(src_tbl)s()
RETURNS trigger
LANGUAGE 'plpgsql'
SECURITY DEFINER
AS '
DECLARE
_is_allowed_deleter boolean;
BEGIN
-- is the session user allowed to delete data ?
SELECT gm.account_is_dbowner_or_staff(SESSION_USER) INTO STRICT _is_allowed_deleter;
IF _is_allowed_deleter IS FALSE THEN
RAISE EXCEPTION
''DELETE: gm.account_is_dbowner_or_staff(NAME): <%%> is neither database owner, nor <postgres>, nor on staff'', SESSION_USER
USING ERRCODE = ''integrity_constraint_violation''
;
return OLD;
END IF;
INSERT INTO audit.%(log_tbl)s (
orig_version, orig_when, orig_by, orig_tableoid, audit_action,
%(cols_clause)s
) VALUES (
OLD.row_version, OLD.modified_when, OLD.modified_by, TG_RELID, TG_OP,
%(vals_clause)s
);
return OLD;
END;';
CREATE TRIGGER zt_del_%(src_tbl)s
BEFORE DELETE ON %(src_schema)s.%(src_tbl)s
FOR EACH ROW EXECUTE PROCEDURE audit.ft_del_%(src_tbl)s();
"""
SQL_TEMPLATE_DELETE_NO_DELETER_CHECK = u"""DROP FUNCTION IF EXISTS audit.ft_del_%(src_tbl)s() cascade;
CREATE FUNCTION audit.ft_del_%(src_tbl)s()
RETURNS trigger
LANGUAGE 'plpgsql'
SECURITY DEFINER
AS '
BEGIN
INSERT INTO audit.%(log_tbl)s (
orig_version, orig_when, orig_by, orig_tableoid, audit_action,
%(cols_clause)s
) VALUES (
OLD.row_version, OLD.modified_when, OLD.modified_by, TG_RELID, TG_OP,
%(vals_clause)s
);
return OLD;
END;';
CREATE TRIGGER zt_del_%(src_tbl)s
BEFORE DELETE ON %(src_schema)s.%(src_tbl)s
FOR EACH ROW EXECUTE PROCEDURE audit.ft_del_%(src_tbl)s();
"""
# we cannot do this because NOT VALID only applies to the time when
# we add the constraint, the FK would still be enforced during later
# INSERTs/UPDATEs
#SQL_TEMPLATE_FK_MODIFIED_BY = u"""ALTER TABLE %(src_schema)s.%(src_tbl)s
# DROP CONSTRAINT IF EXISTS fk_%(src_schema)s_%(src_tbl)s_fk_modified_by CASCADE;
#
#-- this is set NOT VALID because it only serves to tell pg_dump
#-- to dump dem.staff before other tables such that we do not run
#-- into trouble with checking gm.is_dbowner_or_staff(SESSION_USER)
#ALTER TABLE %(src_schema)s.%(src_tbl)s
# ADD CONSTRAINT fk_%(src_schema)s_%(src_tbl)s_fk_modified_by
# FOREIGN KEY (modified_by)
# REFERENCES dem.staff(db_user)
# ON UPDATE RESTRICT
# ON DELETE RESTRICT
# NOT VALID;"""
#
#SQL_TEMPLATE_DEM_STAFF_FK = u"""
#ALTER TABLE dem.staff
# DROP CONSTRAINT IF EXISTS fk_dem_staff_fk_modified_by CASCADE;
#"""
SQL_TEMPLATE_CREATE_AUDIT_TRAIL_TABLE = u"""
create table %(log_schema)s.%(log_tbl)s (
%(log_cols)s
) inherits (%(log_schema)s.%(log_base_tbl)s);
COMMENT ON COLUMN %(log_schema)s.%(log_tbl)s.orig_version is
'the .row_version in the original row before the audited action took place, should be equal to .row_version';
COMMENT ON COLUMN %(log_schema)s.%(log_tbl)s.orig_when is
'the .modified_when in the original row before the audited action took place, should be equal to .modified_when';
COMMENT ON COLUMN %(log_schema)s.%(log_tbl)s.orig_by is
'the .modified_by in the original row before the audited action took place, should be equal to .modified_by';
COMMENT ON COLUMN %(log_schema)s.%(log_tbl)s.orig_tableoid is
'the TG_RELID when the audit trigger was run';
"""
#grant insert on %s.%s to group "gm-public"
#------------------------------------------------------------------
#------------------------------------------------------------------
def audit_trail_table_ddl(aCursor=None, schema=None, table2audit=None):
audit_trail_table = '%s%s' % (LOG_TABLE_PREFIX, table2audit)
# which columns to potentially audit
cols2potentially_audit = gmPG2.get_col_defs(link_obj = aCursor, schema = schema, table = table2audit)
# which to skip
cols2skip = gmPG2.get_col_names(link_obj = aCursor, schema = AUDIT_SCHEMA, table = AUDIT_FIELDS_TABLE)
# which ones to really audit
cols2really_audit = []
for col in cols2potentially_audit[0]:
if col in cols2skip:
continue
cols2really_audit.append("\t%s %s" % (col, cols2potentially_audit[1][col]))
# does the audit trail target table exist ?
exists = gmPG2.table_exists(aCursor, AUDIT_SCHEMA, audit_trail_table)
if exists is None:
_log.error('cannot check existence of table [audit.%s]' % audit_trail_table)
return None
if exists:
_log.info('audit trail table [audit.%s] already exists' % audit_trail_table)
# sanity check table structure
currently_audited_cols = gmPG2.get_col_defs(link_obj = aCursor, schema = AUDIT_SCHEMA, table = audit_trail_table)
currently_audited_cols = [ '\t%s %s' % (c, currently_audited_cols[1][c]) for c in currently_audited_cols[0] ]
for col in cols2really_audit:
try:
currently_audited_cols.index(col)
except ValueError:
_log.error('table structure incompatible: column ".%s" not found in audit table' % col.strip())
_log.error('%s.%s:' % (schema, table2audit))
_log.error('%s' % ','.join(cols2really_audit))
_log.error('%s.%s:' % (AUDIT_SCHEMA, audit_trail_table))
_log.error('%s' % ','.join(currently_audited_cols))
return None
return []
# must create audit trail table
_log.info('no audit trail table found for [%s.%s]' % (schema, table2audit))
_log.info('creating audit trail table [audit.%s]' % audit_trail_table)
args = {
'log_schema': AUDIT_SCHEMA,
'log_base_tbl': AUDIT_TRAIL_PARENT_TABLE,
'log_tbl': audit_trail_table,
'log_cols': u',\n '.join(cols2really_audit)
}
return [SQL_TEMPLATE_CREATE_AUDIT_TRAIL_TABLE % args, '']
#------------------------------------------------------------------
def trigger_ddl(aCursor='default', schema=AUDIT_SCHEMA, audited_table=None):
target_columns = gmPG2.get_col_names(link_obj = aCursor, schema = schema, table = audited_table)
columns2skip = gmPG2.get_col_names(link_obj = aCursor, schema = AUDIT_SCHEMA, table = AUDIT_FIELDS_TABLE)
columns = []
values = []
for column in target_columns:
if column not in columns2skip:
columns.append(column)
values.append(u'OLD.%s' % column)
args = {
'src_tbl': audited_table,
'src_schema': schema,
'log_tbl': u'%s%s' % (LOG_TABLE_PREFIX, audited_table),
'cols_clause': u', '.join(columns),
'vals_clause': u', '.join(values)
}
modified_by_func_exists = gmPG2.function_exists(link_obj = aCursor, schema = u'gm', function = u'account_is_dbowner_or_staff')
ddl = []
if modified_by_func_exists:
ddl.append(SQL_TEMPLATE_INSERT % args)
ddl.append(u'')
ddl.append(SQL_TEMPLATE_UPDATE % args)
ddl.append(u'')
ddl.append(SQL_TEMPLATE_DELETE % args)
#ddl.append(u'')
#ddl.append(SQL_TEMPLATE_FK_MODIFIED_BY % args)
else:
# the *_NO_*_CHECK variants are needed for pre-v21 databases
# where gm.account_is_dbowner_or_staff() doesn't exist yet
ddl.append(SQL_TEMPLATE_INSERT_NO_INSERTER_CHECK % args)
ddl.append(u'')
ddl.append(SQL_TEMPLATE_UPDATE_NO_UPDATER_CHECK % args)
ddl.append(u'')
ddl.append(SQL_TEMPLATE_DELETE_NO_DELETER_CHECK % args)
ddl.append(u'')
return ddl
#------------------------------------------------------------------
def create_audit_ddl(aCursor):
# get list of all marked tables
# we could also get the child tables for audit.audit_fields
# but we would have to potentially parse down several levels
# of interitance (such as with clin.clin_root_item) to find
# the actual leaf table to audit
cmd = u"select schema, table_name from audit.audited_tables"
rows, idx = gmPG2.run_ro_queries(link_obj = aCursor, queries = [{'cmd': cmd}])
if len(rows) == 0:
_log.info('no tables to audit')
return None
_log.debug('the following tables will be audited:')
_log.debug(rows)
ddl = []
ddl.append('\set check_function_bodies 1\n')
ddl.append('set check_function_bodies to on;\n\n')
# for each marked table
for row in rows:
if not gmPG2.table_exists(link_obj = aCursor, schema = row['schema'], table = row['table_name']):
_log.error('table to audit (%s) does not exist', row)
return None
# create log table if necessary
audit_trail_ddl = audit_trail_table_ddl(aCursor = aCursor, schema = row['schema'], table2audit = row['table_name'])
if audit_trail_ddl is None:
_log.error('cannot generate audit trail DDL for audited table [%s]' % row['table_name'])
return None
ddl.extend(audit_trail_ddl)
if len(audit_trail_ddl) != 0:
ddl.append('-- ----------------------------------------------')
# create functions and triggers on log table
ddl.extend(trigger_ddl(aCursor = aCursor, schema = row['schema'], audited_table = row['table_name']))
ddl.append('-- ----------------------------------------------')
#ddl.append(SQL_TEMPLATE_DEM_STAFF_FK)
return ddl
#==================================================================
# main
#------------------------------------------------------------------
if __name__ == "__main__" :
tmp = ''
try:
tmp = raw_input("audit trail parent table [%s]: " % AUDIT_TRAIL_PARENT_TABLE)
except KeyboardError:
pass
if tmp != '':
AUDIT_TRAIL_PARENT_TABLE = tmp
conn = gmPG2.get_connection(readonly=False, pooled=False)
curs = conn.cursor()
schema = create_audit_ddl(curs)
curs.close()
conn.close()
if schema is None:
print "error creating schema"
sys.exit(-1)
f = io.open('audit-trail-schema.sql', mode = 'wb', encoding = 'utf8')
for line in schema:
f.write("%s;\n" % line)
f.close()
......@@ -158,6 +158,7 @@ database alias = gnumed_v22
minimum postgresql version = 9.2
schema base directory = ../sql/v21-v22/fixups/
schema = $schema$
v22-ref-paperwork_templates-fixups.sql
v22-release_notes-fixup.sql
$schema$
......
......@@ -1198,9 +1198,9 @@ def tex_escape_string(text=None, replace_known_unicode=True, replace_eol=False,
is preserved in the LaTeX source (think multi-
row table cells)
"""
text = text.replace(u'\\', u'\\textbackslash') # requires \usepackage{textcomp} in LaTeX source
text = text.replace(u'^', u'\\textasciicircum') # requires \usepackage{textcomp} in LaTeX source
text = text.replace(u'~', u'\\textasciitilde') # requires \usepackage{textcomp} in LaTeX source
text = text.replace(u'\\', u'\\textbackslash')
text = text.replace(u'^', u'\\textasciicircum')
text = text.replace(u'~', u'\\textasciitilde')
text = text.replace(u'{', u'\\{')
text = text.replace(u'}', u'\\}')
......@@ -1217,7 +1217,8 @@ def tex_escape_string(text=None, replace_known_unicode=True, replace_eol=False,
if replace_known_unicode:
# this should NOT be replaced for Xe(La)Tex
text = text.replace(u_euro, u'\\EUR')
text = text.replace(u_euro, u'\\EUR') # requires \usepackage{textcomp} in LaTeX source
text = text.replace(u_sum, u'$\\Sigma$')
return text
......@@ -1525,6 +1526,36 @@ def get_icon(wx=None):
return icon
#---------------------------------------------------------------------------
def create_qrcode(text=None, filename=None, qr_filename=None, verbose=False):
assert (not ((text is None) and (filename is None))), 'either <text> or <filename> must be specified'
try:
import pyqrcode
except ImportError:
_log.exception('cannot import <pyqrcode>')
return None
if text is None:
with io.open(filename, mode = 'rt', encoding = 'utf8') as input_file:
text = input_file.read()
if qr_filename is None:
if filename is None:
qr_filename = get_unique_filename(prefix = 'gm-qr-', suffix = '.png')
else:
qr_filename = get_unique_filename (
prefix = fname_stem(filename) + '-',
suffix = fname_extension(filename) + '.png'
)
_log.debug('[%s] -> [%s]', filename, qr_filename)
qr = pyqrcode.create(text, encoding = 'utf8')
if verbose:
print('input file:', filename)
print('output file:', qr_filename)
print('text to encode:', text)
print(qr.terminal())
qr.png(qr_filename, quiet_zone = 1)
return qr_filename
#===========================================================================
# main
#---------------------------------------------------------------------------
......@@ -1967,7 +1998,11 @@ second line\n
print (test, fname_sanitize(test))
#-----------------------------------------------------------------------
test_coalesce()
def test_create_qrcode():
print(create_qrcode(text = sys.argv[2], filename=None, qr_filename=None, verbose = True))
#-----------------------------------------------------------------------
#test_coalesce()
#test_capitalize()
#test_import_module()
#test_mkdir()
......@@ -1996,5 +2031,6 @@ second line\n
#test_shorten_text()
#test_format_compare_dicts()
#test_fname_sanitize()
test_create_qrcode()
#===========================================================================
#!/usr/bin/python3
import sys
import pyudev
import psutil
def enumerate_removable_partitions():
removable_partitions = {}
ctxt = pyudev.Context()
removable_devices = [ dev for dev in ctxt.list_devices(subsystem='block', DEVTYPE='disk') if dev.attributes.get('removable') == b'1' ]
all_mounted_partitions = { part.device: part for part in psutil.disk_partitions() }
for device in removable_devices:
partitions_on_removable_device = {
part.device_node: {
'device': part['DEVNAME'],
'vendor': part['ID_VENDOR'],
'model': part['ID_MODEL'],
'fs_label': part['ID_FS_LABEL'],
'is_mounted': False,
'mountpoint': None,
'fs_type': None,
} for part in ctxt.list_devices(subsystem='block', DEVTYPE='partition', parent=device)
}
for part in partitions_on_removable_device:
try:
partitions_on_removable_device[part]['mountpoint'] = all_mounted_partitions[part].mountpoint
partitions_on_removable_device[part]['is_mounted'] = True
partitions_on_removable_device[part]['fs_type'] = all_mounted_partitions[part].fstype
except KeyError:
pass # not mounted
removable_partitions.update(partitions_on_removable_device)
return removable_partitions
parts = enumerate_removable_partitions()
for part_name in parts:
part = parts[part_name]
if part['is_mounted']:
print('mounted:', part)
%------------------------------------------------------------------
% Based on:
%
% Deutsche LaTeX Briefvorlage von Jan-Philip Gehrcke
% http://gehrcke.de -- jgehrcke@googlemail.com
% November 2009, Aktualisierung Januar 2013
%
% Stark angepaßt von Karsten.Hilbert@gmx.net für GNUmed.
%
% use with pdflatex, NOT xelatex
%
% License: GPL v2 or later
%------------------------------------------------------------------
\documentclass[
paper=a4,
BCOR=0mm, % keine BindeCORrektur
DIN,
version=last,
enlargefirstpage=on,
fontsize=11pt,
foldmarks=true,
foldmarks=HP,
parskip=full, % Absätze mit Leerzeilen trennen, kein Einzug
fromurl=false, % explizit in der Fußzeile
fromemail=false, % explizit in der Fußzeile
fromfax=false, % explizit in der Fußzeile
fromphone=false, % explizit in der Fußzeile
fromlogo=true,
fromalign=center,
fromrule=afteraddress,
symbolicnames=true,
headsepline=true,
footsepline=true,
pagenumber=footright
]{scrlttr2}
\usepackage{scrlayer-scrpage} % Kopf- und Fußzeilen
\usepackage[cjkjis,graphics]{ucs} % lots of UTF8 symbols, breaks with xelatex
\usepackage[utf8x]{inputenc} % content is UTF8, breaks with xelatex
\usepackage[T1]{fontenc} % fonts are T1
\usepackage[ngerman]{babel} % Deutsch und Trennung
\usepackage{marvosym} % Symbole: Handy, Telefon, E-Mail
\usepackage{textcomp} % Symbole für Textmodus zum Escapen
\usepackage{lmodern} % sans serif Latin Modern
\usepackage{longtable} % Tabellen über mehrere Seiten
\usepackage{tabu} % bessere Tabellen
\usepackage{graphicx} % Grafiken laden (Logo und Unterschrift)
\usepackage[space]{grffile} % besserer Zugriff auf Grafikdateien
\usepackage{lastpage} % easy access to page number of last page
\usepackage{calc} % \widthof (für signature)
\usepackage{hyperref} % aktive URLs
% Definiere Grundschrift: sans serif Latin Modern
\renewcommand*\familydefault{\sfdefault}
\begin{document}
% Kopfzeile ab zweiter Seite
\lehead{$<title::::>$ $<lastname::::>$, $<firstname::::>$ ($<date_of_birth::%d.%B %Y::>$)}
\lohead{$<title::::>$ $<lastname::::>$, $<firstname::::>$ ($<date_of_birth::%d.%B %Y::>$)}
\cehead{}
\cohead{}
\rehead{Seite \thepage/\pageref{LastPage}}
\rohead{Seite \thepage/\pageref{LastPage}}
% Absenderdetails
\setkomavar{fromname}{$<current_provider_name::%(title)s %(firstnames)s %(lastnames)s::>$ $<<if_not_empty::$<current_provider_external_id::Fachgebiet//Ärztekammer::50>$//, FA für %s//::>>$}
\setkomavar{fromaddress}{\small
$<praxis::%(praxis)s, %(branch)s::120>$ $<<if_not_empty::$<praxis_address::%(street)s::>$//\\//::>>$
$<praxis_address::%(street)s %(number)s (%(subunit)s), %(postcode)s %(urb)s::60>$
}
\setkomavar{fromlogo}{$<data_snippet::praxis-logo//\includegraphics[width=30mm]{%s}//image/png//.png::250>$}%$ -- this dollarsign unconfuses mcedit syntax coloring
\setkomavar{backaddress}{$<current_provider_firstnames::::1>$.$<current_provider_lastnames::::>$,$<praxis_address::%(street)s %(number)s,%(postcode)s %(urb)s::60>$}
% Geschäftszeile
\setkomavar{yourref}{$<free_text::Angabe unter "Ihr Zeichen"::40>$}
\setkomavar{yourmail}{$<free_text::Angabe unter "Ihr Schreiben vom"::20>$}
\setkomavar{myref}{$<free_text::Angabe unter "Unser Zeichen"::40>$}
\setkomavar{date}{$<today::%d.%B %Y::50>$}
\setkomavar{place}{$<praxis_address::%(urb)s::120>$}
% Betreff, nämlich Patientendaten
\setkomavar{subject}[]{%
$<<<if_not_empty::$<<free_text::Betreff für den Brief::120>>$//%s\\//::>>>$
Patient: $<title::::>$ $<firstname::::>$ $<lastname::::>$ (geb $<date_of_birth::%d.%B %Y::>$) $<<if_not_empty::$<adr_street::home::>$//\\//::>>$
$<<if_not_empty::$<adr_street::home::>$//Adresse: $<adr_street::home::>$ $<adr_number::home::>$, $<adr_postcode::home::>$ $<adr_location::home::>$\\//::>>$
\begin{itemize}
\setlength\topsep{0pt}
\setlength\partopsep{0pt}
\setlength\itemsep{0pt}
$<diagnoses:: \item %(diagnosis)s::>$
\end{itemize}
}
% Unterschrift
\setkomavar{signature}{%
\centering
$<data_snippet::autograph-$<<current_provider_lastnames::::>>$_$<<current_provider_firstnames::::>>$//\includegraphics[width=30mm]{%s}\\//image/png//.png::250>$\rule{\widthof{\tiny (Der Unterzeichner haftet nicht für unsignierte Änderungen des Inhalts.)}}{.1pt}\\
$<current_provider_name::%(title)s %(firstnames)s %(lastnames)s::>$\\
$<<if_not_empty::$<current_provider_external_id::Fachgebiet//Ärztekammer::50>$//FA für %s\\//::>>$
{\tiny (Der Unterzeichner haftet nicht für unsignierte Änderungen des Inhalts.)}
}
\renewcommand*{\raggedsignature}{\raggedright}
\makeatletter
\@setplength{sigbeforevskip}{1.8cm} % Definiere vertikalen Abstand vor der Unterschrift
\makeatother
% Fußzeile 1.Seite
\setkomavar{firstfoot}{%
\rule{\textwidth}{.3pt}
\parbox[t]{\textwidth}{%
\tiny
\begin{tabular}[t]{ll}%
% \multicolumn{2}{l}{Erreichbarkeit:}\\
\Telefon & $<praxis_comm::workphone::60>$\\
\FAX & $<praxis_comm::fax::60>$\\
\Email & \href{mailto:$<praxis_comm::email::60>$}{$<praxis_comm::email::60>$}\\
\ComputerMouse & \href{http://$<praxis_comm::web::60>$}{$<praxis_comm::web::60>$}\\
\end{tabular}%
\hfill
\begin{tabular}[t]{ll}%
\multicolumn{2}{l}{FA für $<current_provider_external_id::Fachgebiet//Ärztekammer::50>$}\\
BSNR & $<praxis_id::KV-BSNR//KV//%(value)s::25>$\\
LANR & $<current_provider_external_id::KV-LANR//KV::25>$\\
\multicolumn{2}{l}{GNUmed $<client_version::::>$ (\href{http://www.gnumed.org}{www.gnumed.org})}\\
\end{tabular}%
\hfill
\begin{tabular}[t]{ll}%
\multicolumn{2}{l}{$<praxis_id::Bankname//Bank//%(value)s::60>$}\\
IBAN & $<praxis_id::IBAN//Bank//%(value)s::30>$\\
BIC & $<praxis_id::BIC//Bank//%(value)s::30>$\\
\multicolumn{2}{l}{Vorlage $<form_name_long::::60>$ v$<form_version::::20>$}\\
\end{tabular}%
}
}
% Fußzeile ab zweiter Seite
\lefoot{{\tiny $<current_provider::::>$, $<praxis::%(praxis)s: %(branch)s::120>$}}
\lofoot{{\tiny $<current_provider::::>$, $<praxis::%(praxis)s: %(branch)s::120>$}}
\cefoot{}
\cofoot{}
\refoot{{\tiny $<today::%d.%B %Y::50>$}}
\rofoot{{\tiny $<today::%d.%B %Y::50>$}}
% Definiere Brief und Empfaenger
\begin{letter}{%
$<receiver_name::::>$\\
$<receiver_street::::>$\ $<receiver_number::::>$\ $<receiver_subunit::::>$\\
$<receiver_postcode::::>$\ $<receiver_location::::>$\\
$<receiver_country::::>$
}
% Anrede
\opening{%
$<<free_text::Anrede, z.B. "Sehr geehrte Frau" (wird automatisch ergänzt durch " $<receiver_name::::>$,")::140>>$ $<receiver_name::::>$,
}
% Brieftext
\selectlanguage{ngerman}
$<<free_text::Der eigentliche Brieftext (in LaTeX)::>>$
\closing{%
$<<free_text::Grußformel, z.B. "Mit freundlichen Grüßen" (ohne Komma am Ende)::140>>$,
}
% Anlagen
%\setkomavar*{enclseparator}[Anlage(n)] % Titel für Anlagebereich
$<<<if_not_empty::$<<free_text::Liste von Anlagen::300>>$//\encl{%s}//%\encl{}::>>>$
% kein Verteiler
%\cc{}
\end{letter}
\end{document}
%------------------------------------------------------------------
% generic letter template based on scrlttr2
%
% Author: Karsten Hilbert
% Author: karsten.hilbert@gmx.net
% License: GPL v2 or later
%
% requires pdflatex to be run with -recorder option
%------------------------------------------------------------------
% documentclass with options for *all* packages:
\documentclass[
version=last, % use latest scrlttr2 code
BCOR=0mm, % keine BindeCORrektur
paper=portrait, % not landscape
paper=a4, % set paper size
fontsize=11pt, % set fontsize early such that recalctypearea is not necessary
foldmarks=true, % switch on foldmarks
foldmarks=HPV, % select ALL foldmarks (Horz/Punch/Vert)
enlargefirstpage=on, % allow for more text on first page, if possible
firsthead=true, % do show Sender information on first page
fromalign=left, % center Sender information at top of first page
fromrule=afteraddress, % horiz rule after Sender address at top of first page
fromurl=false, % explizit in der Fußzeile
fromemail=false, % explizit in der Fußzeile
fromfax=false, % explizit in der Fußzeile
fromphone=false, % explizit in der Fußzeile
frommobilephone=false, % explizit in der Fußzeile
fromlogo=true, % at top of page, if available
symbolicnames=true, % use MarvoSym symbols for <from*> labelling rather than textual labels
locfield=wide, % make available lots of space in the location field
headsepline=true, % do show line below page header
footsepline=true, % do show line above page footer
pagenumber=footright % where to place page number by default
]{scrlttr2}
% package loading:
\usepackage{scrlayer-scrpage} % header and footer control
\usepackage[ngerman]{babel} % Deutsch und Trennung
\usepackage[utf8]{inputenc} % input is UTF8
\usepackage[T1]{fontenc} % fonts are T1
\usepackage{textcomp} % symbols for textmode escaping, does not mix with "ucs", unless utf8x used
\usepackage{marvosym} % symbols: Handy, Telefon, E-Mail
\usepackage{lmodern} % sans serif Latin Modern
\usepackage{array} % improved table column styles
\usepackage{graphicx} % enhanced graphics loading (logo and signature)
\usepackage[space,extendedchars]{grffile} % better access to graphics files
\usepackage[export]{adjustbox} % improved options for \includegraphics
\usepackage{ragged2e} % improved alignment
\usepackage{lastpage} % easy access to page number of last page
\usepackage{embedfile} % store data files in PDF (patient, praxis)
%\usepackage[abspath]{currfile} % generically refer to LaTeX input file
\usepackage{calc} % \widthof (for signature)
\usepackage{microtype} % micro-adjustments to typesetting
% debugging
$<if_debugging:://%::>$\usepackage{interfaces} % provides \papergraduate
$<if_debugging:://%::>$\usepackage{showkeys} % print labels (anchors and stuff) as margin notes
$<if_debugging:://%::>$\usepackage[noframe]{showframe} % show page margins as boxes
$<if_debugging:://%::>$\usepackage[verbose]{layout} % generate a page with the current layout
$<if_debugging:://%::>$\usepackage[pass]{geometry} % nicely display geometry in log file
$<if_debugging:://%::>$\usepackage{afterpage} % add stuff after next page bread
% load last:
\usepackage{hyperref} % aktive URLs, needs to be loaded last, most of the time
% package setup:
% - debugging
\listfiles % list all input files used
\errorcontextlines 10000 % list lots of context lines with errors
\RequirePackage[l2tabu, orthodox]{nag} % show unorthodox/faulty/obsolete uses
\hypersetup{debug=true} % extra debugging log messages
% %\tracingtabu=3 % trace tabu tables if using tabu package
$<if_debugging:://%::>$\usetikz{basic} % needed for \papergraduate from package interfaces
$<if_debugging:://%::>$\overfullrule=2cm % mark overfull horizontal boxes
$<if_debugging:://%::>$\LoadLetterOption{visualize} % visualize letter title page layout
$<if_debugging:://%::>$\showfields{head,foot,address,location,refline} % show srlttr2 fields
$<if_debugging:://%::>$\geometry{pass,verbose} % put geometry into log file
$<if_debugging:://%::>$\renewcommand\ShowFrameLinethickness{0.25pt} % configure showframe
$<if_debugging:://%::>$\renewcommand*\ShowFrameColor{\color{red}} % configure showframe
% - PDF metadata
\hypersetup{%
pdftitle = {Patient: $<name::%(firstnames)s %(lastnames)s::>$, $<date_of_birth::%d.%m.%Y::>$},
pdfauthor = {$<current_provider::::>$, $<praxis::%(branch)s, %(praxis)s::>$},
pdfsubject = {Begleitbrief},
pdfproducer = {GNUmed $<client_version::::>$, Template $<form_name_long::::>$, $<form_version::::>$ [$<form_version_internal::::>$, $<form_last_modified::::>$]},
pdfdisplaydoctitle = true,
pdfprintscaling = None
}
% - base font: sans serif Latin Modern
\renewcommand*\familydefault{\sfdefault}
%------------------------------------------------------------------
\begin{document}
% letter options and settings:
%\LoadLetterOption{DIN} % suitable for C4/C5/C6/C6-lang
% - Adressfeld etwas weiter oben (per Faltmarkenverschiebung)
\LoadLetterOption{DINmtext} % suitable for C6/C6-lang only
% - sender details
\setkomavar{fromname}{%
$<current_provider_name::%(title)s %(firstnames)s %(lastnames)s::>$, FA für $<current_provider_external_id::Fachgebiet//Ärztekammer::50>$
}
\setkomavar{fromaddress}{%
\small
$2<ph_cfg::argumentsdivider//#2#//%% <%(name)s> set to [%(value)s]::>2$
$<praxis::%(praxis)s, %(branch)s::120>$$2<if_not_empty::$<praxis_address::%(street)s::>$#2#\\#2#::>2$
$3<ph_cfg::argumentsdivider//#3#//%% <%(name)s> set to [%(value)s]::>3$
$3<if_not_empty::$<praxis_address::%(street)s::>$#3#\href{http://nominatim.openstreetmap.org/search/$2<url_escape::$<praxis_address::%(country)s::>$::>2$/$2<url_escape::$<praxis_address::%(urb)s::>$::>2$/$2<url_escape::$<praxis_address::%(street)s::>$::>2$/$2<url_escape::$<praxis_address::%(number)s::>$::>2$?limit=3}{$<praxis_address::%(street)s %(number)s::>$$2<if_not_empty::$<praxis_address::%(subunit)s::>$#2# (%s)#2#::>2$$<praxis_address::, %(postcode)s %(urb)s::>$}#3#%% no praxis address available::>3$
$3<ph_cfg::argumentsdivider//DEFAULT//%% <%(name)s> set to [%(value)s]::>3$
$2<ph_cfg::argumentsdivider//DEFAULT//%% <%(name)s> set to [%(value)s]::>2$
}
\setkomavar{fromlogo}{%
$3<ph_cfg::argumentsdivider//#3#//%% <%(name)s> set to [%(value)s]::>3$
$2<ph_cfg::argumentsdivider//#2#//%% <%(name)s> set to [%(value)s]::>2$
$1<ph_cfg::argumentsdivider//#1#//%% <%(name)s> set to [%(value)s]::>1$
$3<if_not_empty::$<data_snippet::praxis-logo#1#%s#1#image/png#1#.png::>$#3#$2<if_not_empty::$<praxis_comm::web::>$#2#\href{http://%s}{$1<data_snippet::praxis-logo#1#\includegraphics[width=20mm]{%s}#1#image/png#1#.png::250>1$}#2#$1<data_snippet::praxis-logo#1#\includegraphics[width=20mm]{%s}#1#image/png#1#.png::250>1$::>2$#3#\href{http://www.gnumed.de}{$<qrcode::http://www.gnumed.de#1#\includegraphics[width=15mm]{%s}} %% no praxis logo available::>$::>3$
$1<ph_cfg::argumentsdivider//DEFAULT//%% <%(name)s> set to [%(value)s]::>1$
$2<ph_cfg::argumentsdivider//DEFAULT//%% <%(name)s> set to [%(value)s]::>2$
$3<ph_cfg::argumentsdivider//DEFAULT//%% <%(name)s> set to [%(value)s]::>3$
}
% explicit backaddress, not calculated from <from*> values
\setkomavar{backaddress}{$<current_provider_firstnames::::1>$.$<current_provider_lastnames::::>$\\$<praxis_address::%(street)s %(number)s\\%(postcode)s %(urb)s::60>$}
\setkomavar{location}{%
\begin{tabular}[t]{cc}%
Patient & Absender \\
$3<ph_cfg::argumentsdivider//#3#//%% <%(name)s> set to [%(value)s]::>3$
\includegraphics[width=30mm]{$<patient_mcf::fmt=qr//%s::>$} & $3<if_not_empty::$1<praxis_address::%(street)s::>1$#3#\href{http://nominatim.openstreetmap.org/search/$2<url_escape::$1<praxis_address::%(country)s::>1$::>2$/$2<url_escape::$1<praxis_address::%(urb)s::>1$::>2$/$2<url_escape::$1<praxis_address::%(street)s::>1$::>2$/$2<url_escape::$1<praxis_address::%(number)s::>1$::>2$?limit=3}{\includegraphics[width=30mm]{$1<praxis_mcf::fmt=qr//%s::>1$}}#3#\includegraphics[width=30mm]{$1<praxis_mcf::fmt=qr//%s::>1$} %% no praxis address available::>3$
$3<ph_cfg::argumentsdivider//DEFAULT//%% <%(name)s> set to [%(value)s]::>3$
\end{tabular}%
}
% not needed:
%\setkomavar{fromurl}{}
%\setkomavar{fromemail}{}
%\setkomavar{fromfax}{}
%\setkomavar{fromphone}{}
%\setkomavar{frommobilephone}{}
% - reference line
\setkomavar{myref}{$2<free_text::"Unser Zeichen" (z.B. "$1<current_provider_name::%(firstnames)s::1>1$$1<current_provider_name::%(lastnames)s::1>1$" für $1<current_provider_name::%(firstnames)s %(lastnames)s::>1$)//$1<current_provider_name::%(firstnames)s::1>1$$1<current_provider_name::%(lastnames)s::1>1$::40>2$}
\setkomavar{yourref}{$2<free_text::"Ihr Zeichen"::40>2$}
\setkomavar{yourmail}{$2<free_text::"Ihr Schreiben vom"::20>2$}
\setkomavar{date}{$<today::%d.%B %Y::50>$}
\setkomavar{place}{$<praxis_address::%(urb)s::120>$}
% - Subject, namely patient data
\setkomavar{subject}[]{%
$3<ph_cfg::argumentsdivider//#3#//%% <%(name)s> set to [%(value)s]::>3$
$3<if_not_empty::$2<free_text::Betreff (Patientenstammdaten werden hinzugefügt)::120>2$#3#%s\\#3#%% no additional Subject by user::>3$
$3<ph_cfg::argumentsdivider//DEFAULT//%% <%(name)s> set to [%(value)s]::>3$
$2<ph_cfg::argumentsdivider//#2#//%% <%(name)s> set to [%(value)s]::>2$
Patient: $<title::::>$ $<firstname::::>$ $<lastname::::1>$\textsc{$<lastname::::2-99>$} (geb $<date_of_birth::%d.%B %Y::>$)$2<if_not_empty::$<adr_street::home::>$#2#\\#2#::>2$
$2<if_not_empty::$<adr_street::home::>$#2#Adresse: $<adr_street::home::>$ $<adr_number::home::>$, $<adr_postcode::home::>$ $<adr_location::home::>$#2#%% no address available::>2$
$2<ph_cfg::argumentsdivider//DEFAULT//%% <%(name)s> set to [%(value)s]::>2$
\begin{itemize}
\setlength\topsep{0pt}
\setlength\partopsep{0pt}
\setlength\itemsep{0pt}
$<diagnoses:: \item %(diagnosis)s::>$
\end{itemize}
}
% - signature
\setkomavar{signature}{%
$3<ph_cfg::argumentsdivider//#3#//%% <%(name)s> set to [%(value)s]::>3$
$3<if_not_empty::$2<data_snippet::autograph-$<current_provider_lastnames::::>$_$<current_provider_firstnames::::>$//\includegraphics[width=30mm]{%s}//image/png//.png::250>2$#3#%s\\#3#%% no signature file available::>3$
$3<ph_cfg::argumentsdivider//DEFAULT//%% <%(name)s> set to [%(value)s]::>3$
\rule{\widthof{\tiny{}(Der Unterzeichner haftet nicht für unsignierte Änderungen des Inhalts.)}}{.1pt}\\
$2<ph_cfg::argumentsdivider//#2#//%% <%(name)s> set to [%(value)s]::>2$
$2<if_not_empty::$<current_provider_name::%(title)s::>$#2#$<current_provider_name::%(title)s %(firstnames)s %(lastnames)s::>$\\#2#$<current_provider_name::%(firstnames)s %(lastnames)s::>$\\::>2$
$2<if_not_empty::$<current_provider_external_id::Fachgebiet//Ärztekammer::50>$#2#FA für %s\\#2#%% no speciality available::>2$
$2<ph_cfg::argumentsdivider//DEFAULT//%% <%(name)s> set to [%(value)s]::>2$
{\tiny{}(Der Unterzeichner haftet nicht für unsignierte Änderungen des Inhalts.)}
}
\renewcommand*{\raggedsignature}{\raggedright}
\makeatletter
\@setplength{sigbeforevskip}{1.8cm} % Definiere vertikalen Abstand vor der Unterschrift
\makeatother
% - headings starting on second page
\lehead{$2<if_not_empty::$<title::::>$//%s //::>2$$<lastname::::1>$\textsc{$<lastname::::2-99>$}, $<firstname::::>$ ($<date_of_birth::%d.%B %Y::>$)}
\lohead{$2<if_not_empty::$<title::::>$//%s //::>2$$<lastname::::1>$\textsc{$<lastname::::2-99>$}, $<firstname::::>$ ($<date_of_birth::%d.%B %Y::>$)}
\cehead{}
\cohead{}
\rehead{Seite \thepage/\pageref{LastPage}}
\rohead{Seite \thepage/\pageref{LastPage}}
% - footer on first page
\setkomavar{firstfoot}{%
\rule{\textwidth}{.3pt}
\parbox[t]{\textwidth}{%
\tiny
\begin{tabular}[t]{ll}%
\Telefon{} & $<praxis_comm::workphone::60>$\\
\FAX{} & $<praxis_comm::fax::60>$\\
\Email{} & \href{mailto:$<praxis_comm::email::60>$}{$<praxis_comm::email::60>$}\\
$2<ph_cfg::argumentsdivider//##//%% <%(name)s> set to [%(value)s]::>2$
\ComputerMouse{} & $2<if_not_empty::$<praxis_comm::web::>$##\href{http://%s}{$<praxis_comm::web::60>$}##%% no praxis web address available::>2$
$2<ph_cfg::argumentsdivider//DEFAULT//%% <%(name)s> set to [%(value)s]::>2$
\end{tabular}%
\hfill
\begin{tabular}[t]{ll}%
$2<ph_cfg::argumentsdivider//##//%% <%(name)s> set to [%(value)s]::>2$
\multicolumn{2}{l}{$2<if_not_empty::$<current_provider_external_id::Fachgebiet//Ärztekammer::50>$##FA für %s##::>2$}\\
$2<ph_cfg::argumentsdivider//DEFAULT//%% <%(name)s> set to [%(value)s]::>2$
BSNR & $<praxis_id::KV-BSNR//KV//%(value)s::25>$\\
LANR & $<current_provider_external_id::KV-LANR//KV::25>$\\
\multicolumn{2}{l}{GNUmed $<client_version::::>$ (\href{http://www.gnumed.org}{www.gnumed.org})}
\end{tabular}%
\hfill
\begin{tabular}[t]{ll}%
\multicolumn{2}{l}{$<praxis_id::Bankname//Bank//%(value)s::60>$}\\
IBAN & $<praxis_id::IBAN//Bank//%(value)s::30>$\\
BIC & $<praxis_id::BIC//Bank//%(value)s::30>$\\
\multicolumn{2}{l}{Vorlage $<form_name_long::::60>$ v$<form_version::::20>$}
\end{tabular}%
}
}
% - footer starting on second page
\lefoot{{\tiny{}$<current_provider::::>$, $<praxis::%(praxis)s: %(branch)s::120>$}}
\lofoot{{\tiny{}$<current_provider::::>$, $<praxis::%(praxis)s: %(branch)s::120>$}}
\cefoot{}
\cofoot{}
\refoot{{\tiny{}$<today::%d.%B %Y::50>$}}
\rofoot{{\tiny{}$<today::%d.%B %Y::50>$}}
%------------------------------------------------------------------
% start letter by setting receiver data
% FIXME: use if_empty because empty lines are not allowed
\begin{letter}{%
$<receiver_name::::>$\\
$<receiver_street::::>$\ $<receiver_number::::>$\ $<receiver_subunit::::>$\\
$<receiver_postcode::::>$\ $<receiver_location::::>$\\
$<receiver_country::::>$
}
% debugging
$<if_debugging:://%::>$\papergraduate % show coordinate system on first page
$<if_debugging:://%::>$\afterpage{\AddToShipoutPicture*{\ShowFramePicture}} % show "normal" page layout starting with second page
% define opening (Anrede)
\opening{%
$2<free_text::Anrede, z.B. "Sehr geehrte/geehrter $<receiver_name::::>$,"//Sehr geehrte Kollegin $<receiver_name::::>$,::140>2$%
}
% the actual content
\selectlanguage{ngerman} % if German
$2<free_text::Der eigentliche Brieftext (in LaTeX)::>2$
% define closing of letter (Grußformel)
% multiple lines with \\, no empty lines
\closing{%
$2<free_text::Grußformel, z.B. "Mit kollegialen Grüßen,"//Mit kollegialen Grüßen,::140>2$%
}
% no Post Scriptum
%\ps
% Anlagen
%\setkomavar*{enclseparator}[Anlage(n)] % title for "enclosures" area
$3<ph_cfg::argumentsdivider//#3#//%% <%(name)s> set to [%(value)s]::>3$
$3<if_not_empty::$2<free_text::Liste von Anlagen::300>2$#3#\encl{%s}#3#%\encl{}::>3$
$3<ph_cfg::argumentsdivider//DEFAULT//%% <%(name)s> set to [%(value)s]::>3$
% no Carbon Copies
%\setkomavar*{ccseparator}[Verteiler]
% multiple lines with \\, no empty lines
%\cc{%
%}
\end{letter}
%------------------------------------------------------------------
% embed data into PDF for easier processing:
% VCF of creator
\IfFileExists{$<praxis_vcf::::>$}{%
\embedfile[
desc=Praxis - digital business card (sender),
mimetype=text/vcf,
ucfilespec=praxis.vcf
]{$<praxis_vcf::::>$}
}{\typeout{[$<praxis_vcf::::>$] not found}}
% VCF of patient
\IfFileExists{$<patient_vcf::::>$}{%
\embedfile[
desc=Patient - digital business card,
mimetype=text/vcf,
ucfilespec=patient.vcf
]{$<patient_vcf::::>$}
}{\typeout{[$<patient_vcf::::>$] (patient VCF) not found}}
%------------------------------------------------------------------
% debugging
$<if_debugging:://%::>$\layout % show page layout page
\end{document}
%------------------------------------------------------------------
% Author: Karsten Hilbert
% License: GPL v2 or later
%
%------------------------------------------------------------------
\documentclass[english]{article}
\usepackage[T1]{fontenc}
\usepackage[cjkjis,graphics]{ucs}
\usepackage[utf8]{inputenc}
\usepackage{marvosym} % Symbole: Handy, Telefon, E-Mail
%\usepackage{textcomp} % Symbole für Textmodus zum Escapen
\usepackage[a4paper]{geometry}
\usepackage{microtype}
\usepackage{hyperref}
% debugging
%\usepackage{interfaces} % \papergraduate
%\usepackage{showkeys} % print labels (anchors and stuff) as margin notes
% debugging
\errorcontextlines 10000
% - show all files used
\listfiles
% - show unorthodox/faulty/obsolete uses
\RequirePackage[l2tabu, orthodox]{nag}
% - mark overfull horizontal boxes
%\overfullrule=2cm
% - show coordinate system on paper
%\papergraduate
\geometry{verbose,lmargin=1cm}
\pagestyle{empty}
\setlength{\parskip}{\medskipamount}
\setlength{\parindent}{0pt}
\usepackage{babel}
%------------------------------------------------------------------
\begin{document}
\footnotetext{\tiny \href{http://www.gnumed.org}{GNUmed} $<client_version::::>$ -- \href{http://www.gnumed.org}{www.gnumed.org}}
\footnotetext{\tiny Dokumentenvorlage: $<form_name_long::::60>$ v$<form_version::::20>$}
\noindent \begin{center}
{\Large Most Recent Vaccinations (printed $<today::%Y %B %d::>$)}%
\par\end{center}
\noindent Patient: $<lastname::::>$, $<firstname::::>$ ($<date_of_birth::%Y %B %d::>$)
{\footnotesize%
$2<if_not_empty::$<adr_street::home::>$//$<adr_street::home::>$ $<adr_number::home::>$ \\//::>2$
$2<if_not_empty::$<adr_location::home::>$//$<adr_postcode::home::>$ $<adr_location::home::>$//::>2$
}
\vspace*{\medskipamount}
$<latest_vaccs_table::latex::>$
\vfill{}
\noindent Known allergies:
\begin{tabular}{|l|l|l|}
\hline
Agent & Type & Reaction\\
\hline
\hline
$<allergies::%(descriptor)s & %(l10n_type)s & {\footnotesize %(reaction)s}\\ \hline::>$
\end{tabular}
\medskip{}
\noindent \begin{flushright}
\texttt{\textsl{\footnotesize Practice Stamp / Physician Signature}}
\par\end{flushright}
\end{document}
%------------------------------------------------------------------
%------------------------------------------------------------------
% Current medication list
%
% Author: Karsten Hilbert
% Author: karsten.hilbert@gmx.net
% License: GPL v2 or later
%
% requires pdflatex to be run with -recorder option
%------------------------------------------------------------------
\documentclass[
version=last, % use latest KomaScript code
paper=portrait, % not landscape
paper=a4, % set paper size
DIV=9, % help typearea find a good Satzspiegel
BCOR=0mm, % keine BindeCORrektur
fontsize=11pt, % set fontsize early such that recalctypearea is not necessary
parskip=half*, % Absätze mit halber Leerzeilen trennen, kein Einzug, Vorabsatz endet mit maxial 3/4-Zeile
headsepline=off,
footsepline=true, % do show line above page footer
titlepage=false % do not set a dedicated title page
]{scrartcl}
%------------------------------------------------------------------
% package loading:
\usepackage{scrlayer-scrpage} % header and footer control
\usepackage[ngerman]{babel} % Deutsch und Trennung
\usepackage[utf8]{inputenc} % input is UTF8
\usepackage[T1]{fontenc} % fonts are T1
\usepackage{textcomp} % symbols for textmode escaping, does not mix with "ucs", unless utf8x used
\usepackage{marvosym} % symbols: Handy, Telefon, E-Mail
%\usepackage{helvet} % Arial-alike Helvetica
\usepackage{lmodern} % sans serif Latin Modern
\usepackage{array} % improved table column styles
\usepackage{graphicx} % enhanced graphics loading (logo and signature)
\usepackage[space,extendedchars]{grffile} % better access to graphics files
\usepackage[export]{adjustbox} % improved options for \includegraphics
\usepackage{ragged2e} % improved alignment
\usepackage{lastpage} % easy access to page number of last page
\usepackage{embedfile} % store data files in PDF (patient, praxis)
%\usepackage[abspath]{currfile} % generically refer to LaTeX input file
\usepackage{calc} % \widthof (for signature)
\usepackage{microtype} % micro-adjustments to typesetting
\usepackage{tabularx} % bessere Tabellen
\usepackage{tabu} % bessere Tabellen
\usepackage{longtable} % Tabellen über mehrere Seiten
% debugging
$<if_debugging:://%::>$\usepackage{interfaces} % provides \papergraduate
$<if_debugging:://%::>$\usepackage{showkeys} % print labels (anchors and stuff) as margin notes
$<if_debugging:://%::>$\usepackage[noframe]{showframe} % show page margins as boxes
$<if_debugging:://%::>$\usepackage[verbose]{layout} % generate a page with the current layout
$<if_debugging:://%::>$\usepackage[pass]{geometry} % nicely display geometry in log file
$<if_debugging:://%::>$\usepackage{afterpage} % add stuff after next page bread
% load last:
\usepackage{hyperref} % aktive URLs, needs to be loaded last, most of the time
% package setup:
% - debugging
\listfiles % list all input files used
\errorcontextlines 10000 % list lots of context lines with errors
\RequirePackage[l2tabu, orthodox]{nag} % show unorthodox/faulty/obsolete uses
\hypersetup{debug=true} % extra debugging log messages
% %\tracingtabu=3 % trace tabu tables if using tabu package
$<if_debugging:://%::>$\usetikz{basic} % needed for \papergraduate from package interfaces
$<if_debugging:://%::>$\overfullrule=2cm % mark overfull horizontal boxes
$<if_debugging:://%::>$\geometry{pass,verbose} % put geometry into log file
$<if_debugging:://%::>$\renewcommand\ShowFrameLinethickness{0.25pt} % configure showframe
$<if_debugging:://%::>$\renewcommand*\ShowFrameColor{\color{red}} % configure showframe
% - PDF metadata
\hypersetup{%
pdftitle = {Current Medication List: $<name::%(firstnames)s %(lastnames)s::>$, $<date_of_birth::%d.%m.%Y::>$},
pdfauthor = {$<current_provider::::>$, $<praxis::%(branch)s, %(praxis)s::>$},
pdfsubject = {Current Medication List},
pdfproducer = {GNUmed $<client_version::::>$, Template $<form_name_long::::>$, $<form_version::::>$ [$<form_version_internal::::>$, $<form_last_modified::::>$]},
pdfdisplaydoctitle = true,
pdfprintscaling = None
}
% - base font: sans serif Latin Modern
\renewcommand*\familydefault{\sfdefault}
% - precise positioning of things to satisfy spec
%\setlength{\tabcolsep}{0pt}
%\setlength{\parskip}{0pt}
%\setlength{\topskip}{0pt}
%\setlength{\floatsep}{0pt}
%\setlength{\textfloatsep}{0pt}
% "enough" space at the top
\setlength{\topmargin}{-50pt}
\setlength{\headheight}{80pt}
% - tabu
\tabulinesep=^1mm_1mm
% - header = top part
\lohead{{%
\parbox[t]{\textwidth}{%
\upshape
\centering
{\Large Current Medication List}\\
$<today::%d.%B %Y::>$ -- Page \thepage{} of \pageref{LastPage}\\
\begin{tabular}[t]{ll}%
Patient & {\large $<lastname::::1>$\textsc{$<lastname::::2-99>$}, $<firstname::::>$}\\
born & $<date_of_birth::%d.%B %Y::>$\\
$2<if_not_empty::$<adr_street::home::>$$<adr_number::home::>$$<adr_postcode::home::>$$<adr_location::home::>$//\multicolumn{2}{l}{{\footnotesize $<adr_street::home::>$ $<adr_number::home::>$, $<adr_postcode::home::>$ $<adr_location::home::>$}}\\//% address empty::>2$
\end{tabular}%
\hfill
\begin{tabular}[t]{ll}%
Doctor & $<current_provider::::>$\\
$2<if_not_empty::$<current_provider_external_id::Fachgebiet//Ärztekammer::>$//{\footnotesize Specialty} & {\footnotesize %s}\\//% speciality not available::>2$
$2<if_not_empty::$<current_provider_external_id::KV-LANR//KV::>$//{\footnotesize LANR} & {\footnotesize %s}\\//% no LANR available::>2$
\end{tabular}%
}
}}
\lehead{{%
\parbox[t]{\textwidth}{%
\upshape
\centering
{\Large Current Medication List}\\
$<today::%d.%B %Y::>$ -- Page \thepage{} of \pageref{LastPage}\\
\begin{tabular}[t]{ll}%
Patient & {\large $<lastname::::1>$\textsc{$<lastname::::2-99>$}, $<firstname::::>$}\\
born & $<date_of_birth::%d.%B %Y::>$\\
$2<if_not_empty::$<adr_street::home::>$$<adr_number::home::>$$<adr_postcode::home::>$$<adr_location::home::>$//\multicolumn{2}{l}{{\footnotesize $<adr_street::home::>$ $<adr_number::home::>$, $<adr_postcode::home::>$ $<adr_location::home::>$}}\\//% address empty::>2$
\end{tabular}%
\hfill
\begin{tabular}[t]{ll}%
Doctor & $<current_provider::::>$\\
$2<if_not_empty::$<current_provider_external_id::Fachgebiet//Ärztekammer::>$//{\footnotesize Speciality} & {\footnotesize %s}\\//% speciality not available::>2$
$2<if_not_empty::$<current_provider_external_id::KV-LANR//KV::>$//{\footnotesize LANR} & {\footnotesize %s}\\//% no LANR available::>2$
\end{tabular}%
}
}}
\cehead{}
\cohead{}
\rehead{}
\rohead{}
% footer setup = bottom part
\lofoot{{%
\parbox[t]{\textwidth}{%
\tiny
\begin{tabular}[t]{ll}%
\multicolumn{2}{l}{$<praxis::%(praxis)s, %(branch)s::>$}\\
\multicolumn{2}{l}{$<praxis_address::%(street)s %(number)s %(subunit)s, %(postcode)s %(urb)s::>$}\\
\multicolumn{2}{l}{\Email $2<if_not_empty::$<praxis_comm::email::>$//\href{mailto:$<praxis_comm::email::>$}{%s}//::>2$}
\end{tabular}%
\begin{tabular}[t]{ll}%
\Telefon & $<praxis_comm::workphone::>$\\
\FAX & $<praxis_comm::fax::>$\\
$2<ph_cfg::argumentsdivider//#2#//%% <%(name)s> set to [%(value)s]::>2$
$2<if_not_empty::$<praxis_comm::web::>$#2#\ComputerMouse & \href{http://%s}{%s}#2#% no praxis web address available::>2$
$2<ph_cfg::argumentsdivider//DEFAULT//%% <%(name)s> set to [%(value)s]::>2$
\end{tabular}%
\begin{tabular}[t]{ll}%
BSNR & $<praxis_id::KV-BSNR//KV//%(value)s::>$\\
GNUmed & v$<client_version::::>$ (\href{http://www.gnumed.org}{www.gnumed.org})\\
Vorlage & $<form_name_long::::>$ v$<form_version::::>$
\end{tabular}%
}
}}
\lefoot{{%
\parbox[t]{\textwidth}{%
\tiny
\begin{tabular}[t]{ll}%
\multicolumn{2}{l}{$<praxis::%(praxis)s, %(branch)s::>$}\\
\multicolumn{2}{l}{$<praxis_address::%(street)s %(number)s %(subunit)s, %(postcode)s %(urb)s::>$}\\
\multicolumn{2}{l}{\Email $2<if_not_empty::$<praxis_comm::email::>$//\href{mailto:$<praxis_comm::email::>$}{%s}//::>2$}
\end{tabular}%
\begin{tabular}[t]{ll}%
\Telefon & $<praxis_comm::workphone::>$\\
\FAX & $<praxis_comm::fax::>$\\
$2<ph_cfg::argumentsdivider//#2#//%% <%(name)s> set to [%(value)s]::>2$
$2<if_not_empty::$<praxis_comm::web::>$#2#\ComputerMouse & \href{http://%s}{%s}#2#% no praxis web address available::>2$
$2<ph_cfg::argumentsdivider//DEFAULT//%% <%(name)s> set to [%(value)s]::>2$
\end{tabular}%
\begin{tabular}[t]{ll}%
BSNR & $<praxis_id::KV-BSNR//KV//%(value)s::>$\\
GNUmed & v$<client_version::::>$ (\href{http://www.gnumed.org}{www.gnumed.org})\\
Vorlage & $<form_name_long::::>$ v$<form_version::::>$
\end{tabular}%
}
}}
\cefoot{}
\cofoot{}
\refoot{}
\rofoot{}
%------------------------------------------------------------------
\begin{document}
% debugging
$<if_debugging:://%::>$\papergraduate % show coordinate system on first page
$<if_debugging:://%::>$\afterpage{\AddToShipoutPicture*{\ShowFramePicture}} % show "normal" page layout starting with second page
%------------------------------------------------------------------
% the actual content
\selectlanguage{ngerman} % if German
% medication table
$<current_meds_table::latex::>$
% uncomment, if and as needed, the next lines to append text below the table
%{\footnotesize % start smaller font
% <any line(s) of info you wish to always be printed immediately below the table>
%} % end smaller font
$<free_text::Extra notes to the patient::9999>$
%------------------------------------------------------------------
% Doctor's information
\clearpage
$<current_meds_notes::latex::>$
% Allergien
Known allergies:
$<allergy_state::::>$
\begin{tabularx}{\textwidth}{|l|l|X|}
\hline
Agent & Type & Reaction\\
\hline
$<allergies::%(descriptor)s & %(l10n_type)s & {\footnotesize %(reaction)s}\\\hline::>$
\end{tabularx}
%------------------------------------------------------------------
\medskip{}
\medskip{}
\medskip{}
\medskip{}
%------------------------------------------------------------------
% Unterschrift
\begin{flushright}
\texttt{\textsl{\footnotesize Practice Stamp / Physician Signature}}
\par\end{flushright}
%------------------------------------------------------------------
% embed data into PDF for easier processing:
% VCF of creator
\IfFileExists{$<praxis_vcf::::>$}{%
\embedfile[
desc=01) Praxis - digital business card (originator),
mimetype=text/vcf,
ucfilespec=praxis.vcf
]{$<praxis_vcf::::>$}
}{\typeout{[$<praxis_vcf::::>$] not found}}
% VCF of patient
\IfFileExists{$<patient_vcf::::>$}{%
\embedfile[
desc=02) Patient - digital business card,
mimetype=text/vcf,
ucfilespec=patient.vcf
]{$<patient_vcf::::>$}
}{\typeout{[$<patient_vcf::::>$] (patient VCF) not found}}
%------------------------------------------------------------------
% debugging
$<if_debugging:://%::>$\layout % show page layout page
%------------------------------------------------------------------
\end{document}
%------------------------------------------------------------------
%------------------------------------------------------------------
% Author: Karsten Hilbert
% License: GPL v2 or later
%------------------------------------------------------------------
\documentclass[english]{article}
\usepackage[T1]{fontenc}
\usepackage[cjkjis,graphics]{ucs}
\usepackage[utf8]{inputenc}
\usepackage{marvosym} % Symbole: Handy, Telefon, E-Mail
%\usepackage{textcomp} % Symbole für Textmodus zum Escapen
\usepackage{longtable}
\usepackage{tabu}
\usepackage{graphicx}
\usepackage[space]{grffile}
\usepackage[a4paper]{geometry}
\usepackage{microtype}
\usepackage{hyperref}
% debugging
%\usepackage{interfaces} % \papergraduate
%\usepackage{showkeys} % print labels (anchors and stuff) as margin notes
% debugging
\errorcontextlines 10000
% - show all files used
\listfiles
% - show unorthodox/faulty/obsolete uses
\RequirePackage[l2tabu, orthodox]{nag}
% - mark overfull horizontal boxes
%\overfullrule=2cm
% - show coordinate system on paper
%\papergraduate
\geometry{verbose,lmargin=1cm}
\pagestyle{empty}
\setlength{\parskip}{\medskipamount}
\setlength{\parindent}{0pt}
\usepackage{babel}
%------------------------------------------------------------------
\begin{document}
\footnotetext{\tiny \href{http://www.gnumed.org}{GNUmed} $<client_version::::>$ -- \href{http://www.gnumed.org}{www.gnumed.org}}
\footnotetext{\tiny Template: $<form_name_long::::60>$ v$<form_version::::20>$}
\noindent \begin{center}
{\large Vaccination history (printed $<today::%Y %B %d::>$)}%
\par\end{center}
\noindent Patient: $<lastname::::>$, $<firstname::::>$ ($<date_of_birth::%Y %B %d::>$)
{\footnotesize%
$2<if_not_empty::$<adr_street::home::>$//$<adr_street::home::>$ $<adr_number::home::>$ \\//::>2$
$2<if_not_empty::$<adr_location::home::>$//$<adr_postcode::home::>$ $<adr_location::home::>$//::>2$
}
\noindent \begin{center}
$<patient_photo::\includegraphics[width=30mm]{%s}//image/png//.png::250>$
\par\end{center}
\begin{longtabu} to \textwidth {|l|X[,L]|X[,L]|}
\hline
Given & Vaccine (batch) & Indications\\
\hline
\hline
$<vaccination_history::%(date_given)s & %(vaccine)s {\footnotesize (%(batch_no)s) } & {\footnotesize %(l10n_indications)s }\\ \hline//%Y %b %d::>$
\end{longtabu}
\vfill{}
\noindent Known allergies:
\begin{tabular}{|l|l|l|}
\hline
Agent & Type & Reaction\\
\hline
\hline
$<allergies::%(descriptor)s & %(l10n_type)s & {\footnotesize %(reaction)s}\\ \hline::>$
\end{tabular}
\medskip{}
\noindent \begin{flushright}
$<data_snippet::autograph-LMcC//\includegraphics[width=30mm]{%s}//image/png//.png::250>$
\texttt{\textsl{\footnotesize Practice Stamp / Physician Signature}}
\par\end{flushright}
\end{document}
%------------------------------------------------------------------
......@@ -8,152 +8,130 @@
% requires pdflatex to be run with -recorder option
%------------------------------------------------------------------
% debugging
\listfiles
\errorcontextlines 10000
\documentclass[
version=last,
paper=portrait,
paper=a4,
version=last, % use latest KomaScript code
paper=portrait, % not landscape
paper=a4, % set paper size
DIV=9, % help typearea find a good Satzspiegel
BCOR=0mm, % keine BindeCORrektur
fontsize=12pt, % per spec
parskip=full, % Absätze mit Leerzeilen trennen, kein Einzug
fontsize=11pt, % set fontsize early such that recalctypearea is not necessary
parskip=half*, % Absätze mit halber Leerzeilen trennen, kein Einzug, Vorabsatz endet mit maxial 3/4-Zeile
headsepline=off,
footsepline=on,
titlepage=false
footsepline=true, % do show line above page footer
titlepage=false % do not set a dedicated title page
]{scrartcl}
%------------------------------------------------------------------
% packages
\usepackage{scrlayer-scrpage} % Kopf- und Fußzeilen
\usepackage{geometry} % setup margins
\usepackage{microtype} % micro-adjustments to typesetting
\usepackage[cjkjis,graphics]{ucs} % lots of UTF8 symbols, breaks with xelatex
\usepackage[T1]{fontenc} % fonts are T1
% package loading:
\usepackage{scrlayer-scrpage} % header and footer control
\usepackage[ngerman]{babel} % Deutsch und Trennung
\usepackage[utf8x]{inputenc} % content is UTF8, breaks with xelatex
\usepackage{textcomp} % Symbole für Textmodus zum Escapen
\usepackage{ragged2e} % improved alignment, needed for raggedleft in header table cell
\usepackage[utf8]{inputenc} % input is UTF8
\usepackage[T1]{fontenc} % fonts are T1
\usepackage{textcomp} % symbols for textmode escaping, does not mix with "ucs", unless utf8x used
\usepackage{marvosym} % symbols: Handy, Telefon, E-Mail
%\usepackage{helvet} % Arial-alike Helvetica
\usepackage{lmodern} % sans serif Latin Modern
\usepackage{array} % improved table column styles
\usepackage{graphicx} % enhanced graphics loading (logo and signature)
\usepackage[space,extendedchars]{grffile} % better access to graphics files
\usepackage[export]{adjustbox} % improved options for \includegraphics
\usepackage{ragged2e} % improved alignment
\usepackage{lastpage} % easy access to page number of last page
\usepackage{embedfile} % store data files in PDF (patient, praxis)
%\usepackage[abspath]{currfile} % generically refer to LaTeX input file
\usepackage{calc} % \widthof (for signature)
\usepackage{microtype} % micro-adjustments to typesetting
\usepackage{tabularx} % bessere Tabellen
\usepackage{tabu} % bessere Tabellen
\usepackage{longtable} % Tabellen über mehrere Seiten
%\usepackage[table]{xcolor} % gray headers
%\usepackage{helvet} % Arial alike Helvetica
\usepackage{lastpage} % easy access to page number of last page
%\usepackage{embedfile} % store copy of data file for producing data matrix inside PDF
\usepackage{array} % improved column styles
%\usepackage[abspath]{currfile} % generically refer to input file
%\usepackage{graphicx} % Grafiken laden (datamatrix)
%\usepackage[space]{grffile} % besserer Zugriff auf Grafikdateien
%\usepackage[export]{adjustbox} % improved options for \includegraphics
\usepackage{marvosym} % Symbole: Handy, Telefon, E-Mail, used in non-conformant layout
%\usepackage[ocgcolorlinks=true]{hyperref} % aktive URLs, needs to be loaded last, most of the time
% debugging
$<if_debugging:://%::>$\usepackage{interfaces} % provides \papergraduate
$<if_debugging:://%::>$\usepackage{showkeys} % print labels (anchors and stuff) as margin notes
$<if_debugging:://%::>$\usepackage[noframe]{showframe} % show page margins as boxes
$<if_debugging:://%::>$\usepackage[verbose]{layout} % generate a page with the current layout
$<if_debugging:://%::>$\usepackage[pass]{geometry} % nicely display geometry in log file
$<if_debugging:://%::>$\usepackage{afterpage} % add stuff after next page bread
% load last:
\usepackage{hyperref} % aktive URLs, needs to be loaded last, most of the time
% debugging:
%\usepackage{showkeys} % print labels (anchors and stuff) as margin notes
%\usepackage{interfaces} % \papergraduate
%\usepackage{calc} % \widthof (für signature)
%------------------------------------------------------------------
% setup:
% package setup:
% - debugging
% %\tracingtabu=3
%\usetikz{basic}
%\hypersetup{debug=true}
\listfiles % list all input files used
\errorcontextlines 10000 % list lots of context lines with errors
\RequirePackage[l2tabu, orthodox]{nag} % show unorthodox/faulty/obsolete uses
\hypersetup{debug=true} % extra debugging log messages
% %\tracingtabu=3 % trace tabu tables if using tabu package
$<if_debugging:://%::>$\usetikz{basic} % needed for \papergraduate from package interfaces
$<if_debugging:://%::>$\overfullrule=2cm % mark overfull horizontal boxes
$<if_debugging:://%::>$\geometry{pass,verbose} % put geometry into log file
$<if_debugging:://%::>$\renewcommand\ShowFrameLinethickness{0.25pt} % configure showframe
$<if_debugging:://%::>$\renewcommand*\ShowFrameColor{\color{red}} % configure showframe
% - PDF metadata
\hypersetup{
pdftitle = {Medikationsplan: $<name::%(firstnames)s %(lastnames)s::>$, $<date_of_birth::%d.%m.%Y::>$},
\hypersetup{%
pdftitle = {Medikation: $<name::%(firstnames)s %(lastnames)s::>$, $<date_of_birth::%d.%m.%Y::>$},
pdfauthor = {$<current_provider::::>$, $<praxis::%(branch)s, %(praxis)s::>$},
pdfsubject = {Medikationsplan},
pdfproducer = {GNUmed $<client_version::::>$, Vorlage $<form_name_long::::>$, $<form_version::::>$ [$<form_version_internal::::>$, $<form_last_modified::::>$]},
pdfdisplaydoctitle = true
pdfsubject = {Aktuelle Medikation},
pdfproducer = {GNUmed $<client_version::::>$, Template $<form_name_long::::>$, $<form_version::::>$ [$<form_version_internal::::>$, $<form_last_modified::::>$]},
pdfdisplaydoctitle = true,
pdfprintscaling = None
}
% - base font: sans serif Latin Modern
\renewcommand*\familydefault{\sfdefault}
% - precise positioning of things to satisfy spec
%\setlength{\tabcolsep}{0pt}
\setlength{\parskip}{0pt}
\setlength{\topskip}{0pt}
\setlength{\floatsep}{0pt}
\setlength{\textfloatsep}{0pt}
% - page
\geometry{
verbose,
% debugging:
% showframe, % show page frames
% showcrop, % show crop marks
a4paper,
portrait,
bindingoffset=0pt,
% %
% % top-to-bottom on page:
% top=8mm, % per spec
% includehead, % into <total body>, not into topmargin
% headheight=48mm, % per spec, decrease textheight, top margin (8mm) + actual header size (40mm)
headsep=0mm, % no more space until *top* of textheight (not baseline of first line ...)
% %textheight, % is calculated by the other dimensions, should amount to 144mm (210 - (8+40+0+10+9))
% includefoot, % into <total body>, not into bottommargin
% % need to be calculated to work:
% footskip=\dimexpr+\ht\strutbox\relax, % 10mm per spec, decreases textheight
bottom=\dimexpr25mm+\ht\strutbox\relax, % 8mm per spec, 15mm found empirically (includes the 10mm footskip, but why ?)
% %
% % left-to-right on page:
% left=8mm, % per spec
% %textwidth, % is calculated by the other dimensions, should amount to 281mm (297 - (8+0+0+8))
% includemp, % include marginparsep and marginparwidth into width, decreases textwidth (but set to 0 below)
% marginparsep=0mm, % no margin notes offset
% marginparwidth=0mm, % no margin notes width
% right=8mm % per spec
}
%\setlength{\parskip}{0pt}
%\setlength{\topskip}{0pt}
%\setlength{\floatsep}{0pt}
%\setlength{\textfloatsep}{0pt}
% "enough" space at the top
\setlength{\topmargin}{-50pt}
\setlength{\headheight}{80pt}
% - tabu
\tabulinesep=^1mm_1mm
% - header = top part
\lohead{{
\parbox[t]{\textwidth}{
\lohead{{%
\parbox[t]{\textwidth}{%
\upshape
{\centering {\LARGE Medikamentenliste} \\}
{\centering $<today::%d.%B %Y::>$ -- Seite \thepage von \pageref{LastPage} \\}
\begin{tabular}[t]{ll}
Patient & {\large $<lastname::::1>$\textsc{$<<lastname::::2-99>>$}, $<firstname::::>$}\tabularnewline
geb & $<date_of_birth::%d.%B %Y::>$\tabularnewline
$<<if_not_empty::$<adr_street::home::>$$<adr_number::home::>$$<adr_postcode::home::>$$<adr_location::home::>$//\multicolumn{2}{l}{{\footnotesize $<adr_street::home::>$ $<adr_number::home::>$, $<adr_postcode::home::>$ $<adr_location::home::>$}}\tabularnewline//% address empty::>>$
\end{tabular}
\centering
{\Large Medikamentenliste}\\
$<today::%d.%B %Y::>$ -- Seite \thepage{} von \pageref{LastPage}\\
\begin{tabular}[t]{ll}%
Patient & {\large $<lastname::::1>$\textsc{$<lastname::::2-99>$}, $<firstname::::>$}\\
geb & $<date_of_birth::%d.%B %Y::>$\\
$2<if_not_empty::$<adr_street::home::>$$<adr_number::home::>$$<adr_postcode::home::>$$<adr_location::home::>$//\multicolumn{2}{l}{{\footnotesize $<adr_street::home::>$ $<adr_number::home::>$, $<adr_postcode::home::>$ $<adr_location::home::>$}}\\//% address empty::>2$
\end{tabular}%
\hfill
\begin{tabular}[t]{ll}
Arzt & $<current_provider::::>$\tabularnewline
$<<if_not_empty::$<current_provider_external_id::Fachgebiet//Ärztekammer::>$//{\footnotesize FA für & %s}\tabularnewline//% speciality not available::>>$
$<<if_not_empty::$<current_provider_external_id::KV-LANR//KV::>$//{\footnotesize LANR & %s}\tabularnewline//% no LANR available::>>$
\end{tabular}
\begin{tabular}[t]{ll}%
Arzt & $<current_provider::::>$\\
$2<if_not_empty::$<current_provider_external_id::Fachgebiet//Ärztekammer::>$//{\footnotesize FA für} & {\footnotesize %s}\\//% speciality not available::>2$
$2<if_not_empty::$<current_provider_external_id::KV-LANR//KV::>$//{\footnotesize LANR} & {\footnotesize %s}\\//% no LANR available::>2$
\end{tabular}%
}
}}
\lehead{{
\parbox[t]{\textwidth}{
\lehead{{%
\parbox[t]{\textwidth}{%
\upshape
{\centering {\LARGE Medikamentenliste} \\}
{\centering $<today::%d.%B %Y::>$ -- Seite \thepage von \pageref{LastPage} \\}
\begin{tabular}[t]{ll}
Patient & {\large $<lastname::::1>$\textsc{$<<lastname::::2-99>>$}, $<firstname::::>$}\tabularnewline
geb & $<date_of_birth::%d.%B %Y::>$\tabularnewline
$<<if_not_empty::$<adr_street::home::>$$<adr_number::home::>$$<adr_postcode::home::>$$<adr_location::home::>$//\multicolumn{2}{l}{{\footnotesize $<adr_street::home::>$ $<adr_number::home::>$, $<adr_postcode::home::>$ $<adr_location::home::>$}}\tabularnewline//% address empty::>>$
\end{tabular}
\centering
{\Large Medikamentenliste}\\
$<today::%d.%B %Y::>$ -- Seite \thepage{} von \pageref{LastPage}\\
\begin{tabular}[t]{ll}%
Patient & {\large $<lastname::::1>$\textsc{$<lastname::::2-99>$}, $<firstname::::>$}\\
geb & $<date_of_birth::%d.%B %Y::>$\\
$2<if_not_empty::$<adr_street::home::>$$<adr_number::home::>$$<adr_postcode::home::>$$<adr_location::home::>$//\multicolumn{2}{l}{{\footnotesize $<adr_street::home::>$ $<adr_number::home::>$, $<adr_postcode::home::>$ $<adr_location::home::>$}}\\//% address empty::>2$
\end{tabular}%
\hfill
\begin{tabular}[t]{ll}
Arzt & $<current_provider::::>$\tabularnewline
$<<if_not_empty::$<current_provider_external_id::Fachgebiet//Ärztekammer::>$//{\footnotesize FA für & %s}\tabularnewline//% speciality not available::>>$
$<<if_not_empty::$<current_provider_external_id::KV-LANR//KV::>$//{\footnotesize LANR & %s}\tabularnewline//% no LANR available::>>$
\end{tabular}
\begin{tabular}[t]{ll}%
Arzt & $<current_provider::::>$\\
$2<if_not_empty::$<current_provider_external_id::Fachgebiet//Ärztekammer::>$//{\footnotesize FA für} & {\footnotesize %s}\\//% speciality not available::>2$
$2<if_not_empty::$<current_provider_external_id::KV-LANR//KV::>$//{\footnotesize LANR} & {\footnotesize %s}\\//% no LANR available::>2$
\end{tabular}%
}
}}
\cehead{}
......@@ -164,52 +142,46 @@
% footer setup = bottom part
\lofoot{{%
\parbox[t]{\textwidth}{
\parbox[t]{\textwidth}{%
\tiny
\begin{tabular}[t]{ll}%
\multicolumn{2}{l}{$<praxis::%(praxis)s, %(branch)s::>$}\tabularnewline
\multicolumn{2}{l}{$<praxis_address::%(street)s %(number)s %(subunit)s, %(postcode)s %(urb)s::>$}\tabularnewline
\multicolumn{2}{l}{\Email $<<if_not_empty::$<praxis_comm::email::>$//\href{mailto:$<praxis_comm::email::>$}{%s}//::>>$}\tabularnewline
%\Email & $<<if_not_empty::$<praxis_comm::email::>$//\href{mailto:$<praxis_comm::email::>$}{%s}//::>>$\tabularnewline
\multicolumn{2}{l}{$<praxis::%(praxis)s, %(branch)s::>$}\\
\multicolumn{2}{l}{$<praxis_address::%(street)s %(number)s %(subunit)s, %(postcode)s %(urb)s::>$}\\
\multicolumn{2}{l}{\Email $2<if_not_empty::$<praxis_comm::email::>$//\href{mailto:$<praxis_comm::email::>$}{%s}//::>2$}
\end{tabular}%
%\hfill
\begin{tabular}[t]{ll}%
\Telefon & $<praxis_comm::workphone::>$\tabularnewline
\FAX & $<praxis_comm::fax::>$\tabularnewline
$<<ph_cfg::argumentsdivider//##//%% <%(name)s> set to [%(value)s]::>>$
$<<if_not_empty::$<praxis_comm::web::>$##\ComputerMouse & \href{http://%s}{%s}\tabularnewline##% no praxis web address available::>>$
$<<ph_cfg::argumentsdivider//DEFAULT//%% <%(name)s> set to [%(value)s]::>>$
\Telefon & $<praxis_comm::workphone::>$\\
\FAX & $<praxis_comm::fax::>$\\
$2<ph_cfg::argumentsdivider//#2#//%% <%(name)s> set to [%(value)s]::>2$
$2<if_not_empty::$<praxis_comm::web::>$#2#\ComputerMouse & \href{http://%s}{%s}#2#% no praxis web address available::>2$
$2<ph_cfg::argumentsdivider//DEFAULT//%% <%(name)s> set to [%(value)s]::>2$
\end{tabular}%
%\hfill
\begin{tabular}[t]{ll}%
BSNR & $<praxis_id::KV-BSNR//KV//%(value)s::>$\tabularnewline
GNUmed & v$<client_version::::>$ (\href{http://www.gnumed.org}{www.gnumed.org})\tabularnewline
Vorlage & $<form_name_long::::>$ v$<form_version::::>$\tabularnewline
BSNR & $<praxis_id::KV-BSNR//KV//%(value)s::>$\\
GNUmed & v$<client_version::::>$ (\href{http://www.gnumed.org}{www.gnumed.org})\\
Vorlage & $<form_name_long::::>$ v$<form_version::::>$
\end{tabular}%
}
}}
\lefoot{{%
\parbox[t]{\textwidth}{
\parbox[t]{\textwidth}{%
\tiny
\begin{tabular}[t]{ll}%
\multicolumn{2}{l}{$<praxis::%(praxis)s, %(branch)s::>$}\tabularnewline
\multicolumn{2}{l}{$<praxis_address::%(street)s %(number)s %(subunit)s, %(postcode)s %(urb)s::>$}\tabularnewline
\multicolumn{2}{l}{\Email $<<if_not_empty::$<praxis_comm::email::>$//\href{mailto:$<praxis_comm::email::>$}{%s}//::>>$}\tabularnewline
%\Email & $<<if_not_empty::$<praxis_comm::email::>$//\href{mailto:$<praxis_comm::email::>$}{%s}//::>>$\tabularnewline
\multicolumn{2}{l}{$<praxis::%(praxis)s, %(branch)s::>$}\\
\multicolumn{2}{l}{$<praxis_address::%(street)s %(number)s %(subunit)s, %(postcode)s %(urb)s::>$}\\
\multicolumn{2}{l}{\Email $2<if_not_empty::$<praxis_comm::email::>$//\href{mailto:$<praxis_comm::email::>$}{%s}//::>2$}
\end{tabular}%
%\hfill
\begin{tabular}[t]{ll}%
\Telefon & $<praxis_comm::workphone::>$\tabularnewline
\FAX & $<praxis_comm::fax::>$\tabularnewline
$<<ph_cfg::argumentsdivider//##//%% <%(name)s> set to [%(value)s]::>>$
$<<if_not_empty::$<praxis_comm::web::>$##\ComputerMouse & \href{http://%s}{%s}\tabularnewline##% no praxis web address available::>>$
$<<ph_cfg::argumentsdivider//DEFAULT//%% <%(name)s> set to [%(value)s]::>>$
\Telefon & $<praxis_comm::workphone::>$\\
\FAX & $<praxis_comm::fax::>$\\
$2<ph_cfg::argumentsdivider//#2#//%% <%(name)s> set to [%(value)s]::>2$
$2<if_not_empty::$<praxis_comm::web::>$#2#\ComputerMouse & \href{http://%s}{%s}#2#% no praxis web address available::>2$
$2<ph_cfg::argumentsdivider//DEFAULT//%% <%(name)s> set to [%(value)s]::>2$
\end{tabular}%
%\hfill
\begin{tabular}[t]{ll}%
BSNR & $<praxis_id::KV-BSNR//KV//%(value)s::>$\tabularnewline
GNUmed & v$<client_version::::>$ (\href{http://www.gnumed.org}{www.gnumed.org})\tabularnewline
Vorlage & $<form_name_long::::>$ v$<form_version::::>$\tabularnewline
BSNR & $<praxis_id::KV-BSNR//KV//%(value)s::>$\\
GNUmed & v$<client_version::::>$ (\href{http://www.gnumed.org}{www.gnumed.org})\\
Vorlage & $<form_name_long::::>$ v$<form_version::::>$
\end{tabular}%
}
}}
......@@ -222,13 +194,16 @@
\begin{document}
% debugging
%\papergraduate
$<if_debugging:://%::>$\papergraduate % show coordinate system on first page
$<if_debugging:://%::>$\afterpage{\AddToShipoutPicture*{\ShowFramePicture}} % show "normal" page layout starting with second page
%------------------------------------------------------------------
% the actual content
\selectlanguage{ngerman} % if German
% Medikamente
$<current_meds_table::latex::>$
% Hinweise
% uncomment, if and as needed, the next lines to append text below the table
%{\footnotesize % start smaller font
% <any line(s) of info you wish to always be printed immediately below the table>
......@@ -242,26 +217,55 @@ $<free_text::Hinweise an den Patienten::9999>$
$<current_meds_notes::latex::>$
% Allergien
\noindent Bislang bekannte Allergien:
Bislang bekannte Allergien:
\noindent $<allergy_state::::>$
$<allergy_state::::>$
\noindent \begin{tabularx}{\textwidth}{|l|l|X|}
\begin{tabularx}{\textwidth}{|l|l|X|}
\hline
Auslöser & Typ & Reaktion\tabularnewline
Auslöser & Typ & Reaktion\\
\hline
$<allergies::%(descriptor)s & %(l10n_type)s & {\footnotesize %(reaction)s} \tabularnewline \hline::>$
$<allergies::%(descriptor)s & %(l10n_type)s & {\footnotesize %(reaction)s}\\\hline::>$
\end{tabularx}
%------------------------------------------------------------------
\medskip{}
\medskip{}
\medskip{}
\medskip{}
%------------------------------------------------------------------
% Unterschrift
\noindent \begin{flushright}
\begin{flushright}
\texttt{\textsl{\footnotesize Stempel / Unterschrift}}
\par\end{flushright}
%------------------------------------------------------------------
% embed data into PDF for easier processing:
% VCF of creator
\IfFileExists{$<praxis_vcf::::>$}{%
\embedfile[
desc=01) Praxis - digital business card (originator),
mimetype=text/vcf,
ucfilespec=praxis.vcf
]{$<praxis_vcf::::>$}
}{\typeout{[$<praxis_vcf::::>$] not found}}
% VCF of patient
\IfFileExists{$<patient_vcf::::>$}{%
\embedfile[
desc=02) Patient - digital business card,
mimetype=text/vcf,
ucfilespec=patient.vcf
]{$<patient_vcf::::>$}
}{\typeout{[$<patient_vcf::::>$] (patient VCF) not found}}
%------------------------------------------------------------------
% debugging
$<if_debugging:://%::>$\layout % show page layout page
%------------------------------------------------------------------
\end{document}
%------------------------------------------------------------------
-- ==============================================================
-- GNUmed database schema change script
--
-- License: GPL v2 or later
-- Author: karsten.hilbert@gmx.net
--
-- ==============================================================
\set ON_ERROR_STOP 1
--set default_transaction_read_only to off;
-- --------------------------------------------------------------
delete from ref.paperwork_templates where name_long = 'Begleitbrief mit Diagnosen [K.Hilbert]';
insert into ref.paperwork_templates (
fk_template_type,
instance_type,
name_short,
name_long,
external_version,
engine,
filename,
data
) values (
(select pk from ref.form_types where name = 'referral'),
'sonstiger Arztbrief',
'Begleitbrf m.Dg.[KH]',
'Begleitbrief mit Diagnosen [K.Hilbert]',
'22.4',
'L',
'begleitbrief.tex',
'real template missing'::bytea
);
-- --------------------------------------------------------------
-- convert paperwork templates
-- $<<<...>>>$ -> $3<...>3$
update ref.paperwork_templates r_pt_u set
data = (
select
replace(encode(r_pt_s.data, 'escape'), '$<<<', '$3<')
from
ref.paperwork_templates r_pt_s
where
r_pt_s.engine = 'L'
and
r_pt_s.pk = r_pt_u.pk
)::bytea
;
update ref.paperwork_templates r_pt_u set
data = (
select
replace(encode(r_pt_s.data, 'escape'), '>>>$', '>3$')
from
ref.paperwork_templates r_pt_s
where
r_pt_s.engine = 'L'
and
r_pt_s.pk = r_pt_u.pk
)::bytea
;
-- $<<...>>$ -> $2<...>2$
update ref.paperwork_templates r_pt_u set
data = (
select
replace(encode(r_pt_s.data, 'escape'), '$<<', '$2<')
from
ref.paperwork_templates r_pt_s
where
r_pt_s.engine = 'L'
and
r_pt_s.pk = r_pt_u.pk
)::bytea
;
update ref.paperwork_templates r_pt_u set
data = (
select
replace(encode(r_pt_s.data, 'escape'), '>>$', '>2$')
from
ref.paperwork_templates r_pt_s
where
r_pt_s.engine = 'L'
and
r_pt_s.pk = r_pt_u.pk
)::bytea
;
-- --------------------------------------------------------------
select gm.log_script_insertion('v22-ref-paperwork_templates-fixups.sql', '22.4');