diff --git a/landa/hooks.py b/landa/hooks.py index 861e7dcd..9ae31271 100644 --- a/landa/hooks.py +++ b/landa/hooks.py @@ -340,6 +340,9 @@ "0 0 1 10 *": [ # every 1st october at 00:00 "landa.water_body_management.doctype.stocking_target.stocking_target.copy_to_next_year", ], + "0 0 1 1 *": [ # every 1st january at 00:00 + "landa.organization_management.doctype.work_ledger_entry.work_ledger_entry.create_yearly_negative_entries", + ], }, # "all": ["landa.tasks.all"], # , "hourly": [ diff --git a/landa/locale/de.po b/landa/locale/de.po index c487bc61..935dcd5a 100644 --- a/landa/locale/de.po +++ b/landa/locale/de.po @@ -94,6 +94,12 @@ msgstr "Kürzel \"{}\" existiert bereits in Attribut {}." msgid "Access Level" msgstr "Zugangs Level" +#. Label of a Data field in DocType 'Work Assignment' +#: landa/organization_management/doctype/work_assignment/work_assignment.json +#: landa/organization_management/report/work_hours/work_hours.py:49 +msgid "Activity Title" +msgstr "Bezeichnung der Tätigkeit" + #. Label of a Data field in DocType 'Member Data Import' #: landa/organization_management/doctype/member_data_import/member_data_import.json #: landa/organization_management/report/current_member_data/current_member_data.py:174 @@ -156,10 +162,25 @@ msgstr "Art der Auszeichnung" msgid "Awards" msgstr "Auszeichnungen" +#: landa/organization_management/report/work_ledger_balance/work_ledger_balance.py:26 +msgid "Balance End Previous Year" +msgstr "Saldo am Ende des Vorjahres" + +#: landa/organization_management/report/work_ledger_balance/work_ledger_balance.py:44 +msgid "Balance End of Year" +msgstr "Saldo am Ende des Jahres" + #: landa/water_body_management/doctype/stocking_measure/stocking_measure_list.js:30 msgid "Based on your selection, Stocking Targets are created accordingly for the specified year." msgstr "Basierend auf Ihrer Auswahl werden für das angegebene Jahr entsprechende Besatzplanungen erstellt." +#. Label of a Section Break field in DocType 'Work Assignment' +#. Label of a Section Break field in DocType 'Work Ledger Entry' +#: landa/organization_management/doctype/work_assignment/work_assignment.json +#: landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json +msgid "Basic Information" +msgstr "Allgemeine Informationen" + #. Label of a Card Break in the Water Body Management Workspace #: landa/water_body_management/workspace/water_body_management/water_body_management.json msgid "Berichte" @@ -225,9 +246,9 @@ msgstr "Kann untergeordnete Vereine enthalten" msgid "Cannot be a member of organization {} because it is a group." msgstr "Kann kein Mitglied von Verein/Verband {} sein, da nur Vereine bzw. Ortsgruppen Mitglieder haben dürfen, keine Regional- und Landesverbände." -#: landa/organization_management/doctype/organization/organization.py:70 +#: landa/organization_management/doctype/organization/organization.py:74 msgid "Cannot set Parent Organization to a local group." -msgstr "" +msgstr "Ortsgruppe kann nicht als Elternverein festgelegt werden." #. Name of a report #. Label of a Link in the Water Body Management Workspace @@ -345,7 +366,7 @@ msgstr "Aktuelle Informationen werden an diesem Tag automatisch entfernt" #. Name of a DocType #: landa/water_body_management/doctype/custom_icon/custom_icon.json msgid "Custom Icon" -msgstr "" +msgstr "Benutzerdefiniertes Symbol" #. Label of a Section Break field in DocType 'Water Body' #: landa/water_body_management/doctype/water_body/water_body.json @@ -392,11 +413,30 @@ msgstr "Sperrbereich zeichnen" msgid "Dummy" msgstr "" +#. Label of a Float field in DocType 'Work Assignment Member' +#: landa/organization_management/doctype/work_assignment_member/work_assignment_member.json +#: landa/organization_management/report/work_hours/work_hours.py:56 +msgid "Duration (Hours)" +msgstr "Dauer (Stunden)" + #. Label of a Check field in DocType 'Firebase Settings' #: landa/water_body_management/doctype/firebase_settings/firebase_settings.json msgid "Enable Firebase Notifications" msgstr "Firebase-Benachrichtigungen aktivieren" +#: landa/organization_management/report/work_ledger_balance/work_ledger_balance.py:32 +msgid "Expected This Year" +msgstr "Erwartet dieses Jahr" + +#. Label of a Float field in DocType 'Organization' +#: landa/organization_management/doctype/organization/organization.json +msgid "Expected Work Hours per Year" +msgstr "Erwartete Arbeitsstunden pro Jahr" + +#: landa/organization_management/report/work_hours/work_hours.py:119 +msgid "Expected work hours adjustment" +msgstr "Anpassung der erwarteten Arbeitszeit" + #. Name of a DocType #. Label of a Heading field in DocType 'External Contact' #. Label of a Link in the Organization Management Workspace @@ -488,6 +528,9 @@ msgid "" "
\n" "Eg. footballfans" msgstr "" +"Firebase Thema für Push-Benachrichtigungen\n" +"
\n" +"z.B. footballfans" #: landa/water_body_management/doctype/firebase_settings/firebase_settings.js:19 msgid "Firebase credentials uploaded successfully" @@ -633,7 +676,7 @@ msgstr "Vollständiger Name des Lieferanten" #: landa/organization_management/doctype/organization/organization_tree.js:30 msgid "Full name of the organization. For example, \"Landesverband Sächsischer Angler e.V.\"" -msgstr "" +msgstr "Vollständiger Name des Vereins, z.B. \"Landesverband Sächsischer Angler e.V.\"" #. Label of a Table MultiSelect field in DocType 'External Contact' #: landa/organization_management/doctype/external_contact/external_contact.json @@ -694,6 +737,10 @@ msgstr "Zugriff auf bestimmte Daten von Vereinen / Verbänden unterhalb dieses L msgid "Group By Fish Species" msgstr "Nach Fischart gruppieren" +#: landa/organization_management/report/work_hours/work_hours.js:36 +msgid "Group by Member" +msgstr "Nach Mitglied gruppieren" + #. Label of a Check field in DocType 'Water Body' #: landa/water_body_management/doctype/water_body/water_body.json #: landa/water_body_management/report/water_body_export/water_body_export.py:55 @@ -780,6 +827,15 @@ msgstr "" msgid "History" msgstr "Verlauf" +#: landa/organization_management/report/work_hours/work_hours.py:32 +msgid "Hours Balance" +msgstr "Stundensaldo" + +#. Label of a Float field in DocType 'Work Ledger Entry' +#: landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json +msgid "Hours Change" +msgstr "Stundenänderung" + #. Label of a Link field in DocType 'Member Data Import' #: landa/organization_management/doctype/member_data_import/member_data_import.json #: landa/organization_management/report/current_member_data/current_member_data.py:221 @@ -789,12 +845,18 @@ msgstr "Eindeutige Erlaubnisschein Identifikation" #. Label of a Attach Image field in DocType 'Water Body' #: landa/water_body_management/doctype/water_body/water_body.json msgid "Icon Path" -msgstr "" +msgstr "Symbolpfad" #. Label of a Image field in DocType 'Water Body' #: landa/water_body_management/doctype/water_body/water_body.json msgid "Icon Preview" -msgstr "" +msgstr "Symbolvorschau" + +#. Description of the 'Work Assignment' (Link) field in DocType 'Work Ledger +#. Entry' +#: landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json +msgid "If not set, this entry will be treated as an adjustment of expected hours." +msgstr "Ohne Einsatz gilt dieser Eintrag als Anpassung der erwarteten Arbeitsstunden." #. Label of a Card Break in the Water Body Management Workspace #: landa/water_body_management/workspace/water_body_management/water_body_management.json @@ -818,7 +880,7 @@ msgstr "Eingehende Zahlung" #: landa/organization_management/doctype/landa_member/landa_member_list.js:39 msgid "Incorrect password" -msgstr "" +msgstr "Falsches Passwort" #. Label of a Section Break field in DocType 'Award' #. Label of a Section Break field in DocType 'External Contact' @@ -978,12 +1040,15 @@ msgstr "LANDA Mitgliederverwaltung Ortsgruppe" #: landa/organization_management/doctype/member_function/member_function.json #: landa/organization_management/doctype/member_function_category/member_function_category.json #: landa/organization_management/doctype/organization/organization.json +#: landa/organization_management/doctype/work_assignment/work_assignment.json +#: landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json #: landa/organization_management/doctype/yearly_fishing_permit/yearly_fishing_permit.json #: landa/water_body_management/doctype/catch_log_entry/catch_log_entry.json msgid "LANDA Local Organization Management" msgstr "LANDA Mitgliederverwaltung Verein" #. Name of a role +#: landa/organization_management/doctype/work_assignment/work_assignment.json #: landa/water_body_management/doctype/catch_log_entry/catch_log_entry.json #: landa/water_body_management/doctype/stocking_measure_import/stocking_measure_import.json #: landa/water_body_management/doctype/stocking_target/stocking_target.json @@ -1034,12 +1099,12 @@ msgstr "Mitglied {0} wurde erstellt bzw. aktualisiert." #. Name of a DocType #: landa/landa_sales/doctype/landa_payment_row/landa_payment_row.json msgid "LANDA Payment Row" -msgstr "" +msgstr "LANDA Zahlungszeile" #. Name of a report #: landa/organization_management/report/landa_power_users/landa_power_users.json msgid "LANDA Power Users" -msgstr "" +msgstr "LANDA Power-Nutzer" #. Label of a Section Break field in DocType 'Organization' #: landa/organization_management/doctype/organization/organization.json @@ -1057,6 +1122,8 @@ msgstr "LANDA Einstellungen" #: landa/organization_management/doctype/member_function/member_function.json #: landa/organization_management/doctype/member_function_category/member_function_category.json #: landa/organization_management/doctype/organization/organization.json +#: landa/organization_management/doctype/work_assignment/work_assignment.json +#: landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json #: landa/organization_management/doctype/yearly_fishing_permit/yearly_fishing_permit.json #: landa/organization_management/doctype/yearly_fishing_permit_type/yearly_fishing_permit_type.json #: landa/water_body_management/doctype/catch_log_entry/catch_log_entry.json @@ -1093,6 +1160,8 @@ msgstr "" #: landa/organization_management/doctype/member_function/member_function.json #: landa/organization_management/doctype/member_function_category/member_function_category.json #: landa/organization_management/doctype/organization/organization.json +#: landa/organization_management/doctype/work_assignment/work_assignment.json +#: landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json #: landa/organization_management/doctype/yearly_fishing_permit/yearly_fishing_permit.json #: landa/organization_management/doctype/yearly_fishing_permit_type/yearly_fishing_permit_type.json #: landa/water_body_management/doctype/catch_log_entry/catch_log_entry.json @@ -1266,11 +1335,15 @@ msgstr "" #. Label of a Heading field in DocType 'LANDA Member' #. Label of a Link field in DocType 'Member Function' +#. Label of a Link field in DocType 'Work Assignment Member' +#. Label of a Link field in DocType 'Work Ledger Entry' #. Label of a Link field in DocType 'Yearly Fishing Permit' #. Label of a Link in the Organization Management Workspace #: landa/landa_sales/customer/customer.py:26 #: landa/organization_management/doctype/landa_member/landa_member.json #: landa/organization_management/doctype/member_function/member_function.json +#: landa/organization_management/doctype/work_assignment_member/work_assignment_member.json +#: landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json #: landa/organization_management/doctype/yearly_fishing_permit/yearly_fishing_permit.json #: landa/organization_management/report/magazine_address_list/magazine_address_list.py:214 #: landa/organization_management/report/member_address_list/member_address_list.js:10 @@ -1279,6 +1352,11 @@ msgstr "" #: landa/organization_management/report/member_contact_list/member_contact_list.js:10 #: landa/organization_management/report/member_contact_list/member_contact_list.py:53 #: landa/organization_management/report/members_with_member_functions/members_with_member_functions.py:21 +#: landa/organization_management/report/work_hours/work_hours.js:24 +#: landa/organization_management/report/work_hours/work_hours.py:19 +#: landa/organization_management/report/work_hours/work_hours.py:42 +#: landa/organization_management/report/work_ledger_balance/work_ledger_balance.js:24 +#: landa/organization_management/report/work_ledger_balance/work_ledger_balance.py:18 #: landa/organization_management/workspace/organization_management/organization_management.json #: landa/water_body_management/report/members_in_water_body_management/members_in_water_body_management.py:17 msgid "Member" @@ -1378,6 +1456,16 @@ msgstr "Mitgliedsnummer" msgid "Member Last Name" msgstr "Nachname des Mitglieds" +#. Label of a Data field in DocType 'Work Assignment Member' +#. Label of a Data field in DocType 'Work Ledger Entry' +#: landa/organization_management/doctype/work_assignment_member/work_assignment_member.json +#: landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json +#: landa/organization_management/report/work_hours/work_hours.py:26 +#: landa/organization_management/report/work_hours/work_hours.py:48 +#: landa/organization_management/report/work_ledger_balance/work_ledger_balance.py:24 +msgid "Member Name" +msgstr "Mitgliedsname" + #. Label of a Date field in DocType 'LANDA Member' #: landa/organization_management/doctype/landa_member/landa_member.json msgid "Member Since" @@ -1469,7 +1557,7 @@ msgstr "Neue Mitgliedsfunktion anlegen" msgid "New Stocking Measure Import" msgstr "Neuer Besatzmaßnahmenimport" -#: landa/organization_management/doctype/organization/organization.py:320 +#: landa/organization_management/doctype/organization/organization.py:335 msgid "No Company found for Organization {0}." msgstr "Kein Bestellwesenkonto RV für Verein {0} gefunden." @@ -1557,6 +1645,11 @@ msgstr "Lebenslange Gültigkeit des Fischereischeins" msgid "Permit Issue Date" msgstr "Ausgabedatum Fischereischein" +#. Label of a Float field in DocType 'Work Assignment' +#: landa/organization_management/doctype/work_assignment/work_assignment.json +#: landa/organization_management/report/work_hours/work_hours.py:51 +msgid "Planned Duration (Hours)" +msgstr "Geplante Dauer (Stunden)" #: landa/organization_management/doctype/landa_member/landa_member_list.js:115 msgid "Permits have been created for {0} members and skipped for {1} members." msgstr "" @@ -1594,7 +1687,7 @@ msgstr "Bitte tragen Sie vor dem Buchen der Rechnung eine Rechnungsadresse ein." msgid "Please set a Billing Contact before submitting the Sales Invoice." msgstr "Bitte tragen Sie vor dem Buchen der Rechnung einen Rechnungskontakt ein." -#: landa/organization_management/doctype/organization/organization.py:62 +#: landa/organization_management/doctype/organization/organization.py:66 msgid "Please set a Parent Organization." msgstr "Bitte tragen Sie einen übergeordneten Verein ein." @@ -1811,7 +1904,7 @@ msgstr "Abkürzung" #: landa/organization_management/doctype/organization/organization_tree.js:40 msgid "Short code for regional organizations. For example, \"LVSA\", \"AVL\", etc." -msgstr "" +msgstr "Kürzel für Regionalverbände. z.B. \"LVSA\", \"AVL\", etc." #: landa/organization_management/report/magazine_address_list/magazine_address_list.js:33 msgid "Show Only Current Recipients" @@ -1950,7 +2043,7 @@ msgstr "Kostenübersicht Zusammenfassung" #. Name of a DocType #: landa/organization_management/doctype/tag_organization/tag_organization.json msgid "Tag Organization" -msgstr "" +msgstr "Tag-Verein" #. Label of a Link in the Organization Management Workspace #: landa/organization_management/workspace/organization_management/organization_management.json @@ -1981,15 +2074,15 @@ msgstr "Die hochgeladene Datei enthält keine Projekt-ID." msgid "The weight of {0} in row {1} diverges from the typical weight by more than 40 %" msgstr "Das Gewicht von {0} in Zeile {1} weicht um mehr als 40 % vom typischen Gewicht ab" -#: landa/organization_management/doctype/organization/organization.py:316 +#: landa/organization_management/doctype/organization/organization.py:331 msgid "There is no Customer linked to {0}." msgstr "Es ist kein Bestellwesenkonto mit {0} verknüpft." -#: landa/organization_management/doctype/organization/organization.py:239 +#: landa/organization_management/doctype/organization/organization.py:254 msgid "There is no single address linked to {0}." msgstr "Es ist keine einzelne Adresse mit {0} verknüpft." -#: landa/organization_management/doctype/organization/organization.py:231 +#: landa/organization_management/doctype/organization/organization.py:246 msgid "There is no single contact linked to {0}." msgstr "Es ist kein einzelner Kontakt mit {0} verknüpft." @@ -2113,6 +2206,7 @@ msgstr "" msgid "Vollzahler" msgstr "" +#. Label of a Link field in DocType 'Work Assignment' #. Label of a Link field in DocType 'Catch Log Entry' #. Linked DocType in Fishing Area's connections #. Label of a Link field in DocType 'Lease Contract' @@ -2126,6 +2220,9 @@ msgstr "" #. Name of a DocType #. Label of a Link field in DocType 'Water Body Management Local Organization' #. Label of a Link in the Water Body Management Workspace +#: landa/organization_management/doctype/work_assignment/work_assignment.json +#: landa/organization_management/report/work_hours/work_hours.js:30 +#: landa/organization_management/report/work_hours/work_hours.py:58 #: landa/water_body_management/doctype/catch_log_entry/catch_log_entry.json #: landa/water_body_management/doctype/fishing_area/fishing_area.json #: landa/water_body_management/doctype/lease_contract/lease_contract.json @@ -2256,11 +2353,13 @@ msgstr "Gewässer Sonderbestimmungen" msgid "Water Body Status" msgstr "Gewässerstatus" +#. Label of a Data field in DocType 'Work Assignment' #. Label of a Data field in DocType 'Catch Log Entry' #. Label of a Data field in DocType 'Lease Contract' #. Label of a Data field in DocType 'Stocking Measure' #. Label of a Data field in DocType 'Stocking Target' #. Label of a Data field in DocType 'Water Body Management Local Organization' +#: landa/organization_management/doctype/work_assignment/work_assignment.json #: landa/water_body_management/doctype/catch_log_entry/catch_log_entry.json #: landa/water_body_management/doctype/lease_contract/lease_contract.json #: landa/water_body_management/doctype/stocking_measure/stocking_measure.json @@ -2301,6 +2400,56 @@ msgstr "Gewicht pro Gewässer Fläche/Länge" msgid "Wikipedia Link" msgstr "" +#. Name of a DocType +#. Label of a Link field in DocType 'Work Ledger Entry' +#: landa/organization_management/doctype/landa_member/landa_member.js:77 +#: landa/organization_management/doctype/work_assignment/work_assignment.json +#: landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json +msgid "Work Assignment" +msgstr "Arbeitseinsatz" + +#. Name of a DocType +#: landa/organization_management/doctype/work_assignment_member/work_assignment_member.json +msgid "Work Assignment Member" +msgstr "Arbeitseinsatz Teilnehmer" + +#. Name of a report +#. Label of a Link in the Organization Management Workspace +#: landa/organization_management/report/work_hours/work_hours.json +#: landa/organization_management/workspace/organization_management/organization_management.json +msgid "Work Hours" +msgstr "Arbeitsstunden" + +#. Label of a Section Break field in DocType 'Organization' +#: landa/organization_management/doctype/organization/organization.json +msgid "Work Hours Account" +msgstr "Arbeitsstundenkonto" + +#. Label of a Link in the Organization Management Workspace +#: landa/organization_management/workspace/organization_management/organization_management.json +msgid "Work Hours Per Member and Year" +msgstr "Arbeitsstunden pro Mitglied und Jahr" + +#. Name of a report +#. Label of a Link in the Organization Management Workspace +#: landa/organization_management/report/work_ledger_balance/work_ledger_balance.json +#: landa/organization_management/workspace/organization_management/organization_management.json +msgid "Work Ledger Balance" +msgstr "Arbeitszeit je Verein und Jahr" + +#. Linked DocType in Organization's connections +#. Linked DocType in Work Assignment's connections +#. Name of a DocType +#: landa/organization_management/doctype/organization/organization.json +#: landa/organization_management/doctype/work_assignment/work_assignment.json +#: landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json +msgid "Work Ledger Entry" +msgstr "Arbeitsbucheintrag" + +#: landa/organization_management/report/work_ledger_balance/work_ledger_balance.py:38 +msgid "Worked This Year" +msgstr "Geleistet dieses Jahr" + #: landa/water_body_management/stocking_controller.py:23 msgid "Year must be between {0} and {1}." msgstr "Jahr muss zwischen {0} und {1} liegen." diff --git a/landa/locale/main.pot b/landa/locale/main.pot index 0b8c2abe..6b85d0c0 100644 --- a/landa/locale/main.pot +++ b/landa/locale/main.pot @@ -94,6 +94,12 @@ msgstr "" msgid "Access Level" msgstr "" +#. Label of a Data field in DocType 'Work Assignment' +#: landa/organization_management/doctype/work_assignment/work_assignment.json +#: landa/organization_management/report/work_hours/work_hours.py:49 +msgid "Activity Title" +msgstr "" + #. Label of a Data field in DocType 'Member Data Import' #: landa/organization_management/doctype/member_data_import/member_data_import.json #: landa/organization_management/report/current_member_data/current_member_data.py:174 @@ -156,10 +162,25 @@ msgstr "" msgid "Awards" msgstr "" +#: landa/organization_management/report/work_ledger_balance/work_ledger_balance.py:26 +msgid "Balance End Previous Year" +msgstr "" + +#: landa/organization_management/report/work_ledger_balance/work_ledger_balance.py:44 +msgid "Balance End of Year" +msgstr "" + #: landa/water_body_management/doctype/stocking_measure/stocking_measure_list.js:30 msgid "Based on your selection, Stocking Targets are created accordingly for the specified year." msgstr "" +#. Label of a Section Break field in DocType 'Work Assignment' +#. Label of a Section Break field in DocType 'Work Ledger Entry' +#: landa/organization_management/doctype/work_assignment/work_assignment.json +#: landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json +msgid "Basic Information" +msgstr "" + #. Label of a Card Break in the Water Body Management Workspace #: landa/water_body_management/workspace/water_body_management/water_body_management.json msgid "Berichte" @@ -225,7 +246,7 @@ msgstr "" msgid "Cannot be a member of organization {} because it is a group." msgstr "" -#: landa/organization_management/doctype/organization/organization.py:70 +#: landa/organization_management/doctype/organization/organization.py:74 msgid "Cannot set Parent Organization to a local group." msgstr "" @@ -392,11 +413,30 @@ msgstr "" msgid "Dummy" msgstr "" +#. Label of a Float field in DocType 'Work Assignment Member' +#: landa/organization_management/doctype/work_assignment_member/work_assignment_member.json +#: landa/organization_management/report/work_hours/work_hours.py:56 +msgid "Duration (Hours)" +msgstr "" + #. Label of a Check field in DocType 'Firebase Settings' #: landa/water_body_management/doctype/firebase_settings/firebase_settings.json msgid "Enable Firebase Notifications" msgstr "" +#: landa/organization_management/report/work_ledger_balance/work_ledger_balance.py:32 +msgid "Expected This Year" +msgstr "" + +#. Label of a Float field in DocType 'Organization' +#: landa/organization_management/doctype/organization/organization.json +msgid "Expected Work Hours per Year" +msgstr "" + +#: landa/organization_management/report/work_hours/work_hours.py:119 +msgid "Expected work hours adjustment" +msgstr "" + #. Name of a DocType #. Label of a Heading field in DocType 'External Contact' #. Label of a Link in the Organization Management Workspace @@ -694,6 +734,10 @@ msgstr "" msgid "Group By Fish Species" msgstr "" +#: landa/organization_management/report/work_hours/work_hours.js:36 +msgid "Group by Member" +msgstr "" + #. Label of a Check field in DocType 'Water Body' #: landa/water_body_management/doctype/water_body/water_body.json #: landa/water_body_management/report/water_body_export/water_body_export.py:55 @@ -780,6 +824,15 @@ msgstr "" msgid "History" msgstr "" +#: landa/organization_management/report/work_hours/work_hours.py:32 +msgid "Hours Balance" +msgstr "" + +#. Label of a Float field in DocType 'Work Ledger Entry' +#: landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json +msgid "Hours Change" +msgstr "" + #. Label of a Link field in DocType 'Member Data Import' #: landa/organization_management/doctype/member_data_import/member_data_import.json #: landa/organization_management/report/current_member_data/current_member_data.py:221 @@ -796,6 +849,12 @@ msgstr "" msgid "Icon Preview" msgstr "" +#. Description of the 'Work Assignment' (Link) field in DocType 'Work Ledger +#. Entry' +#: landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json +msgid "If not set, this entry will be treated as an adjustment of expected hours." +msgstr "" + #. Label of a Card Break in the Water Body Management Workspace #: landa/water_body_management/workspace/water_body_management/water_body_management.json msgid "Importe" @@ -978,12 +1037,15 @@ msgstr "" #: landa/organization_management/doctype/member_function/member_function.json #: landa/organization_management/doctype/member_function_category/member_function_category.json #: landa/organization_management/doctype/organization/organization.json +#: landa/organization_management/doctype/work_assignment/work_assignment.json +#: landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json #: landa/organization_management/doctype/yearly_fishing_permit/yearly_fishing_permit.json #: landa/water_body_management/doctype/catch_log_entry/catch_log_entry.json msgid "LANDA Local Organization Management" msgstr "" #. Name of a role +#: landa/organization_management/doctype/work_assignment/work_assignment.json #: landa/water_body_management/doctype/catch_log_entry/catch_log_entry.json #: landa/water_body_management/doctype/stocking_measure_import/stocking_measure_import.json #: landa/water_body_management/doctype/stocking_target/stocking_target.json @@ -1057,6 +1119,8 @@ msgstr "" #: landa/organization_management/doctype/member_function/member_function.json #: landa/organization_management/doctype/member_function_category/member_function_category.json #: landa/organization_management/doctype/organization/organization.json +#: landa/organization_management/doctype/work_assignment/work_assignment.json +#: landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json #: landa/organization_management/doctype/yearly_fishing_permit/yearly_fishing_permit.json #: landa/organization_management/doctype/yearly_fishing_permit_type/yearly_fishing_permit_type.json #: landa/water_body_management/doctype/catch_log_entry/catch_log_entry.json @@ -1093,6 +1157,8 @@ msgstr "" #: landa/organization_management/doctype/member_function/member_function.json #: landa/organization_management/doctype/member_function_category/member_function_category.json #: landa/organization_management/doctype/organization/organization.json +#: landa/organization_management/doctype/work_assignment/work_assignment.json +#: landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json #: landa/organization_management/doctype/yearly_fishing_permit/yearly_fishing_permit.json #: landa/organization_management/doctype/yearly_fishing_permit_type/yearly_fishing_permit_type.json #: landa/water_body_management/doctype/catch_log_entry/catch_log_entry.json @@ -1266,11 +1332,15 @@ msgstr "" #. Label of a Heading field in DocType 'LANDA Member' #. Label of a Link field in DocType 'Member Function' +#. Label of a Link field in DocType 'Work Assignment Member' +#. Label of a Link field in DocType 'Work Ledger Entry' #. Label of a Link field in DocType 'Yearly Fishing Permit' #. Label of a Link in the Organization Management Workspace #: landa/landa_sales/customer/customer.py:26 #: landa/organization_management/doctype/landa_member/landa_member.json #: landa/organization_management/doctype/member_function/member_function.json +#: landa/organization_management/doctype/work_assignment_member/work_assignment_member.json +#: landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json #: landa/organization_management/doctype/yearly_fishing_permit/yearly_fishing_permit.json #: landa/organization_management/report/magazine_address_list/magazine_address_list.py:214 #: landa/organization_management/report/member_address_list/member_address_list.js:10 @@ -1279,6 +1349,11 @@ msgstr "" #: landa/organization_management/report/member_contact_list/member_contact_list.js:10 #: landa/organization_management/report/member_contact_list/member_contact_list.py:53 #: landa/organization_management/report/members_with_member_functions/members_with_member_functions.py:21 +#: landa/organization_management/report/work_hours/work_hours.js:24 +#: landa/organization_management/report/work_hours/work_hours.py:19 +#: landa/organization_management/report/work_hours/work_hours.py:42 +#: landa/organization_management/report/work_ledger_balance/work_ledger_balance.js:24 +#: landa/organization_management/report/work_ledger_balance/work_ledger_balance.py:18 #: landa/organization_management/workspace/organization_management/organization_management.json #: landa/water_body_management/report/members_in_water_body_management/members_in_water_body_management.py:17 msgid "Member" @@ -1378,6 +1453,16 @@ msgstr "" msgid "Member Last Name" msgstr "" +#. Label of a Data field in DocType 'Work Assignment Member' +#. Label of a Data field in DocType 'Work Ledger Entry' +#: landa/organization_management/doctype/work_assignment_member/work_assignment_member.json +#: landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json +#: landa/organization_management/report/work_hours/work_hours.py:26 +#: landa/organization_management/report/work_hours/work_hours.py:48 +#: landa/organization_management/report/work_ledger_balance/work_ledger_balance.py:24 +msgid "Member Name" +msgstr "" + #. Label of a Date field in DocType 'LANDA Member' #: landa/organization_management/doctype/landa_member/landa_member.json msgid "Member Since" @@ -1469,7 +1554,7 @@ msgstr "" msgid "New Stocking Measure Import" msgstr "" -#: landa/organization_management/doctype/organization/organization.py:320 +#: landa/organization_management/doctype/organization/organization.py:335 msgid "No Company found for Organization {0}." msgstr "" @@ -1557,6 +1642,11 @@ msgstr "" msgid "Permit Issue Date" msgstr "" +#. Label of a Float field in DocType 'Work Assignment' +#: landa/organization_management/doctype/work_assignment/work_assignment.json +#: landa/organization_management/report/work_hours/work_hours.py:51 +msgid "Planned Duration (Hours)" +msgstr "" #: landa/organization_management/doctype/landa_member/landa_member_list.js:115 msgid "Permits have been created for {0} members and skipped for {1} members." msgstr "" @@ -1594,7 +1684,7 @@ msgstr "" msgid "Please set a Billing Contact before submitting the Sales Invoice." msgstr "" -#: landa/organization_management/doctype/organization/organization.py:62 +#: landa/organization_management/doctype/organization/organization.py:66 msgid "Please set a Parent Organization." msgstr "" @@ -1981,15 +2071,15 @@ msgstr "" msgid "The weight of {0} in row {1} diverges from the typical weight by more than 40 %" msgstr "" -#: landa/organization_management/doctype/organization/organization.py:316 +#: landa/organization_management/doctype/organization/organization.py:331 msgid "There is no Customer linked to {0}." msgstr "" -#: landa/organization_management/doctype/organization/organization.py:239 +#: landa/organization_management/doctype/organization/organization.py:254 msgid "There is no single address linked to {0}." msgstr "" -#: landa/organization_management/doctype/organization/organization.py:231 +#: landa/organization_management/doctype/organization/organization.py:246 msgid "There is no single contact linked to {0}." msgstr "" @@ -2113,6 +2203,7 @@ msgstr "" msgid "Vollzahler" msgstr "" +#. Label of a Link field in DocType 'Work Assignment' #. Label of a Link field in DocType 'Catch Log Entry' #. Linked DocType in Fishing Area's connections #. Label of a Link field in DocType 'Lease Contract' @@ -2126,6 +2217,9 @@ msgstr "" #. Name of a DocType #. Label of a Link field in DocType 'Water Body Management Local Organization' #. Label of a Link in the Water Body Management Workspace +#: landa/organization_management/doctype/work_assignment/work_assignment.json +#: landa/organization_management/report/work_hours/work_hours.js:30 +#: landa/organization_management/report/work_hours/work_hours.py:58 #: landa/water_body_management/doctype/catch_log_entry/catch_log_entry.json #: landa/water_body_management/doctype/fishing_area/fishing_area.json #: landa/water_body_management/doctype/lease_contract/lease_contract.json @@ -2256,11 +2350,13 @@ msgstr "" msgid "Water Body Status" msgstr "" +#. Label of a Data field in DocType 'Work Assignment' #. Label of a Data field in DocType 'Catch Log Entry' #. Label of a Data field in DocType 'Lease Contract' #. Label of a Data field in DocType 'Stocking Measure' #. Label of a Data field in DocType 'Stocking Target' #. Label of a Data field in DocType 'Water Body Management Local Organization' +#: landa/organization_management/doctype/work_assignment/work_assignment.json #: landa/water_body_management/doctype/catch_log_entry/catch_log_entry.json #: landa/water_body_management/doctype/lease_contract/lease_contract.json #: landa/water_body_management/doctype/stocking_measure/stocking_measure.json @@ -2301,6 +2397,56 @@ msgstr "" msgid "Wikipedia Link" msgstr "" +#. Name of a DocType +#. Label of a Link field in DocType 'Work Ledger Entry' +#: landa/organization_management/doctype/landa_member/landa_member.js:77 +#: landa/organization_management/doctype/work_assignment/work_assignment.json +#: landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json +msgid "Work Assignment" +msgstr "" + +#. Name of a DocType +#: landa/organization_management/doctype/work_assignment_member/work_assignment_member.json +msgid "Work Assignment Member" +msgstr "" + +#. Name of a report +#. Label of a Link in the Organization Management Workspace +#: landa/organization_management/report/work_hours/work_hours.json +#: landa/organization_management/workspace/organization_management/organization_management.json +msgid "Work Hours" +msgstr "" + +#. Label of a Section Break field in DocType 'Organization' +#: landa/organization_management/doctype/organization/organization.json +msgid "Work Hours Account" +msgstr "" + +#. Label of a Link in the Organization Management Workspace +#: landa/organization_management/workspace/organization_management/organization_management.json +msgid "Work Hours Per Member and Year" +msgstr "" + +#. Name of a report +#. Label of a Link in the Organization Management Workspace +#: landa/organization_management/report/work_ledger_balance/work_ledger_balance.json +#: landa/organization_management/workspace/organization_management/organization_management.json +msgid "Work Ledger Balance" +msgstr "" + +#. Linked DocType in Organization's connections +#. Linked DocType in Work Assignment's connections +#. Name of a DocType +#: landa/organization_management/doctype/organization/organization.json +#: landa/organization_management/doctype/work_assignment/work_assignment.json +#: landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json +msgid "Work Ledger Entry" +msgstr "" + +#: landa/organization_management/report/work_ledger_balance/work_ledger_balance.py:38 +msgid "Worked This Year" +msgstr "" + #: landa/water_body_management/stocking_controller.py:23 msgid "Year must be between {0} and {1}." msgstr "" diff --git a/landa/organization_management/doctype/landa_member/landa_member.js b/landa/organization_management/doctype/landa_member/landa_member.js index e20fb5f4..702515a4 100644 --- a/landa/organization_management/doctype/landa_member/landa_member.js +++ b/landa/organization_management/doctype/landa_member/landa_member.js @@ -21,6 +21,21 @@ frappe.ui.form.on("LANDA Member", { organization: frm.doc.organization, }); }, + "Work Assignment": () => { + frappe.model.with_doctype("Work Assignment", () => { + let new_doc = frappe.model.get_new_doc("Work Assignment"); + new_doc.organization = frm.doc.organization; + + let child = frappe.model.add_child( + new_doc, + "Work Assignment Member", + "members", + ); + child.member = frm.doc.name; + + frappe.set_route("Form", "Work Assignment", new_doc.name); + }); + }, }; }, refresh: function (frm) { @@ -57,6 +72,14 @@ frappe.ui.form.on("LANDA Member", { }); }); }); + + frm.add_custom_button( + __("Work Assignment"), + function () { + frm.make_methods["Work Assignment"](); + }, + __("Create"), + ); } }, }); diff --git a/landa/organization_management/doctype/organization/organization.json b/landa/organization_management/doctype/organization/organization.json index 28f92ece..cbc48ba6 100644 --- a/landa/organization_management/doctype/organization/organization.json +++ b/landa/organization_management/doctype/organization/organization.json @@ -28,6 +28,8 @@ "section_break_15", "is_group", "disabled", + "section_break_work_hours", + "expected_work_hours_per_year", "lft", "rgt", "old_parent", @@ -198,6 +200,17 @@ "fieldtype": "Check", "label": "Disabled", "permlevel": 1 + }, + { + "fieldname": "section_break_work_hours", + "fieldtype": "Section Break", + "label": "Work Hours Account" + }, + { + "fieldname": "expected_work_hours_per_year", + "fieldtype": "Float", + "label": "Expected Work Hours per Year", + "non_negative": 1 } ], "grid_page_length": 50, @@ -247,6 +260,11 @@ "group": "Gew\u00e4sserverwaltung", "link_doctype": "Water Body Management Local Organization", "link_fieldname": "organization" + }, + { + "group": "Vereinsverwaltung", + "link_doctype": "Work Assignment", + "link_fieldname": "organization" } ], "modified": "2026-05-30 19:17:07.406605", diff --git a/landa/organization_management/doctype/organization/organization.py b/landa/organization_management/doctype/organization/organization.py index 77273705..578d0302 100644 --- a/landa/organization_management/doctype/organization/organization.py +++ b/landa/organization_management/doctype/organization/organization.py @@ -12,10 +12,13 @@ from frappe.desk.treeview import make_tree_args from frappe.model.naming import make_autoname, revert_series_if_last from frappe.permissions import has_permission -from frappe.utils.data import cint, get_link_to_form +from frappe.utils.data import cint, flt, get_link_to_form from frappe.utils.nestedset import NestedSet from landa.organization_management.doctype.landa_member.landa_member import get_address_or_contact +from landa.organization_management.doctype.work_ledger_entry.work_ledger_entry import ( + create_expected_hours_adjustment_entries, +) class Organization(NestedSet): @@ -29,6 +32,7 @@ class Organization(NestedSet): charitable_until: DF.Date | None disabled: DF.Check + expected_work_hours_per_year: DF.Float fishing_area: DF.Link | None is_charitable: DF.Check is_group: DF.Check @@ -84,10 +88,21 @@ def after_insert(self): # of it yet. frappe.cache().delete_key("user_permissions") + def before_save(self): + old = 0.0 + if frappe.db.exists("Organization", self.name): + old = flt(frappe.db.get_value("Organization", self.name, "expected_work_hours_per_year")) + self._expected_work_hours_before_save = old + def onload(self): load_address_and_contact(self) def on_update(self): + if getattr(self, "_expected_work_hours_before_save", None) is not None: + old = flt(self._expected_work_hours_before_save) + new = flt(self.expected_work_hours_per_year) + if old != new: + create_expected_hours_adjustment_entries(self.name, old - new) super().on_update() def on_trash(self): diff --git a/landa/organization_management/doctype/work_assignment/__init__.py b/landa/organization_management/doctype/work_assignment/__init__.py new file mode 100644 index 00000000..6addbb82 --- /dev/null +++ b/landa/organization_management/doctype/work_assignment/__init__.py @@ -0,0 +1,3 @@ +# Copyright (c) 2026, ALYF GmbH and contributors +# For license information, please see license.txt + diff --git a/landa/organization_management/doctype/work_assignment/test_work_assignment.py b/landa/organization_management/doctype/work_assignment/test_work_assignment.py new file mode 100644 index 00000000..8a23a0b9 --- /dev/null +++ b/landa/organization_management/doctype/work_assignment/test_work_assignment.py @@ -0,0 +1,8 @@ +# Copyright (c) 2026, ALYF GmbH and Contributors +# See license.txt + +from frappe.tests.utils import FrappeTestCase + + +class TestWorkAssignment(FrappeTestCase): + pass diff --git a/landa/organization_management/doctype/work_assignment/work_assignment.js b/landa/organization_management/doctype/work_assignment/work_assignment.js new file mode 100644 index 00000000..ba606429 --- /dev/null +++ b/landa/organization_management/doctype/work_assignment/work_assignment.js @@ -0,0 +1,40 @@ +// Copyright (c) 2026, ALYF GmbH and contributors +// For license information, please see license.txt + +frappe.ui.form.on("Work Assignment", { + setup(frm) { + const can_select_any = + frappe.user.has_role("LANDA State Organization Employee") || + frappe.user.has_role("LANDA Regional Organization Management"); + const local_organization = frappe.boot.landa?.local_organization; + + if (!can_select_any && local_organization && frm.is_new()) { + frm.set_value("organization", local_organization); + } + + frm.set_query("organization", function () { + let filters = { is_group: 0 }; + if (!can_select_any && local_organization) { + filters.name = local_organization; + } + return { filters }; + }); + + frm.set_query("member", "members", function (doc) { + return { + filters: { + organization: doc.organization, + }, + }; + }); + }, +}); + +frappe.ui.form.on("Work Assignment Member", { + member(frm, cdt, cdn) { + let row = frappe.get_doc(cdt, cdn); + if (!row.duration && frm.doc.planned_duration) { + frappe.model.set_value(cdt, cdn, "duration", frm.doc.planned_duration); + } + }, +}); diff --git a/landa/organization_management/doctype/work_assignment/work_assignment.json b/landa/organization_management/doctype/work_assignment/work_assignment.json new file mode 100644 index 00000000..47bfca2c --- /dev/null +++ b/landa/organization_management/doctype/work_assignment/work_assignment.json @@ -0,0 +1,228 @@ +{ + "actions": [], + "allow_import": 1, + "autoname": "hash", + "creation": "2026-01-08 10:00:00", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "section_basic", + "organization", + "organization_name", + "date", + "column_break_basic", + "title", + "planned_duration", + "section_location", + "water_body", + "water_body_title", + "column_break_location", + "location", + "description", + "section_members", + "members", + "amended_from" + ], + "fields": [ + { + "fieldname": "section_basic", + "fieldtype": "Section Break", + "label": "Basic Information" + }, + { + "fieldname": "organization", + "fieldtype": "Link", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Organization", + "options": "Organization", + "reqd": 1, + "search_index": 1 + }, + { + "fetch_from": "organization.organization_name", + "fieldname": "organization_name", + "fieldtype": "Data", + "label": "Organization Name", + "read_only": 1 + }, + { + "default": "Today", + "fieldname": "date", + "fieldtype": "Date", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Date", + "reqd": 1 + }, + { + "fieldname": "column_break_basic", + "fieldtype": "Column Break" + }, + { + "fieldname": "title", + "fieldtype": "Data", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Activity Title", + "reqd": 1 + }, + { + "fieldname": "planned_duration", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Planned Duration (Hours)", + "reqd": 1 + }, + { + "fieldname": "section_location", + "fieldtype": "Section Break", + "label": "Location" + }, + { + "fieldname": "water_body", + "fieldtype": "Link", + "in_standard_filter": 1, + "label": "Water Body", + "options": "Water Body" + }, + { + "fetch_from": "water_body.title", + "fieldname": "water_body_title", + "fieldtype": "Data", + "label": "Water Body Title", + "read_only": 1 + }, + { + "fieldname": "column_break_location", + "fieldtype": "Column Break" + }, + { + "fieldname": "location", + "fieldtype": "Data", + "label": "Location" + }, + { + "fieldname": "description", + "fieldtype": "Small Text", + "label": "Description" + }, + { + "fieldname": "section_members", + "fieldtype": "Section Break", + "label": "Participants" + }, + { + "fieldname": "members", + "fieldtype": "Table", + "label": "Members", + "options": "Work Assignment Member" + }, + { + "fieldname": "amended_from", + "fieldtype": "Link", + "label": "Amended From", + "no_copy": 1, + "options": "Work Assignment", + "print_hide": 1, + "read_only": 1, + "search_index": 1 + } + ], + "grid_page_length": 50, + "is_submittable": 1, + "links": [ + { + "link_doctype": "Work Ledger Entry", + "link_fieldname": "work_assignment" + } + ], + "modified": "2026-05-06 09:45:36.342442", + "modified_by": "Administrator", + "module": "Organization Management", + "name": "Work Assignment", + "naming_rule": "Random", + "owner": "Administrator", + "permissions": [ + { + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "import": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "submit": 1, + "write": 1 + }, + { + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "LANDA State Organization Employee", + "submit": 1, + "write": 1 + }, + { + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "LANDA Regional Organization Management", + "submit": 1, + "write": 1 + }, + { + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "LANDA Local Organization Management", + "submit": 1, + "write": 1 + }, + { + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "LANDA Local Water Body Management", + "share": 1, + "submit": 1, + "write": 1 + } + ], + "row_format": "Dynamic", + "rows_threshold_for_grid_search": 20, + "search_fields": "title,organization", + "show_title_field_in_link": 1, + "sort_field": "modified", + "sort_order": "DESC", + "states": [], + "title_field": "title", + "track_changes": 1 +} \ No newline at end of file diff --git a/landa/organization_management/doctype/work_assignment/work_assignment.py b/landa/organization_management/doctype/work_assignment/work_assignment.py new file mode 100644 index 00000000..a9af8da1 --- /dev/null +++ b/landa/organization_management/doctype/work_assignment/work_assignment.py @@ -0,0 +1,58 @@ +# Copyright (c) 2026, ALYF GmbH and contributors +# For license information, please see license.txt + +import frappe +from frappe.model.document import Document + + +class WorkAssignment(Document): + # begin: auto-generated types + # This code is auto-generated. Do not modify anything in this block. + + from typing import TYPE_CHECKING + + if TYPE_CHECKING: + from frappe.types import DF + + from landa.organization_management.doctype.work_assignment_member.work_assignment_member import ( + WorkAssignmentMember, + ) + + amended_from: DF.Link | None + date: DF.Date + description: DF.SmallText | None + location: DF.Data | None + members: DF.Table[WorkAssignmentMember] + organization: DF.Link + organization_name: DF.Data | None + planned_duration: DF.Float + title: DF.Data + water_body: DF.Link | None + water_body_title: DF.Data | None + # end: auto-generated types + + def on_submit(self): + self.create_work_ledger_entry() + + def on_cancel(self): + self.delete_work_ledger_entry() + + def create_work_ledger_entry(self): + if not self.members: + return + for member in self.members: + work_ledger_entry = frappe.new_doc("Work Ledger Entry") + work_ledger_entry.member = member.member + work_ledger_entry.organization = self.organization + work_ledger_entry.date = self.date + work_ledger_entry.work_assignment = self.name + work_ledger_entry.hours_change = member.duration + work_ledger_entry.insert() + + def delete_work_ledger_entry(self): + for name in frappe.get_all( + "Work Ledger Entry", + filters={"work_assignment": self.name}, + pluck="name", + ): + frappe.delete_doc("Work Ledger Entry", name) diff --git a/landa/organization_management/doctype/work_assignment_member/__init__.py b/landa/organization_management/doctype/work_assignment_member/__init__.py new file mode 100644 index 00000000..6addbb82 --- /dev/null +++ b/landa/organization_management/doctype/work_assignment_member/__init__.py @@ -0,0 +1,3 @@ +# Copyright (c) 2026, ALYF GmbH and contributors +# For license information, please see license.txt + diff --git a/landa/organization_management/doctype/work_assignment_member/work_assignment_member.json b/landa/organization_management/doctype/work_assignment_member/work_assignment_member.json new file mode 100644 index 00000000..f43c0a83 --- /dev/null +++ b/landa/organization_management/doctype/work_assignment_member/work_assignment_member.json @@ -0,0 +1,51 @@ +{ + "actions": [], + "creation": "2026-01-08 10:00:00.000000", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "member", + "member_name", + "duration" + ], + "fields": [ + { + "fieldname": "member", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Member", + "options": "LANDA Member", + "reqd": 1 + }, + { + "fetch_from": "member.full_name", + "fieldname": "member_name", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Member Name", + "read_only": 1 + }, + { + "fieldname": "duration", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Duration (Hours)", + "reqd": 1 + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2026-01-08 10:00:00.000000", + "modified_by": "Administrator", + "module": "Organization Management", + "name": "Work Assignment Member", + "owner": "Administrator", + "permissions": [], + "row_format": "Dynamic", + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} + diff --git a/landa/organization_management/doctype/work_assignment_member/work_assignment_member.py b/landa/organization_management/doctype/work_assignment_member/work_assignment_member.py new file mode 100644 index 00000000..dd5b85f2 --- /dev/null +++ b/landa/organization_management/doctype/work_assignment_member/work_assignment_member.py @@ -0,0 +1,8 @@ +# Copyright (c) 2026, ALYF GmbH and contributors +# For license information, please see license.txt + +from frappe.model.document import Document + + +class WorkAssignmentMember(Document): + pass diff --git a/landa/organization_management/doctype/work_ledger_entry/__init__.py b/landa/organization_management/doctype/work_ledger_entry/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/landa/organization_management/doctype/work_ledger_entry/test_work_ledger_entry.py b/landa/organization_management/doctype/work_ledger_entry/test_work_ledger_entry.py new file mode 100644 index 00000000..c5ef9427 --- /dev/null +++ b/landa/organization_management/doctype/work_ledger_entry/test_work_ledger_entry.py @@ -0,0 +1,9 @@ +# Copyright (c) 2026, ALYF GmbH and Contributors +# See license.txt + +# import frappe +from frappe.tests.utils import FrappeTestCase + + +class TestWorkLedgerEntry(FrappeTestCase): + pass diff --git a/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.js b/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.js new file mode 100644 index 00000000..2997a13c --- /dev/null +++ b/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.js @@ -0,0 +1,18 @@ +// Copyright (c) 2026, ALYF GmbH and contributors +// For license information, please see license.txt + +frappe.ui.form.on("Work Ledger Entry", { + setup(frm) { + frm.set_query("member", function () { + return { + filters: { organization: frm.doc.organization }, + }; + }); + }, + + refresh(frm) { + if (!frm.is_new() && frm.doc.work_assignment) { + frm.disable_form(); + } + }, +}); diff --git a/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json b/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json new file mode 100644 index 00000000..35b3726c --- /dev/null +++ b/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json @@ -0,0 +1,154 @@ +{ + "actions": [], + "allow_import": 1, + "allow_rename": 1, + "autoname": "hash", + "creation": "2026-01-28 12:55:36.000975", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "section_basic", + "organization", + "organization_name", + "member", + "member_name", + "column_break_basic", + "date", + "work_assignment", + "hours_change" + ], + "fields": [ + { + "fieldname": "section_basic", + "fieldtype": "Section Break", + "label": "Basic Information" + }, + { + "depends_on": "eval:doc.organization", + "fieldname": "member", + "fieldtype": "Link", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Member", + "options": "LANDA Member", + "reqd": 1, + "search_index": 1 + }, + { + "fetch_from": "member.full_name", + "fieldname": "member_name", + "fieldtype": "Data", + "label": "Member Name", + "read_only": 1 + }, + { + "fieldname": "organization", + "fieldtype": "Link", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Organization", + "options": "Organization", + "reqd": 1, + "search_index": 1 + }, + { + "fetch_from": "organization.organization_name", + "fieldname": "organization_name", + "fieldtype": "Data", + "label": "Organization Name", + "read_only": 1 + }, + { + "fieldname": "column_break_basic", + "fieldtype": "Column Break" + }, + { + "default": "Today", + "fieldname": "date", + "fieldtype": "Date", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Date", + "reqd": 1 + }, + { + "description": "If not set, this entry will be treated as an adjustment of expected hours.", + "fieldname": "work_assignment", + "fieldtype": "Link", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Work Assignment", + "options": "Work Assignment" + }, + { + "fieldname": "hours_change", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Hours Change", + "reqd": 1 + } + ], + "grid_page_length": 50, + "index_web_pages_for_search": 1, + "links": [], + "modified": "2026-03-09 21:22:56.616937", + "modified_by": "Administrator", + "module": "Organization Management", + "name": "Work Ledger Entry", + "naming_rule": "Random", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "import": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "write": 1 + }, + { + "create": 1, + "delete": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "LANDA State Organization Employee", + "write": 1 + }, + { + "create": 1, + "delete": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "LANDA Regional Organization Management", + "write": 1 + }, + { + "create": 1, + "delete": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "LANDA Local Organization Management", + "write": 1 + } + ], + "row_format": "Dynamic", + "rows_threshold_for_grid_search": 20, + "search_fields": "member,organization", + "sort_field": "modified", + "sort_order": "DESC", + "states": [], + "title_field": "member_name", + "track_changes": 1 +} \ No newline at end of file diff --git a/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.py b/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.py new file mode 100644 index 00000000..256a5727 --- /dev/null +++ b/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.py @@ -0,0 +1,78 @@ +# Copyright (c) 2026, ALYF GmbH and contributors +# For license information, please see license.txt + +import frappe +from frappe.model.document import Document +from frappe.utils import getdate +from frappe.utils.data import now_datetime + + +class WorkLedgerEntry(Document): + # begin: auto-generated types + # This code is auto-generated. Do not modify anything in this block. + + from typing import TYPE_CHECKING + + if TYPE_CHECKING: + from frappe.types import DF + + date: DF.Date + hours_change: DF.Float + member: DF.Link + member_name: DF.Data | None + organization: DF.Link + organization_name: DF.Data | None + work_assignment: DF.Link | None + # end: auto-generated types + + +def create_yearly_negative_entries(): + """Create negative Work Ledger Entries for all members based on expected work hours per year.""" + + organizations = frappe.get_list( + "Organization", + filters={"expected_work_hours_per_year": [">", 0]}, + fields=["name", "expected_work_hours_per_year"], + ) + + if not organizations: + return + + # Get all active members for each organization + for org in organizations: + members = frappe.get_list( + "LANDA Member", + filters={"organization": org.name}, + fields=["name"], + ) + + for member in members: + ledger_entry = frappe.new_doc("Work Ledger Entry") + ledger_entry.member = member.name + ledger_entry.organization = org.name + ledger_entry.date = f"{now_datetime().year}-01-01" + ledger_entry.hours_change = -org.expected_work_hours_per_year + ledger_entry.insert() + + +def create_expected_hours_adjustment_entries(organization: str, hours_change: float): + """ + Create one Work Ledger Entry per member of the organization for the given hours change. + Its called when Organization.expected_work_hours_per_year is updated. + """ + + if hours_change == 0: + return + + members = frappe.get_list( + "LANDA Member", + filters={"organization": organization}, + fields=["name"], + ) + for m in members: + entry = frappe.new_doc("Work Ledger Entry") + entry.organization = organization + entry.member = m.name + entry.date = getdate() + entry.hours_change = hours_change + entry.insert() diff --git a/landa/organization_management/report/work_hours/__init__.py b/landa/organization_management/report/work_hours/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/landa/organization_management/report/work_hours/work_hours.js b/landa/organization_management/report/work_hours/work_hours.js new file mode 100644 index 00000000..46db7496 --- /dev/null +++ b/landa/organization_management/report/work_hours/work_hours.js @@ -0,0 +1,50 @@ +// Copyright (c) 2026, ALYF GmbH and contributors +// For license information, please see license.txt + +frappe.query_reports["Work Hours"] = { + filters: [ + { + fieldname: "year", + label: __("Year"), + fieldtype: "Select", + options: get_year_options(), + default: new Date().getFullYear().toString(), + }, + { + fieldname: "organization", + label: __("Organization"), + fieldtype: "Link", + options: "Organization", + get_query: function () { + return { filters: { is_group: 0 } }; + }, + }, + { + fieldname: "member", + label: __("Member"), + fieldtype: "Link", + options: "LANDA Member", + }, + { + fieldname: "water_body", + label: __("Water Body"), + fieldtype: "Link", + options: "Water Body", + }, + { + fieldname: "group_by_member", + label: __("Group by Member"), + fieldtype: "Check", + default: 0, + }, + ], +}; + +function get_year_options() { + const current_year = new Date().getFullYear(); + const years = []; + for (let i = current_year; i >= current_year - 5; i--) { + years.push(i.toString()); + } + return years.join("\n"); +} diff --git a/landa/organization_management/report/work_hours/work_hours.json b/landa/organization_management/report/work_hours/work_hours.json new file mode 100644 index 00000000..dbfd30f4 --- /dev/null +++ b/landa/organization_management/report/work_hours/work_hours.json @@ -0,0 +1,43 @@ +{ + "add_total_row": 1, + "add_translate_data": 0, + "columns": [], + "creation": "2026-01-08 17:06:21.498262", + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "letter_head": null, + "modified": "2026-05-06 10:14:44.943018", + "modified_by": "Administrator", + "module": "Organization Management", + "name": "Work Hours", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Work Ledger Entry", + "report_name": "Work Hours", + "report_type": "Script Report", + "roles": [ + { + "role": "System Manager" + }, + { + "role": "LANDA Member" + }, + { + "role": "LANDA State Organization Employee" + }, + { + "role": "LANDA Regional Organization Management" + }, + { + "role": "LANDA Local Organization Management" + }, + { + "role": "LANDA Local Group Management" + } + ], + "timeout": 0 +} \ No newline at end of file diff --git a/landa/organization_management/report/work_hours/work_hours.py b/landa/organization_management/report/work_hours/work_hours.py new file mode 100644 index 00000000..b3c0d956 --- /dev/null +++ b/landa/organization_management/report/work_hours/work_hours.py @@ -0,0 +1,154 @@ +# Copyright (c) 2026, ALYF GmbH and contributors +# For license information, please see license.txt + +import frappe +from frappe import _ +from frappe.utils import getdate + + +def execute(filters=None): + columns = get_columns(filters) + data = get_data(filters) + return columns, data + + +def get_columns(filters): + if filters.get("group_by_member"): + return [ + { + "label": _("Member"), + "fieldname": "member", + "fieldtype": "Link", + "options": "LANDA Member", + "width": 150, + }, + { + "label": _("Member Name"), + "fieldname": "member_name", + "fieldtype": "Data", + "width": 200, + }, + { + "label": _("Hours Balance"), + "fieldname": "total_hours", + "fieldtype": "Float", + "width": 120, + }, + ] + + return [ + {"label": _("Date"), "fieldname": "date", "fieldtype": "Date", "width": 100}, + { + "label": _("Member"), + "fieldname": "member", + "fieldtype": "Link", + "options": "LANDA Member", + "width": 120, + }, + {"label": _("Member Name"), "fieldname": "member_name", "fieldtype": "Data", "width": 150}, + {"label": _("Activity Title"), "fieldname": "title", "fieldtype": "Data", "width": 200}, + { + "label": _("Planned Duration (Hours)"), + "fieldname": "planned_duration", + "fieldtype": "Float", + "width": 120, + }, + {"label": _("Duration (Hours)"), "fieldname": "duration", "fieldtype": "Float", "width": 120}, + { + "label": _("Water Body"), + "fieldname": "water_body", + "fieldtype": "Link", + "options": "Water Body", + "width": 150, + }, + {"label": _("Location"), "fieldname": "location", "fieldtype": "Data", "width": 150}, + {"label": _("Description"), "fieldname": "description", "fieldtype": "Data", "width": 200}, + ] + + +def get_data(filters): + filters = filters or {} + ledger_filters = _get_ledger_filters(filters) + + if filters.get("group_by_member"): + return frappe.get_list( + "Work Ledger Entry", + filters=ledger_filters, + fields=[ + "member", + "member_name", + "sum(hours_change) as total_hours", + ], + group_by="member, member_name", + order_by="total_hours desc", + ) + + entries = frappe.get_list( + "Work Ledger Entry", + filters=ledger_filters, + fields=["date", "member", "member_name", "work_assignment", "hours_change"], + order_by="date desc", + ) + + if not entries: + return [] + + assignment_names = list({e.get("work_assignment") for e in entries if e.get("work_assignment")}) + assignments_by_name = {} + if assignment_names: + for a in frappe.get_list( + "Work Assignment", + filters={"name": ("in", assignment_names)}, + fields=["name", "title", "planned_duration", "water_body", "location", "description"], + ): + assignments_by_name[a["name"]] = a + + data = [] + for row in entries: + assignment = assignments_by_name.get(row.get("work_assignment")) or {} + data.append( + { + "date": row.get("date"), + "member": row.get("member"), + "member_name": row.get("member_name"), + "title": assignment.get("title"), + "planned_duration": assignment.get("planned_duration"), + "duration": row.get("hours_change"), + "water_body": assignment.get("water_body"), + "location": assignment.get("location"), + "description": _("Expected work hours adjustment") + if not row.get("work_assignment") + else assignment.get("description"), + } + ) + + default_date = getdate("1900-01-01") + data.sort(key=lambda r: (r.get("member") or "")) + data.sort(key=lambda r: r.get("date") or default_date, reverse=True) + return data + + +def _get_ledger_filters(filters): + ledger_filters = {} + + if filters.get("year"): + year = int(filters["year"]) + ledger_filters["date"] = ["between", [f"{year}-01-01", f"{year}-12-31"]] + + if filters.get("organization"): + ledger_filters["organization"] = filters["organization"] + + if filters.get("member"): + ledger_filters["member"] = filters["member"] + + if filters.get("water_body"): + assignment_names = frappe.get_list( + "Work Assignment", + filters={"water_body": filters["water_body"]}, + pluck="name", + ) + if not assignment_names: + return {"name": "__no_match__"} + ledger_filters["work_assignment"] = ("in", assignment_names) + + return ledger_filters diff --git a/landa/organization_management/report/work_ledger_balance/__init__.py b/landa/organization_management/report/work_ledger_balance/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/landa/organization_management/report/work_ledger_balance/work_ledger_balance.js b/landa/organization_management/report/work_ledger_balance/work_ledger_balance.js new file mode 100644 index 00000000..c5776fd0 --- /dev/null +++ b/landa/organization_management/report/work_ledger_balance/work_ledger_balance.js @@ -0,0 +1,38 @@ +// Copyright (c) 2026, ALYF GmbH and contributors +// For license information, please see license.txt + +frappe.query_reports["Work Ledger Balance"] = { + filters: [ + { + fieldname: "year", + label: __("Year"), + fieldtype: "Select", + options: get_year_options(), + default: new Date().getFullYear().toString(), + }, + { + fieldname: "organization", + label: __("Organization"), + fieldtype: "Link", + options: "Organization", + get_query: function () { + return { filters: { is_group: 0 } }; + }, + }, + { + fieldname: "member", + label: __("Member"), + fieldtype: "Link", + options: "LANDA Member", + }, + ], +}; + +function get_year_options() { + const current_year = new Date().getFullYear(); + const years = []; + for (let i = current_year; i >= current_year - 10; i--) { + years.push(i.toString()); + } + return years.join("\n"); +} diff --git a/landa/organization_management/report/work_ledger_balance/work_ledger_balance.json b/landa/organization_management/report/work_ledger_balance/work_ledger_balance.json new file mode 100644 index 00000000..b5554912 --- /dev/null +++ b/landa/organization_management/report/work_ledger_balance/work_ledger_balance.json @@ -0,0 +1,31 @@ +{ + "add_total_row": 0, + "add_translate_data": 0, + "columns": [], + "creation": "2026-02-18 12:00:00.000000", + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "filters": [], + "idx": 0, + "is_standard": "Yes", + "letter_head": null, + "modified": "2026-02-18 12:00:00.000000", + "modified_by": "Administrator", + "module": "Organization Management", + "name": "Work Ledger Balance", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Work Ledger Entry", + "report_name": "Work Ledger Balance", + "report_type": "Script Report", + "roles": [ + {"role": "System Manager"}, + {"role": "LANDA Member"}, + {"role": "LANDA State Organization Employee"}, + {"role": "LANDA Regional Organization Management"}, + {"role": "LANDA Local Organization Management"}, + {"role": "LANDA Local Group Management"} + ], + "timeout": 0 +} diff --git a/landa/organization_management/report/work_ledger_balance/work_ledger_balance.py b/landa/organization_management/report/work_ledger_balance/work_ledger_balance.py new file mode 100644 index 00000000..3016d899 --- /dev/null +++ b/landa/organization_management/report/work_ledger_balance/work_ledger_balance.py @@ -0,0 +1,115 @@ +# Copyright (c) 2026, ALYF GmbH and contributors +# For license information, please see license.txt + +import frappe +from frappe import _ +from frappe.utils import getdate + + +def execute(filters=None): + columns = get_columns() + data = get_data(filters or {}) + return columns, data + + +def get_columns(): + return [ + { + "label": _("Member"), + "fieldname": "member", + "fieldtype": "Link", + "options": "LANDA Member", + "width": 150, + }, + {"label": _("Member Name"), "fieldname": "member_name", "fieldtype": "Data", "width": 180}, + { + "label": _("Balance End Previous Year"), + "fieldname": "balance_previous_year", + "fieldtype": "Float", + "width": 200, + }, + { + "label": _("Expected This Year"), + "fieldname": "expected_this_year", + "fieldtype": "Float", + "width": 200, + }, + { + "label": _("Worked This Year"), + "fieldname": "worked_this_year", + "fieldtype": "Float", + "width": 200, + }, + { + "label": _("Balance End of Year"), + "fieldname": "balance_end_of_year", + "fieldtype": "Float", + "width": 200, + }, + ] + + +def get_data(filters): + year = int(filters.get("year") or frappe.utils.getdate().year) + year_start = getdate(f"{year}-01-01") + year_end = getdate(f"{year}-12-31") + + org_filter = filters.get("organization") + member_filter = filters.get("member") + + base_filters = [["date", "<=", year_end]] + if org_filter: + base_filters.append(["organization", "=", org_filter]) + if member_filter: + base_filters.append(["member", "=", member_filter]) + + entries = frappe.get_list( + "Work Ledger Entry", + filters=base_filters, + fields=["member", "member_name", "date", "hours_change", "work_assignment"], + ) + if not entries: + return [] + + by_member = {} + for row in entries: + m = row["member"] + if m not in by_member: + by_member[m] = {"member": m, "member_name": row.get("member_name"), "rows": []} + by_member[m]["rows"].append( + { + "date": row["date"], + "hours_change": float(row.get("hours_change") or 0), + "work_assignment": row.get("work_assignment"), + } + ) + + result = [] + for member, data in by_member.items(): + balance_previous = sum( + r["hours_change"] for r in data["rows"] if r["date"] is not None and r["date"] < year_start + ) + in_year = [ + row for row in data["rows"] if row["date"] is not None and year_start <= row["date"] <= year_end + ] + expected_this_year = -1 * sum( + row.get("hours_change") for row in in_year if row.get("work_assignment") is None + ) + worked_this_year = sum( + row.get("hours_change") for row in in_year if row.get("work_assignment") is not None + ) + balance_end = balance_previous - expected_this_year + worked_this_year + + result.append( + { + "member": member, + "member_name": data["member_name"], + "balance_previous_year": round(balance_previous, 2), + "expected_this_year": round(expected_this_year, 2), + "worked_this_year": round(worked_this_year, 2), + "balance_end_of_year": round(balance_end, 2), + } + ) + + result.sort(key=lambda r: (r["member_name"] or "", r["member"])) + return result diff --git a/landa/organization_management/workspace/organization_management/organization_management.json b/landa/organization_management/workspace/organization_management/organization_management.json index 51b9911d..db1b0b73 100644 --- a/landa/organization_management/workspace/organization_management/organization_management.json +++ b/landa/organization_management/workspace/organization_management/organization_management.json @@ -1,6 +1,6 @@ { "charts": [], - "content": "[{\"id\":\"1uTyrJlebP\",\"type\":\"header\",\"data\":{\"text\":\"Schnellzugriff\",\"col\":12}},{\"id\":\"vSObTmx5FJ\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Neues Mitglied anlegen\",\"col\":4}},{\"id\":\"kIubCGyGa6\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Member Address List\",\"col\":4}},{\"id\":\"hxillFj4xC\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Member Contact List\",\"col\":4}},{\"id\":\"TdmgLajXcz\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Member Birthday List\",\"col\":4}},{\"id\":\"pyW2rRoxN5\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"New Award Entry\",\"col\":4}},{\"id\":\"LhkZgoe7J6\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"New Member Function Entry\",\"col\":4}},{\"id\":\"M6BGPcbTdL\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Show Organization List\",\"col\":4}},{\"id\":\"4XErd7BVw_\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"RgNOYMq0fd\",\"type\":\"header\",\"data\":{\"text\":\"Berichte & Stammdaten\",\"col\":12}},{\"id\":\"Vs8PWZl7sT\",\"type\":\"card\",\"data\":{\"card_name\":\"Masters\",\"col\":4}},{\"id\":\"T-qvfB98nf\",\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}},{\"id\":\"ce1489-Jj0\",\"type\":\"card\",\"data\":{\"card_name\":\"Imports\",\"col\":4}},{\"id\":\"KN8t-FsoLs\",\"type\":\"card\",\"data\":{\"card_name\":\"Setup\",\"col\":4}}]", + "content": "[{\"id\":\"1uTyrJlebP\",\"type\":\"header\",\"data\":{\"text\":\"Schnellzugriff\",\"col\":12}},{\"id\":\"vSObTmx5FJ\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Neues Mitglied anlegen\",\"col\":4}},{\"id\":\"kIubCGyGa6\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Member Address List\",\"col\":4}},{\"id\":\"hxillFj4xC\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Member Contact List\",\"col\":4}},{\"id\":\"TdmgLajXcz\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Member Birthday List\",\"col\":4}},{\"id\":\"pyW2rRoxN5\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"New Award Entry\",\"col\":4}},{\"id\":\"LhkZgoe7J6\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"New Member Function Entry\",\"col\":4}},{\"id\":\"M6BGPcbTdL\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Show Organization List\",\"col\":4}},{\"id\":\"js1RQK6MeL\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"New Work Assignment\",\"col\":4}},{\"id\":\"rCLi2ifrHP\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Show Work Assignment List\",\"col\":4}},{\"id\":\"4XErd7BVw_\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"RgNOYMq0fd\",\"type\":\"header\",\"data\":{\"text\":\"Berichte & Stammdaten\",\"col\":12}},{\"id\":\"Vs8PWZl7sT\",\"type\":\"card\",\"data\":{\"card_name\":\"Masters\",\"col\":4}},{\"id\":\"T-qvfB98nf\",\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}},{\"id\":\"ce1489-Jj0\",\"type\":\"card\",\"data\":{\"card_name\":\"Imports\",\"col\":4}},{\"id\":\"KN8t-FsoLs\",\"type\":\"card\",\"data\":{\"card_name\":\"Setup\",\"col\":4}}]", "creation": "2021-04-19 18:01:23.947644", "custom_blocks": [], "docstatus": 0, @@ -213,6 +213,7 @@ "link_to": "Yearly Fishing Permits Issued", "link_type": "Report", "onboard": 0, + "report_ref_doctype": "Yearly Fishing Permit", "type": "Link" }, { @@ -225,6 +226,28 @@ "onboard": 0, "type": "Link" }, + { + "hidden": 0, + "is_query_report": 1, + "label": "Work Hours", + "link_count": 0, + "link_to": "Work Hours", + "link_type": "Report", + "onboard": 0, + "report_ref_doctype": "Work Assignment", + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 1, + "label": "Work Ledger Balance", + "link_count": 0, + "link_to": "Work Ledger Balance", + "link_type": "Report", + "onboard": 0, + "report_ref_doctype": "Work Ledger Entry", + "type": "Link" + }, { "hidden": 0, "is_query_report": 0, @@ -285,7 +308,7 @@ "type": "Link" } ], - "modified": "2024-07-11 14:59:31.302312", + "modified": "2026-05-05 16:36:15.445843", "modified_by": "Administrator", "module": "Organization Management", "name": "Organization Management", @@ -304,22 +327,41 @@ "stats_filter": "[]", "type": "DocType" }, + { + "color": "Grey", + "doc_view": "New", + "label": "New Work Assignment", + "link_to": "Work Assignment", + "stats_filter": "[]", + "type": "DocType" + }, { "doc_view": "", "label": "Member Address List", "link_to": "Member Address List", + "report_ref_doctype": "LANDA Member", "type": "Report" }, + { + "color": "Grey", + "doc_view": "List", + "label": "Show Work Assignment List", + "link_to": "Work Assignment", + "stats_filter": "[]", + "type": "DocType" + }, { "doc_view": "", "label": "Member Contact List", "link_to": "Member Contact List", + "report_ref_doctype": "LANDA Member", "type": "Report" }, { "doc_view": "", "label": "Member Birthday List", "link_to": "Member Birthday List", + "report_ref_doctype": "LANDA Member", "type": "Report" }, {