├── CONTRIBUTING ├── config ├── .htaccess └── default_config.php ├── src ├── php │ ├── restful-api │ │ ├── roster │ │ │ ├── PUT-roster.php │ │ │ └── GET-roster.php │ │ └── authentication │ │ │ └── POST-authenticate.php │ ├── logout.php │ ├── 3rdparty │ │ ├── icalendar │ │ │ ├── includes │ │ │ │ ├── index.html │ │ │ │ └── framework.php │ │ │ ├── zapcallib.php │ │ │ └── examples │ │ │ │ ├── recurringdate.php │ │ │ │ ├── parseicalendar.php │ │ │ │ ├── simpleevent.php │ │ │ │ └── timezoneevent.php │ │ └── PHPMailer │ │ │ └── Exception.php │ ├── database_version_hash.php │ ├── fragments │ │ ├── fragment.footer.php │ │ ├── fragment.saturdayRotationTeamsAddEmployee.php │ │ ├── fragment.saturdayRotationTeamsAddTeam.php │ │ ├── fragment.add_roster_input_row.php │ │ └── ajax.php │ ├── pages │ │ ├── absence-read.php │ │ ├── install_head.php │ │ ├── overtime-overview.php │ │ ├── install_page_intro.php │ │ ├── remaining-vacation-overview.php │ │ ├── about.php │ │ ├── menu-tiles.php │ │ ├── lost_password.php │ │ ├── maintenance_write_gettext_for_javascript.php │ │ ├── upload-pep.php │ │ ├── collaborative-vacation-year.php │ │ ├── collaborative-vacation-month.php │ │ ├── install_page_welcome.php │ │ ├── overtime-read.php │ │ └── install_page_admin.php │ ├── ajax │ │ └── install.php │ ├── gettext.php │ ├── background_maintenance.php │ ├── classes │ │ ├── PDR │ │ │ ├── DateTime │ │ │ │ └── DateTimeUtility.php │ │ │ ├── Roster │ │ │ │ ├── OvertimeCollection.php │ │ │ │ ├── Overtime.php │ │ │ │ └── EmergencyService.php │ │ │ └── Workforce │ │ │ │ └── user_base.php │ │ ├── class.general_calculations.php │ │ ├── class.roster_item_empty.php │ │ ├── class.principle_roster_item.php │ │ ├── class.email.php │ │ └── class.pharmacy_emergency_service_builder.php │ ├── basic_access_authentication.php │ ├── backup-database.php │ └── login.php ├── sql │ ├── Feiertage.sql │ ├── Schulferien.sql │ ├── pep_month_day.sql │ ├── pep_year_month.sql │ ├── absence_reasons.sql │ ├── pep.sql │ ├── opening_times_special.sql │ ├── pep_weekday_time.sql │ ├── branch.sql │ ├── saturday_rotation.sql │ ├── users_privileges.sql │ ├── maintenance.sql │ ├── users_lost_password_token.sql │ ├── opening_times.sql │ ├── emergency_services.sql │ ├── approval.sql │ ├── user_email_notification_cache.sql │ ├── pdr_self.sql │ ├── Stunden.sql │ ├── task_rotation.sql │ ├── saturday_rotation_teams.sql │ ├── principle_roster_archive.sql │ ├── Dienstplan.sql │ ├── roster.sql │ ├── principle_roster.sql │ ├── employees_archive.sql │ ├── absence.sql │ ├── employees.sql │ └── users.sql ├── sh │ └── script.update.sh ├── js │ ├── translations.js │ ├── unsaved-changes-prompt.js │ ├── emergency-service-list.js │ ├── user_dialog.js │ ├── roster-day-edit.js │ └── keyboard_navigation.js └── css │ ├── printOrientationPortrait.css │ ├── saturday_list.css │ ├── install_style.css │ ├── principle-roster-employee.css │ ├── roster-day-edit.css │ ├── emergency_service.css │ ├── user_dialog.css │ ├── print.css │ └── overtime.css ├── tmp └── .htaccess ├── upload └── .htaccess ├── img ├── forward.png ├── history.png ├── md_edit.png ├── md_save.png ├── user_1.png ├── backward.png ├── download.png ├── edit-icon.png ├── employee_2.png ├── information.png ├── md_view_week.png ├── md_today-24px.png ├── watch_overtime.png ├── md_delete_forever.png ├── md_card_travel-24px.png ├── md_add.svg ├── md_emergency.svg ├── md_lists.svg ├── md_checklist.svg ├── md_person-24px.svg ├── md_logout.svg ├── md_view_week.svg ├── md_date_range-24px.svg ├── md_edit.svg ├── md_local_pharmacy.svg ├── md_description.svg ├── md_help_clinic.svg ├── md_account_tree.svg ├── md_upload_file.svg ├── md_delete_forever.svg ├── md_save.svg ├── md_directions_run-24px.svg ├── md_thumb_up-24px.svg ├── md_thumb_down-24px.svg ├── md_attach_file.svg ├── md_data_alert.svg ├── md_format_list_bulleted.svg ├── md_event_repeat.svg ├── md_work_history.svg ├── md_person.svg ├── md_patient_list.svg ├── md_face-24px.svg ├── md_quick_reference.svg ├── md_work_alert.svg ├── md_cut.svg ├── md_badge.svg ├── md_settings.svg ├── md_manage_accounts.svg ├── md_sick.svg ├── md_face_3.svg ├── user_1.svg ├── md_today-24px.svg ├── md_card_travel-24px.svg └── information.svg ├── docs ├── po4a │ └── po │ │ ├── de.mo │ │ └── documentation_user.mo ├── documentation.pdf ├── documentation_de.pdf ├── database_structure.dia ├── images │ ├── en_GB │ │ ├── login.php.png │ │ ├── navigation.png │ │ ├── register.php.png │ │ ├── menu-tiles.php.png │ │ ├── upload-pep.php.png │ │ ├── absence-edit.php.png │ │ ├── absence-read.php.png │ │ ├── lost_password.php.png │ │ ├── overtime-edit.php.png │ │ ├── overtime-read.php.png │ │ ├── attendance-list.php.png │ │ ├── roster-day-edit.php.png │ │ ├── roster-day-read.php.png │ │ ├── user-management.php.png │ │ ├── branch-management.php.PNG │ │ ├── reset-lost-password.php.png │ │ ├── roster-week-images.php.png │ │ ├── roster-week-table.php.png │ │ ├── principle-roster-day.php.png │ │ ├── roster-employee-table.php.png │ │ ├── human-resource-management.php.PNG │ │ ├── principle-roster-employee.php.png │ │ ├── colloborative-vacation-month.php.png │ │ ├── colloborative-vacation-year.php.png │ │ ├── marginal-employment-hours-list.php.png │ │ └── colloborative-vacation-month_input.php.png │ └── de_DE │ │ ├── user-page.php.png │ │ ├── menu-tiles.php.png │ │ ├── upload-pep.php.png │ │ ├── absence-edit.php.png │ │ ├── absence-read.php.png │ │ ├── configuration.php.png │ │ ├── iCalendar_import_0.png │ │ ├── iCalendar_import_1.png │ │ ├── iCalendar_import_2.png │ │ ├── iCalendar_import_3.png │ │ ├── iCalendar_import_4.png │ │ ├── overtime-edit.php.png │ │ ├── overtime-read.php.png │ │ ├── saturday-list.php.png │ │ ├── attendance-list.php.png │ │ ├── roster-day-edit.php.png │ │ ├── roster-day-read.php.png │ │ ├── user-management.php.png │ │ ├── branch-management.php.png │ │ ├── overtime-overview.php.png │ │ ├── roster-week-table.php.png │ │ ├── principle-roster-day.php.png │ │ ├── roster-employee-table.php.png │ │ ├── emergency-service-list.php.png │ │ ├── human-resource-management.php.png │ │ ├── principle-roster-employee.php.png │ │ ├── collaborative-vacation-month.php.png │ │ ├── collaborative-vacation-year.php.png │ │ ├── marginal-employment-hours-list.php.png │ │ └── collaborative-vacation-year.php_input_box.png ├── create_pdf_from_svg.sh ├── po4a.conf ├── documentation.tex ├── documentation_de.tex ├── documentation_introduction.tex └── setup.tex ├── locale └── de_DE │ └── LC_MESSAGES │ └── messages.mo ├── scripts ├── git-filter-smudge-project-version.sh ├── git-filter-clean-project-version.sh ├── git-filter-smudge-project-version.ps1 ├── git-filter-clean-project-version.ps1 ├── check_citations.sh ├── prepare-commit-msg - Kopie └── restart_docker_container.sh ├── exception-codes.md ├── .htaccess ├── CHANGELOG.md ├── funktionen.php ├── .gitattributes ├── phpinfo.php ├── docker-compose.yml ├── index.php ├── default.php ├── pep.sh ├── README.md ├── .gitignore └── webdav.php /CONTRIBUTING: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /config/.htaccess: -------------------------------------------------------------------------------- 1 | deny from all -------------------------------------------------------------------------------- /src/php/restful-api/roster/PUT-roster.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tmp/.htaccess: -------------------------------------------------------------------------------- 1 | #allow from all 2 | deny from all -------------------------------------------------------------------------------- /upload/.htaccess: -------------------------------------------------------------------------------- 1 | #allow from all 2 | deny from all -------------------------------------------------------------------------------- /img/forward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/img/forward.png -------------------------------------------------------------------------------- /img/history.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/img/history.png -------------------------------------------------------------------------------- /img/md_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/img/md_edit.png -------------------------------------------------------------------------------- /img/md_save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/img/md_save.png -------------------------------------------------------------------------------- /img/user_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/img/user_1.png -------------------------------------------------------------------------------- /src/php/logout.php: -------------------------------------------------------------------------------- 1 | logout(); 5 | -------------------------------------------------------------------------------- /img/backward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/img/backward.png -------------------------------------------------------------------------------- /img/download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/img/download.png -------------------------------------------------------------------------------- /img/edit-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/img/edit-icon.png -------------------------------------------------------------------------------- /docs/po4a/po/de.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/po4a/po/de.mo -------------------------------------------------------------------------------- /img/employee_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/img/employee_2.png -------------------------------------------------------------------------------- /img/information.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/img/information.png -------------------------------------------------------------------------------- /img/md_view_week.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/img/md_view_week.png -------------------------------------------------------------------------------- /docs/documentation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/documentation.pdf -------------------------------------------------------------------------------- /img/md_today-24px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/img/md_today-24px.png -------------------------------------------------------------------------------- /img/watch_overtime.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/img/watch_overtime.png -------------------------------------------------------------------------------- /docs/documentation_de.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/documentation_de.pdf -------------------------------------------------------------------------------- /img/md_delete_forever.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/img/md_delete_forever.png -------------------------------------------------------------------------------- /docs/database_structure.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/database_structure.dia -------------------------------------------------------------------------------- /img/md_card_travel-24px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/img/md_card_travel-24px.png -------------------------------------------------------------------------------- /src/php/3rdparty/icalendar/includes/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /docs/images/en_GB/login.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/en_GB/login.php.png -------------------------------------------------------------------------------- /docs/images/en_GB/navigation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/en_GB/navigation.png -------------------------------------------------------------------------------- /docs/images/de_DE/user-page.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/de_DE/user-page.php.png -------------------------------------------------------------------------------- /docs/images/en_GB/register.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/en_GB/register.php.png -------------------------------------------------------------------------------- /docs/po4a/po/documentation_user.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/po4a/po/documentation_user.mo -------------------------------------------------------------------------------- /src/php/database_version_hash.php: -------------------------------------------------------------------------------- 1 | .*<\/span>/currentVersionString/ /src/php/pages/about.php -------------------------------------------------------------------------------- /docs/images/de_DE/attendance-list.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/de_DE/attendance-list.php.png -------------------------------------------------------------------------------- /docs/images/de_DE/roster-day-edit.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/de_DE/roster-day-edit.php.png -------------------------------------------------------------------------------- /docs/images/de_DE/roster-day-read.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/de_DE/roster-day-read.php.png -------------------------------------------------------------------------------- /docs/images/de_DE/user-management.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/de_DE/user-management.php.png -------------------------------------------------------------------------------- /docs/images/en_GB/attendance-list.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/en_GB/attendance-list.php.png -------------------------------------------------------------------------------- /docs/images/en_GB/roster-day-edit.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/en_GB/roster-day-edit.php.png -------------------------------------------------------------------------------- /docs/images/en_GB/roster-day-read.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/en_GB/roster-day-read.php.png -------------------------------------------------------------------------------- /docs/images/en_GB/user-management.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/en_GB/user-management.php.png -------------------------------------------------------------------------------- /docs/images/de_DE/branch-management.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/de_DE/branch-management.php.png -------------------------------------------------------------------------------- /docs/images/de_DE/overtime-overview.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/de_DE/overtime-overview.php.png -------------------------------------------------------------------------------- /docs/images/de_DE/roster-week-table.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/de_DE/roster-week-table.php.png -------------------------------------------------------------------------------- /docs/images/en_GB/branch-management.php.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/en_GB/branch-management.php.PNG -------------------------------------------------------------------------------- /docs/images/en_GB/reset-lost-password.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/en_GB/reset-lost-password.php.png -------------------------------------------------------------------------------- /docs/images/en_GB/roster-week-images.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/en_GB/roster-week-images.php.png -------------------------------------------------------------------------------- /docs/images/en_GB/roster-week-table.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/en_GB/roster-week-table.php.png -------------------------------------------------------------------------------- /docs/images/de_DE/principle-roster-day.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/de_DE/principle-roster-day.php.png -------------------------------------------------------------------------------- /docs/images/de_DE/roster-employee-table.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/de_DE/roster-employee-table.php.png -------------------------------------------------------------------------------- /docs/images/en_GB/principle-roster-day.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/en_GB/principle-roster-day.php.png -------------------------------------------------------------------------------- /docs/images/en_GB/roster-employee-table.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/en_GB/roster-employee-table.php.png -------------------------------------------------------------------------------- /docs/images/de_DE/emergency-service-list.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/de_DE/emergency-service-list.php.png -------------------------------------------------------------------------------- /docs/images/de_DE/human-resource-management.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/de_DE/human-resource-management.php.png -------------------------------------------------------------------------------- /docs/images/de_DE/principle-roster-employee.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/de_DE/principle-roster-employee.php.png -------------------------------------------------------------------------------- /docs/images/en_GB/human-resource-management.php.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/en_GB/human-resource-management.php.PNG -------------------------------------------------------------------------------- /docs/images/en_GB/principle-roster-employee.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/en_GB/principle-roster-employee.php.png -------------------------------------------------------------------------------- /docs/images/de_DE/collaborative-vacation-month.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/de_DE/collaborative-vacation-month.php.png -------------------------------------------------------------------------------- /docs/images/de_DE/collaborative-vacation-year.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/de_DE/collaborative-vacation-year.php.png -------------------------------------------------------------------------------- /docs/images/en_GB/colloborative-vacation-month.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/en_GB/colloborative-vacation-month.php.png -------------------------------------------------------------------------------- /docs/images/en_GB/colloborative-vacation-year.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/en_GB/colloborative-vacation-year.php.png -------------------------------------------------------------------------------- /scripts/git-filter-clean-project-version.sh: -------------------------------------------------------------------------------- 1 | versionString=`git describe --abbrev=0 --tags` 2 | sed -i -e 's/currentVersionString/'$versionString'/' /src/php/pages/about.php -------------------------------------------------------------------------------- /docs/images/de_DE/marginal-employment-hours-list.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/de_DE/marginal-employment-hours-list.php.png -------------------------------------------------------------------------------- /docs/images/en_GB/marginal-employment-hours-list.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/en_GB/marginal-employment-hours-list.php.png -------------------------------------------------------------------------------- /img/md_add.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/images/en_GB/colloborative-vacation-month_input.php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/en_GB/colloborative-vacation-month_input.php.png -------------------------------------------------------------------------------- /docs/images/de_DE/collaborative-vacation-year.php_input_box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaMaKow/dienstplan-apotheke/HEAD/docs/images/de_DE/collaborative-vacation-year.php_input_box.png -------------------------------------------------------------------------------- /docs/create_pdf_from_svg.sh: -------------------------------------------------------------------------------- 1 | cd ../img/ 2 | for file in *.svg 3 | do 4 | filename=$(basename "$file") 5 | inkscape -D -z --file=$file --export-pdf=${filename%.svg}.pdf 6 | done 7 | 8 | -------------------------------------------------------------------------------- /src/sql/Feiertage.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `Feiertage` ( 2 | `Name` varchar(64) NOT NULL, 3 | `Datum` date NOT NULL, 4 | PRIMARY KEY (`Datum`) 5 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 -------------------------------------------------------------------------------- /src/sql/Schulferien.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `Schulferien` ( 2 | `Name` varchar(64) NOT NULL, 3 | `Beginn` date NOT NULL, 4 | `Ende` date NOT NULL, 5 | PRIMARY KEY (`Beginn`) 6 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 -------------------------------------------------------------------------------- /src/sql/pep_month_day.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `pep_month_day` ( 2 | `day` int(11) NOT NULL, 3 | `factor` float NOT NULL, 4 | `branch` int(11) NOT NULL, 5 | PRIMARY KEY (`day`,`branch`) 6 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 -------------------------------------------------------------------------------- /src/sql/pep_year_month.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `pep_year_month` ( 2 | `month` int(11) NOT NULL, 3 | `factor` float NOT NULL, 4 | `branch` int(11) NOT NULL, 5 | PRIMARY KEY (`month`,`branch`) 6 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 -------------------------------------------------------------------------------- /img/md_emergency.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /img/md_lists.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /img/md_checklist.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /img/md_person-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /img/md_logout.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/sql/absence_reasons.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `absence_reasons` ( 2 | `id` tinyint(3) unsigned NOT NULL, 3 | `reason_string` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL, 4 | PRIMARY KEY (`id`) 5 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci -------------------------------------------------------------------------------- /src/sql/pep.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `pep` ( 2 | `hash` binary(32) NOT NULL, 3 | `Datum` date NOT NULL, 4 | `Zeit` time NOT NULL, 5 | `Anzahl` int(11) NOT NULL, 6 | `Mandant` int(11) DEFAULT 1, 7 | PRIMARY KEY (`hash`) 8 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 -------------------------------------------------------------------------------- /scripts/git-filter-smudge-project-version.ps1: -------------------------------------------------------------------------------- 1 | $versionString=git describe --abbrev=0 --tags 2 | (Get-Content .\src\php\pages\about.php) -Replace '.*

', ('currentVersionString

') | Set-Content .\src\php\pages\about.php -------------------------------------------------------------------------------- /src/sql/opening_times_special.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `opening_times_special` ( 2 | `date` date NOT NULL, 3 | `start` time NOT NULL, 4 | `end` time NOT NULL, 5 | `event_name` varchar(64) DEFAULT NULL, 6 | PRIMARY KEY (`date`) 7 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 -------------------------------------------------------------------------------- /scripts/git-filter-clean-project-version.ps1: -------------------------------------------------------------------------------- 1 | $versionString=git describe --abbrev=0 --tags 2 | (Get-Content .\src\php\pages\about.php) -Replace '.*

', ('' + $versionString + '

') | Set-Content .\src\php\pages\about.php -------------------------------------------------------------------------------- /exception-codes.md: -------------------------------------------------------------------------------- 1 | # Exception codes 2 | This is a list of exception codes. 3 | ## List of Exception codes 4 | - const EXCEPTION_CODE_DUTY_START_INVALID = 1001; 5 | - duty_start_sql MUST be a valid time! 6 | - const EXCEPTION_CODE_DUTY_END_INVALID = 1002; 7 | - duty_end_sql MUST be a valid time! 8 | -------------------------------------------------------------------------------- /img/md_view_week.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/sh/script.update.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo "Checking out the master branch with git"; 4 | git checkout master; 5 | 6 | echo "Pulling the current state from origin"; 7 | git pull; 8 | 9 | echo "Performing maintenance tasks, including database updates"; 10 | php ./src/php/background_maintenance.php; -------------------------------------------------------------------------------- /img/md_date_range-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /img/md_edit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /img/md_local_pharmacy.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/sql/pep_weekday_time.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `pep_weekday_time` ( 2 | `Uhrzeit` time NOT NULL, 3 | `Wochentag` int(11) NOT NULL COMMENT '0=Monday', 4 | `Mittelwert` float DEFAULT NULL, 5 | `Mandant` int(11) NOT NULL, 6 | PRIMARY KEY (`Uhrzeit`,`Wochentag`,`Mandant`) 7 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 -------------------------------------------------------------------------------- /img/md_description.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /img/md_help_clinic.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /img/md_account_tree.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /img/md_upload_file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /img/md_delete_forever.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /img/md_save.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/po4a.conf: -------------------------------------------------------------------------------- 1 | [po_directory] po4a/po/ 2 | 3 | [type: latex] documentation_user.tex de:documentation_user_de.tex 4 | [type: latex] documentation_introduction.tex de:documentation_introduction_de.tex 5 | [type: latex] documentation_administrator.tex de:documentation_administrator_de.tex 6 | [type: latex] documentation_developer.tex de:documentation_developer_de.tex 7 | -------------------------------------------------------------------------------- /img/md_directions_run-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /img/md_thumb_up-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /img/md_thumb_down-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /img/md_attach_file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.htaccess: -------------------------------------------------------------------------------- 1 | 2 | deny from all 3 | 4 | 5 | # If PHP is not installed in the form of an Apache module, then php_value is not a valid command. 6 | # TODO: Also it is considered unsafe to use php_value inside .htaccess 7 | php_value upload_max_filesize 300M 8 | php_value post_max_size 300M 9 | php_value max_input_time 180 10 | 11 | -------------------------------------------------------------------------------- /src/php/fragments/fragment.footer.php: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.14.0 2 | Allow users to change passwords on the user-page 3 | Add mail and SMTP settings to the configuration GUI 4 | Use PHPMailer for sending email 5 | 6 | 7 | Debug Time quirks on daylight saving time. 8 | 9 | ## 0.13.0 10 | * Execute background maintenance upon login 11 | * Inform users via email about roster changes 12 | * Provide a user initial page 13 | * Build a testing infrastructure 14 | -------------------------------------------------------------------------------- /img/md_data_alert.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/sql/branch.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `branch` ( 2 | `branch_id` tinyint(3) unsigned NOT NULL, 3 | `name` varchar(64) NOT NULL, 4 | `short_name` varchar(32) NOT NULL, 5 | `address` varchar(64) NOT NULL, 6 | `manager` varchar(64) NOT NULL, 7 | `PEP` int(11) DEFAULT NULL COMMENT 'Dieser Wert wird vom ASYS PEP-Modul vorgegeben.', 8 | PRIMARY KEY (`branch_id`) 9 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 10 | -------------------------------------------------------------------------------- /src/sql/saturday_rotation.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `saturday_rotation` ( 2 | `date` date NOT NULL, 3 | `team_id` tinyint(4) NOT NULL, 4 | `branch_id` tinyint(3) unsigned NOT NULL, 5 | PRIMARY KEY (`date`,`branch_id`), 6 | CONSTRAINT `saturday_rotation_ibfk_1` FOREIGN KEY (`branch_id`) REFERENCES `branch`(`branch_id`) ON DELETE RESTRICT ON UPDATE RESTRICT 7 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci 8 | -------------------------------------------------------------------------------- /src/sql/users_privileges.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `users_privileges` ( 2 | `user_key` int(10) UNSIGNED NOT NULL, 3 | `privilege` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL, 4 | PRIMARY KEY (`user_key`,`privilege`), 5 | CONSTRAINT `users_privileges_ibfk_1` FOREIGN KEY (`user_key`) REFERENCES `users`(`primary_key`) ON DELETE RESTRICT ON UPDATE RESTRICT 6 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci 7 | -------------------------------------------------------------------------------- /src/sql/maintenance.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `maintenance` ( 2 | `id` enum('1') COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '1' COMMENT 'The ENUM(''1'') construct as primary key is used to prevent that more than one row can be entered to the table', 3 | `last_execution` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), 4 | PRIMARY KEY (`id`) 5 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci -------------------------------------------------------------------------------- /src/sql/users_lost_password_token.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `users_lost_password_token` ( 2 | `user_key` int(10) unsigned NOT NULL, 3 | `token` binary(20) NOT NULL, 4 | `time_created` timestamp NOT NULL DEFAULT current_timestamp(), 5 | CONSTRAINT `users_lost_password_token_ibfk_1` FOREIGN KEY (`user_key`) REFERENCES `users`(`primary_key`) ON DELETE RESTRICT ON UPDATE RESTRICT 6 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci 7 | -------------------------------------------------------------------------------- /docs/documentation.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt,a4paper,titlepage]{report} 2 | \usepackage[english]{babel} 3 | \include{setup} 4 | 5 | \author{Martin Mandelkow} 6 | \title{pharmacy duty roster\\Documentation} 7 | 8 | \begin{document} 9 | \maketitle 10 | \tableofcontents 11 | 12 | 13 | \include{documentation_introduction} 14 | \include{documentation_user} 15 | \include{documentation_administrator} 16 | \include{documentation_developer} 17 | \end{document} 18 | -------------------------------------------------------------------------------- /src/sql/opening_times.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `opening_times` ( 2 | `weekday` tinyint(4) NOT NULL, 3 | `start` time NOT NULL, 4 | `end` time NOT NULL, 5 | `branch_id` tinyint(3) unsigned NOT NULL, 6 | PRIMARY KEY (`weekday`,`start`,`branch_id`), 7 | CONSTRAINT `opening_times_ibfk_1` FOREIGN KEY (`branch_id`) REFERENCES `branch`(`branch_id`) ON DELETE RESTRICT ON UPDATE RESTRICT 8 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci 9 | -------------------------------------------------------------------------------- /src/sql/emergency_services.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `emergency_services` ( 2 | `primary_key` INT UNSIGNED NOT NULL AUTO_INCREMENT, 3 | `employee_key` int(10) unsigned DEFAULT NULL, 4 | `date` date NOT NULL, 5 | `branch_id` tinyint(3) unsigned NOT NULL DEFAULT 1, 6 | PRIMARY KEY (`primary_key`), 7 | CONSTRAINT `emergency_services_ibfk_1` FOREIGN KEY (`branch_id`) REFERENCES `branch`(`branch_id`) ON DELETE RESTRICT ON UPDATE RESTRICT 8 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 9 | -------------------------------------------------------------------------------- /img/md_format_list_bulleted.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /img/md_event_repeat.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /img/md_work_history.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/js/translations.js: -------------------------------------------------------------------------------- 1 | var pdr_translations = {"de_DE":{"Please see the error log for more details!":"Bitte beachten Sie das Fehlerprotokoll für weitere Details!","The end date is before the start date.":"Das End-Datum liegt vor dem Start-Datum.","Warning! Caps lock is ON.":"Achtung! Großschreibung ist aktiviert.","The input date lies before the last existent date.":"Das Datum des Eintrages liegt vor dem letzten vorhandenen Datum.","Are you sure, that the data is correct?":"Sind Sie sicher, dass die Daten korrekt sind?"}}; 2 | -------------------------------------------------------------------------------- /img/md_person.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/sql/approval.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `approval` ( 2 | `date` date NOT NULL, 3 | `state` set('approved','not_yet_approved','disapproved','changed_after_approval') NOT NULL, 4 | `branch` tinyint(3) unsigned NOT NULL, 5 | `user` varchar(64) NOT NULL, 6 | `timestamp` timestamp NOT NULL DEFAULT current_timestamp(), 7 | PRIMARY KEY (`date`,`branch`), 8 | CONSTRAINT `approval_ibfk_1` FOREIGN KEY (`branch`) REFERENCES `branch`(`branch_id`) ON DELETE RESTRICT ON UPDATE RESTRICT 9 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 10 | -------------------------------------------------------------------------------- /img/md_patient_list.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/sql/user_email_notification_cache.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `user_email_notification_cache` ( 2 | `notification_id` int(10) unsigned NOT NULL AUTO_INCREMENT, 3 | `user_key` int(10) unsigned NULL, 4 | `date` date NOT NULL, 5 | `timestamp` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), 6 | `notification_text` text COLLATE utf8mb4_unicode_ci NOT NULL, 7 | `notification_ics_file` blob NOT NULL, 8 | PRIMARY KEY (`notification_id`) 9 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci 10 | -------------------------------------------------------------------------------- /img/md_face-24px.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /img/md_quick_reference.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/sql/pdr_self.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `pdr_self` ( 2 | `id` enum('1') COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '1', 3 | `pdr_version_number` int(6) unsigned zerofill DEFAULT NULL, 4 | `pdr_version_string` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL, 5 | `pdr_database_version_hash` char(40) COLLATE utf8mb4_unicode_ci DEFAULT NULL, 6 | `last_execution_of_maintenance` timestamp NULL DEFAULT NULL, 7 | `principle_roster_start_date` date DEFAULT NULL, 8 | PRIMARY KEY (`id`) 9 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci -------------------------------------------------------------------------------- /img/md_work_alert.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/documentation_de.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt,a4paper,titlepage]{report} 2 | \usepackage[ngerman]{babel} 3 | \include{setup} 4 | \renewcommand{\ctrlname}{Strg} %for menukeys 5 | \renewcommand{\delname}{Entf} %for menukeys 6 | 7 | \author{Martin Mandelkow} 8 | \title{Dienstplan Apotheke\\Dokumentation} 9 | 10 | \begin{document} 11 | \maketitle 12 | \tableofcontents 13 | 14 | 15 | \include{documentation_introduction_de} 16 | \include{documentation_user_de} 17 | \include{documentation_administrator_de} 18 | \include{documentation_developer_de} 19 | \end{document} 20 | -------------------------------------------------------------------------------- /src/sql/Stunden.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `Stunden` ( 2 | `employee_key` int(10) unsigned NOT NULL, 3 | `Datum` date NOT NULL, 4 | `Stunden` float DEFAULT NULL, 5 | `Saldo` float NOT NULL, 6 | `Grund` varchar(64) DEFAULT NULL, 7 | `Aktualisierung` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), 8 | PRIMARY KEY (`employee_key`,`Datum`), 9 | CONSTRAINT `Stunden_ibfk_1` FOREIGN KEY (`employee_key`) REFERENCES `employees`(`primary_key`) ON DELETE RESTRICT ON UPDATE RESTRICT 10 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 11 | -------------------------------------------------------------------------------- /scripts/check_citations.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script to compare listed artwork with found images 4 | 5 | # find artwork which is cited: 6 | grep '\.\./img' src/php/pages/list_of_artwork.php | cut -d"/" -f 5 | cut -d\" -f 1 | sort > tmp/listed_artwork.del 7 | 8 | # find images in the image path: 9 | ls -lQ img/ | cut -d\" -f2 > tmp/found_artwork.del 10 | 11 | # compare the lists to find missing citations: 12 | diff --color tmp/found_artwork.del tmp/listed_artwork.del 13 | 14 | # remove temporary files: 15 | rm tmp/listed_artwork.del 16 | rm tmp/found_artwork.del 17 | -------------------------------------------------------------------------------- /src/sql/task_rotation.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `task_rotation` ( 2 | `date` date NOT NULL, 3 | `task` varchar(64) NOT NULL, 4 | `employee_key` int(10) unsigned NOT NULL, 5 | `branch_id` tinyint(3) unsigned NOT NULL, 6 | PRIMARY KEY (`date`,`task`,`branch_id`), 7 | CONSTRAINT `task_rotation_ibfk_1` FOREIGN KEY (`branch_id`) REFERENCES `branch`(`branch_id`) ON DELETE RESTRICT ON UPDATE RESTRICT, 8 | CONSTRAINT `task_rotation_ibfk_2` FOREIGN KEY (`employee_key`) REFERENCES `employees`(`primary_key`) ON DELETE RESTRICT ON UPDATE RESTRICT 9 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 10 | -------------------------------------------------------------------------------- /img/md_cut.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/sql/saturday_rotation_teams.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `saturday_rotation_teams` ( 2 | `team_id` tinyint(3) unsigned NOT NULL, 3 | `employee_key` int(10) unsigned NOT NULL, 4 | `branch_id` tinyint(3) unsigned NOT NULL, 5 | PRIMARY KEY (`team_id`,`employee_key`,`branch_id`), 6 | CONSTRAINT `saturday_rotation_teams_ibfk_1` FOREIGN KEY (`branch_id`) REFERENCES `branch`(`branch_id`) ON DELETE RESTRICT ON UPDATE RESTRICT, 7 | CONSTRAINT `saturday_rotation_teams_ibfk_2` FOREIGN KEY (`employee_key`) REFERENCES `employees`(`primary_key`) ON DELETE RESTRICT ON UPDATE RESTRICT 8 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci 9 | -------------------------------------------------------------------------------- /img/md_badge.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /scripts/prepare-commit-msg - Kopie: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # A hook script to prepare the commit log message. 4 | # Called by "git commit" with the name of the file that has the 5 | # commit message, followed by the description of the commit 6 | # message's source. The hook's purpose is to edit the commit 7 | # message file. If the hook fails with a non-zero status, 8 | # the commit is aborted. 9 | # 10 | 11 | COMMIT_MSG_FILE=$1 12 | COMMIT_SOURCE=$2 13 | SHA1=$3 14 | 15 | RESULT="# Differences to be committed:" 16 | while IFS= read -r line 17 | do 18 | RESULT+="$IFS# $line" 19 | done <<< $(git diff --staged) 20 | 21 | echo "$RESULT" >> $COMMIT_MSG_FILE 22 | 23 | -------------------------------------------------------------------------------- /src/php/3rdparty/icalendar/zapcallib.php: -------------------------------------------------------------------------------- 1 | 7 | * @copyright Copyright (C) 2006 - 2017 by Dan Cogliano 8 | * @license GNU GPLv3 9 | * @link http://icalendar.org/php-library.html 10 | */ 11 | 12 | /** 13 | * used by ZapCalLib 14 | * @var integer 15 | */ 16 | define('_ZAPCAL',1); 17 | 18 | if(!defined('_ZAPCAL_BASE')) 19 | { 20 | /** 21 | * the base folder of the library 22 | * @var string 23 | */ 24 | define('_ZAPCAL_BASE',__DIR__); 25 | } 26 | 27 | require_once(_ZAPCAL_BASE . '/includes/framework.php'); 28 | 29 | -------------------------------------------------------------------------------- /img/md_settings.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/sql/principle_roster_archive.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `principle_roster_archive` ( 2 | `primary_key` int(10) unsigned NOT NULL AUTO_INCREMENT, 3 | `alternating_week_id` tinyint(4) NOT NULL, 4 | `employee_key` int(10) unsigned NOT NULL, 5 | `weekday` tinyint(4) NOT NULL, 6 | `duty_start` time NOT NULL, 7 | `duty_end` time NOT NULL, 8 | `break_start` time DEFAULT NULL, 9 | `break_end` time DEFAULT NULL, 10 | `comment` text COLLATE utf8mb4_unicode_ci DEFAULT NULL, 11 | `working_hours` float DEFAULT NULL, 12 | `branch_id` tinyint(3) unsigned NOT NULL DEFAULT 1, 13 | `was_valid_until` date DEFAULT (CURRENT_DATE), 14 | PRIMARY KEY (`primary_key`) 15 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci 16 | -------------------------------------------------------------------------------- /funktionen.php: -------------------------------------------------------------------------------- 1 | . 18 | */ 19 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default behavior, in case people don't have core.autocrlf set. 2 | # https://help.github.com/articles/dealing-with-line-endings/ 3 | * text=auto eol=lf 4 | 5 | # Explicitly declare text files you want to always be normalized and converted 6 | # to native line endings on checkout. 7 | #*.c text 8 | #*.h text 9 | #*.sh text 10 | *.php text eol=lf 11 | 12 | # Declare files that will always have CRLF line endings on checkout. 13 | #*.sln text eol=crlf 14 | 15 | # Denote all files that are truly binary and should not be modified. 16 | *.png binary 17 | *.jpg binary 18 | 19 | #Use pdfdiff to show differences in pdf files: 20 | *.pdf diff=pdfdiff 21 | 22 | # Do not include the tests/ directory in project tarballs: 23 | tests/ export-ignore 24 | 25 | about.php filter=add-project-version 26 | -------------------------------------------------------------------------------- /img/md_manage_accounts.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/sql/Dienstplan.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `Dienstplan` ( 2 | `employee_key` int(10) unsigned NOT NULL, 3 | `Datum` date NOT NULL, 4 | `Dienstbeginn` time NOT NULL DEFAULT '00:00:00', 5 | `Dienstende` time DEFAULT NULL, 6 | `Mittagsbeginn` time DEFAULT NULL, 7 | `Mittagsende` time DEFAULT NULL, 8 | `Kommentar` text CHARACTER SET utf8mb4 DEFAULT NULL, 9 | `Stunden` float DEFAULT NULL, 10 | `Mandant` int(11) NOT NULL DEFAULT 1, 11 | `user` varchar(64) CHARACTER SET utf8mb4 NOT NULL, 12 | `timestamp` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), 13 | PRIMARY KEY (`employee_key`,`Datum`,`Dienstbeginn`), 14 | CONSTRAINT `Dienstplan_ibfk_1` FOREIGN KEY (`employee_key`) REFERENCES `employees` (`primary_key`) 15 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci 16 | -------------------------------------------------------------------------------- /phpinfo.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | phpinfo(); 21 | -------------------------------------------------------------------------------- /img/md_sick.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /img/md_face_3.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/sql/roster.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `roster` ( 2 | `roster_element_id` int(11) NOT NULL, 3 | `employee_key` int(10) unsigned NOT NULL, 4 | `date` date NOT NULL, 5 | `dtstart` datetime DEFAULT NULL, 6 | `dtend` datetime DEFAULT NULL, 7 | `Mittagsbeginn` time DEFAULT NULL, 8 | `Mittagsende` time DEFAULT NULL, 9 | `comment` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, 10 | `status` set('confirmed','cancelled','tentative','') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, 11 | `working_hours` float DEFAULT NULL, 12 | `branch_id` tinyint(3) unsigned NOT NULL DEFAULT 1, 13 | `user` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, 14 | `timestamp` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), 15 | PRIMARY KEY (`roster_element_id`) 16 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci 17 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | # This Dockerfile is not to be used in production! 2 | # It serves for development and testing purposes only. 3 | version: '3.8' 4 | 5 | services: 6 | web: 7 | build: . 8 | ports: 9 | - "${SECURE_WEB_PORT}:443" 10 | depends_on: 11 | - db 12 | environment: 13 | MYSQL_DATABASE: ${MYSQL_DATABASE} 14 | MYSQL_USER: ${MYSQL_USER} 15 | MYSQL_PASSWORD: ${MYSQL_PASSWORD} 16 | MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} 17 | #This database does not need volumes. Data shall not be persisted. 18 | # Tests are carried out with fresh data on every run. 19 | db: 20 | image: mysql:8.4 21 | environment: 22 | MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} 23 | MYSQL_DATABASE: ${MYSQL_DATABASE} 24 | MYSQL_USER: ${MYSQL_USER} 25 | MYSQL_PASSWORD: ${MYSQL_PASSWORD} 26 | command: --general-log --general-log-file=/var/lib/mysql/general.log 27 | -------------------------------------------------------------------------------- /src/sql/principle_roster.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `principle_roster` ( 2 | `primary_key` int(10) unsigned NOT NULL AUTO_INCREMENT, 3 | `alternating_week_id` tinyint(4) NOT NULL, 4 | `employee_key` int(10) unsigned NOT NULL, 5 | `weekday` tinyint(4) NOT NULL, 6 | `duty_start` time DEFAULT NULL, 7 | `duty_end` time DEFAULT NULL, 8 | `break_start` time DEFAULT NULL, 9 | `break_end` time DEFAULT NULL, 10 | `comment` text COLLATE utf8mb4_unicode_ci DEFAULT NULL, 11 | `working_hours` float DEFAULT NULL, 12 | `branch_id` tinyint(3) unsigned NOT NULL DEFAULT 1, 13 | PRIMARY KEY (`primary_key`), 14 | CONSTRAINT `principle_roster_ibfk_1` FOREIGN KEY (`employee_key`) REFERENCES `employees`(`primary_key`) ON DELETE RESTRICT ON UPDATE RESTRICT, 15 | CONSTRAINT `principle_roster_ibfk_2` FOREIGN KEY (`branch_id`) REFERENCES `branch`(`branch_id`) ON DELETE RESTRICT ON UPDATE RESTRICT 16 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci 17 | -------------------------------------------------------------------------------- /src/css/printOrientationPortrait.css: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2023 Mandelkow 3 | 4 | Dienstplan Apotheke 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU Affero General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU Affero General Public License for more details. 15 | 16 | You should have received a copy of the GNU Affero General Public License 17 | along with this program. If not, see . 18 | */ 19 | /** 20 | * Created on : 12.10.2023 21 | * Author : Mandelkow 22 | */ 23 | 24 | @page { 25 | size: A4; 26 | margin: 0.5cm; 27 | size: portrait !important; 28 | } 29 | -------------------------------------------------------------------------------- /src/sql/employees_archive.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `employees_archive` ( 2 | `row_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, 3 | `employee_key` int(10) UNSIGNED NOT NULL, 4 | `last_name` varchar(35) COLLATE utf8mb4_unicode_ci NOT NULL, 5 | `first_name` varchar(35) COLLATE utf8mb4_unicode_ci NOT NULL, 6 | `profession` set('Apotheker','PI','PTA','PKA','Praktikant','Kosmetiker','Zugehfrau') COLLATE utf8mb4_unicode_ci NOT NULL, 7 | `working_week_hours` float NOT NULL DEFAULT 38.5, 8 | `holidays` tinyint(11) NOT NULL DEFAULT 28, 9 | `lunch_break_minutes` tinyint(11) NOT NULL DEFAULT 30, 10 | `goods_receipt` tinyint(1) DEFAULT NULL, 11 | `compounding` tinyint(1) DEFAULT NULL, 12 | `branch` tinyint(3) UNSIGNED DEFAULT 1, 13 | `start_of_employment` date DEFAULT NULL, 14 | `end_of_employment` date DEFAULT NULL, 15 | `timestamp` timestamp NOT NULL DEFAULT current_timestamp(), 16 | PRIMARY KEY (`row_id`) 17 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; 18 | -------------------------------------------------------------------------------- /src/php/3rdparty/icalendar/includes/framework.php: -------------------------------------------------------------------------------- 1 | 7 | * @copyright Copyright (C) 2006 - 2017 by Dan Cogliano 8 | * @license GNU GPLv3 9 | * @link http://icalendar.org/php-library.html 10 | */ 11 | 12 | // No direct access 13 | defined('_ZAPCAL') or die( 'Restricted access' ); 14 | 15 | /** 16 | * set MAXYEAR to 2036 for 32 bit systems, can be higher for 64 bit systems 17 | * 18 | * @var integer 19 | */ 20 | define('_ZAPCAL_MAXYEAR', 2036); 21 | 22 | /** 23 | * set MAXREVENTS to maximum # of repeating events 24 | * 25 | * @var integer 26 | */ 27 | define('_ZAPCAL_MAXREVENTS', 5000); 28 | 29 | require_once(_ZAPCAL_BASE . '/includes/date.php'); 30 | require_once(_ZAPCAL_BASE . '/includes/recurringdate.php'); 31 | require_once(_ZAPCAL_BASE . '/includes/ical.php'); 32 | require_once(_ZAPCAL_BASE . '/includes/timezone.php'); 33 | -------------------------------------------------------------------------------- /src/sql/absence.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `absence` ( 2 | `employee_key` int(10) unsigned NOT NULL, 3 | `reason_id` tinyint(3) unsigned NOT NULL, 4 | `start` date NOT NULL, 5 | `end` date NOT NULL, 6 | `days` int(11) NOT NULL, 7 | `comment` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL, 8 | `approval` enum('approved','not_yet_approved','disapproved','changed_after_approval') CHARACTER SET utf8mb4 NOT NULL DEFAULT 'not_yet_approved', 9 | `user` varchar(64) CHARACTER SET utf8mb4 NOT NULL, 10 | `timestamp` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), 11 | PRIMARY KEY (`employee_key`,`start`), 12 | KEY `reason_id` (`reason_id`), 13 | CONSTRAINT `absence_ibfk_1` FOREIGN KEY (`reason_id`) REFERENCES `absence_reasons` (`id`) ON UPDATE CASCADE, 14 | CONSTRAINT `absence_ibfk_2` FOREIGN KEY (`employee_key`) REFERENCES `employees`(`primary_key`) ON DELETE RESTRICT ON UPDATE RESTRICT 15 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci 16 | -------------------------------------------------------------------------------- /src/php/pages/absence-read.php: -------------------------------------------------------------------------------- 1 | . 18 | */ 19 | require '../../../default.php'; 20 | $location = \PDR_HTTP_SERVER_APPLICATION_PATH . 'src/php/pages/absence-edit.php'; 21 | header('Location:' . $location); 22 | die("

Redirect to: $location

"); 23 | -------------------------------------------------------------------------------- /src/php/ajax/install.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | /* 21 | * The purpose of this file is to answer XMLHttpRequests from the installation pages. 22 | * These will be the validation of database parameters and the creation of users. 23 | * Data will be given as POST from the form fields. 24 | */ 25 | 26 | -------------------------------------------------------------------------------- /src/php/pages/install_head.php: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | Pharmacy Duty Roster 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/css/saturday_list.css: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2018 Martin Mandelkow 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with this program. If not, see . 16 | */ 17 | /* 18 | Created on : 24.08.2018, 20:58:57 19 | Author : Martin Mandelkow 20 | */ 21 | 22 | table#saturdayList tr td span.absent { 23 | color: red; 24 | text-decoration: underline; 25 | } 26 | table#saturdayList tr.saturday-list-row-holiday { 27 | font-style: italic; 28 | } 29 | -------------------------------------------------------------------------------- /src/sql/employees.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `employees` ( 2 | `primary_key` int(10) unsigned NOT NULL AUTO_INCREMENT, 3 | `last_name` varchar(35) COLLATE utf8mb4_unicode_ci NOT NULL, 4 | `first_name` varchar(35) COLLATE utf8mb4_unicode_ci NOT NULL, 5 | `profession` set('Apotheker','PI','PTA','PKA','Praktikant','Ernährungsberater','Kosmetiker','Zugehfrau') COLLATE utf8mb4_unicode_ci NOT NULL, 6 | `working_week_hours` float NOT NULL DEFAULT 40, 7 | `holidays` tinyint(11) NOT NULL DEFAULT 28, 8 | `lunch_break_minutes` tinyint(11) NOT NULL DEFAULT 30, 9 | `goods_receipt` tinyint(1) DEFAULT NULL, 10 | `compounding` tinyint(1) DEFAULT NULL, 11 | `branch` tinyint(3) unsigned NULL DEFAULT NULL, 12 | `start_of_employment` date DEFAULT NULL, 13 | `end_of_employment` date DEFAULT NULL, 14 | `timestamp` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), 15 | PRIMARY KEY (`primary_key`), 16 | CONSTRAINT `employees_ibfk_1` FOREIGN KEY (`branch`) REFERENCES `branch`(`branch_id`) ON DELETE RESTRICT ON UPDATE RESTRICT 17 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci 18 | -------------------------------------------------------------------------------- /src/php/pages/overtime-overview.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | require_once '../../../default.php'; 21 | 22 | require PDR_FILE_SYSTEM_APPLICATION_PATH . 'head.php'; 23 | require PDR_FILE_SYSTEM_APPLICATION_PATH . 'src/php/pages/menu.php'; 24 | 25 | $table = PDR\Output\HTML\OvertimeHtmlBuilder::buildOverviewTable(); 26 | echo $table; 27 | -------------------------------------------------------------------------------- /src/sql/users.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `users` ( 2 | `primary_key` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, 3 | `employee_key` int(10) unsigned NULL, 4 | `user_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, 5 | `email` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL, 6 | `password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, 7 | `status` set('deleted','blocked','inactive','active') COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'inactive', 8 | `failed_login_attempts` tinyint(3) unsigned NOT NULL DEFAULT 0, 9 | `failed_login_attempt_time` timestamp NULL DEFAULT NULL, 10 | `receive_emails_on_changed_roster` tinyint(1) NOT NULL DEFAULT 0, 11 | `created_at` timestamp NOT NULL DEFAULT current_timestamp(), 12 | `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), 13 | PRIMARY KEY (`primary_key`), 14 | UNIQUE KEY `user_name` (`user_name`), 15 | UNIQUE KEY `email` (`email`), 16 | CONSTRAINT `users_ibfk_1` FOREIGN KEY (`employee_key`) REFERENCES `employees` (`primary_key`) ON DELETE RESTRICT ON UPDATE RESTRICT 17 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci 18 | -------------------------------------------------------------------------------- /src/php/gettext.php: -------------------------------------------------------------------------------- 1 | . 18 | */ 19 | 20 | /* 21 | * This file is meant to be used by JavaScript. It will take a GET parameter string_to_translate and return the translated string. 22 | */ 23 | require_once '../../default.php'; 24 | 25 | //TODO: support for ngettext might be added. 26 | $string_to_translate = filter_input(INPUT_GET, 'string_to_translate', FILTER_SANITIZE_SPECIAL_CHARS); 27 | $translated_string = gettext($string_to_translate); 28 | echo $translated_string; 29 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | /* 20 | * Unfortunately we had a "301 Moved Permanently" to "tag-out.php" set on the old index.php 21 | * Therefore we have to keep that file there and make another redirect. 22 | * Some browsers might still take their users to the page "src/php/pages/roster-day-read.php" 23 | */ 24 | 25 | header("HTTP/1.1 307 Temporary Redirect"); 26 | header("Location: src/php/pages/menu-tiles.php"); 27 | exit(); 28 | ?> 29 | -------------------------------------------------------------------------------- /src/php/background_maintenance.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | /** 21 | * The purpose of this file is to be called in the background to do stuff once in a while. 22 | * It is called upon login() of any user for example. 23 | * It is the responsibility of the classes to check if there is work to do and how much. 24 | */ 25 | chdir(dirname(__DIR__, 2)); 26 | require_once 'bootstrap.php'; 27 | new update_database(); 28 | new maintenance(); 29 | //new auto_upgrader(); 30 | -------------------------------------------------------------------------------- /src/css/install_style.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | /* 3 | Copyright (C) 2017 Martin Mandelkow 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Affero General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Affero General Public License for more details. 14 | 15 | You should have received a copy of the GNU Affero General Public License 16 | along with this program. If not, see . 17 | */ 18 | /* 19 | Created on : 02.11.2017, 22:13:29 20 | Author : Mandelkow 21 | */ 22 | 23 | .install-info-postive{ 24 | color: green; 25 | margin-left: 2em; 26 | } 27 | .install-info-negative{ 28 | color: red; 29 | margin-left: 2em; 30 | } 31 | 32 | pre.install-cli { 33 | overflow: auto; 34 | padding: 1em; 35 | color: black; 36 | background-color: #F5F5F5; 37 | border: 1px solid #000000; 38 | border-radius: 3px; 39 | } 40 | div#errorMessageDiv{ 41 | color: red; 42 | } 43 | -------------------------------------------------------------------------------- /src/css/principle-roster-employee.css: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2019 Martin Mandelkow 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with this program. If not, see . 16 | */ 17 | /* 18 | Created on : 12.04.2019, 22:58:42 19 | Author : Martin Mandelkow 20 | */ 21 | 22 | form.change-principle-roster-employee-form { 23 | border: 5px solid #BDE682; 24 | margin-bottom: 1em; 25 | padding: 1em 1em 1em 1em; 26 | } 27 | form.change-principle-roster-employee-form:last-child { 28 | margin-bottom: 0em; 29 | } 30 | div.principle-roster-alternation-container { 31 | border: 2px solid #73AC22; 32 | margin-bottom: 1em; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/css/roster-day-edit.css: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2018 Martin Mandelkow 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with this program. If not, see . 16 | */ 17 | /* 18 | Created on : 25.07.2018, 10:57:02 19 | Author : Martin Mandelkow 20 | */ 21 | 22 | div#taskRotationSelectDiv { 23 | background-color: #ECE7E8; 24 | float: left; 25 | padding-top: 0.5em; 26 | padding-bottom: 2em; 27 | padding-left: 1em; 28 | padding-right: 1em; 29 | margin: 1em; 30 | } 31 | div.image-group-container { 32 | float: right; 33 | } 34 | 35 | div.user-dialog-container > div.warning > span > button > img{ 36 | height: 2em; 37 | vertical-align: middle; 38 | } 39 | -------------------------------------------------------------------------------- /src/php/3rdparty/icalendar/examples/recurringdate.php: -------------------------------------------------------------------------------- 1 | 7 | * @copyright Copyright (C) 2006 - 2017 by Dan Cogliano 8 | * @license GNU GPLv3 9 | * @link http://icalendar.org/php-library.html 10 | */ 11 | 12 | /** 13 | * Recurring Date Example 14 | * 15 | * Recurring date examples with RRULE property 16 | * 17 | */ 18 | 19 | require_once("../zapcallib.php"); 20 | 21 | $examples = 22 | array( 23 | array( 24 | "name" => "Abraham Lincon's birthday", 25 | "date" => "2015-02-12", 26 | "rule" => "FREQ=YEARLY;INTERVAL=1;BYMONTH=2;BYMONTHDAY=12" 27 | ), 28 | 29 | array( 30 | "name" => "Start of U.S. Supreme Court Session (1st Monday in October)", 31 | "date" => "2015-10-01", 32 | "rule" => "FREQ=YEARLY;INTERVAL=1;BYMONTH=10;BYDAY=1MO" 33 | ) 34 | ); 35 | 36 | // Use maxdate to limit # of infinitely repeating events 37 | $maxdate = strtotime("2021-01-01"); 38 | 39 | foreach($examples as $example) 40 | { 41 | echo $example["name"] . ":\n"; 42 | $rd = new ZCRecurringDate($example["rule"],strtotime($example["date"])); 43 | $dates = $rd->getDates($maxdate); 44 | foreach($dates as $d) 45 | { 46 | echo " " . date('l, F j, Y ',$d) . "\n"; 47 | } 48 | echo "\n"; 49 | } 50 | -------------------------------------------------------------------------------- /default.php: -------------------------------------------------------------------------------- 1 | . 18 | */ 19 | require_once 'bootstrap.php'; 20 | 21 | /* 22 | * session management 23 | */ 24 | $session = new sessions; 25 | 26 | /* 27 | * Guess the navigator (=browser) language from HTTP_ACCEPT_LANGUAGE: 28 | * This is used in the head.php 29 | */ 30 | $navigator_language = "de-DE"; //default language 31 | if (filter_has_var(INPUT_SERVER, 'HTTP_ACCEPT_LANGUAGE')) { 32 | $navigator_languages = preg_split('/[,;]/', filter_input(INPUT_SERVER, 'HTTP_ACCEPT_LANGUAGE', FILTER_SANITIZE_SPECIAL_CHARS)); 33 | $navigator_language = $navigator_languages[0]; //ignore the other options 34 | } 35 | -------------------------------------------------------------------------------- /pep.sh: -------------------------------------------------------------------------------- 1 | #Dieses Script soll die Daten aus dem PEP-Modul von Asys in die Datenbank 'Apotheke' einfügen. 2 | 3 | date #Das PHP-Script leitet den Output in die Datei "tmp/pep.log" um. Dort können wir dann sehen, welcher Eintrag zu welchem Datum gehört. 4 | 5 | #Das Passwort und die sonstigen Datanbank-Daten werden von php an dieses Script übergeben. 6 | database_user="$1" 7 | database_password="$2" 8 | database_name="$3" 9 | if [ "$database_user" != "" ] && [ "$database_password" != "" ] && [ "$database_name" != "" ] 10 | then 11 | echo "Alle Daten vorhanden." 12 | else 13 | echo "Es fehlen Zugangsdaten zur Datenbank." 14 | exit 1 15 | fi 16 | 17 | 18 | #Neueste Input Datei vom PEP-Modul: 19 | pepdatei="tmp/pep.txt" 20 | for asydatei in `ls -t upload/I*.asy` 21 | do 22 | #Das Datum muss gedreht werden von 31.12.2015 auf 2015-12-31. Anschließend werden nur die Spalten Datum, Zeit, Anzahl und Mandant genutzt. Umsatzzahlen gehen uns nichts an. 23 | sed -e 's/\([0-9]\{2\}\)\.\([0-9]\{2\}\)\.\([0-9]\{4\}\)/\3-\2-\1/' $asydatei | cut -d\; -f 1,2,4,6 > $pepdatei 24 | #Jetzt können wir die Daten in die Datenbank eintragen. 25 | mysqlimport \ 26 | --ignore-lines=0 \ 27 | --fields-terminated-by=\; \ 28 | --columns='Datum,Zeit,Anzahl,Mandant' \ 29 | --local -u "$database_user" -p"$database_password" "$database_name" \ 30 | $pepdatei \ 31 | && rm $pepdatei && rm $asydatei 32 | done 33 | 34 | php pep.php 35 | -------------------------------------------------------------------------------- /src/php/3rdparty/PHPMailer/Exception.php: -------------------------------------------------------------------------------- 1 | 9 | * @author Jim Jagielski (jimjag) 10 | * @author Andy Prevost (codeworxtech) 11 | * @author Brent R. Matzelle (original founder) 12 | * @copyright 2012 - 2017 Marcus Bointon 13 | * @copyright 2010 - 2012 Jim Jagielski 14 | * @copyright 2004 - 2009 Andy Prevost 15 | * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License 16 | * @note This program is distributed in the hope that it will be useful - WITHOUT 17 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 18 | * FITNESS FOR A PARTICULAR PURPOSE. 19 | */ 20 | 21 | namespace PHPMailer\PHPMailer; 22 | 23 | /** 24 | * PHPMailer exception handler. 25 | * 26 | * @author Marcus Bointon 27 | */ 28 | class Exception extends \Exception 29 | { 30 | /** 31 | * Prettify error message output. 32 | * 33 | * @return string 34 | */ 35 | public function errorMessage() 36 | { 37 | return '' . htmlspecialchars($this->getMessage()) . "
\n"; 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /src/php/fragments/fragment.saturdayRotationTeamsAddEmployee.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | require_once '../../../default.php'; 20 | $network_of_branch_offices = new \PDR\Pharmacy\NetworkOfBranchOffices(); 21 | $branch_id = user_input::get_variable_from_any_input('mandant', FILTER_SANITIZE_NUMBER_INT, $network_of_branch_offices->get_main_branch_id()); 22 | $team_id = user_input::get_variable_from_any_input('team_id', FILTER_SANITIZE_NUMBER_INT, 0); 23 | 24 | $saturday_rotation = new saturday_rotation($branch_id); 25 | $html_string = $saturday_rotation->buildSaturdayRotationTeamsAddEmployee($team_id, $branch_id, $session); 26 | 27 | echo $html_string; 28 | -------------------------------------------------------------------------------- /config/default_config.php: -------------------------------------------------------------------------------- 1 | . 18 | */ 19 | 20 | /* Die Konfiguration könnte über die Datei default.php eingelesen werden. */ 21 | $config = array( 22 | 'database_name' => "Apotheke", //Name der MySQL-Datenbank 23 | 'database_user' => "apotheke", //Name des Datenbankbenutzers 24 | 'application_name' => "Dienstplan Apotheke", //Für den Title des HTML HEAD 25 | 'LC_TIME' => "de_DE.utf8", 26 | 'mb_internal_encoding' => "UTF-8", 27 | 'error_reporting' => E_ALL, 28 | 'hide_disapproved' => false 29 | ); 30 | 31 | 32 | //Diese Datei kann später mit folgendem Befehl neu geschrieben werden: 33 | // file_put_contents('config/config.php', ' 7 | * @copyright Copyright (C) 2006 - 2017 by Dan Cogliano 8 | * @license GNU GPLv3 9 | * @link http://icalendar.org/php-library.html 10 | */ 11 | 12 | /** 13 | * Parse iCalendar Example 14 | * 15 | * Enter an ics filename or URL on the command line, 16 | * or leave blank to parse the default file. 17 | * 18 | */ 19 | 20 | require_once("../zapcallib.php"); 21 | 22 | $icalfile = count($argv) > 1 ? $argv[1] : "abrahamlincoln.ics"; 23 | $icalfeed = file_get_contents($icalfile); 24 | 25 | // create the ical object 26 | $icalobj = new ZCiCal($icalfeed); 27 | 28 | echo "Number of events found: " . $icalobj->countEvents() . "\n"; 29 | 30 | $ecount = 0; 31 | 32 | // read back icalendar data that was just parsed 33 | if(isset($icalobj->tree->child)) 34 | { 35 | foreach($icalobj->tree->child as $node) 36 | { 37 | if($node->getName() == "VEVENT") 38 | { 39 | $ecount++; 40 | echo "Event $ecount:\n"; 41 | foreach($node->data as $key => $value) 42 | { 43 | if(is_array($value)) 44 | { 45 | for($i = 0; $i < count($value); $i++) 46 | { 47 | $p = $value[$i]->getParameters(); 48 | echo " $key: " . $value[$i]->getValues() . "\n"; 49 | } 50 | } 51 | else 52 | { 53 | echo " $key: " . $value->getValues() . "\n"; 54 | } 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/php/classes/PDR/DateTime/DateTimeUtility.php: -------------------------------------------------------------------------------- 1 | . 20 | */ 21 | 22 | namespace PDR\DateTime; 23 | 24 | /** 25 | * Description of DateTimeUtility 26 | * 27 | * @author Mandelkow 28 | */ 29 | abstract class DateTimeUtility { 30 | 31 | /** 32 | * Convert time string to hours using DateTime class 33 | * 34 | * @param string $timeString 35 | * @return float time in hours 36 | */ 37 | public static function timeFromTextToFloat(string $timeString) { 38 | $time = \DateTime::createFromFormat('H:i:s', $timeString); 39 | $hour = (float) $time->format('H'); 40 | $minute = (float) $time->format('i'); 41 | $second = (float) $time->format('s'); 42 | $time_float = $hour + $minute / 60 + $second / 3600; 43 | return $time_float; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/php/pages/install_page_intro.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Introduction to PDR 7 | 8 | 9 |

Introduction

10 | 11 |

Welcome to PDR!

12 | 13 |

Pharmacy Duty Roster (PDR) is a web application designed to streamline and manage duty schedules for pharmacies effectively. It provides an alternative to traditional methods like excel sheets, offering user-friendly features while covering all necessary aspects of duty roster management.

14 | 15 |

PDR, initiated in 2015, aims to continuously improve based on user feedback. Your requests and wishes are valued contributions to its development, and it strives to meet your expectations.

16 | 17 |

These installation pages will guide you through the installation process of PDR. For more detailed instructions, please refer to the installation guide.

18 | 19 |

Please make sure to have at least PHP version 8.0 installed.

20 | 21 | 22 |
23 |

Select your preferred language:

24 | 28 | 29 | "> 30 |
31 | 32 | 33 | -------------------------------------------------------------------------------- /src/js/unsaved-changes-prompt.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023 Mandelkow 3 | * 4 | * Dienstplan Apotheke 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | // Variable to track if changes have been made. 21 | let changesMadeInForm = false; 22 | 23 | // Function to enable the unsaved changes prompt. 24 | function enableUnsavedChangesPrompt(formElement) { 25 | // Add an event listener to the window to display the confirmation message. 26 | window.addEventListener('beforeunload', function (e) { 27 | if (changesMadeInForm) { 28 | e.returnValue = "You have unsaved changes. Are you sure you want to leave?"; 29 | } 30 | }); 31 | 32 | // Add an event listener for form submission to reset the changesMade variable. 33 | var form = formElement; 34 | if (form) { 35 | form.addEventListener('submit', function () { 36 | console.log("I saw some submit"); 37 | changesMadeInForm = false; 38 | }); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/php/basic_access_authentication.php: -------------------------------------------------------------------------------- 1 | . 18 | */ 19 | const PDR_HTTP_401_UNAUTHORIZED_RESPONSE_TEXT = "

Unauthorized

This server could not verify that you are authorized to access the document you requested. Either you supplied the wrong credentials (e.g., bad password), or your browser doesn't understand how to supply the credentials required.

"; 20 | if (!isset($_SERVER['PHP_AUTH_USER'])) { 21 | header('WWW-Authenticate: Basic realm="PDR"'); 22 | header('HTTP/1.0 401 Unauthorized'); 23 | die(PDR_HTTP_401_UNAUTHORIZED_RESPONSE_TEXT); 24 | } else { 25 | $login_success = $session->login($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'], FALSE); 26 | if (TRUE !== $login_success) { 27 | header('WWW-Authenticate: Basic realm="PDR"'); 28 | header('HTTP/1.0 401 Unauthorized'); 29 | die(PDR_HTTP_401_UNAUTHORIZED_RESPONSE_TEXT); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/php/fragments/fragment.saturdayRotationTeamsAddTeam.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | require_once '../../../default.php'; 20 | $network_of_branch_offices = new \PDR\Pharmacy\NetworkOfBranchOffices(); 21 | $branch_id = user_input::get_variable_from_any_input('mandant', FILTER_SANITIZE_NUMBER_INT, $network_of_branch_offices->get_main_branch_id()); 22 | $team_id = user_input::get_variable_from_any_input('team_id', FILTER_SANITIZE_NUMBER_INT, 0); 23 | $saturday_date_string = user_input::get_variable_from_any_input('saturday_date_string', FILTER_SANITIZE_NUMBER_INT, (new DateTime("this saturday"))->format('Y-m-d')); 24 | $saturday_date_object = new DateTime($saturday_date_string); 25 | 26 | $saturday_rotation = new saturday_rotation($branch_id); 27 | $html_string = $saturday_rotation->buildSaturdayRotationTeamsAddTeam($team_id, $branch_id, $saturday_date_object, $session); 28 | 29 | echo $html_string; 30 | -------------------------------------------------------------------------------- /src/php/fragments/fragment.add_roster_input_row.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | require_once '../../../default.php'; 20 | $Roster = array(); 21 | $day_iterator = user_input::get_variable_from_any_input('day_iterator', FILTER_SANITIZE_NUMBER_INT); 22 | $roster_row_iterator = user_input::get_variable_from_any_input('roster_row_iterator', FILTER_SANITIZE_NUMBER_INT); 23 | $network_of_branch_offices = new \PDR\Pharmacy\NetworkOfBranchOffices; 24 | $maximum_number_of_rows = user_input::get_variable_from_any_input('maximum_number_of_rows', FILTER_SANITIZE_NUMBER_INT); 25 | $branch_id = user_input::get_variable_from_any_input('branch_id', FILTER_SANITIZE_NUMBER_INT, $network_of_branch_offices->get_main_branch_id()); 26 | 27 | $html_string = build_html_roster_views::build_roster_input_row($Roster, $day_iterator, $roster_row_iterator, $maximum_number_of_rows, $branch_id, array('add_select_employee')); 28 | echo $html_string; 29 | -------------------------------------------------------------------------------- /src/php/pages/remaining-vacation-overview.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | require_once '../../../default.php'; 21 | $year = user_input::get_variable_from_any_input('year', FILTER_SANITIZE_NUMBER_INT, date('Y')); 22 | \PDR\Utility\GeneralUtility::createCookie('year', $year, 1); 23 | if (isset($_POST) && !empty($_POST)) { 24 | // POST data has been submitted; PRG 25 | $location = PDR_HTTP_SERVER_APPLICATION_PATH . 'src/php/pages/remaining-vacation-overview.php' . "?year=$year"; 26 | header('Location:' . $location); 27 | die("

Redirect to: $location

"); 28 | } 29 | 30 | require PDR_FILE_SYSTEM_APPLICATION_PATH . 'head.php'; 31 | require PDR_FILE_SYSTEM_APPLICATION_PATH . 'src/php/pages/menu.php'; 32 | 33 | echo \form_element_builder::build_html_select_year($year); 34 | 35 | $vacationPageBuilder = new \PDR\Output\HTML\vacationPageBuilder; 36 | $table = $vacationPageBuilder->build_overview_table($year); 37 | echo $table; 38 | -------------------------------------------------------------------------------- /src/php/classes/PDR/Roster/OvertimeCollection.php: -------------------------------------------------------------------------------- 1 | . 20 | */ 21 | 22 | namespace PDR\Roster; 23 | 24 | /** 25 | * Description of OvertimeCollection 26 | * 27 | * @author Mandelkow 28 | * @implements \IteratorAggregate 29 | */ 30 | class OvertimeCollection implements \IteratorAggregate, \Countable { 31 | 32 | private array $listOfOvertimes = array(); 33 | 34 | public function addOvertime(\PDR\Roster\Overtime $overtime): void { 35 | $this->listOfOvertimes[] = $overtime; 36 | } 37 | 38 | /** 39 | * Implement the IteratorAggregate interface 40 | * 41 | * @return \ArrayIterator<\PDR\Roster\Overtime> 42 | */ 43 | public function getIterator(): \ArrayIterator { 44 | return new \ArrayIterator($this->listOfOvertimes); 45 | } 46 | 47 | /** 48 | * Implement the Countable interface 49 | * @return int 50 | */ 51 | public function count(): int { 52 | return count($this->listOfOvertimes); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/php/backup-database.php: -------------------------------------------------------------------------------- 1 | . 18 | */ 19 | 20 | require_once '../../default.php'; 21 | 22 | $sql_query = "SELECT TABLE_NAME FROM `information_schema`.`TABLES` WHERE `TABLE_SCHEMA` = :database_name"; 23 | $result = database_wrapper::instance()->run($sql_query, array('database_name' => $config['database_name'])); 24 | while ($row = $result->fetch(PDO::FETCH_OBJ)) { 25 | $Table_names[] = $row->TABLE_NAME; 26 | } 27 | 28 | foreach ($Table_names as $key => $table_name) { 29 | //This script lies within /src/php/ so therefore we have to move up by two levels: 30 | $dirname = str_replace('\\', '/', __DIR__); 31 | //$dir_above1 = substr($dirname, 0, strrpos($dirname, '/')); 32 | $dir_above2 = dirname(dirname($dirname)); 33 | 34 | $backup_file = $dir_above2 . "/tmp/$table_name.sql"; 35 | $file_name = iconv("UTF-8", "ISO-8859-1", $backup_file); //This is necessary for Microsoft Windows to recognise special chars. 36 | 37 | $sql_query = "SELECT * INTO OUTFILE :file_name FROM :table_name"; 38 | $result = database_wrapper::instance()->run($sql_query, array('file_name' => $file_name, 'table_name' => $table_name)); 39 | } 40 | -------------------------------------------------------------------------------- /src/css/emergency_service.css: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2018 Martin Mandelkow 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with this program. If not, see . 16 | */ 17 | /* 18 | Created on : 02.08.2018, 22:46:40 19 | Author : Martin Mandelkow 20 | */ 21 | 22 | table#emergencyServiceTable { 23 | clear: left; 24 | } 25 | table#emergencyServiceTable tr th { 26 | border-bottom: solid black 3px; 27 | } 28 | table#emergencyServiceTable tr td { 29 | border-left: none; 30 | border-right: none; 31 | border-bottom: none; 32 | } 33 | 34 | table#emergencyServiceTable td.saturday { 35 | font-weight: bold; 36 | } 37 | table#emergencyServiceTable td.sunday { 38 | font-style: italic; 39 | font-weight: bold; 40 | } 41 | table#emergencyServiceTable td.holiday { 42 | font-weight: normal; 43 | text-decoration: underline; 44 | } 45 | 46 | /** 47 | * Make the third column invisible on the screen: 48 | */ 49 | @media screen { 50 | table#emergencyServiceTable th.replacement-td { 51 | display: none; 52 | } 53 | table#emergencyServiceTable td.replacement-td { 54 | border: none; 55 | } 56 | @media print { 57 | table#emergencyServiceTable td.replacement-td { 58 | width: 10em; 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /src/php/classes/class.general_calculations.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | /** 21 | * Description of class 22 | * 23 | * @author Martin Mandelkow 24 | */ 25 | abstract class general_calculations { 26 | 27 | /** 28 | * Get the first day of the week. 29 | * 30 | * We aim for the monday of the given week. 31 | * Be aware though, that strtotime('Monday this week') on a sunday will return the monday, which follows the sunday. 32 | * This is desired for this application. 33 | * If this is not acceptable for you please consider: 34 | * https://gist.github.com/stecman/0203410aa4da0ef01ea9 35 | * 36 | * @param $date_sql string 37 | * @return $first_day_of_week_sql string 38 | * 39 | */ 40 | public static function get_first_day_of_week($date_sql = NULL) { 41 | 42 | if (NULL === $date_sql) { 43 | $date_sql = date('Y-m-d'); 44 | } 45 | $date_unix = strtotime('Monday this week', strtotime($date_sql)); 46 | $first_day_of_week_sql = date('Y-m-d', $date_unix); 47 | return $first_day_of_week_sql; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/php/pages/about.php: -------------------------------------------------------------------------------- 1 | . 17 | */ 18 | require '../../../default.php'; 19 | require PDR_FILE_SYSTEM_APPLICATION_PATH . 'head.php'; 20 | require PDR_FILE_SYSTEM_APPLICATION_PATH . 'src/php/pages/menu.php'; 21 | ?> 22 |
23 |

:

24 |

25 |

Version: 0.32.2

26 |

27 | License: Copyright © 2019, Martin Mandelkow 28 |

29 |

30 | This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. 31 |
32 | uses PHPMailer from the authors: Marcus Bointon, Jim Jagielski, Andy Prevostand and Brent R. Matzelle 33 |
34 | Also, find a list of included artwork. 35 | 36 |

37 |

Download source code

38 |
39 | 40 | 41 | -------------------------------------------------------------------------------- /src/php/3rdparty/icalendar/examples/simpleevent.php: -------------------------------------------------------------------------------- 1 | 7 | * @copyright Copyright (C) 2006 - 2017 by Dan Cogliano 8 | * @license GNU GPLv3 9 | * @link http://icalendar.org/php-library.html 10 | */ 11 | 12 | /** 13 | * Simple Event Example 14 | * 15 | * Create a simple iCalendar event 16 | * No time zone specified, so this event will be in UTC time zone 17 | * 18 | */ 19 | 20 | require_once("../zapcallib.php"); 21 | 22 | $title = "Simple Event"; 23 | // date/time is in SQL datetime format 24 | $event_start = "2020-01-01 12:00:00"; 25 | $event_end = "2020-01-01 13:00:00"; 26 | 27 | // create the ical object 28 | $icalobj = new ZCiCal(); 29 | 30 | // create the event within the ical object 31 | $eventobj = new ZCiCalNode("VEVENT", $icalobj->curnode); 32 | 33 | // add title 34 | $eventobj->addNode(new ZCiCalDataNode("SUMMARY:" . $title)); 35 | 36 | // add start date 37 | $eventobj->addNode(new ZCiCalDataNode("DTSTART:" . ZCiCal::fromSqlDateTime($event_start))); 38 | 39 | // add end date 40 | $eventobj->addNode(new ZCiCalDataNode("DTEND:" . ZCiCal::fromSqlDateTime($event_end))); 41 | 42 | // UID is a required item in VEVENT, create unique string for this event 43 | // Adding your domain to the end is a good way of creating uniqueness 44 | $uid = date('Y-m-d-H-i-s') . "@demo.icalendar.org"; 45 | $eventobj->addNode(new ZCiCalDataNode("UID:" . $uid)); 46 | 47 | // DTSTAMP is a required item in VEVENT 48 | $eventobj->addNode(new ZCiCalDataNode("DTSTAMP:" . ZCiCal::fromSqlDateTime())); 49 | 50 | // Add description 51 | $eventobj->addNode(new ZCiCalDataNode("Description:" . ZCiCal::formatContent( 52 | "This is a simple event, using the Zap Calendar PHP library. " . 53 | "Visit http://icalendar.org to validate icalendar files."))); 54 | 55 | // write iCalendar feed to stdout 56 | echo $icalobj->export(); 57 | 58 | -------------------------------------------------------------------------------- /src/php/3rdparty/icalendar/examples/timezoneevent.php: -------------------------------------------------------------------------------- 1 | 7 | * @copyright Copyright (C) 2006 - 2017 by Dan Cogliano 8 | * @license GNU GPLv3 9 | * @link http://icalendar.org/php-library.html 10 | */ 11 | 12 | /** 13 | * Create Event Example With Local Timezone 14 | * 15 | */ 16 | 17 | require_once("../zapcallib.php"); 18 | 19 | $title = "Event in New York timezone"; 20 | // date/time is in SQL datetime format 21 | $event_start = "2020-01-01 12:00:00"; 22 | $event_end = "2020-01-01 13:00:00"; 23 | // timezone must be a supported PHP timezone 24 | // (see http://php.net/manual/en/timezones.php ) 25 | // Note: multi-word timezones must use underscore "_" separator 26 | $tzid = "America/New_York"; 27 | 28 | // create the ical object 29 | $icalobj = new ZCiCal(); 30 | 31 | // Add timezone data 32 | ZCTimeZoneHelper::getTZNode(substr($event_start,0,4),substr($event_end,0,4),$tzid, $icalobj->curnode); 33 | 34 | // create the event within the ical object 35 | $eventobj = new ZCiCalNode("VEVENT", $icalobj->curnode); 36 | 37 | // add title 38 | $eventobj->addNode(new ZCiCalDataNode("SUMMARY:" . $title)); 39 | 40 | // add start date 41 | $eventobj->addNode(new ZCiCalDataNode("DTSTART:" . ZCiCal::fromSqlDateTime($event_start))); 42 | 43 | // add end date 44 | $eventobj->addNode(new ZCiCalDataNode("DTEND:" . ZCiCal::fromSqlDateTime($event_end))); 45 | 46 | // UID is a required item in VEVENT, create unique string for this event 47 | // Adding your domain to the end is a good way of creating uniqueness 48 | $uid = date('Y-m-d-H-i-s') . "@demo.icalendar.org"; 49 | $eventobj->addNode(new ZCiCalDataNode("UID:" . $uid)); 50 | 51 | // DTSTAMP is a required item in VEVENT 52 | $eventobj->addNode(new ZCiCalDataNode("DTSTAMP:" . ZCiCal::fromSqlDateTime())); 53 | 54 | // write iCalendar feed to stdout 55 | echo $icalobj->export(); 56 | 57 | -------------------------------------------------------------------------------- /src/php/classes/class.roster_item_empty.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | /** 21 | * Description of class 22 | * 23 | * @author Martin Mandelkow 24 | */ 25 | class roster_item_empty extends roster_item { 26 | 27 | public $date_sql; 28 | public $date_unix; 29 | public $employee_key; 30 | public $branch_id; 31 | public $comment; 32 | protected $duty_start_int; 33 | protected $duty_start_sql; 34 | protected $duty_end_int; 35 | protected $duty_end_sql; 36 | protected $break_start_int; 37 | protected $break_start_sql; 38 | protected $break_end_int; 39 | protected $break_end_sql; 40 | public $working_hours; 41 | public $break_duration; 42 | public $duty_duration; 43 | public $working_seconds; 44 | public $empty; 45 | 46 | public function __construct(string $date_sql, int $branch_id = NULL) { 47 | 48 | $this->empty = TRUE; 49 | $this->date_sql = $this->format_time_string_correct($date_sql, 'Y-m-d'); 50 | $this->date_object = new DateTime($date_sql); 51 | $this->date_unix = $this->date_object->getTimestamp(); 52 | $this->branch_id = $branch_id; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/css/user_dialog.css: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2018 Martin Mandelkow 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with this program. If not, see . 16 | */ 17 | /* 18 | Created on : 17.07.2018, 20:38:27 19 | Author : Martin Mandelkow 20 | */ 21 | 22 | div#userDialogContactFormDiv { 23 | display: none; 24 | position: fixed; 25 | left: 0; 26 | top: 0; 27 | width: 100%; 28 | height: 100%; 29 | background-color: rgba(0, 171, 231, 0.9); 30 | white-space: normal; 31 | padding: 1em; 32 | margin: auto; 33 | z-index: 99; 34 | } 35 | 36 | div#userDialogContactFormDiv form#contact_form { 37 | position: absolute; 38 | top: 50%; 39 | left: 50%; 40 | transform: translate(-50%, -50%); 41 | 42 | } 43 | 44 | div#userDialogContactFormDiv form#contact_form textarea { 45 | /*width: 320px;*/ 46 | width: 50vw; 47 | height: 50vh; 48 | } 49 | div#userDialogContactFormDiv form#contact_form p { 50 | margin: auto; 51 | } 52 | 53 | div#userDialogContactFormDiv #removeFormDivSpan { 54 | font-size: xx-large; 55 | color: black; 56 | background-color: white; 57 | padding: 1em; 58 | margin-right: 1em; 59 | position: absolute; 60 | top: 0; 61 | right: 0; 62 | } 63 | div#userDialogContactFormDiv #removeFormDivSpan:hover { 64 | color: white; 65 | background-color: red; 66 | } 67 | -------------------------------------------------------------------------------- /src/js/emergency-service-list.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 Martin Mandelkow 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | /** 19 | * 20 | * @param {type} element 21 | * @returns {undefined} 22 | */ 23 | function unhideButtonOnChange(element) { 24 | //console.log(element); 25 | //console.log(element.parentNode.parentNode); 26 | rowIndex = element.parentNode.parentNode.dataset.iterator; 27 | buttonSaveElement = document.getElementById("save_" + rowIndex); 28 | buttonDeleteElement = document.getElementById("delete_" + rowIndex); 29 | if (element.value !== element.defaultValue) { 30 | preventLeavingPage(); 31 | buttonSaveElement.style.display = "inline"; 32 | buttonDeleteElement.style.display = "none"; 33 | } else { 34 | enableLeavingPage(); 35 | buttonSaveElement.style.display = "none"; 36 | buttonDeleteElement.style.display = "inline"; 37 | } 38 | } 39 | function updateCommandAndSubmit(selectElement, rowNumber) { 40 | var form = selectElement.form; 41 | var commandValue = 'replace'; 42 | 43 | // Using getElementById to directly access the element by ID 44 | var commandInput = document.getElementById('command_' + rowNumber); 45 | 46 | if (commandInput) { 47 | commandInput.value = commandValue; 48 | form.submit(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /img/user_1.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml 43 | 46 | 49 | -------------------------------------------------------------------------------- /img/md_today-24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 20 | 22 | 23 | 25 | image/svg+xml 26 | 28 | 29 | 30 | 31 | 32 | 34 | 54 | 58 | 61 | 62 | -------------------------------------------------------------------------------- /src/php/classes/PDR/Roster/Overtime.php: -------------------------------------------------------------------------------- 1 | . 20 | */ 21 | 22 | namespace PDR\Roster; 23 | 24 | /** 25 | * An Overtime is the difference between actual hours worked and 26 | * expected hours for a given period, such as a day, week or month. 27 | * 28 | * In the context of PDR, an overtime is allways tied to a specific date. 29 | * In most cases, this is the last day of the week for which the sums of 30 | * actual hours worked and expected hours are compared. 31 | * 32 | * @author Mandelkow 33 | */ 34 | class Overtime { 35 | 36 | private int $employeeKey; 37 | private \DateTime $dateObject; 38 | private float $hours; 39 | private float $balance; 40 | 41 | public function __construct(int $employeeKey, \DateTime $dateObject, float $hours, float $balance = null) { 42 | $this->employeeKey = $employeeKey; 43 | $this->dateObject = $dateObject; 44 | $this->hours = $hours; 45 | $this->balance = $balance; 46 | } 47 | 48 | public function getEmployeeKey(): int { 49 | return $this->employeeKey; 50 | } 51 | 52 | public function getDate(): \DateTime { 53 | return $this->dateObject; 54 | } 55 | 56 | public function getHours(): float { 57 | return $this->hours; 58 | } 59 | 60 | public function getBalance(): float { 61 | return $this->balance; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Konfigurationsdateien, die für jeden Nutzer individuell sind # 2 | # Diese Daten sind zudem geheim, weil sie das Passwort enthalten. # 3 | ######################################################################### 4 | config/ 5 | 6 | # These files are for development purposes only: # 7 | ################################################## 8 | nbproject/ 9 | errorScreenshots/ 10 | 11 | # Dateien, die im Dienstplan erzeugt werden # 12 | ############################################# 13 | upload/ 14 | tmp/ 15 | *.ics 16 | *.csv 17 | 18 | # Dateien, die von Latex erzeugt werden. # 19 | ########################################## 20 | *.dvi 21 | *.aux 22 | *.log 23 | *.bak 24 | *.bbl 25 | *.blg 26 | *.out 27 | *.toc 28 | *.tks 29 | 30 | # Temporäre Dateien # 31 | ##################### 32 | *.*~ 33 | *.autosave 34 | 35 | 36 | # Compiled source # 37 | ################### 38 | *.com 39 | *.class 40 | *.dll 41 | *.exe 42 | *.o 43 | *.so 44 | 45 | # Packages # 46 | ############ 47 | # it's better to unpack these files and commit the raw source 48 | # git has its own built in compression methods 49 | *.7z 50 | *.dmg 51 | *.gz 52 | *.iso 53 | *.jar 54 | *.rar 55 | *.tar 56 | *.zip 57 | 58 | # Logs and databases # 59 | ###################### 60 | *.log 61 | *.sqlite 62 | 63 | # OS generated files # 64 | ###################### 65 | .DS_Store 66 | .DS_Store? 67 | ._* 68 | .Spotlight-V100 69 | .Trashes 70 | ehthumbs.db 71 | Thumbs.db 72 | /nbproject/private/ 73 | 74 | # Selenium Java Test Output # 75 | ###################### 76 | surefire-reports/ 77 | tests/selenium/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst 78 | *.lst 79 | tests/selenium/src/test/config.properties 80 | tests/selenium/src/test/Configuration.properties 81 | *.properties 82 | .vs/ 83 | .vscode/ 84 | *.prefs 85 | target/ 86 | tests/selenium/.project_old 87 | tests/selenium/.classpath_old 88 | tests/selenium/nb-configuration.xml 89 | tests/selenium/.project 90 | tests/selenium/.classpath 91 | tests/selenium/test-output/ 92 | tests/selenium/failed_test_page.html 93 | tests/selenium/test-result 94 | .project 95 | /scripts/mockup-database.sh 96 | # Docker secrets 97 | .env 98 | -------------------------------------------------------------------------------- /scripts/restart_docker_container.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Function to restart or run a container 4 | manage_container() { 5 | local IMAGE_NAME="$1" 6 | local RUN_COMMAND="$2" 7 | 8 | # Find the container ID based on the image name 9 | local CONTAINER_ID=$(docker ps -q --filter "ancestor=$IMAGE_NAME") 10 | 11 | # Check if a container was found and restart or run it 12 | if [ -z "$CONTAINER_ID" ]; then 13 | echo "No container found for image: $IMAGE_NAME" 14 | eval "$RUN_COMMAND" 15 | else 16 | echo "Restarting container ID: $CONTAINER_ID" 17 | docker stop "$CONTAINER_ID" 18 | docker start "$CONTAINER_ID" 19 | fi 20 | 21 | # Display the status of the container 22 | docker ps --filter "id=$CONTAINER_ID" 23 | } 24 | 25 | # Prepare the shared downloads directory with appropriate permissions 26 | mkdir -p /tmp/selenium/shared_downloads 27 | chmod o+w /tmp/selenium/ -R 28 | chmod o+w /tmp/selenium/shared_downloads -R 29 | 30 | # Start/restart Selenium container 31 | # -p 4444:4444 -> Exposes the Selenium WebDriver port, allowing your tests to connect to the Selenium server. 32 | # -p 7900:7900 -> Exposes the VNC server port, which allows you to view the browser running your tests in real-time using a VNC viewer. 33 | # -p 5900:5900 -> Another VNC server port, used by some configurations or can be an alternative VNC access point. 34 | # --shm-size="2g" -> Increases the shared memory size to 2 GB, which is important for running browsers inside the container to avoid out-of-memory issues. 35 | # -v /tmp/selenium/shared_downloads:/home/seluser/Downloads -> Mounts the shared downloads directory so that files downloaded during tests are accessible on your host machine. 36 | manage_container "dienstplan_selenium" "docker run -d -p 4444:4444 -p 7900:7900 -p 5900:5900 --shm-size='2g' -v /tmp/selenium/shared_downloads:/home/seluser/Downloads dienstplan_selenium" 37 | 38 | # Start/restart MailHog container 39 | # A simple SMTP server that captures emails and provides a web interface to view them. 40 | # the SMTP server starts on port 1025 41 | # the HTTP server starts on port 8025 42 | manage_container "mailhog/mailhog" "docker run -d -p 1025:1025 -p 8025:8025 mailhog/mailhog" 43 | -------------------------------------------------------------------------------- /img/md_card_travel-24px.svg: -------------------------------------------------------------------------------- 1 | 2 | 20 | 22 | 23 | 25 | image/svg+xml 26 | 28 | 29 | 30 | 31 | 32 | 34 | 54 | 58 | 61 | 62 | -------------------------------------------------------------------------------- /src/css/print.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @page { 3 | size: A4; 4 | margin: 0.5cm; 5 | size: landscape; 6 | /* 7 | */ 8 | } 9 | div { 10 | /* 11 | margin: 3px; 12 | border: 1px solid #FF0000; 13 | */ 14 | } 15 | a, body { 16 | /* 17 | zoom: 70%; 18 | */ 19 | color: #000000; /*!important;*/ 20 | } 21 | select { 22 | color: #000000; 23 | -webkit-appearance: none; 24 | border: none; 25 | } 26 | .no-print, .no-print * { 27 | /*Elemente die nicht gedruckt werden sollen.*/ 28 | display: none !important; 29 | } 30 | .only-print { 31 | display: block; 32 | } 33 | .page-break { 34 | display: block; 35 | page-break-before: always; 36 | } 37 | tr.wochenende { 38 | -webkit-print-color-adjust: exact; 39 | } 40 | #mainArea { 41 | width: 29.7cm; 42 | /* 43 | height: available; 44 | height: 19.0cm; 45 | */ 46 | } 47 | div#tableOverlayArea { 48 | top: 0.5cm; /*equals margin-top on @page*/ 49 | float: left; 50 | padding-left: 0px; 51 | margin-left: 0px; 52 | transform: translateX(-10mm) translateY(-10mm) scale(.9) ; 53 | width: 23.7cm; 54 | /* 55 | height: 19.0cm; 56 | */ 57 | } 58 | div#weeklyRotation { 59 | position: fixed; 60 | top: 0cm; 61 | right: 0cm; 62 | width: 4cm; 63 | font-size: xx-small; 64 | } 65 | div#weekHoursTableDiv { 66 | position: fixed; 67 | bottom: 2cm; 68 | right: 0cm; 69 | width: 5.2cm; 70 | font-size: xx-small; 71 | } 72 | table#dutyRosterTable { 73 | width: 85%; 74 | font-size: 3.5mm; 75 | } 76 | #rosterImageDiv { 77 | width: 50%; 78 | height: 100%; 79 | } 80 | #rosterImageDiv svg, #rosterImageDiv canvas { 81 | width: 99%; 82 | height: 48%; 83 | } 84 | strong { 85 | font-style: italic; 86 | } 87 | svg foreignObject p { 88 | border: 1px solid black; 89 | } 90 | /* 91 | * The following styles are for: 92 | * marginal-employment-hours-list.php 93 | */ 94 | table#marginalEmploymentHoursListTable tr td { 95 | min-width: 8em; 96 | } 97 | /* 98 | * The preceding styles are for: 99 | * marginal-employment-hours-list.php 100 | */ 101 | -------------------------------------------------------------------------------- /src/php/pages/menu-tiles.php: -------------------------------------------------------------------------------- 1 | . 17 | */ 18 | require_once '../../../default.php'; 19 | require_once PDR_FILE_SYSTEM_APPLICATION_PATH . 'head.php'; 20 | require_once PDR_FILE_SYSTEM_APPLICATION_PATH . 'src/php/pages/menu.php'; 21 | ?> 22 | 40 | -------------------------------------------------------------------------------- /src/php/pages/lost_password.php: -------------------------------------------------------------------------------- 1 | . 17 | */ 18 | require '../../../default.php'; 19 | 20 | if (filter_has_var(INPUT_GET, 'request_new_password')) { 21 | $token = sha1(uniqid()); 22 | $identifier = filter_input(INPUT_POST, 'identifier', FILTER_SANITIZE_SPECIAL_CHARS); 23 | $user_dialog = new user_dialog(); 24 | if (!empty($identifier)) { 25 | $user_base = new \PDR\Workforce\user_base(); 26 | $user = $user_base->guess_user_by_identifier($identifier); 27 | if (FALSE !== $user and $user instanceof user) { 28 | $session->write_lost_password_token_to_database($user, $token); 29 | $session->send_mail_about_lost_password($user, $token); 30 | } 31 | unset($token); 32 | $user_dialog->add_message(gettext("If the user exists, an email has been sent."), E_USER_NOTICE); 33 | } 34 | } 35 | require PDR_FILE_SYSTEM_APPLICATION_PATH . "/head.php"; 36 | 37 | echo "
"; 38 | if (isset($config['application_name'])) { 39 | $application_name = $config['application_name']; 40 | } else { 41 | $application_name = 'PDR'; 42 | } 43 | 44 | echo "

" . $application_name . "

\n"; 45 | ?> 46 | 47 |
48 |

49 | ">
50 |
51 | build_messages(); 54 | ?> 55 |
56 |
57 | 58 | 59 | -------------------------------------------------------------------------------- /src/php/restful-api/authentication/POST-authenticate.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | require_once '../../../../bootstrap.php'; 21 | // Set the maximum allowed content length 22 | $maxContentLength = 1024 * 1024; // 1 MB, adjust as needed 23 | // Read the raw JSON data from the request body, limiting the content length 24 | $jsonData = file_get_contents("php://input", false, null, 0, $maxContentLength + 1); 25 | 26 | // Check if the content length exceeds the limit 27 | if (strlen($jsonData) > $maxContentLength) { 28 | // Handle the request with excessive content length 29 | echo json_encode(['error' => 'Request payload too large']); 30 | exit; 31 | } 32 | // Decode JSON data 33 | $data = json_decode($jsonData, true); 34 | 35 | if ($data === null && json_last_error() !== JSON_ERROR_NONE) { 36 | // Handle JSON decoding error 37 | echo json_encode(['error' => 'Invalid JSON data']); 38 | exit; 39 | } 40 | 41 | // Validate and sanitize user_name and user_password 42 | $userName = filter_var($data['userName'] ?? '', FILTER_SANITIZE_SPECIAL_CHARS); 43 | $userPassphrase = filter_var($data['userPassphrase'] ?? '', FILTER_SANITIZE_SPECIAL_CHARS); 44 | 45 | // Assuming you have a class/method for user authentication 46 | $session = new sessions(); 47 | $session->login($userName, $userPassphrase, FALSE); 48 | 49 | if ($session->user_is_logged_in()) { 50 | // Generate and return an access token 51 | $accessToken = $session->generateAccessToken($session->getUserObject()); 52 | echo json_encode(['accessToken' => $accessToken]); 53 | } else { 54 | // Handle authentication failure 55 | echo json_encode(['error' => 'Authentication failed']); 56 | } 57 | -------------------------------------------------------------------------------- /webdav.php: -------------------------------------------------------------------------------- 1 | . 18 | */ 19 | 20 | /* 21 | * We are creating an iCalendar file (*.ics). This file can be read by calendaring applications. 22 | */ 23 | 24 | require_once 'default.php'; 25 | if (!isset($_SESSION['user_object']) or null === $_SESSION['user_object']->get_primary_key()) { 26 | require_once PDR_FILE_SYSTEM_APPLICATION_PATH . '/src/php/basic_access_authentication.php'; 27 | } 28 | /* 29 | * @var $days_into_the_future int Number of days into the future. The roster for this number of consecutive days will be added to the iCalendar file. 30 | */ 31 | $days_into_the_future = user_input::get_variable_from_any_input('days_into_the_future', FILTER_SANITIZE_SPECIAL_CHARS, 30); 32 | $date_string = user_input::get_variable_from_any_input('date_string', FILTER_SANITIZE_SPECIAL_CHARS, date('Y-m-d')); 33 | $date_start_object = new \DateTime($date_string); 34 | $workforce = new workforce($date_string); 35 | $employee_key = user_input::get_variable_from_any_input('employee_key', FILTER_SANITIZE_NUMBER_INT, $workforce->get_default_employee_key()); 36 | $create_valarm = user_input::get_variable_from_any_input('create_valarm', FILTER_SANITIZE_NUMBER_INT, 0); 37 | $date_end_object = clone $date_start_object; 38 | $date_end_object->add(new \DateInterval('P' . $days_into_the_future . 'D')); 39 | $roster_object = new roster(clone $date_start_object, clone $date_end_object, $employee_key, NULL); 40 | $Roster = $roster_object->array_of_days_of_roster_items; 41 | header('Content-type: text/Calendar; charset=UTF-8'); 42 | header('Content-Disposition: attachment; filename="Calendar.ics"'); 43 | $iCalendarFileContentString = iCalendar::build_ics_roster_employee($Roster, $create_valarm); 44 | echo $iCalendarFileContentString; 45 | -------------------------------------------------------------------------------- /src/php/pages/maintenance_write_gettext_for_javascript.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | require_once '../../../default.php'; 21 | $Javascript_files = glob(PDR_FILE_SYSTEM_APPLICATION_PATH . 'src/js/*.js'); 22 | $Strings_to_translate = array(); 23 | $match = ''; 24 | foreach ($Javascript_files as $javascript_file) { 25 | $fh = fopen($javascript_file, 'r'); 26 | while (FALSE !== ($line = fgets($fh))) { 27 | preg_match('/gettext\s*\((.*)\)\s*;/u', $line, $match); 28 | if (!empty($match)) { 29 | $Strings_to_translate[] = trim(trim(trim($match[1]), '"'), "'"); 30 | } 31 | } 32 | fclose($fh); 33 | } 34 | /** 35 | * @todo test this new glob 36 | */ 37 | $Localization_folders = glob(PDR_FILE_SYSTEM_APPLICATION_PATH . 'locale/[a-z][a-z]_[A-Z][A-Z]', GLOB_ONLYDIR); 38 | foreach ($Localization_folders as $localization_folder) { 39 | $localization = basename($localization_folder); 40 | localization::initialize_gettext($localization); 41 | foreach ($Strings_to_translate as $string_to_translate) { 42 | $translated_string = localization::gettext($string_to_translate); 43 | if ($translated_string !== $string_to_translate) { 44 | /* 45 | * The string only gets inserted, if a translation is existent. 46 | */ 47 | $Translations[$localization][$string_to_translate] = $translated_string; 48 | } 49 | } 50 | } 51 | if (!empty($Translations)) { 52 | $json_string = 'var pdr_translations = ' . json_encode($Translations, JSON_UNESCAPED_UNICODE) . ';' . PHP_EOL; 53 | $result = file_put_contents(PDR_FILE_SYSTEM_APPLICATION_PATH . 'src/js/translations.js', $json_string); 54 | } 55 | -------------------------------------------------------------------------------- /src/css/overtime.css: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2018 Martin Mandelkow 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with this program. If not, see . 16 | */ 17 | /* 18 | Created on : 08.07.2018, 23:34:55 19 | Author : Martin Mandelkow 20 | */ 21 | 22 | table#overtimeOverviewTable tr.negative { 23 | color: #E6828B; 24 | font-style: normal; 25 | font-weight: normal; 26 | } 27 | table#overtimeOverviewTable tr.positive { 28 | color: #73AC22; 29 | font-style: italic; 30 | font-weight: normal; 31 | } 32 | table#overtimeOverviewTable tr.positive-high { 33 | color: #73AC22; 34 | font-style: normal; 35 | font-weight: bold; 36 | } 37 | table#overtimeOverviewTable tr.not-updated { 38 | background-color: #ECE7E8; 39 | text-decoration: underline; 40 | } 41 | table#overtimeOverviewTable tr.positive-very-high { 42 | color: #73AC22; 43 | font-style: oblique; 44 | font-weight: bold; 45 | font-size: larger; 46 | } 47 | table#overtimeOverviewTable tr.zero { 48 | color: #000000; 49 | font-style: normal; 50 | font-weight: normal; 51 | } 52 | 53 | html body div#mainArea table tbody tr td input[readOnly] { 54 | background-color: transparent; 55 | border: none; 56 | color: inherit; /* Inherit text color from parent */ 57 | font-size: inherit; /* Inherit font size from parent */ 58 | cursor: default; 59 | padding: 0; /* Remove any padding */ 60 | width: auto; /* Adjust width to fit content */ 61 | -webkit-appearance: none; /* Remove default input styling for Safari */ 62 | -moz-appearance: textfield; 63 | appearance: textfield; /* Remove arrows for disabled number inputs */ 64 | } 65 | /* Remove arrows for disabled number inputs in Chrome, Safari, Edge, and Opera */ 66 | input[type=number][readOnly]::-webkit-outer-spin-button, 67 | input[type=number][readOnly]::-webkit-inner-spin-button { 68 | -webkit-appearance: none; 69 | margin: 0; 70 | } 71 | -------------------------------------------------------------------------------- /src/php/classes/class.principle_roster_item.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | /** 21 | * A principle roster item is similar to a roster_item. 22 | * 23 | *

The difference is, that a principle_roster_item is not bound to a specific date.

24 | * 25 | * @author Mandelkow 26 | */ 27 | class principle_roster_item extends roster_item { 28 | 29 | /** 30 | * 31 | * @var int

primary key in the database

32 | * @todo

The class roster_item might get a primary_key too. 33 | * When that happens, this declaration is probably not neccessary anymore.

34 | */ 35 | public $primary_key; 36 | 37 | /** 38 | * 39 | * @param int $primary_key 40 | * @param string $date_sql 41 | * @param int $employee_key 42 | * @param int $branch_id 43 | * @param string $duty_start 44 | * @param string $duty_end 45 | * @param string $break_start 46 | * @param string $break_end 47 | * @param string $comment 48 | * @throws \InvalidArgumentException 49 | */ 50 | public function __construct(int $primary_key = NULL, string $date_sql, int $employee_key = NULL, int $branch_id, string $duty_start, string $duty_end, string $break_start = NULL, string $break_end = NULL, string $comment = NULL) { 51 | /** 52 | *

TODO: Ich weiß nicht mehr, warum der key nicht null sein darf.

53 | if (NULL === $primary_key) { 54 | throw new \InvalidArgumentException('$primary_key MUST NOT be NULL'); 55 | } 56 | */ 57 | $this->primary_key = $primary_key; 58 | parent::__construct($date_sql, $employee_key, $branch_id, $duty_start, $duty_end, $break_start, $break_end, $comment); 59 | } 60 | 61 | public function get_primary_key() { 62 | return $this->primary_key; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/php/pages/upload-pep.php: -------------------------------------------------------------------------------- 1 | . 17 | */ 18 | 19 | //TODO: drei Graphen mit den jeweils aktuellen pep Zahlen .; 20 | require "../../../default.php"; 21 | require PDR_FILE_SYSTEM_APPLICATION_PATH . 'head.php'; 22 | require PDR_FILE_SYSTEM_APPLICATION_PATH . 'src/php/pages/menu.php'; 23 | $user_dialog = new user_dialog(); 24 | $session->exit_on_missing_privilege('administration'); 25 | if (isset($_FILES['file_to_upload']['name'])) { 26 | $pepUploadHandler = new PDR\Input\PepUploadHandler; 27 | $pepUploadHandler->handleFileUpload(); 28 | } 29 | ?> 30 |

31 |
32 |
33 |
34 |
35 |
36 |

37 | build_messages(); 39 | $histogramm = new \pep_histogramm(); 40 | $Expectation_javascripft_object = $histogramm->get_expectation_javascript_object(1); 41 | echo "
"; 42 | echo "
"; 43 | $canvas_width = 650; 44 | $canvas_height = 300; 45 | echo $histogramm->get_last_update_of_pep_data_date_string(); 46 | echo "\n Your browser does not support the HTML5 canvas tag.\n \n"; 47 | ?> 48 | 49 | 50 |
51 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /img/information.svg: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 21 | 23 | image/svg+xml 24 | 26 | 27 | 28 | 29 | 31 | 51 | 58 | 61 | 62 | 65 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /src/php/pages/collaborative-vacation-year.php: -------------------------------------------------------------------------------- 1 | . 17 | */ 18 | require_once "../../../default.php"; 19 | $year = \user_input::get_variable_from_any_input('year', FILTER_SANITIZE_NUMBER_INT, date("Y")); 20 | $month_number = \user_input::get_variable_from_any_input('month_number', FILTER_SANITIZE_NUMBER_INT, date("n")); 21 | $dateStartObject = new DateTime("$year-01-01"); 22 | $dateEndObject = new DateTime("$year-12-31"); 23 | $workforce = new workforce($dateStartObject->format("Y-m-d"), $dateEndObject->format("Y-m-d")); 24 | $employee_key = user_input::get_variable_from_any_input('employee_key', FILTER_SANITIZE_NUMBER_INT, $workforce->get_default_employee_key()); 25 | \PDR\Utility\GeneralUtility::createCookie('month_number', $month_number, 1); 26 | \PDR\Utility\GeneralUtility::createCookie('year', $year, 1); 27 | \PDR\Utility\GeneralUtility::createCookie('employee_key', $employee_key, 1); 28 | $collaborative_vacation = new collaborative_vacation(); 29 | $collaborative_vacation->handle_user_data_input($session); 30 | if (isset($_POST) && !empty($_POST)) { 31 | // POST data has been submitted 32 | $location = PDR_HTTP_SERVER_APPLICATION_PATH . 'src/php/pages/collaborative-vacation-year.php' . "?year=$year&month_number=$month_number&employee_key=$employee_key"; 33 | header('Location:' . $location); 34 | die("

Redirect to: $location

"); 35 | } 36 | 37 | 38 | require PDR_FILE_SYSTEM_APPLICATION_PATH . 'head.php'; 39 | require PDR_FILE_SYSTEM_APPLICATION_PATH . 'src/php/pages/menu.php'; 40 | $session->exit_on_missing_privilege('request_own_absence'); //TODO: Handle non existing rights without exit! 41 | 42 | echo "
"; 43 | echo "\n"; 44 | echo $collaborative_vacation->build_absence_year($year, $workforce); 45 | require PDR_FILE_SYSTEM_APPLICATION_PATH . 'src/php/fragments/fragment.footer.php'; 46 | ?> 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/php/pages/collaborative-vacation-month.php: -------------------------------------------------------------------------------- 1 | . 17 | */ 18 | require_once "../../../default.php"; 19 | $year = \user_input::get_variable_from_any_input('year', FILTER_SANITIZE_NUMBER_INT, date("Y")); 20 | $month_number = \user_input::get_variable_from_any_input('month_number', FILTER_SANITIZE_NUMBER_INT, date("n")); 21 | $dateStartObject = new DateTime("$year-01-01"); 22 | $dateEndObject = new DateTime("$year-12-31"); 23 | $workforce = new workforce($dateStartObject->format("Y-m-d"), $dateEndObject->format("Y-m-d")); 24 | $employee_key = user_input::get_variable_from_any_input('employee_key', FILTER_SANITIZE_NUMBER_INT, $workforce->get_default_employee_key()); 25 | \PDR\Utility\GeneralUtility::createCookie('month_number', $month_number, 1); 26 | \PDR\Utility\GeneralUtility::createCookie('year', $year, 1); 27 | \PDR\Utility\GeneralUtility::createCookie("employee_key", $employee_key, 30); 28 | //require_once PDR_FILE_SYSTEM_APPLICATION_PATH . "src/php/collaborative-vacation.php"; 29 | $collaborative_vacation = new collaborative_vacation(); 30 | $collaborative_vacation->handle_user_data_input($session); 31 | if (isset($_POST) && !empty($_POST)) { 32 | // POST data has been submitted 33 | $location = PDR_HTTP_SERVER_APPLICATION_PATH . 'src/php/pages/collaborative-vacation-month.php' . "?year=$year&month_number=$month_number&employee_key=$employee_key"; 34 | header('Location:' . $location); 35 | die("

Redirect to: $location

"); 36 | } 37 | require PDR_FILE_SYSTEM_APPLICATION_PATH . 'head.php'; 38 | require PDR_FILE_SYSTEM_APPLICATION_PATH . 'src/php/pages/menu.php'; 39 | $session->exit_on_missing_privilege('request_own_absence'); 40 | 41 | echo "
"; 42 | echo "\n"; 43 | echo $collaborative_vacation->build_absence_month($year, $month_number); 44 | require PDR_FILE_SYSTEM_APPLICATION_PATH . 'src/php/fragments/fragment.footer.php'; 45 | ?> 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/php/restful-api/roster/GET-roster.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | require_once '../../../../bootstrap.php'; 21 | /** 22 | * We create a session object. 23 | * Normally this is only possible in a logged in state or on the login page. 24 | * But in this case we will authorize via access token. 25 | * Therefore we create the session object and $allowUnauthorized. 26 | */ 27 | $allowUnauthorized = true; 28 | $session = new sessions($allowUnauthorized); 29 | $session->verifyAccessToken(); 30 | /** 31 | * Get input data from GET: 32 | */ 33 | $dateStartString = \user_input::getVariableFromSpecificInput('dateStart', INPUT_GET, FILTER_SANITIZE_SPECIAL_CHARS, (new DateTime('now'))->format("Y-m-d")); 34 | $dateEndString = \user_input::getVariableFromSpecificInput('dateEnd', INPUT_GET, FILTER_SANITIZE_SPECIAL_CHARS, $dateStartString); 35 | $workforce = new \workforce($dateStartString, $dateEndString); 36 | $defaultEmployeeKey = $workforce->get_default_employee_key(); 37 | $defaultEmployeeFullName = $workforce->getEmployeeFullName($defaultEmployeeKey); 38 | $employeeFullName = \user_input::getVariableFromSpecificInput('employeeFullName', INPUT_GET, FILTER_SANITIZE_SPECIAL_CHARS, $defaultEmployeeFullName); 39 | $employeeKey = $workforce->getKeyByFullName($employeeFullName); 40 | 41 | /** 42 | * Fetch the roster data from the database or any other source 43 | */ 44 | $startDate = new DateTime($dateStartString); 45 | $endDate = new DateTime($dateEndString); 46 | //$branch_id = 1; 47 | 48 | try { 49 | $roster = new roster($startDate, $endDate, $employeeKey); 50 | //$roster = roster::read_roster_from_database($branch_id, $startDate->format('Y-m-d'), $endDate->format('Y-m-d')); 51 | $rosterData = $roster->encodeToJson(); 52 | echo $rosterData; 53 | } catch (Exception $e) { 54 | /** 55 | * Handle exceptions, e.g., log the error or send an error response 56 | */ 57 | PDR\Utility\GeneralUtility::printDebugVariable($e->getMessage()); 58 | echo json_encode(['error' => $e->getMessage()]); 59 | } 60 | -------------------------------------------------------------------------------- /src/js/user_dialog.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Martin Mandelkow 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | 19 | /** 20 | * Displays the element "contact_form". 21 | * 22 | * @returns void 23 | */ 24 | function unhide_contact_form() { 25 | document.getElementById("userDialogContactFormDiv").style.display = "inline"; 26 | } 27 | function hide_contact_form() { 28 | document.getElementById("userDialogContactFormDiv").style.display = "none"; 29 | } 30 | 31 | function writeErrorToUserDialogContainer(errorString, errorId = null) { 32 | if (document.getElementById(errorId)) { 33 | /** 34 | * This exact error allready exists. We will not create it again. 35 | */ 36 | return null; 37 | } 38 | /** 39 | * Create paragraph: 40 | */ 41 | var p = document.createElement("p"); 42 | p.innerText = errorString; 43 | /** 44 | * Create div to contain the paragraph: 45 | */ 46 | var div = document.createElement("div"); 47 | div.appendChild(p); 48 | div.classList.add("error"); 49 | div.id = errorId; 50 | /** 51 | * 52 | * Add div to the user-dialog-container: 53 | */ 54 | var listOfUserDialogContainers = document.getElementsByClassName("user-dialog-container"); 55 | var userDialogContainer = listOfUserDialogContainers[0]; 56 | userDialogContainer.appendChild(div); 57 | } 58 | 59 | function removeErrorFromUserDialogContainer(errorId) { 60 | var errorElement = document.getElementById(errorId); 61 | if (null === errorElement) { 62 | /** 63 | * This error div does not exist. There is nothing to be removed. 64 | */ 65 | return false; 66 | } 67 | /** 68 | *

69 | * This function does not delete every element by id. 70 | * Only direct children of user-dialog-container are removed. 71 | *

72 | */ 73 | var listOfUserDialogContainers = document.getElementsByClassName("user-dialog-container"); 74 | var userDialogContainer = listOfUserDialogContainers[0]; 75 | userDialogContainer.removeChild(errorElement); 76 | } 77 | -------------------------------------------------------------------------------- /src/php/classes/PDR/Roster/EmergencyService.php: -------------------------------------------------------------------------------- 1 | . 20 | */ 21 | 22 | namespace PDR\Roster; 23 | 24 | /** 25 | *

26 | * Ein Notdienst ist eine Öffnung der Apotheke nachts, an Wochenenden oder Feiertagen. 27 | * Die Apotheke bleibt bis zum folgenden Tag um 08:00 Uhr geöffnet. 28 | *

29 | * 30 | * @author Mandelkow 31 | */ 32 | class EmergencyService { 33 | 34 | private $dateObject; 35 | private $employeeKey; 36 | private $branchId; 37 | 38 | public function __construct(\DateTime $dateObject, int $branchId, ?int $employeeKey) { 39 | $this->dateObject = $dateObject; 40 | $this->employeeKey = $employeeKey; 41 | $this->branchId = $branchId; 42 | } 43 | 44 | public function getBranchId(): int { 45 | return $this->branchId; 46 | } 47 | 48 | public function getEmployeeShortDescriptor() { 49 | $workforce = new \workforce(); 50 | return $workforce->get_employee_short_descriptor($this->employeeKey); 51 | } 52 | 53 | public function getEmployeeLastName(): string { 54 | $workforce = new \workforce($this->dateObject->format('Y-m-d')); 55 | if (is_integer($this->employeeKey)) { 56 | $employeeLastName = $workforce->get_employee_last_name($this->employeeKey); 57 | return $employeeLastName; 58 | } 59 | return '???'; 60 | } 61 | 62 | public function getEmployeeKey(): ?int { 63 | return $this->employeeKey; 64 | } 65 | 66 | public function getBranchNameShort(): string { 67 | $networkOfBranchOffices = new \PDR\Pharmacy\NetworkOfBranchOffices(); 68 | $ListOfBranchObjects = $networkOfBranchOffices->get_list_of_branch_objects(); 69 | if (is_integer($this->branchId) and isset($ListOfBranchObjects[$this->branchId])) { 70 | $branchNameShort = $ListOfBranchObjects[$this->branchId]->getShortName(); 71 | return $branchNameShort; 72 | } 73 | return '???'; 74 | } 75 | 76 | public function getDateObject(): \DateTime { 77 | return $this->dateObject; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/js/roster-day-edit.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Martin Mandelkow 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | 19 | function roster_input_row_add(id) { 20 | /* 21 | * TODO: The new element does not yet work properly with the plot. 22 | * Try to sync the information upon adding here to the plot. 23 | */ 24 | var xml_http_request = new XMLHttpRequest(); 25 | var buttonAddRowElement = id; 26 | var day_iterator = buttonAddRowElement.dataset.day_iterator; 27 | var roster_row_iterator = Number(buttonAddRowElement.dataset.roster_row_iterator); 28 | var maximum_number_of_rows = Number(buttonAddRowElement.dataset.maximum_number_of_rows); 29 | var branch_id = Number(buttonAddRowElement.dataset.branch_id); 30 | xml_http_request.onreadystatechange = function () { 31 | if (this.readyState === 4 && this.status === 200) { 32 | buttonAddRowElement.dataset.roster_row_iterator = Number(buttonAddRowElement.dataset.roster_row_iterator) + 1; 33 | buttonAddRowElement.dataset.maximum_number_of_rows = Number(buttonAddRowElement.dataset.maximum_number_of_rows) + 1; 34 | var newRow = document.createElement('tr'); 35 | newRow.innerHTML = this.responseText; 36 | newRow.class += "insertedRow"; 37 | newRow.dataset.roster_row_iterator = Number(roster_row_iterator) + 1; 38 | var buttonColumnInTableElement = buttonAddRowElement.parentNode; 39 | var buttonRowInTableElement = buttonColumnInTableElement.parentNode; 40 | var buttonTableElement = buttonRowInTableElement.parentNode; 41 | buttonTableElement.insertBefore(newRow, buttonRowInTableElement); 42 | } 43 | }; 44 | var url = http_server_application_path + "src/php/fragments/fragment.add_roster_input_row.php?" 45 | + "day_iterator=" + String(day_iterator) 46 | + "&" + "roster_row_iterator=" + String(roster_row_iterator) 47 | + "&" + "maximum_number_of_rows=" + String(maximum_number_of_rows) 48 | + "&" + "branch_id=" + String(branch_id); 49 | 50 | xml_http_request.open("GET", url, true); 51 | xml_http_request.send(); 52 | } 53 | -------------------------------------------------------------------------------- /src/php/classes/PDR/Workforce/user_base.php: -------------------------------------------------------------------------------- 1 | . 20 | */ 21 | 22 | /** 23 | * The user_base is the collection of users registered to access this instance of PDR. 24 | * 25 | * @author Mandelkow 26 | */ 27 | 28 | namespace PDR\Workforce; 29 | 30 | class user_base { 31 | 32 | private $user_list; 33 | 34 | function __construct() { 35 | $this->read_user_list_from_database(); 36 | } 37 | 38 | private function read_user_list_from_database() { 39 | $this->user_list = array(); 40 | $sql_query = "SELECT `primary_key` FROM `users` ORDER BY `primary_key` ASC"; 41 | $result = \database_wrapper::instance()->run($sql_query); 42 | while ($row = $result->fetch(\PDO::FETCH_OBJ)) { 43 | $this->user_list[$row->primary_key] = new \user($row->primary_key); 44 | } 45 | } 46 | 47 | public function get_user_list() { 48 | return $this->user_list; 49 | } 50 | 51 | /** 52 | * 53 | * @param string $identifier 54 | * @return boolean|int primary_key 55 | */ 56 | public function guess_user_id_by_identifier($identifier) { 57 | $sql_query = "SELECT `primary_key` FROM `users` WHERE `email` = :email OR `user_name` = :user_name"; 58 | $result = \database_wrapper::instance()->run($sql_query, array('email' => $identifier, 'user_name' => $identifier)); 59 | while ($row = $result->fetch(\PDO::FETCH_OBJ)) { 60 | return $row->primary_key; 61 | } 62 | return FALSE; 63 | } 64 | 65 | public function guess_user_by_identifier($identifier) { 66 | $primary_key = $this->guess_user_id_by_identifier($identifier); 67 | if (false === $primary_key) { 68 | return false; 69 | } 70 | return $this->user_list[$primary_key]; 71 | } 72 | 73 | public function create_new_user(string $user_name, string $password_hash, string $email, string $status) { 74 | $user = new \user(null); 75 | $new_user = $user->create_new(null, $user_name, $password_hash, $email, $status); 76 | $this->read_user_list_from_database(); 77 | return $new_user; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/php/pages/install_page_welcome.php: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 | 17 | 18 | 19 | PDR Installation Wizard 20 | 21 | 22 |

23 | 24 |

25 |

26 |
    27 |
  • 28 |
  • 29 |
  • 30 |
  • 31 |
  • 32 |
  • 33 |
34 | 35 |

36 | 37 |

38 |

39 |
    40 |
  • 41 |
42 | 43 |

44 |

46 |

47 |

49 | 50 |
51 | 52 |
53 | 54 | 55 | -------------------------------------------------------------------------------- /src/php/pages/overtime-read.php: -------------------------------------------------------------------------------- 1 | . 17 | */ 18 | require '../../../default.php'; 19 | $workforce = new workforce(); 20 | $employee_key = user_input::get_variable_from_any_input('employee_key', FILTER_SANITIZE_NUMBER_INT, $workforce->get_default_employee_key()); 21 | \PDR\Utility\GeneralUtility::createCookie('employee_key', $employee_key, 1); 22 | $sql_query = "SELECT * FROM `Stunden` WHERE `employee_key` = :employee_key ORDER BY `Datum` DESC"; 23 | $result = database_wrapper::instance()->run($sql_query, array('employee_key' => $employee_key)); 24 | $tablebody = "\n"; 25 | while ($row = $result->fetch(PDO::FETCH_OBJ)) { 26 | $tablebody .= "\n"; 27 | $tablebody .= ""; 28 | $tablebody .= "" . date("d.m.Y", strtotime($row->Datum)) . ""; 29 | $tablebody .= "\n"; 30 | $tablebody .= "" . "$row->Grund" . "\n"; 31 | $tablebody .= "" . "$row->Stunden" . "\n"; 32 | $tablebody .= "" . "$row->Saldo" . "\n"; 33 | $tablebody .= "\n"; 34 | } 35 | $tablebody .= "\n"; 36 | 37 | //Hier beginnt die Ausgabe 38 | require PDR_FILE_SYSTEM_APPLICATION_PATH . 'head.php'; 39 | require PDR_FILE_SYSTEM_APPLICATION_PATH . 'src/php/pages/menu.php'; 40 | echo "
\n"; 41 | 42 | echo build_html_navigation_elements::build_select_employee($employee_key, $workforce->List_of_employees); 43 | echo build_html_navigation_elements::build_button_open_edit_version('src/php/pages/overtime-edit.php', array('employee_key' => $employee_key)); 44 | //echo "
\n"; 45 | echo "\n"; 46 | /* 47 | * table head 48 | */ 49 | echo "\n" . 50 | "\n" . 51 | "\n" . 52 | "\n" . 53 | "\n" . 54 | "\n"; 55 | /* 56 | * table body 57 | */ 58 | echo "$tablebody"; 59 | echo "
" . gettext('Date') . "" . gettext('Reason') . "" . gettext('Hours') . "" . gettext('Balance') . "
\n"; 60 | echo "\n"; 61 | require PDR_FILE_SYSTEM_APPLICATION_PATH . 'src/php/fragments/fragment.footer.php'; 62 | ?> 63 | 64 | 65 | -------------------------------------------------------------------------------- /docs/documentation_introduction.tex: -------------------------------------------------------------------------------- 1 | \chapter{Introduction} 2 | Pharmacy Duty Roster (PDR) is a web application that allows to operate a duty roster for pharmacies. 3 | PDR started in 2015 as an alternative to a really simple excel sheet without formulas. 4 | PDR aims to be user-friendly but at the same time cover all necessary features. 5 | PDR continuously strives to improve. It is open to your requests and wishes. 6 | I hope it will fulfil your expectations. 7 | 8 | \section{Getting PDR} 9 | The latest release of PDR is available on \href{https://github.com/MaMaKow/dienstplan-apotheke/releases/latest}{GitHub}. GitHub provides the source code as *.zip file or *.tar.gz ball. Extract the files into a folder. 10 | 11 | Make sure to unpack PDR to a directory, that your webserver has access to. PHP and the webserver must have read access to all the files and folders. It also needs write access to the subdirectories upload, tmp and config. You might want to change the owner of the directory to the webservers user with e.g.: 12 | 13 | \begin{lstlisting} 14 | sudo chown -R www-data:www-data /var/www/html/pdr/ 15 | \end{lstlisting} 16 | 17 | You can also clone the repository with git: 18 | \begin{lstlisting} 19 | git clone https://github.com/MaMaKow/dienstplan-apotheke.git 20 | \end{lstlisting} 21 | See the Administrator manual for details! 22 | 23 | \section{License} 24 | PDR is open source software under the AGPL license. 25 | \begin{quote} 26 | Copyright (C) 2018 Dr. Martin Mandelkow 27 | 28 | This program is free software: you can redistribute it and/or modify 29 | it under the terms of the GNU Affero General Public License as 30 | published by the Free Software Foundation, either version 3 of the 31 | License, or (at your option) any later version. 32 | 33 | This program is distributed in the hope that it will be useful, 34 | but WITHOUT ANY WARRANTY; without even the implied warranty of 35 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 36 | GNU Affero General Public License for more details. 37 | 38 | You should have received a copy of the GNU Affero General Public License 39 | along with this program. If not, see . 40 | 41 | \end{quote} 42 | Please see the \href{https://github.com/MaMaKow/dienstplan-apotheke/blob/master/LICENSE.md}{license file} for details! 43 | 44 | \section{Reporting bugs} 45 | The issue tracker is currently located at GitHub \url{https://github.com/MaMaKow/dienstplan-apotheke/issues}. 46 | GitHub requires an account in order to report bugs or feature requests. If you do not want to create one, you might send a mail to \href{mailto:pdr-issues@martin-mandelkow.de}{pdr-issues@martin-mandelkow.de} 47 | 48 | \section{How to contribute} 49 | Pull requests are desired. If you made changes to PDR and want to contribute them to the public, you are welcome to open a pull-request on GitHub or send your changes in any other way. 50 | 51 | You might as well use \lstinline|git send-email| and send patches to \href{mailto:pdr-discuss@martin-mandelkow.de}{pdr-discuss@martin-mandelkow.de} -------------------------------------------------------------------------------- /src/php/pages/install_page_admin.php: -------------------------------------------------------------------------------- 1 | . 17 | */ 18 | require_once '../classes/PDR/Application/Installation/InstallUtility.php'; 19 | require_once '../classes/class.localization.php'; 20 | require_once '../classes/PDR/Utility/GeneralUtility.php'; 21 | $installUtility = new \PDR\Application\Installation\InstallUtility(); 22 | $languageInput = filter_input(INPUT_GET, "language", FILTER_SANITIZE_SPECIAL_CHARS); 23 | $languageBCP47 = localization::standardizeLanguageCode($languageInput); 24 | localization::initialize_gettext($languageBCP47); 25 | $administrationInputHandler = new \PDR\Application\Installation\AdministrationInputHandler(); 26 | if (filter_has_var(INPUT_POST, "user_name")) { 27 | $administrationInputHandler->handleUserInputAdministration(); 28 | } 29 | require_once 'install_head.php'; 30 | ?> 31 |

32 | 33 |
"> 34 |

:
35 | " /> 36 |

37 |

38 | :
39 | " /> 40 |

41 |

42 | :
43 | 44 |
45 | 48 | 49 |

50 |

51 | :
52 | 53 |

54 | 55 | 56 |
57 | buildErrorMessageDiv(); 59 | ?> 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/php/classes/class.email.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | /** 21 | * Maybe I will write a class to handle emails... 22 | * 23 | * @see http://www.faqs.org/rfcs/rfc2822.html 24 | * @author Martin Mandelkow 25 | */ 26 | class email { 27 | 28 | /** 29 | * End of line defined by RFC 5322 30 | */ 31 | const EMAIL_EOL = "\r\n"; 32 | 33 | public $recipient; 34 | public $subject; 35 | public $header; 36 | public $header_from; 37 | public $header_reply_to; 38 | public $message_text; 39 | public $message_html; 40 | public $message_attachment; 41 | 42 | public function __construct() { 43 | throw new BadMethodCallException('This method is not implemented yet. I am sorry!'); 44 | } 45 | 46 | public function set_recipient(string $recipient) { 47 | $this->recipient = $recipient; 48 | } 49 | 50 | public function set_subject(string $subject) { 51 | $this->subject = $subject; 52 | } 53 | 54 | public function create_header($from, $reply_to) { 55 | throw new BadMethodCallException('This method is not implemented yet. I am sorry!'); 56 | $header = ''; 57 | $header .= 'From: ' . $config['contact_email'] . self::EMAIL_EOL; 58 | $header .= 'Reply-To: ' . $config['contact_email'] . self::EMAIL_EOL; 59 | $header .= "MIME-Version: 1.0" . self::EMAIL_EOL; 60 | $header .= 'X-Mailer: PHP/' . phpversion() . self::EMAIL_EOL; 61 | //$header .= "Content-type: text/plain; charset=UTF-8;" . self::EMAIL_EOL; 62 | $random_hash = md5(time()); 63 | $header .= 'Content-Type: multipart/mixed; boundary="' . $random_hash . '"' . self::EMAIL_EOL . self::EMAIL_EOL; 64 | } 65 | 66 | public function add_attachment(string $filename, $content) { 67 | throw new BadMethodCallException('This method is not implemented yet. I am sorry!'); 68 | $attachment_content = chunk_split(base64_encode($content)); 69 | } 70 | 71 | public function send() { 72 | throw new BadMethodCallException('This method is not implemented yet. I am sorry!'); 73 | $mail_result = (bool) mail($to, $subject, $message, $additional_headers, $additional_parameters); 74 | return $mail_result; 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/php/login.php: -------------------------------------------------------------------------------- 1 | . 17 | */ 18 | require '../../default.php'; 19 | /* 20 | * TODO: send referer via session? 21 | */ 22 | 23 | if (filter_has_var(INPUT_POST, 'login')) { 24 | $user_name = filter_input(INPUT_POST, 'user_name', FILTER_SANITIZE_SPECIAL_CHARS); 25 | $user_password = filter_input(INPUT_POST, 'user_password', FILTER_SANITIZE_SPECIAL_CHARS); 26 | 27 | $errorMessage = $session->login($user_name, $user_password, TRUE); 28 | } 29 | require "../../head.php"; 30 | 31 | echo "
"; 32 | if (isset($config['application_name'])) { 33 | $application_name = $config['application_name']; 34 | } else { 35 | $application_name = 'PDR'; 36 | } 37 | echo "

" . $application_name . "

\n"; 38 | $user_dialog = new user_dialog(); 39 | $user_dialog->build_messages(); 40 | ?> 41 | 42 |
43 | 44 |
45 |
46 | 47 |

 

48 | ' . $errorMessage . '

'; 51 | } 52 | ?> 53 |
54 |

55 |

56 | ' ?> 57 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/php/fragments/ajax.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | /** 21 | * The purpose of this file is to receive general POST information via AJAX. 22 | * This might be asynchronous delivery of form information. 23 | */ 24 | require_once '../../../default.php'; 25 | 26 | /** 27 | * This function is meant to distribute data to the user_page action functions. 28 | */ 29 | function form_input_user_page() { 30 | $receive_emails_opt_in = filter_input(INPUT_POST, 'receive_emails_opt_in', FILTER_SANITIZE_SPECIAL_CHARS); 31 | if ('true' === $receive_emails_opt_in) { 32 | return toggle_receive_emails_opt_in(1); 33 | } 34 | if ('false' === $receive_emails_opt_in) { 35 | return toggle_receive_emails_opt_in(0); 36 | } 37 | return FALSE; 38 | } 39 | 40 | /** 41 | * Write receive_emails_opt_in into the `users` table of the database 42 | * 43 | * @param bool $receive_emails_opt_in If the user wishes to receive emails when the roster is changed. 44 | * @return bool Success of the database query 45 | */ 46 | //function toggle_receive_emails_opt_in(bool $receive_emails_opt_in) { 47 | function toggle_receive_emails_opt_in(int $receive_emails_opt_in) { 48 | $user = $_SESSION['user_object']; 49 | if ($user->set_receive_emails_opt_in($receive_emails_opt_in)) { 50 | echo "success"; 51 | return TRUE; 52 | } 53 | return FALSE; 54 | } 55 | 56 | if (filter_has_var(INPUT_POST, 'form')) { 57 | if ('user_form' === filter_input(INPUT_POST, 'form', FILTER_SANITIZE_SPECIAL_CHARS)) { 58 | form_input_user_page(); 59 | } 60 | } elseif (filter_has_var(INPUT_GET, 'saturdayRotationTeamsRemoveTeamId')) { 61 | $team_id_to_remove = filter_input(INPUT_GET, 'saturdayRotationTeamsRemoveTeamId', FILTER_SANITIZE_NUMBER_INT); 62 | $branch_id_to_remove = filter_input(INPUT_GET, 'saturdayRotationTeamsRemoveBranchId', FILTER_SANITIZE_NUMBER_INT); 63 | if (!$session->user_has_privilege(sessions::PRIVILEGE_CREATE_ROSTER)) { 64 | return null; 65 | } 66 | $network_of_branch_offices = new \PDR\Pharmacy\NetworkOfBranchOffices(); 67 | if (false === $network_of_branch_offices->branch_exists($branch_id_to_remove)) { 68 | return null; 69 | } 70 | $saturday_rotation = new saturday_rotation($branch_id_to_remove); 71 | 72 | if (!array_key_exists($team_id_to_remove, $saturday_rotation->List_of_teams)) { 73 | return null; 74 | } 75 | $saturday_rotation->remove_team_from_database($branch_id_to_remove, $team_id_to_remove); 76 | } 77 | -------------------------------------------------------------------------------- /src/php/classes/class.pharmacy_emergency_service_builder.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | /** 21 | * Description of class 22 | * 23 | * @author Martin Mandelkow 24 | */ 25 | class pharmacy_emergency_service_builder { 26 | 27 | public static function build_emergency_service_table_employee_select($employee_key_selected, $branch_id, $date_sql, $emergencyServiceIndex) { 28 | global $workforce; 29 | if (NULL === $workforce) { 30 | $workforce = new workforce(); 31 | } 32 | $table_employee_select = ""; 33 | $table_employee_select .= ""; 34 | $table_employee_select .= ""; 35 | $table_employee_select .= ""; 36 | $table_employee_select .= ""; 58 | $table_employee_select .= ""; 59 | return $table_employee_select; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/js/keyboard_navigation.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Martin Mandelkow 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | */ 17 | document.onkeydown = function (evt) { 18 | keyboard_navigation_main(evt); 19 | }; 20 | 21 | function keyboard_navigation_main(evt) { 22 | evt = evt || window.event; 23 | 24 | if (evt.keyCode === 27) { 25 | /* 26 | * The escape key is pressed. 27 | */ 28 | /* 29 | * Hide the contact form if present: 30 | */ 31 | hide_contact_form(); 32 | /* 33 | * Remove the form in collaborative-vacation 34 | */ 35 | remove_form_div(); 36 | 37 | } 38 | 39 | if (evt.ctrlKey && evt.keyCode == 37 && !evt.shiftKey) { 40 | /* 41 | * The control key and the left arrow key are pressed. 42 | */ 43 | keyboard_navigation_move_backward(); 44 | return false; 45 | } 46 | if (evt.ctrlKey && evt.keyCode == 39 && !evt.shiftKey) { 47 | /* 48 | * The control key and the right arrow key are pressed. 49 | */ 50 | keyboard_navigation_move_forward(); 51 | return false; 52 | } 53 | if (evt.ctrlKey && evt.keyCode == 83 && !evt.shiftKey) { 54 | /* 55 | * The control key and the s key are pressed. 56 | */ 57 | keyboard_navigation_submit_roster(); 58 | if (evt.preventDefault) 59 | { 60 | evt.preventDefault(); 61 | evt.stopPropagation(); 62 | } 63 | return false; 64 | } 65 | //console.log(evt); 66 | return false; 67 | } 68 | 69 | function keyboard_navigation_move_backward() { 70 | var button = document.getElementById('button_day_backward'); 71 | if (button) { 72 | button.click(); 73 | return false; 74 | } 75 | var button = document.getElementById('button_week_backward'); 76 | if (button) { 77 | button.click(); 78 | return false; 79 | } 80 | } 81 | function keyboard_navigation_move_forward() { 82 | var button = document.getElementById('button_day_forward'); 83 | if (button) { 84 | button.click(); 85 | return false; 86 | } 87 | var button = document.getElementById('button_week_forward'); 88 | if (button) { 89 | button.click(); 90 | return false; 91 | } 92 | } 93 | 94 | function keyboard_navigation_submit_roster() { 95 | var button = document.getElementById('submit_button'); 96 | if (button) { 97 | button.click(); 98 | return false; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /docs/setup.tex: -------------------------------------------------------------------------------- 1 | \usepackage[utf8]{inputenc} 2 | \usepackage[T1]{fontenc} 3 | \usepackage{lmodern} 4 | \usepackage{amsmath} 5 | \usepackage{amsfonts} 6 | \usepackage{amssymb} 7 | \usepackage[left=2cm,right=2cm,top=2cm,bottom=2cm]{geometry} 8 | \usepackage{fancyhdr} 9 | \pagestyle{fancy} 10 | % 11 | \usepackage[]{hyperref} 12 | \hypersetup{ 13 | colorlinks, 14 | linkcolor = blue 15 | } 16 | % 17 | \usepackage{graphicx} 18 | \usepackage{svg} 19 | \usepackage{float} 20 | \usepackage{multicol} 21 | % 22 | %%Source code listings: 23 | \usepackage{listingsutf8} 24 | \usepackage{color} 25 | \definecolor{mygreen}{rgb}{0,0.6,0} 26 | \definecolor{mygray}{rgb}{0.5,0.5,0.5} 27 | \definecolor{mymauve}{rgb}{0.58,0,0.82} 28 | \lstset{ 29 | backgroundcolor=\color{white}, % choose the background color; you must add \usepackage{color} 30 | basicstyle=\footnotesize, % the size of the fonts that are used for the code 31 | breakatwhitespace=false, % sets if automatic breaks should only happen at whitespace 32 | breaklines=true, % sets automatic line breaking 33 | captionpos=b, % sets the caption-position to bottom 34 | commentstyle=\color{mygreen}, % comment style 35 | deletekeywords={...}, % if you want to delete keywords from the given language 36 | escapeinside={\%*}{*)}, % if you want to add LaTeX within your code 37 | extendedchars=true, % lets you use non-ASCII characters; for 8-bits encodings only, does not work with UTF-8 38 | frame=single, % adds a frame around the code 39 | keepspaces=true, % keeps spaces in text, useful for keeping indentation of code (possibly needs columns=flexible) 40 | keywordstyle=\color{blue}, % keyword style 41 | language=PHP, % the language of the code 42 | morekeywords={*,...}, % if you want to add more keywords to the set 43 | numbers=left, % where to put the line-numbers; possible values are (none, left, right) 44 | numbersep=5pt, % how far the line-numbers are from the code 45 | numberstyle=\tiny\color{mygray}, % the style that is used for the line-numbers 46 | rulecolor=\color{black}, % if not set, the frame-color may be changed on line-breaks within not-black text (e.g. comments (green here)) 47 | showspaces=false, % show spaces everywhere adding particular underscores; it overrides 'showstringspaces' 48 | showstringspaces=false, % underline spaces within strings only 49 | showtabs=false, % show tabs within strings adding particular underscores 50 | stepnumber=1, % the step between two line-numbers. If it's 1, each line will be numbered 51 | stringstyle=\color{mymauve}, % string literal style 52 | tabsize=4, % sets default tabsize to 2 spaces 53 | title=\lstname % show the filename of files included with \lstinputlisting; also try caption instead of title 54 | } 55 | 56 | %% Drawing Keyboard keys, file paths and menus: 57 | \usepackage[os=win]{menukeys} 58 | \renewmenumacro{\directory}{pathswithfolder} % default: paths 59 | %%\renewmenumacro{\keys}{shadowedangularkeys} % default: roundedkeys 60 | %\newmenucolortheme{name}{model}{bg}{br}{txt} 61 | %\newmenucolortheme{icon}{HTML}{FF0000}{00FF00}{0000FF} 62 | \copymenucolortheme{icon}{gray} 63 | \changemenucolor{icon}{bg}{HTML}{BDE682} --------------------------------------------------------------------------------