From ea53b45346d5c76e8fa4f9863cdffc34f62d1eb9 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Thu, 8 Jan 2026 10:15:53 +0100 Subject: [PATCH 01/43] feat: add work assignment doctype and child table --- .../doctype/work_assignment/__init__.py | 3 + .../work_assignment/test_work_assignment.py | 9 + .../work_assignment/work_assignment.js | 7 + .../work_assignment/work_assignment.json | 206 ++++++++++++++++++ .../work_assignment/work_assignment.py | 32 +++ .../work_assignment_member/__init__.py | 3 + .../work_assignment_member.json | 51 +++++ .../work_assignment_member.py | 8 + 8 files changed, 319 insertions(+) create mode 100644 landa/organization_management/doctype/work_assignment/__init__.py create mode 100644 landa/organization_management/doctype/work_assignment/test_work_assignment.py create mode 100644 landa/organization_management/doctype/work_assignment/work_assignment.js create mode 100644 landa/organization_management/doctype/work_assignment/work_assignment.json create mode 100644 landa/organization_management/doctype/work_assignment/work_assignment.py create mode 100644 landa/organization_management/doctype/work_assignment_member/__init__.py create mode 100644 landa/organization_management/doctype/work_assignment_member/work_assignment_member.json create mode 100644 landa/organization_management/doctype/work_assignment_member/work_assignment_member.py 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..d5cf956c --- /dev/null +++ b/landa/organization_management/doctype/work_assignment/test_work_assignment.py @@ -0,0 +1,9 @@ +# Copyright (c) 2026, ALYF GmbH and Contributors +# See license.txt + +import frappe +from frappe.tests import IntegrationTestCase + + +class TestWorkAssignment(IntegrationTestCase): + 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..3c251871 --- /dev/null +++ b/landa/organization_management/doctype/work_assignment/work_assignment.js @@ -0,0 +1,7 @@ +// Copyright (c) 2026, ALYF GmbH and contributors +// For license information, please see license.txt + +frappe.ui.form.on("Work Assignment", { + // refresh: function(frm) { + // } +}); 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..1d0863f7 --- /dev/null +++ b/landa/organization_management/doctype/work_assignment/work_assignment.json @@ -0,0 +1,206 @@ +{ + "actions": [], + "allow_import": 1, + "autoname": "naming_series:", + "creation": "2026-01-08 10:00:00", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "naming_series", + "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" + ], + "fields": [ + { + "fieldname": "naming_series", + "fieldtype": "Select", + "hidden": 1, + "label": "Naming Series", + "options": "WORK-.YYYY.-.#####" + }, + { + "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" + } + ], + "grid_page_length": 50, + "links": [], + "modified": "2026-01-08 10:04:20.853463", + "modified_by": "Administrator", + "module": "Organization Management", + "name": "Work Assignment", + "naming_rule": "By \"Naming Series\" field", + "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 + }, + { + "print": 1, + "read": 1, + "role": "LANDA Member" + }, + { + "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 + }, + { + "create": 1, + "delete": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "LANDA Local Group Management", + "write": 1 + } + ], + "row_format": "Dynamic", + "rows_threshold_for_grid_search": 20, + "search_fields": "title,organization", + "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..0df676b7 --- /dev/null +++ b/landa/organization_management/doctype/work_assignment/work_assignment.py @@ -0,0 +1,32 @@ +# Copyright (c) 2026, ALYF GmbH and contributors +# For license information, please see license.txt + +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, + ) + + date: DF.Date + description: DF.SmallText | None + location: DF.Data | None + members: DF.Table[WorkAssignmentMember] + naming_series: DF.Literal["WORK-.YYYY.-.#####"] + 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 + pass 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 From 78526c96ebb82c2edc7131dcbaefdf705fd85f30 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Thu, 8 Jan 2026 10:26:00 +0100 Subject: [PATCH 02/43] feat: add organization filter for member --- .../work_assignment/work_assignment.js | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/landa/organization_management/doctype/work_assignment/work_assignment.js b/landa/organization_management/doctype/work_assignment/work_assignment.js index 3c251871..5ccdab70 100644 --- a/landa/organization_management/doctype/work_assignment/work_assignment.js +++ b/landa/organization_management/doctype/work_assignment/work_assignment.js @@ -2,6 +2,21 @@ // For license information, please see license.txt frappe.ui.form.on("Work Assignment", { - // refresh: function(frm) { - // } + setup(frm) { + frm.set_query("organization", function () { + return { + filters: { + is_group: 0, + }, + }; + }); + + frm.set_query("member", "members", function (doc) { + return { + filters: { + organization: ["=", doc.organization], + }, + }; + }); + }, }); From 57c06f8261fc9c77ff42050316c214546d8b73f7 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Thu, 8 Jan 2026 16:54:36 +0100 Subject: [PATCH 03/43] feat: set organization based on user role --- .../work_assignment/work_assignment.js | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/landa/organization_management/doctype/work_assignment/work_assignment.js b/landa/organization_management/doctype/work_assignment/work_assignment.js index 5ccdab70..ff875fde 100644 --- a/landa/organization_management/doctype/work_assignment/work_assignment.js +++ b/landa/organization_management/doctype/work_assignment/work_assignment.js @@ -3,12 +3,21 @@ 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 organization = frappe.boot.landa?.organization; + + if (organization) { + frm.set_value("organization", organization); + } + frm.set_query("organization", function () { - return { - filters: { - is_group: 0, - }, - }; + let filters = { is_group: 0 }; + if (!can_select_any && organization) { + filters.name = organization; + } + return { filters }; }); frm.set_query("member", "members", function (doc) { @@ -20,3 +29,12 @@ frappe.ui.form.on("Work Assignment", { }); }, }); + +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); + } + }, +}); From 382fb3575c371c3d4a83367f4e77765b59c5eedc Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Thu, 8 Jan 2026 17:35:08 +0100 Subject: [PATCH 04/43] feat: add work hours report --- .../report/work_hours/__init__.py | 0 .../report/work_hours/work_hours.js | 50 ++++++ .../report/work_hours/work_hours.json | 43 +++++ .../report/work_hours/work_hours.py | 155 ++++++++++++++++++ landa/public/node_modules | 1 + 5 files changed, 249 insertions(+) create mode 100644 landa/organization_management/report/work_hours/__init__.py create mode 100644 landa/organization_management/report/work_hours/work_hours.js create mode 100644 landa/organization_management/report/work_hours/work_hours.json create mode 100644 landa/organization_management/report/work_hours/work_hours.py create mode 120000 landa/public/node_modules 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..dd138b67 --- /dev/null +++ b/landa/organization_management/report/work_hours/work_hours.json @@ -0,0 +1,43 @@ +{ + "add_total_row": 0, + "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-01-08 17:06:56.924267", + "modified_by": "Administrator", + "module": "Organization Management", + "name": "Work Hours", + "owner": "Administrator", + "prepared_report": 0, + "ref_doctype": "Work Assignment", + "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..62cd8a2a --- /dev/null +++ b/landa/organization_management/report/work_hours/work_hours.py @@ -0,0 +1,155 @@ +# Copyright (c) 2026, ALYF GmbH and contributors +# For license information, please see license.txt + +import frappe +from frappe import _ + + +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": _("Total Hours"), + "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): + conditions = get_conditions(filters) + + if filters.get("group_by_member"): + return frappe.db.sql( + f""" + SELECT + wam.member, + wam.member_name, + SUM(wam.duration) as total_hours + FROM `tabWork Assignment Member` wam + JOIN `tabWork Assignment` wa ON wam.parent = wa.name + WHERE 1=1 {conditions} + GROUP BY wam.member + ORDER BY total_hours DESC + """, + filters, + as_dict=True, + ) + + return frappe.db.sql( + f""" + SELECT + wa.date, + wam.member, + wam.member_name, + wa.title, + wa.planned_duration, + wam.duration, + wa.water_body, + wa.location, + wa.description + FROM `tabWork Assignment Member` wam + JOIN `tabWork Assignment` wa ON wam.parent = wa.name + WHERE 1=1 {conditions} + ORDER BY wa.date DESC, wam.member + """, + filters, + as_dict=True, + ) + + +def get_conditions(filters): + conditions = [] + + if filters.get("year"): + conditions.append("AND YEAR(wa.date) = %(year)s") + + if filters.get("organization"): + conditions.append("AND wa.organization = %(organization)s") + + if filters.get("member"): + conditions.append("AND wam.member = %(member)s") + + if filters.get("water_body"): + conditions.append("AND wa.water_body = %(water_body)s") + + return " ".join(conditions) diff --git a/landa/public/node_modules b/landa/public/node_modules new file mode 120000 index 00000000..a295ae47 --- /dev/null +++ b/landa/public/node_modules @@ -0,0 +1 @@ +/Users/marc/Code/Bench/version-15/apps/landa/node_modules \ No newline at end of file From 9bdf1a6c0a6d47127f50fb06ffa98b71d7059d9c Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Fri, 9 Jan 2026 09:44:14 +0100 Subject: [PATCH 05/43] fix: permissions for work assignment --- .../doctype/work_assignment/work_assignment.json | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/landa/organization_management/doctype/work_assignment/work_assignment.json b/landa/organization_management/doctype/work_assignment/work_assignment.json index 1d0863f7..d8fb192c 100644 --- a/landa/organization_management/doctype/work_assignment/work_assignment.json +++ b/landa/organization_management/doctype/work_assignment/work_assignment.json @@ -129,7 +129,7 @@ ], "grid_page_length": 50, "links": [], - "modified": "2026-01-08 10:04:20.853463", + "modified": "2026-01-09 09:43:31.823627", "modified_by": "Administrator", "module": "Organization Management", "name": "Work Assignment", @@ -149,11 +149,6 @@ "share": 1, "write": 1 }, - { - "print": 1, - "read": 1, - "role": "LANDA Member" - }, { "create": 1, "delete": 1, @@ -187,11 +182,13 @@ { "create": 1, "delete": 1, + "email": 1, "export": 1, "print": 1, "read": 1, "report": 1, - "role": "LANDA Local Group Management", + "role": "LANDA Local Water Body Management", + "share": 1, "write": 1 } ], From 5d6e57b941a03d36adc4acb5907ec6a0784c02aa Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Fri, 9 Jan 2026 09:45:18 +0100 Subject: [PATCH 06/43] feat: create work assignment from member --- .../doctype/landa_member/landa_member.js | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) 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"), + ); } }, }); From 2a1eaf5a91294499c94bbbde60ad6f3b967251a3 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Sat, 10 Jan 2026 17:29:57 +0100 Subject: [PATCH 07/43] fix: remove accidentally committed file --- landa/public/node_modules | 1 - 1 file changed, 1 deletion(-) delete mode 120000 landa/public/node_modules diff --git a/landa/public/node_modules b/landa/public/node_modules deleted file mode 120000 index a295ae47..00000000 --- a/landa/public/node_modules +++ /dev/null @@ -1 +0,0 @@ -/Users/marc/Code/Bench/version-15/apps/landa/node_modules \ No newline at end of file From 5a16aa2b0f3be6c12cfe678f9658d0aed0a4fa57 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Sat, 10 Jan 2026 18:00:38 +0100 Subject: [PATCH 08/43] fix: correct organization assignment --- .../doctype/work_assignment/work_assignment.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/landa/organization_management/doctype/work_assignment/work_assignment.js b/landa/organization_management/doctype/work_assignment/work_assignment.js index ff875fde..b06e7640 100644 --- a/landa/organization_management/doctype/work_assignment/work_assignment.js +++ b/landa/organization_management/doctype/work_assignment/work_assignment.js @@ -6,16 +6,16 @@ frappe.ui.form.on("Work Assignment", { const can_select_any = frappe.user.has_role("LANDA State Organization Employee") || frappe.user.has_role("LANDA Regional Organization Management"); - const organization = frappe.boot.landa?.organization; + const local_organization = frappe.boot.landa?.local_organization; - if (organization) { - frm.set_value("organization", 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 && organization) { - filters.name = organization; + if (!can_select_any && local_organization) { + filters.name = local_organization; } return { filters }; }); From 11b4cf10cf4cebd7c8727988a5c4208b3d17d57b Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Mon, 12 Jan 2026 09:31:20 +0100 Subject: [PATCH 09/43] feat: add translations --- landa/locale/de.po | 71 ++++++++++++++++++++++++++++++++++++++- landa/locale/main.pot | 77 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 143 insertions(+), 5 deletions(-) diff --git a/landa/locale/de.po b/landa/locale/de.po index 7f5747f8..3d187ab2 100644 --- a/landa/locale/de.po +++ b/landa/locale/de.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: LANDA VERSION\n" "Report-Msgid-Bugs-To: hallo@alyf.de\n" -"POT-Creation-Date: 2025-12-10 21:28+0053\n" +"POT-Creation-Date: 2026-01-12 09:20+0053\n" "PO-Revision-Date: 2025-11-29 18:55+0053\n" "Last-Translator: hallo@alyf.de\n" "Language-Team: hallo@alyf.de\n" @@ -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:59 +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:131 @@ -156,6 +162,11 @@ msgstr "Auszeichnungen" 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' +#: landa/organization_management/doctype/work_assignment/work_assignment.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" @@ -379,6 +390,12 @@ 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:71 +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" @@ -672,6 +689,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 @@ -951,12 +972,14 @@ 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/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_target/stocking_target.json #: landa/water_body_management/doctype/water_body_management_local_organization/water_body_management_local_organization.json @@ -1029,6 +1052,7 @@ 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/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 @@ -1065,6 +1089,7 @@ 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/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 @@ -1237,10 +1262,12 @@ 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 'Yearly Fishing Permit' #. Label of a Link in the Organization Management Workspace #: 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/yearly_fishing_permit/yearly_fishing_permit.json #: landa/organization_management/report/magazine_address_list/magazine_address_list.py:150 #: landa/organization_management/report/member_address_list/member_address_list.js:10 @@ -1249,6 +1276,9 @@ 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:18 +#: landa/organization_management/report/work_hours/work_hours.py:46 #: 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" @@ -1348,6 +1378,13 @@ msgstr "Mitgliedsnummer" msgid "Member Last Name" msgstr "Nachname des Mitglieds" +#. Label of a Data 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:25 +#: landa/organization_management/report/work_hours/work_hours.py:53 +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" @@ -1515,6 +1552,12 @@ 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:65 +msgid "Planned Duration (Hours)" +msgstr "Geplante Dauer (Stunden)" + #. Label of a Check field in DocType 'Catch Log Fish Table' #: landa/water_body_management/doctype/catch_log_fish_table/catch_log_fish_table.json msgid "Plausible" @@ -1951,6 +1994,10 @@ msgstr "HTML umschalten" msgid "Total (only for regional org.)" msgstr "Summe (nur für RV)" +#: landa/organization_management/report/work_hours/work_hours.py:31 +msgid "Total Hours" +msgstr "Gesamtstunden" + #. Label of a Small Text field in DocType 'Fish Species' #: landa/water_body_management/doctype/fish_species/fish_species.json msgid "Traits" @@ -2034,6 +2081,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' @@ -2044,6 +2092,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:77 #: 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 @@ -2172,11 +2223,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 @@ -2213,6 +2266,22 @@ msgstr "Gewicht pro Gewässer Fläche/Länge" msgid "Wikipedia Link" msgstr "" +#. Name of a DocType +#: landa/organization_management/doctype/landa_member/landa_member.js:77 +#: landa/organization_management/doctype/work_assignment/work_assignment.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 +#: landa/organization_management/report/work_hours/work_hours.json +msgid "Work Hours" +msgstr "Arbeitsstunden" + #: 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 2610694b..dae0393b 100644 --- a/landa/locale/main.pot +++ b/landa/locale/main.pot @@ -1,14 +1,14 @@ # Translations template for LANDA. -# Copyright (C) 2025 ALYF GmbH +# Copyright (C) 2026 ALYF GmbH # This file is distributed under the same license as the LANDA project. -# FIRST AUTHOR , 2025. +# FIRST AUTHOR , 2026. # msgid "" msgstr "" "Project-Id-Version: LANDA VERSION\n" "Report-Msgid-Bugs-To: hallo@alyf.de\n" -"POT-Creation-Date: 2025-12-10 21:28+0053\n" -"PO-Revision-Date: 2025-12-10 21:28+0053\n" +"POT-Creation-Date: 2026-01-12 09:20+0053\n" +"PO-Revision-Date: 2026-01-12 09:20+0053\n" "Last-Translator: hallo@alyf.de\n" "Language-Team: hallo@alyf.de\n" "MIME-Version: 1.0\n" @@ -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:59 +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:131 @@ -156,6 +162,11 @@ msgstr "" 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' +#: landa/organization_management/doctype/work_assignment/work_assignment.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" @@ -379,6 +390,12 @@ 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:71 +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" @@ -672,6 +689,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 @@ -951,12 +972,14 @@ 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/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_target/stocking_target.json #: landa/water_body_management/doctype/water_body_management_local_organization/water_body_management_local_organization.json @@ -1029,6 +1052,7 @@ 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/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 @@ -1065,6 +1089,7 @@ 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/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 @@ -1237,10 +1262,12 @@ 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 'Yearly Fishing Permit' #. Label of a Link in the Organization Management Workspace #: 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/yearly_fishing_permit/yearly_fishing_permit.json #: landa/organization_management/report/magazine_address_list/magazine_address_list.py:150 #: landa/organization_management/report/member_address_list/member_address_list.js:10 @@ -1249,6 +1276,9 @@ 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:18 +#: landa/organization_management/report/work_hours/work_hours.py:46 #: 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" @@ -1348,6 +1378,13 @@ msgstr "" msgid "Member Last Name" msgstr "" +#. Label of a Data 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:25 +#: landa/organization_management/report/work_hours/work_hours.py:53 +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" @@ -1515,6 +1552,12 @@ 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:65 +msgid "Planned Duration (Hours)" +msgstr "" + #. Label of a Check field in DocType 'Catch Log Fish Table' #: landa/water_body_management/doctype/catch_log_fish_table/catch_log_fish_table.json msgid "Plausible" @@ -1951,6 +1994,10 @@ msgstr "" msgid "Total (only for regional org.)" msgstr "" +#: landa/organization_management/report/work_hours/work_hours.py:31 +msgid "Total Hours" +msgstr "" + #. Label of a Small Text field in DocType 'Fish Species' #: landa/water_body_management/doctype/fish_species/fish_species.json msgid "Traits" @@ -2034,6 +2081,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' @@ -2044,6 +2092,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:77 #: 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 @@ -2172,11 +2223,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 @@ -2213,6 +2266,22 @@ msgstr "" msgid "Wikipedia Link" msgstr "" +#. Name of a DocType +#: landa/organization_management/doctype/landa_member/landa_member.js:77 +#: landa/organization_management/doctype/work_assignment/work_assignment.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 +#: landa/organization_management/report/work_hours/work_hours.json +msgid "Work Hours" +msgstr "" + #: landa/water_body_management/stocking_controller.py:23 msgid "Year must be between {0} and {1}." msgstr "" From 68630698ae3a1a9d028d5df9f5ecf9c6558a927e Mon Sep 17 00:00:00 2001 From: Marc <147735520+MarcCon@users.noreply.github.com> Date: Fri, 16 Jan 2026 09:23:58 +0100 Subject: [PATCH 10/43] fix: delete unnecessary pass Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .../doctype/work_assignment/work_assignment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/landa/organization_management/doctype/work_assignment/work_assignment.py b/landa/organization_management/doctype/work_assignment/work_assignment.py index 0df676b7..2aa308fb 100644 --- a/landa/organization_management/doctype/work_assignment/work_assignment.py +++ b/landa/organization_management/doctype/work_assignment/work_assignment.py @@ -29,4 +29,4 @@ class WorkAssignment(Document): water_body: DF.Link | None water_body_title: DF.Data | None # end: auto-generated types - pass + From 0549fc08d7ac03d0382ab79caf82164112bc11b3 Mon Sep 17 00:00:00 2001 From: Marc <147735520+MarcCon@users.noreply.github.com> Date: Fri, 16 Jan 2026 09:24:43 +0100 Subject: [PATCH 11/43] fix: unused import Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .../doctype/work_assignment/test_work_assignment.py | 1 - 1 file changed, 1 deletion(-) diff --git a/landa/organization_management/doctype/work_assignment/test_work_assignment.py b/landa/organization_management/doctype/work_assignment/test_work_assignment.py index d5cf956c..4ab4ffb2 100644 --- a/landa/organization_management/doctype/work_assignment/test_work_assignment.py +++ b/landa/organization_management/doctype/work_assignment/test_work_assignment.py @@ -1,7 +1,6 @@ # Copyright (c) 2026, ALYF GmbH and Contributors # See license.txt -import frappe from frappe.tests import IntegrationTestCase From adb72ba89f4469c1c798011bad217b504ac1e828 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Mon, 26 Jan 2026 10:23:07 +0100 Subject: [PATCH 12/43] refactor: use get_list instread of raw sql --- .../report/work_hours/work_hours.py | 150 +++++++++++++----- 1 file changed, 106 insertions(+), 44 deletions(-) diff --git a/landa/organization_management/report/work_hours/work_hours.py b/landa/organization_management/report/work_hours/work_hours.py index 62cd8a2a..ec588234 100644 --- a/landa/organization_management/report/work_hours/work_hours.py +++ b/landa/organization_management/report/work_hours/work_hours.py @@ -3,6 +3,7 @@ import frappe from frappe import _ +from frappe.utils import getdate def execute(filters=None): @@ -96,60 +97,121 @@ def get_columns(filters): def get_data(filters): - conditions = get_conditions(filters) + filters = filters or {} + assignment_filters = get_assignment_filters(filters) + member_filters = {} + + if filters.get("member"): + member_filters["member"] = filters.get("member") + + assignments_by_name = {} + if assignment_filters: + assignments_list = frappe.get_list( + "Work Assignment", + filters=assignment_filters, + fields=[ + "name", + "date", + "title", + "planned_duration", + "water_body", + "location", + "description", + ], + limit_page_length=0, + ) + if not assignments_list: + return [] + + assignments_by_name = {a["name"]: a for a in assignments_list} + member_filters["parent"] = ("in", list(assignments_by_name.keys())) + + members = frappe.get_list( + "Work Assignment Member", + filters=member_filters, + fields=["parent", "member", "member_name", "duration"], + parent_doctype="Work Assignment", + limit_page_length=0, + ) + + if not members: + return [] if filters.get("group_by_member"): - return frappe.db.sql( - f""" - SELECT - wam.member, - wam.member_name, - SUM(wam.duration) as total_hours - FROM `tabWork Assignment Member` wam - JOIN `tabWork Assignment` wa ON wam.parent = wa.name - WHERE 1=1 {conditions} - GROUP BY wam.member - ORDER BY total_hours DESC - """, - filters, - as_dict=True, + totals = {} + for row in members: + member = row.get("member") + entry = totals.get(member) + if entry is None: + totals[member] = { + "member": member, + "member_name": row.get("member_name"), + "total_hours": float(row.get("duration") or 0), + } + continue + + entry["total_hours"] += float(row.get("duration") or 0) + if not entry.get("member_name") and row.get("member_name"): + entry["member_name"] = row.get("member_name") + + return sorted(totals.values(), key=lambda row: row["total_hours"], reverse=True) + + if not assignments_by_name: + parent_names = list({row.get("parent") for row in members if row.get("parent")}) + if parent_names: + assignments_list = frappe.get_list( + "Work Assignment", + filters={"name": ("in", parent_names)}, + fields=[ + "name", + "date", + "title", + "planned_duration", + "water_body", + "location", + "description", + ], + limit_page_length=0, + ) + assignments_by_name = {a["name"]: a for a in assignments_list} + + data = [] + for row in members: + assignment = assignments_by_name.get(row.get("parent")) + if not assignment: + continue + + data.append( + { + "date": assignment.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("duration"), + "water_body": assignment.get("water_body"), + "location": assignment.get("location"), + "description": assignment.get("description"), + } ) - return frappe.db.sql( - f""" - SELECT - wa.date, - wam.member, - wam.member_name, - wa.title, - wa.planned_duration, - wam.duration, - wa.water_body, - wa.location, - wa.description - FROM `tabWork Assignment Member` wam - JOIN `tabWork Assignment` wa ON wam.parent = wa.name - WHERE 1=1 {conditions} - ORDER BY wa.date DESC, wam.member - """, - filters, - as_dict=True, - ) + default_date = getdate("1900-01-01") + data.sort(key=lambda row: (row.get("member") or "")) + data.sort(key=lambda row: row.get("date") or default_date, reverse=True) + return data -def get_conditions(filters): - conditions = [] +def get_assignment_filters(filters): + assignment_filters = {} if filters.get("year"): - conditions.append("AND YEAR(wa.date) = %(year)s") + year = int(filters.get("year")) + assignment_filters["date"] = ["between", [f"{year}-01-01", f"{year}-12-31"]] if filters.get("organization"): - conditions.append("AND wa.organization = %(organization)s") - - if filters.get("member"): - conditions.append("AND wam.member = %(member)s") + assignment_filters["organization"] = filters.get("organization") if filters.get("water_body"): - conditions.append("AND wa.water_body = %(water_body)s") + assignment_filters["water_body"] = filters.get("water_body") - return " ".join(conditions) + return assignment_filters From bf410c6f671fc2740d412a3f7f13901de0c07a18 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Mon, 26 Jan 2026 10:26:41 +0100 Subject: [PATCH 13/43] fix: use hash naming --- .../doctype/work_assignment/work_assignment.json | 6 +++--- .../doctype/work_assignment/work_assignment.py | 1 - landa/public/node_modules | 1 + 3 files changed, 4 insertions(+), 4 deletions(-) create mode 120000 landa/public/node_modules diff --git a/landa/organization_management/doctype/work_assignment/work_assignment.json b/landa/organization_management/doctype/work_assignment/work_assignment.json index d8fb192c..c7603ab4 100644 --- a/landa/organization_management/doctype/work_assignment/work_assignment.json +++ b/landa/organization_management/doctype/work_assignment/work_assignment.json @@ -1,7 +1,7 @@ { "actions": [], "allow_import": 1, - "autoname": "naming_series:", + "autoname": "hash", "creation": "2026-01-08 10:00:00", "doctype": "DocType", "editable_grid": 1, @@ -129,11 +129,11 @@ ], "grid_page_length": 50, "links": [], - "modified": "2026-01-09 09:43:31.823627", + "modified": "2026-01-26 10:26:01.173455", "modified_by": "Administrator", "module": "Organization Management", "name": "Work Assignment", - "naming_rule": "By \"Naming Series\" field", + "naming_rule": "Random", "owner": "Administrator", "permissions": [ { diff --git a/landa/organization_management/doctype/work_assignment/work_assignment.py b/landa/organization_management/doctype/work_assignment/work_assignment.py index 2aa308fb..4fdae749 100644 --- a/landa/organization_management/doctype/work_assignment/work_assignment.py +++ b/landa/organization_management/doctype/work_assignment/work_assignment.py @@ -29,4 +29,3 @@ class WorkAssignment(Document): water_body: DF.Link | None water_body_title: DF.Data | None # end: auto-generated types - diff --git a/landa/public/node_modules b/landa/public/node_modules new file mode 120000 index 00000000..a295ae47 --- /dev/null +++ b/landa/public/node_modules @@ -0,0 +1 @@ +/Users/marc/Code/Bench/version-15/apps/landa/node_modules \ No newline at end of file From 17166668997f52f4ad5aa865d349f61a09085ef6 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Mon, 26 Jan 2026 10:27:49 +0100 Subject: [PATCH 14/43] fix: js filter --- .../doctype/work_assignment/work_assignment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/landa/organization_management/doctype/work_assignment/work_assignment.js b/landa/organization_management/doctype/work_assignment/work_assignment.js index b06e7640..ba606429 100644 --- a/landa/organization_management/doctype/work_assignment/work_assignment.js +++ b/landa/organization_management/doctype/work_assignment/work_assignment.js @@ -23,7 +23,7 @@ frappe.ui.form.on("Work Assignment", { frm.set_query("member", "members", function (doc) { return { filters: { - organization: ["=", doc.organization], + organization: doc.organization, }, }; }); From 0f222966b5603be1f4e5deb327fd5309de3c6a88 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Wed, 28 Jan 2026 15:57:11 +0100 Subject: [PATCH 15/43] feat: make work assignment submittable --- .../doctype/work_assignment/work_assignment.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/landa/organization_management/doctype/work_assignment/work_assignment.json b/landa/organization_management/doctype/work_assignment/work_assignment.json index c7603ab4..1ad07643 100644 --- a/landa/organization_management/doctype/work_assignment/work_assignment.json +++ b/landa/organization_management/doctype/work_assignment/work_assignment.json @@ -22,7 +22,8 @@ "location", "description", "section_members", - "members" + "members", + "amended_from" ], "fields": [ { @@ -125,11 +126,22 @@ "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": [], - "modified": "2026-01-26 10:26:01.173455", + "modified": "2026-01-28 13:06:00.844504", "modified_by": "Administrator", "module": "Organization Management", "name": "Work Assignment", From ba6cb69a14111d25a427d855f649f72c2e34a4c9 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Wed, 28 Jan 2026 16:08:28 +0100 Subject: [PATCH 16/43] feat(Organization): add work hours field --- .../doctype/organization/organization.json | 20 ++++++++++++++++++- .../doctype/organization/organization.py | 1 + 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/landa/organization_management/doctype/organization/organization.json b/landa/organization_management/doctype/organization/organization.json index a2cffb40..6e087822 100644 --- a/landa/organization_management/doctype/organization/organization.json +++ b/landa/organization_management/doctype/organization/organization.json @@ -29,6 +29,8 @@ "section_break_15", "is_group", "disabled", + "section_break_work_hours", + "expected_work_hours_per_year", "lft", "rgt", "old_parent", @@ -199,6 +201,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, @@ -248,9 +261,14 @@ "group": "Gew\u00e4sserverwaltung", "link_doctype": "Water Body Management Local Organization", "link_fieldname": "organization" + }, + { + "group": "Vereinsverwaltung", + "link_doctype": "Work Ledger Entry", + "link_fieldname": "organization" } ], - "modified": "2025-12-10 14:37:18.258588", + "modified": "2026-01-28 16:05:42.757333", "modified_by": "Administrator", "module": "Organization Management", "name": "Organization", diff --git a/landa/organization_management/doctype/organization/organization.py b/landa/organization_management/doctype/organization/organization.py index 77273705..11feebc8 100644 --- a/landa/organization_management/doctype/organization/organization.py +++ b/landa/organization_management/doctype/organization/organization.py @@ -29,6 +29,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 From c662199bc409863190638880e1fea263d1c8c7d9 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Wed, 28 Jan 2026 16:10:36 +0100 Subject: [PATCH 17/43] feat: add work ledger entry doctype --- .../doctype/work_ledger_entry/__init__.py | 0 .../test_work_ledger_entry.py | 9 ++ .../work_ledger_entry/work_ledger_entry.js | 8 + .../work_ledger_entry/work_ledger_entry.json | 152 ++++++++++++++++++ .../work_ledger_entry/work_ledger_entry.py | 26 +++ 5 files changed, 195 insertions(+) create mode 100644 landa/organization_management/doctype/work_ledger_entry/__init__.py create mode 100644 landa/organization_management/doctype/work_ledger_entry/test_work_ledger_entry.py create mode 100644 landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.js create mode 100644 landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json create mode 100644 landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.py 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..dc14ac99 --- /dev/null +++ b/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.js @@ -0,0 +1,8 @@ +// Copyright (c) 2026, ALYF GmbH and contributors +// For license information, please see license.txt + +// frappe.ui.form.on("Work Ledger Entry", { +// refresh(frm) { + +// }, +// }); 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..d11f1439 --- /dev/null +++ b/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json @@ -0,0 +1,152 @@ +{ + "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", + "member", + "member_name", + "organization", + "organization_name", + "column_break_basic", + "date", + "work_assignment", + "hours_change" + ], + "fields": [ + { + "fieldname": "section_basic", + "fieldtype": "Section Break", + "label": "Basic Information" + }, + { + "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 + }, + { + "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-01-28 16:04:35.195256", + "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..d5f7c6b2 --- /dev/null +++ b/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.py @@ -0,0 +1,26 @@ +# 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, 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 + pass \ No newline at end of file From ab8fa6cb8f7ecf7f55cebe30b8c63ac3dcb29eb5 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Wed, 28 Jan 2026 16:12:35 +0100 Subject: [PATCH 18/43] feat: create and delete work ledger entry from work assignment --- .../work_assignment/work_assignment.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/landa/organization_management/doctype/work_assignment/work_assignment.py b/landa/organization_management/doctype/work_assignment/work_assignment.py index 4fdae749..8a130dfe 100644 --- a/landa/organization_management/doctype/work_assignment/work_assignment.py +++ b/landa/organization_management/doctype/work_assignment/work_assignment.py @@ -1,6 +1,7 @@ # Copyright (c) 2026, ALYF GmbH and contributors # For license information, please see license.txt +import frappe from frappe.model.document import Document @@ -17,6 +18,7 @@ class WorkAssignment(Document): WorkAssignmentMember, ) + amended_from: DF.Link | None date: DF.Date description: DF.SmallText | None location: DF.Data | None @@ -29,3 +31,24 @@ class WorkAssignment(Document): 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): + frappe.delete_doc("Work Ledger Entry", {"work_assignment": self.name}) From 0f53b47fd306e6164da9879daaf9000759476cf4 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Sat, 31 Jan 2026 10:23:27 +0100 Subject: [PATCH 19/43] feat: create yearly negative entries --- landa/hooks.py | 3 ++ .../work_ledger_entry/work_ledger_entry.py | 33 +++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/landa/hooks.py b/landa/hooks.py index 80533e1a..bbeab63e 100644 --- a/landa/hooks.py +++ b/landa/hooks.py @@ -335,6 +335,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/organization_management/doctype/work_ledger_entry/work_ledger_entry.py b/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.py index d5f7c6b2..91cee15c 100644 --- a/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.py +++ b/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.py @@ -3,7 +3,7 @@ import frappe from frappe.model.document import Document -from frappe.utils import getdate, now_datetime +from frappe.utils.data import now_datetime class WorkLedgerEntry(Document): @@ -23,4 +23,33 @@ class WorkLedgerEntry(Document): organization_name: DF.Data | None work_assignment: DF.Link | None # end: auto-generated types - pass \ No newline at end of file + pass + + +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() From 9c6798b59aa341f8dce6051968e7591df7663bc7 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Sat, 31 Jan 2026 10:51:23 +0100 Subject: [PATCH 20/43] feat(Work Ledger Entry): filter members of organization --- .../doctype/work_ledger_entry/work_ledger_entry.js | 14 +++++++++----- .../work_ledger_entry/work_ledger_entry.json | 7 ++++--- 2 files changed, 13 insertions(+), 8 deletions(-) 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 index dc14ac99..faa9bf8c 100644 --- a/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.js +++ b/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.js @@ -1,8 +1,12 @@ // Copyright (c) 2026, ALYF GmbH and contributors // For license information, please see license.txt -// frappe.ui.form.on("Work Ledger Entry", { -// refresh(frm) { - -// }, -// }); +frappe.ui.form.on("Work Ledger Entry", { + setup(frm) { + frm.set_query("member", function () { + return { + filters: { organization: frm.doc.organization }, + }; + }); + }, +}); 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 index d11f1439..19443065 100644 --- a/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json +++ b/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json @@ -9,10 +9,10 @@ "engine": "InnoDB", "field_order": [ "section_basic", - "member", - "member_name", "organization", "organization_name", + "member", + "member_name", "column_break_basic", "date", "work_assignment", @@ -25,6 +25,7 @@ "label": "Basic Information" }, { + "depends_on": "eval:doc.organization", "fieldname": "member", "fieldtype": "Link", "in_list_view": 1, @@ -90,7 +91,7 @@ "grid_page_length": 50, "index_web_pages_for_search": 1, "links": [], - "modified": "2026-01-28 16:04:35.195256", + "modified": "2026-01-31 10:48:46.175196", "modified_by": "Administrator", "module": "Organization Management", "name": "Work Ledger Entry", From 4e7a49398a9a4d4f87c1d784e572c8b3972fe1ee Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Wed, 18 Feb 2026 10:27:20 +0100 Subject: [PATCH 21/43] fix: remove accidentally commited link --- landa/public/node_modules | 1 - 1 file changed, 1 deletion(-) delete mode 120000 landa/public/node_modules diff --git a/landa/public/node_modules b/landa/public/node_modules deleted file mode 120000 index a295ae47..00000000 --- a/landa/public/node_modules +++ /dev/null @@ -1 +0,0 @@ -/Users/marc/Code/Bench/version-15/apps/landa/node_modules \ No newline at end of file From 4f58745775d13efaaa79517246479ad8e48c71c8 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Wed, 18 Feb 2026 10:31:20 +0100 Subject: [PATCH 22/43] fix: remove naming_series field --- .../doctype/work_assignment/work_assignment.json | 10 +--------- .../doctype/work_assignment/work_assignment.py | 1 - 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/landa/organization_management/doctype/work_assignment/work_assignment.json b/landa/organization_management/doctype/work_assignment/work_assignment.json index 1ad07643..261f86b9 100644 --- a/landa/organization_management/doctype/work_assignment/work_assignment.json +++ b/landa/organization_management/doctype/work_assignment/work_assignment.json @@ -7,7 +7,6 @@ "editable_grid": 1, "engine": "InnoDB", "field_order": [ - "naming_series", "section_basic", "organization", "organization_name", @@ -26,13 +25,6 @@ "amended_from" ], "fields": [ - { - "fieldname": "naming_series", - "fieldtype": "Select", - "hidden": 1, - "label": "Naming Series", - "options": "WORK-.YYYY.-.#####" - }, { "fieldname": "section_basic", "fieldtype": "Section Break", @@ -141,7 +133,7 @@ "grid_page_length": 50, "is_submittable": 1, "links": [], - "modified": "2026-01-28 13:06:00.844504", + "modified": "2026-02-18 10:30:22.306657", "modified_by": "Administrator", "module": "Organization Management", "name": "Work Assignment", diff --git a/landa/organization_management/doctype/work_assignment/work_assignment.py b/landa/organization_management/doctype/work_assignment/work_assignment.py index 8a130dfe..02945c7a 100644 --- a/landa/organization_management/doctype/work_assignment/work_assignment.py +++ b/landa/organization_management/doctype/work_assignment/work_assignment.py @@ -23,7 +23,6 @@ class WorkAssignment(Document): description: DF.SmallText | None location: DF.Data | None members: DF.Table[WorkAssignmentMember] - naming_series: DF.Literal["WORK-.YYYY.-.#####"] organization: DF.Link organization_name: DF.Data | None planned_duration: DF.Float From 19709aae006ee489423584f0c1914f6239a064da Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Wed, 18 Feb 2026 11:58:08 +0100 Subject: [PATCH 23/43] fix: use work ledger entry for report --- .../report/work_hours/work_hours.json | 2 +- .../report/work_hours/work_hours.py | 175 ++++++------------ 2 files changed, 56 insertions(+), 121 deletions(-) diff --git a/landa/organization_management/report/work_hours/work_hours.json b/landa/organization_management/report/work_hours/work_hours.json index dd138b67..7f0c88b8 100644 --- a/landa/organization_management/report/work_hours/work_hours.json +++ b/landa/organization_management/report/work_hours/work_hours.json @@ -16,7 +16,7 @@ "name": "Work Hours", "owner": "Administrator", "prepared_report": 0, - "ref_doctype": "Work Assignment", + "ref_doctype": "Work Ledger Entry", "report_name": "Work Hours", "report_type": "Script Report", "roles": [ diff --git a/landa/organization_management/report/work_hours/work_hours.py b/landa/organization_management/report/work_hours/work_hours.py index ec588234..0b2813ae 100644 --- a/landa/organization_management/report/work_hours/work_hours.py +++ b/landa/organization_management/report/work_hours/work_hours.py @@ -37,12 +37,7 @@ def get_columns(filters): ] return [ - { - "label": _("Date"), - "fieldname": "date", - "fieldtype": "Date", - "width": 100, - }, + {"label": _("Date"), "fieldname": "date", "fieldtype": "Date", "width": 100}, { "label": _("Member"), "fieldname": "member", @@ -50,30 +45,15 @@ def get_columns(filters): "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": _("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": _("Duration (Hours)"), "fieldname": "duration", "fieldtype": "Float", "width": 120}, { "label": _("Water Body"), "fieldname": "water_body", @@ -81,114 +61,59 @@ def get_columns(filters): "options": "Water Body", "width": 150, }, - { - "label": _("Location"), - "fieldname": "location", - "fieldtype": "Data", - "width": 150, - }, - { - "label": _("Description"), - "fieldname": "description", - "fieldtype": "Data", - "width": 200, - }, + {"label": _("Location"), "fieldname": "location", "fieldtype": "Data", "width": 150}, + {"label": _("Description"), "fieldname": "description", "fieldtype": "Data", "width": 200}, ] def get_data(filters): filters = filters or {} - assignment_filters = get_assignment_filters(filters) - member_filters = {} - - if filters.get("member"): - member_filters["member"] = filters.get("member") + ledger_filters = _get_ledger_filters(filters) - assignments_by_name = {} - if assignment_filters: - assignments_list = frappe.get_list( - "Work Assignment", - filters=assignment_filters, + if filters.get("group_by_member"): + return frappe.get_list( + "Work Ledger Entry", + filters=ledger_filters, fields=[ - "name", - "date", - "title", - "planned_duration", - "water_body", - "location", - "description", + "member", + "member_name", + "sum(hours_change) as total_hours", ], - limit_page_length=0, + group_by="member, member_name", + order_by="total_hours desc", ) - if not assignments_list: - return [] - - assignments_by_name = {a["name"]: a for a in assignments_list} - member_filters["parent"] = ("in", list(assignments_by_name.keys())) - - members = frappe.get_list( - "Work Assignment Member", - filters=member_filters, - fields=["parent", "member", "member_name", "duration"], - parent_doctype="Work Assignment", - limit_page_length=0, + + 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 members: + if not entries: return [] - if filters.get("group_by_member"): - totals = {} - for row in members: - member = row.get("member") - entry = totals.get(member) - if entry is None: - totals[member] = { - "member": member, - "member_name": row.get("member_name"), - "total_hours": float(row.get("duration") or 0), - } - continue - - entry["total_hours"] += float(row.get("duration") or 0) - if not entry.get("member_name") and row.get("member_name"): - entry["member_name"] = row.get("member_name") - - return sorted(totals.values(), key=lambda row: row["total_hours"], reverse=True) - - if not assignments_by_name: - parent_names = list({row.get("parent") for row in members if row.get("parent")}) - if parent_names: - assignments_list = frappe.get_list( - "Work Assignment", - filters={"name": ("in", parent_names)}, - fields=[ - "name", - "date", - "title", - "planned_duration", - "water_body", - "location", - "description", - ], - limit_page_length=0, - ) - assignments_by_name = {a["name"]: a for a in assignments_list} + 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 members: - assignment = assignments_by_name.get(row.get("parent")) - if not assignment: - continue - + for row in entries: + assignment = assignments_by_name.get(row.get("work_assignment")) or {} data.append( { - "date": assignment.get("date"), + "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("duration"), + "duration": row.get("hours_change"), "water_body": assignment.get("water_body"), "location": assignment.get("location"), "description": assignment.get("description"), @@ -196,22 +121,32 @@ def get_data(filters): ) default_date = getdate("1900-01-01") - data.sort(key=lambda row: (row.get("member") or "")) - data.sort(key=lambda row: row.get("date") or default_date, reverse=True) + 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_assignment_filters(filters): - assignment_filters = {} +def _get_ledger_filters(filters): + ledger_filters = {} if filters.get("year"): - year = int(filters.get("year")) - assignment_filters["date"] = ["between", [f"{year}-01-01", f"{year}-12-31"]] + year = int(filters["year"]) + ledger_filters["date"] = ["between", [f"{year}-01-01", f"{year}-12-31"]] if filters.get("organization"): - assignment_filters["organization"] = filters.get("organization") + ledger_filters["organization"] = filters["organization"] + + if filters.get("member"): + ledger_filters["member"] = filters["member"] if filters.get("water_body"): - assignment_filters["water_body"] = 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 assignment_filters + return ledger_filters From 718f1500300084e431ab103798af65b375ce4fad Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Wed, 18 Feb 2026 12:30:46 +0100 Subject: [PATCH 24/43] feat(Organization): track expected work hours changes --- .../doctype/organization/organization.py | 14 +++++++++++ .../work_ledger_entry/work_ledger_entry.py | 24 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/landa/organization_management/doctype/organization/organization.py b/landa/organization_management/doctype/organization/organization.py index 11feebc8..56a46cd6 100644 --- a/landa/organization_management/doctype/organization/organization.py +++ b/landa/organization_management/doctype/organization/organization.py @@ -16,6 +16,9 @@ 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): @@ -85,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 = 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 = self._expected_work_hours_before_save + new = 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_ledger_entry/work_ledger_entry.py b/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.py index 91cee15c..2b760693 100644 --- a/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.py +++ b/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.py @@ -3,6 +3,7 @@ import frappe from frappe.model.document import Document +from frappe.utils import getdate from frappe.utils.data import now_datetime @@ -53,3 +54,26 @@ def create_yearly_negative_entries(): 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() From 1c14f45975c4f7f62d8557099f2f0e9f9da80033 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Fri, 27 Feb 2026 17:46:18 +0100 Subject: [PATCH 25/43] feat: add work ledger balance report --- .../report/work_ledger_balance/__init__.py | 0 .../work_ledger_balance.js | 38 +++++++ .../work_ledger_balance.json | 31 ++++++ .../work_ledger_balance.py | 105 ++++++++++++++++++ 4 files changed, 174 insertions(+) create mode 100644 landa/organization_management/report/work_ledger_balance/__init__.py create mode 100644 landa/organization_management/report/work_ledger_balance/work_ledger_balance.js create mode 100644 landa/organization_management/report/work_ledger_balance/work_ledger_balance.json create mode 100644 landa/organization_management/report/work_ledger_balance/work_ledger_balance.py 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..dcccf95d --- /dev/null +++ b/landa/organization_management/report/work_ledger_balance/work_ledger_balance.py @@ -0,0 +1,105 @@ +# 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": 120, + }, + {"label": _("Member Name"), "fieldname": "member_name", "fieldtype": "Data", "width": 180}, + { + "label": _("Balance End Previous Year"), + "fieldname": "balance_previous_year", + "fieldtype": "Float", + "width": 140, + }, + { + "label": _("Expected This Year"), + "fieldname": "expected_this_year", + "fieldtype": "Float", + "width": 120, + }, + { + "label": _("Worked This Year"), + "fieldname": "worked_this_year", + "fieldtype": "Float", + "width": 120, + }, + { + "label": _("Balance End of Year"), + "fieldname": "balance_end_of_year", + "fieldtype": "Float", + "width": 140, + }, + ] + + +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"], + ) + 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)}) + + 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 = [ + r["hours_change"] + for r in data["rows"] + if r["date"] is not None and year_start <= r["date"] <= year_end + ] + expected_this_year = sum(h for h in in_year if h < 0) + worked_this_year = sum(h for h in in_year if h > 0) + balance_end = balance_previous + sum(in_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 \ No newline at end of file From 651d71947eebbeceb088e8cd5eafdba6022b8938 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Fri, 27 Feb 2026 17:53:51 +0100 Subject: [PATCH 26/43] feat: add translations --- landa/locale/de.po | 95 +++++++++++++++++++++++++++++++++--------- landa/locale/main.pot | 97 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 153 insertions(+), 39 deletions(-) diff --git a/landa/locale/de.po b/landa/locale/de.po index af037b08..02d05215 100644 --- a/landa/locale/de.po +++ b/landa/locale/de.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: LANDA VERSION\n" "Report-Msgid-Bugs-To: hallo@alyf.de\n" -"POT-Creation-Date: 2026-01-16 09:20+0053\n" +"POT-Creation-Date: 2026-02-27 17:48+0053\n" "PO-Revision-Date: 2025-11-29 18:55+0053\n" "Last-Translator: hallo@alyf.de\n" "Language-Team: hallo@alyf.de\n" @@ -96,7 +96,7 @@ 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:59 +#: landa/organization_management/report/work_hours/work_hours.py:49 msgid "Activity Title" msgstr "Bezeichnung der Tätigkeit" @@ -162,12 +162,22 @@ 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" @@ -231,7 +241,7 @@ 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 "" @@ -305,7 +315,7 @@ msgstr "Neue Besatzmaßnahme" msgid "Create Stocking Targets" msgstr "Besatzplanungen erstellen" -#: landa/organization_management/doctype/landa_member/landa_member_list.js:79 +#: landa/organization_management/doctype/landa_member/landa_member_list.js:82 msgid "Create Yearly Fishing Permit" msgstr "Erlaubnisschein erstellen" @@ -400,7 +410,7 @@ 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:71 +#: landa/organization_management/report/work_hours/work_hours.py:56 msgid "Duration (Hours)" msgstr "Dauer (Stunden)" @@ -409,6 +419,15 @@ msgstr "Dauer (Stunden)" 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" + #. Name of a DocType #. Label of a Heading field in DocType 'External Contact' #. Label of a Link in the Organization Management Workspace @@ -782,6 +801,11 @@ msgstr "" msgid "Hat VANT Erlaubnisschein" 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 "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:178 @@ -981,6 +1005,7 @@ msgstr "LANDA Mitgliederverwaltung Ortsgruppe" #: 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" @@ -1061,6 +1086,7 @@ msgstr "LANDA Einstellungen" #: 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 @@ -1098,6 +1124,7 @@ msgstr "" #: 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 @@ -1271,11 +1298,13 @@ 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/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:150 #: landa/organization_management/report/member_address_list/member_address_list.js:10 @@ -1285,8 +1314,10 @@ msgstr "" #: 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:18 -#: landa/organization_management/report/work_hours/work_hours.py:46 +#: 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" @@ -1387,9 +1418,12 @@ 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/report/work_hours/work_hours.py:25 -#: landa/organization_management/report/work_hours/work_hours.py:53 +#: 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" @@ -1480,7 +1514,7 @@ msgstr "Neuen Fangbucheintrag anlegen" msgid "New Member Function Entry" msgstr "Neue Mitgliedsfunktion anlegen" -#: 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." @@ -1562,7 +1596,7 @@ 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:65 +#: landa/organization_management/report/work_hours/work_hours.py:51 msgid "Planned Duration (Hours)" msgstr "Geplante Dauer (Stunden)" @@ -1599,7 +1633,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." @@ -1841,7 +1875,7 @@ msgstr "Fangbegrenzung Salmonidengewässer" msgid "Special Yearly Fishing Permits" msgstr "Erlaubnisscheine Gewässerfonds" -#: landa/organization_management/doctype/landa_member/landa_member_list.js:68 +#: landa/organization_management/doctype/landa_member/landa_member_list.js:71 msgid "Special Yearly Fishing Permits cleared." msgstr "Erlaubnisscheine Gewässerfonds gelöscht." @@ -1957,15 +1991,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." @@ -2006,7 +2040,7 @@ msgstr "HTML umschalten" msgid "Total (only for regional org.)" msgstr "Summe (nur für RV)" -#: landa/organization_management/report/work_hours/work_hours.py:31 +#: landa/organization_management/report/work_hours/work_hours.py:32 msgid "Total Hours" msgstr "Gesamtstunden" @@ -2106,7 +2140,7 @@ msgstr "" #. 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:77 +#: 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 @@ -2279,8 +2313,10 @@ 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" @@ -2294,6 +2330,27 @@ msgstr "Arbeitseinsatz Teilnehmer" 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" + +#. Name of a report +#: landa/organization_management/report/work_ledger_balance/work_ledger_balance.json +msgid "Work Ledger Balance" +msgstr "Arbeitszeit je Verein und Jahr" + +#. Linked DocType in Organization's connections +#. Name of a DocType +#: landa/organization_management/doctype/organization/organization.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." @@ -2356,7 +2413,7 @@ msgstr "Erlaubnisschein für Mitglied {0} und Jahr {1} existiert bereits. Bitte msgid "Yearly Fishing Permits Issued" msgstr "Vergebene Erlaubnisscheine" -#: landa/organization_management/doctype/landa_member/landa_member_list.js:110 +#: landa/organization_management/doctype/landa_member/landa_member_list.js:113 msgid "Yearly Fishing Permits have been created for {0} members." msgstr "Erlaubnisscheine für {0} Mitglieder wurden erstellt." diff --git a/landa/locale/main.pot b/landa/locale/main.pot index 7cf3cb39..f57f3346 100644 --- a/landa/locale/main.pot +++ b/landa/locale/main.pot @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: LANDA VERSION\n" "Report-Msgid-Bugs-To: hallo@alyf.de\n" -"POT-Creation-Date: 2026-01-16 09:20+0053\n" -"PO-Revision-Date: 2026-01-16 09:20+0053\n" +"POT-Creation-Date: 2026-02-27 17:48+0053\n" +"PO-Revision-Date: 2026-02-27 17:48+0053\n" "Last-Translator: hallo@alyf.de\n" "Language-Team: hallo@alyf.de\n" "MIME-Version: 1.0\n" @@ -96,7 +96,7 @@ 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:59 +#: landa/organization_management/report/work_hours/work_hours.py:49 msgid "Activity Title" msgstr "" @@ -162,12 +162,22 @@ 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 "" @@ -231,7 +241,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 "" @@ -305,7 +315,7 @@ msgstr "" msgid "Create Stocking Targets" msgstr "" -#: landa/organization_management/doctype/landa_member/landa_member_list.js:79 +#: landa/organization_management/doctype/landa_member/landa_member_list.js:82 msgid "Create Yearly Fishing Permit" msgstr "" @@ -400,7 +410,7 @@ 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:71 +#: landa/organization_management/report/work_hours/work_hours.py:56 msgid "Duration (Hours)" msgstr "" @@ -409,6 +419,15 @@ msgstr "" 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 "" + #. Name of a DocType #. Label of a Heading field in DocType 'External Contact' #. Label of a Link in the Organization Management Workspace @@ -782,6 +801,11 @@ msgstr "" msgid "Hat VANT Erlaubnisschein" 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:178 @@ -981,6 +1005,7 @@ msgstr "" #: 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" @@ -1061,6 +1086,7 @@ msgstr "" #: 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 @@ -1098,6 +1124,7 @@ msgstr "" #: 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 @@ -1271,11 +1298,13 @@ 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/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:150 #: landa/organization_management/report/member_address_list/member_address_list.js:10 @@ -1285,8 +1314,10 @@ msgstr "" #: 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:18 -#: landa/organization_management/report/work_hours/work_hours.py:46 +#: 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" @@ -1387,9 +1418,12 @@ 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/report/work_hours/work_hours.py:25 -#: landa/organization_management/report/work_hours/work_hours.py:53 +#: 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 "" @@ -1480,7 +1514,7 @@ msgstr "" msgid "New Member Function Entry" 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 "" @@ -1562,7 +1596,7 @@ 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:65 +#: landa/organization_management/report/work_hours/work_hours.py:51 msgid "Planned Duration (Hours)" msgstr "" @@ -1599,7 +1633,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 "" @@ -1841,7 +1875,7 @@ msgstr "" msgid "Special Yearly Fishing Permits" msgstr "" -#: landa/organization_management/doctype/landa_member/landa_member_list.js:68 +#: landa/organization_management/doctype/landa_member/landa_member_list.js:71 msgid "Special Yearly Fishing Permits cleared." msgstr "" @@ -1957,15 +1991,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 "" @@ -2006,7 +2040,7 @@ msgstr "" msgid "Total (only for regional org.)" msgstr "" -#: landa/organization_management/report/work_hours/work_hours.py:31 +#: landa/organization_management/report/work_hours/work_hours.py:32 msgid "Total Hours" msgstr "" @@ -2106,7 +2140,7 @@ msgstr "" #. 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:77 +#: 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 @@ -2279,8 +2313,10 @@ 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 "" @@ -2294,6 +2330,27 @@ msgstr "" 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 "" + +#. Name of a report +#: landa/organization_management/report/work_ledger_balance/work_ledger_balance.json +msgid "Work Ledger Balance" +msgstr "" + +#. Linked DocType in Organization's connections +#. Name of a DocType +#: landa/organization_management/doctype/organization/organization.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 "" @@ -2356,7 +2413,7 @@ msgstr "" msgid "Yearly Fishing Permits Issued" msgstr "" -#: landa/organization_management/doctype/landa_member/landa_member_list.js:110 +#: landa/organization_management/doctype/landa_member/landa_member_list.js:113 msgid "Yearly Fishing Permits have been created for {0} members." msgstr "" From 8507b93406fb18a66cc08720f744996a6c6c735c Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Mon, 9 Mar 2026 21:18:56 +0100 Subject: [PATCH 27/43] fix: increase report col width --- .../work_ledger_balance.py | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) 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 index dcccf95d..4108322a 100644 --- a/landa/organization_management/report/work_ledger_balance/work_ledger_balance.py +++ b/landa/organization_management/report/work_ledger_balance/work_ledger_balance.py @@ -19,32 +19,32 @@ def get_columns(): "fieldname": "member", "fieldtype": "Link", "options": "LANDA Member", - "width": 120, + "width": 150, }, {"label": _("Member Name"), "fieldname": "member_name", "fieldtype": "Data", "width": 180}, { "label": _("Balance End Previous Year"), "fieldname": "balance_previous_year", "fieldtype": "Float", - "width": 140, + "width": 200, }, { "label": _("Expected This Year"), "fieldname": "expected_this_year", "fieldtype": "Float", - "width": 120, + "width": 200, }, { "label": _("Worked This Year"), "fieldname": "worked_this_year", "fieldtype": "Float", - "width": 120, + "width": 200, }, { "label": _("Balance End of Year"), "fieldname": "balance_end_of_year", "fieldtype": "Float", - "width": 140, + "width": 200, }, ] @@ -76,7 +76,9 @@ def get_data(filters): 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)}) + by_member[m]["rows"].append( + {"date": row["date"], "hours_change": float(row.get("hours_change") or 0)} + ) result = [] for member, data in by_member.items(): @@ -92,14 +94,16 @@ def get_data(filters): worked_this_year = sum(h for h in in_year if h > 0) balance_end = balance_previous + sum(in_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.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 \ No newline at end of file + return result From fcf3074f56ddeb665a9536321607f35ef2d595d1 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Mon, 9 Mar 2026 21:39:52 +0100 Subject: [PATCH 28/43] fix: treat missing work assignment as adjustment entry --- .../work_ledger_entry/work_ledger_entry.json | 3 ++- .../work_ledger_balance/work_ledger_balance.py | 16 +++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) 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 index 19443065..35b3726c 100644 --- a/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json +++ b/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.json @@ -73,6 +73,7 @@ "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, @@ -91,7 +92,7 @@ "grid_page_length": 50, "index_web_pages_for_search": 1, "links": [], - "modified": "2026-01-31 10:48:46.175196", + "modified": "2026-03-09 21:22:56.616937", "modified_by": "Administrator", "module": "Organization Management", "name": "Work Ledger Entry", 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 index 4108322a..fef7fe67 100644 --- a/landa/organization_management/report/work_ledger_balance/work_ledger_balance.py +++ b/landa/organization_management/report/work_ledger_balance/work_ledger_balance.py @@ -66,7 +66,7 @@ def get_data(filters): entries = frappe.get_list( "Work Ledger Entry", filters=base_filters, - fields=["member", "member_name", "date", "hours_change"], + fields=["member", "member_name", "date", "hours_change", "work_assignment"], ) if not entries: return [] @@ -86,13 +86,15 @@ def get_data(filters): r["hours_change"] for r in data["rows"] if r["date"] is not None and r["date"] < year_start ) in_year = [ - r["hours_change"] - for r in data["rows"] - if r["date"] is not None and year_start <= r["date"] <= year_end + row for row in data["rows"] if row["date"] is not None and year_start <= row["date"] <= year_end ] - expected_this_year = sum(h for h in in_year if h < 0) - worked_this_year = sum(h for h in in_year if h > 0) - balance_end = balance_previous + sum(in_year) + 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( { From 396c0b4b7241b042f9cd25f05dfb99bbb2e36cc5 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Wed, 8 Apr 2026 09:25:44 +0200 Subject: [PATCH 29/43] feat(Work Assignment): add connection to work ledger entry --- .../doctype/work_assignment/work_assignment.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/landa/organization_management/doctype/work_assignment/work_assignment.json b/landa/organization_management/doctype/work_assignment/work_assignment.json index 261f86b9..125aaf89 100644 --- a/landa/organization_management/doctype/work_assignment/work_assignment.json +++ b/landa/organization_management/doctype/work_assignment/work_assignment.json @@ -132,8 +132,13 @@ ], "grid_page_length": 50, "is_submittable": 1, - "links": [], - "modified": "2026-02-18 10:30:22.306657", + "links": [ + { + "link_doctype": "Work Ledger Entry", + "link_fieldname": "work_assignment" + } + ], + "modified": "2026-04-08 09:22:40.975143", "modified_by": "Administrator", "module": "Organization Management", "name": "Work Assignment", From 91c3c7d96325dc81abb2375a0d020edb6393ec0a Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Wed, 8 Apr 2026 09:58:01 +0200 Subject: [PATCH 30/43] feat: add reports to organization management workspace --- .../organization_management.json | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/landa/organization_management/workspace/organization_management/organization_management.json b/landa/organization_management/workspace/organization_management/organization_management.json index 51b9911d..5831fd34 100644 --- a/landa/organization_management/workspace/organization_management/organization_management.json +++ b/landa/organization_management/workspace/organization_management/organization_management.json @@ -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,39 @@ "onboard": 0, "type": "Link" }, + { + "hidden": 0, + "is_query_report": 0, + "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": 0, + "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, + "label": "Work Hours Per Member and Year", + "link_count": 0, + "link_to": "Work Hours Per Member and Year", + "link_type": "Report", + "onboard": 0, + "report_ref_doctype": "Work Ledger Entry", + "type": "Link" + }, { "hidden": 0, "is_query_report": 0, @@ -285,7 +319,7 @@ "type": "Link" } ], - "modified": "2024-07-11 14:59:31.302312", + "modified": "2026-04-08 09:57:02.702836", "modified_by": "Administrator", "module": "Organization Management", "name": "Organization Management", @@ -308,18 +342,21 @@ "doc_view": "", "label": "Member Address List", "link_to": "Member Address List", + "report_ref_doctype": "LANDA Member", "type": "Report" }, { "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" }, { From b180c7537a0534e1d0d00afcfa79c8a6c638f66c Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Wed, 8 Apr 2026 10:11:59 +0200 Subject: [PATCH 31/43] fix(Work Hours Report): handle missing descriptions --- .../organization_management/report/work_hours/work_hours.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/landa/organization_management/report/work_hours/work_hours.py b/landa/organization_management/report/work_hours/work_hours.py index 0b2813ae..b3c0d956 100644 --- a/landa/organization_management/report/work_hours/work_hours.py +++ b/landa/organization_management/report/work_hours/work_hours.py @@ -29,7 +29,7 @@ def get_columns(filters): "width": 200, }, { - "label": _("Total Hours"), + "label": _("Hours Balance"), "fieldname": "total_hours", "fieldtype": "Float", "width": 120, @@ -116,7 +116,9 @@ def get_data(filters): "duration": row.get("hours_change"), "water_body": assignment.get("water_body"), "location": assignment.get("location"), - "description": assignment.get("description"), + "description": _("Expected work hours adjustment") + if not row.get("work_assignment") + else assignment.get("description"), } ) From 628607c281fcc0b8f2eab961931610c1b2d726c5 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Wed, 8 Apr 2026 10:12:07 +0200 Subject: [PATCH 32/43] feat: translations --- landa/locale/de.po | 31 ++++++++++++++++++++++++++----- landa/locale/main.pot | 33 +++++++++++++++++++++++++++------ 2 files changed, 53 insertions(+), 11 deletions(-) diff --git a/landa/locale/de.po b/landa/locale/de.po index d87bb6ee..6426727f 100644 --- a/landa/locale/de.po +++ b/landa/locale/de.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: LANDA VERSION\n" "Report-Msgid-Bugs-To: hallo@alyf.de\n" -"POT-Creation-Date: 2026-03-09 20:57+0053\n" +"POT-Creation-Date: 2026-04-08 10:04+0053\n" "PO-Revision-Date: 2025-11-29 18:55+0053\n" "Last-Translator: hallo@alyf.de\n" "Language-Team: hallo@alyf.de\n" @@ -433,6 +433,10 @@ msgstr "Erwartet dieses Jahr" 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 @@ -822,6 +826,10 @@ 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" @@ -843,6 +851,12 @@ msgstr "Symbolpfad" msgid "Icon Preview" 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 msgid "Importe" @@ -2091,10 +2105,6 @@ msgstr "HTML umschalten" msgid "Total (only for regional org.)" msgstr "Summe (nur für RV)" -#: landa/organization_management/report/work_hours/work_hours.py:32 -msgid "Total Hours" -msgstr "Gesamtstunden" - #. Label of a Small Text field in DocType 'Fish Species' #: landa/water_body_management/doctype/fish_species/fish_species.json msgid "Traits" @@ -2386,7 +2396,9 @@ 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" @@ -2395,14 +2407,23 @@ msgstr "Arbeitsstunden" 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" diff --git a/landa/locale/main.pot b/landa/locale/main.pot index 55ff611c..64c1e56a 100644 --- a/landa/locale/main.pot +++ b/landa/locale/main.pot @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: LANDA VERSION\n" "Report-Msgid-Bugs-To: hallo@alyf.de\n" -"POT-Creation-Date: 2026-03-09 20:57+0053\n" -"PO-Revision-Date: 2026-03-09 20:57+0053\n" +"POT-Creation-Date: 2026-04-08 10:04+0053\n" +"PO-Revision-Date: 2026-04-08 10:04+0053\n" "Last-Translator: hallo@alyf.de\n" "Language-Team: hallo@alyf.de\n" "MIME-Version: 1.0\n" @@ -433,6 +433,10 @@ msgstr "" 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 @@ -819,6 +823,10 @@ 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" @@ -840,6 +848,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" @@ -2088,10 +2102,6 @@ msgstr "" msgid "Total (only for regional org.)" msgstr "" -#: landa/organization_management/report/work_hours/work_hours.py:32 -msgid "Total Hours" -msgstr "" - #. Label of a Small Text field in DocType 'Fish Species' #: landa/water_body_management/doctype/fish_species/fish_species.json msgid "Traits" @@ -2383,7 +2393,9 @@ 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 "" @@ -2392,14 +2404,23 @@ msgstr "" 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 "" From 7ccf61a0682e69e3c6af9eab8c151db9cf32f2f3 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Wed, 8 Apr 2026 10:21:20 +0200 Subject: [PATCH 33/43] fix: type error --- .../doctype/organization/organization.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/landa/organization_management/doctype/organization/organization.py b/landa/organization_management/doctype/organization/organization.py index 56a46cd6..578d0302 100644 --- a/landa/organization_management/doctype/organization/organization.py +++ b/landa/organization_management/doctype/organization/organization.py @@ -12,7 +12,7 @@ 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 @@ -91,7 +91,7 @@ def after_insert(self): def before_save(self): old = 0.0 if frappe.db.exists("Organization", self.name): - old = frappe.db.get_value("Organization", self.name, "expected_work_hours_per_year") + old = flt(frappe.db.get_value("Organization", self.name, "expected_work_hours_per_year")) self._expected_work_hours_before_save = old def onload(self): @@ -99,8 +99,8 @@ def onload(self): def on_update(self): if getattr(self, "_expected_work_hours_before_save", None) is not None: - old = self._expected_work_hours_before_save - new = self.expected_work_hours_per_year + 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() From ad85f12e73b70e8a608c7c83b9a2ad85e4de07db Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Thu, 9 Apr 2026 17:58:54 +0200 Subject: [PATCH 34/43] fix(Work Assignment): update permissions --- .../work_assignment/work_assignment.json | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/landa/organization_management/doctype/work_assignment/work_assignment.json b/landa/organization_management/doctype/work_assignment/work_assignment.json index 125aaf89..efeb38b6 100644 --- a/landa/organization_management/doctype/work_assignment/work_assignment.json +++ b/landa/organization_management/doctype/work_assignment/work_assignment.json @@ -138,7 +138,7 @@ "link_fieldname": "work_assignment" } ], - "modified": "2026-04-08 09:22:40.975143", + "modified": "2026-04-09 17:26:12.763537", "modified_by": "Administrator", "module": "Organization Management", "name": "Work Assignment", @@ -146,6 +146,8 @@ "owner": "Administrator", "permissions": [ { + "amend": 1, + "cancel": 1, "create": 1, "delete": 1, "email": 1, @@ -156,9 +158,12 @@ "report": 1, "role": "System Manager", "share": 1, + "submit": 1, "write": 1 }, { + "amend": 1, + "cancel": 1, "create": 1, "delete": 1, "export": 1, @@ -166,9 +171,12 @@ "read": 1, "report": 1, "role": "LANDA State Organization Employee", + "submit": 1, "write": 1 }, { + "amend": 1, + "cancel": 1, "create": 1, "delete": 1, "export": 1, @@ -176,9 +184,12 @@ "read": 1, "report": 1, "role": "LANDA Regional Organization Management", + "submit": 1, "write": 1 }, { + "amend": 1, + "cancel": 1, "create": 1, "delete": 1, "export": 1, @@ -186,9 +197,12 @@ "read": 1, "report": 1, "role": "LANDA Local Organization Management", + "submit": 1, "write": 1 }, { + "amend": 1, + "cancel": 1, "create": 1, "delete": 1, "email": 1, @@ -198,6 +212,7 @@ "report": 1, "role": "LANDA Local Water Body Management", "share": 1, + "submit": 1, "write": 1 } ], From efb8f7de3a83c9968d80223646b872284e91d586 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Mon, 13 Apr 2026 08:35:25 +0200 Subject: [PATCH 35/43] fix: remove unnecessary pass --- .../doctype/work_ledger_entry/work_ledger_entry.py | 1 - 1 file changed, 1 deletion(-) 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 index 2b760693..256a5727 100644 --- a/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.py +++ b/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.py @@ -24,7 +24,6 @@ class WorkLedgerEntry(Document): organization_name: DF.Data | None work_assignment: DF.Link | None # end: auto-generated types - pass def create_yearly_negative_entries(): From c6f32c5e59bbef4dd24a474c0202c38ef06cef05 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Tue, 28 Apr 2026 00:40:56 +0200 Subject: [PATCH 36/43] test: build on FrappeTestCase --- .../doctype/work_assignment/test_work_assignment.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/landa/organization_management/doctype/work_assignment/test_work_assignment.py b/landa/organization_management/doctype/work_assignment/test_work_assignment.py index 4ab4ffb2..8a23a0b9 100644 --- a/landa/organization_management/doctype/work_assignment/test_work_assignment.py +++ b/landa/organization_management/doctype/work_assignment/test_work_assignment.py @@ -1,8 +1,8 @@ # Copyright (c) 2026, ALYF GmbH and Contributors # See license.txt -from frappe.tests import IntegrationTestCase +from frappe.tests.utils import FrappeTestCase -class TestWorkAssignment(IntegrationTestCase): +class TestWorkAssignment(FrappeTestCase): pass From 870e774c0e3a05c242e745bec59b9fa298a2df42 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Tue, 28 Apr 2026 01:21:21 +0200 Subject: [PATCH 37/43] fix: work assignment data in work ledger balance --- .../report/work_ledger_balance/work_ledger_balance.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 index fef7fe67..3016d899 100644 --- a/landa/organization_management/report/work_ledger_balance/work_ledger_balance.py +++ b/landa/organization_management/report/work_ledger_balance/work_ledger_balance.py @@ -77,7 +77,11 @@ def get_data(filters): 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)} + { + "date": row["date"], + "hours_change": float(row.get("hours_change") or 0), + "work_assignment": row.get("work_assignment"), + } ) result = [] From 7855ce2e29d02987b32c9e673bf6214cd48661ed Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Tue, 5 May 2026 16:49:00 +0200 Subject: [PATCH 38/43] feat: add doctype shortcuts to workspace --- .../organization_management.json | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/landa/organization_management/workspace/organization_management/organization_management.json b/landa/organization_management/workspace/organization_management/organization_management.json index 5831fd34..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, @@ -228,7 +228,7 @@ }, { "hidden": 0, - "is_query_report": 0, + "is_query_report": 1, "label": "Work Hours", "link_count": 0, "link_to": "Work Hours", @@ -239,7 +239,7 @@ }, { "hidden": 0, - "is_query_report": 0, + "is_query_report": 1, "label": "Work Ledger Balance", "link_count": 0, "link_to": "Work Ledger Balance", @@ -248,17 +248,6 @@ "report_ref_doctype": "Work Ledger Entry", "type": "Link" }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Work Hours Per Member and Year", - "link_count": 0, - "link_to": "Work Hours Per Member and Year", - "link_type": "Report", - "onboard": 0, - "report_ref_doctype": "Work Ledger Entry", - "type": "Link" - }, { "hidden": 0, "is_query_report": 0, @@ -319,7 +308,7 @@ "type": "Link" } ], - "modified": "2026-04-08 09:57:02.702836", + "modified": "2026-05-05 16:36:15.445843", "modified_by": "Administrator", "module": "Organization Management", "name": "Organization Management", @@ -338,6 +327,14 @@ "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", @@ -345,6 +342,14 @@ "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", From 179be9f8a4f066ad078b65cc3e98966d40aee636 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Wed, 6 May 2026 09:46:42 +0200 Subject: [PATCH 39/43] feat(Work Assignment): show title in link --- .../doctype/work_assignment/work_assignment.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/landa/organization_management/doctype/work_assignment/work_assignment.json b/landa/organization_management/doctype/work_assignment/work_assignment.json index efeb38b6..47bfca2c 100644 --- a/landa/organization_management/doctype/work_assignment/work_assignment.json +++ b/landa/organization_management/doctype/work_assignment/work_assignment.json @@ -138,7 +138,7 @@ "link_fieldname": "work_assignment" } ], - "modified": "2026-04-09 17:26:12.763537", + "modified": "2026-05-06 09:45:36.342442", "modified_by": "Administrator", "module": "Organization Management", "name": "Work Assignment", @@ -219,6 +219,7 @@ "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": [], From 6fcb6ce5c39bca35fa4ac5e120ea3adc7fff3343 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Wed, 6 May 2026 10:06:31 +0200 Subject: [PATCH 40/43] fix(Organization): update link to Work Assignment --- .../doctype/organization/organization.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/landa/organization_management/doctype/organization/organization.json b/landa/organization_management/doctype/organization/organization.json index 6e087822..44f6b398 100644 --- a/landa/organization_management/doctype/organization/organization.json +++ b/landa/organization_management/doctype/organization/organization.json @@ -264,11 +264,11 @@ }, { "group": "Vereinsverwaltung", - "link_doctype": "Work Ledger Entry", + "link_doctype": "Work Assignment", "link_fieldname": "organization" } ], - "modified": "2026-01-28 16:05:42.757333", + "modified": "2026-05-06 10:05:34.112085", "modified_by": "Administrator", "module": "Organization Management", "name": "Organization", From 4c3e8bbb69d16e9cb2d390df80ed671a241d8b99 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Wed, 6 May 2026 10:17:27 +0200 Subject: [PATCH 41/43] fix(Work Hours Report): activate add_total_row --- .../organization_management/report/work_hours/work_hours.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/landa/organization_management/report/work_hours/work_hours.json b/landa/organization_management/report/work_hours/work_hours.json index 7f0c88b8..dbfd30f4 100644 --- a/landa/organization_management/report/work_hours/work_hours.json +++ b/landa/organization_management/report/work_hours/work_hours.json @@ -1,5 +1,5 @@ { - "add_total_row": 0, + "add_total_row": 1, "add_translate_data": 0, "columns": [], "creation": "2026-01-08 17:06:21.498262", @@ -10,7 +10,7 @@ "idx": 0, "is_standard": "Yes", "letter_head": null, - "modified": "2026-01-08 17:06:56.924267", + "modified": "2026-05-06 10:14:44.943018", "modified_by": "Administrator", "module": "Organization Management", "name": "Work Hours", From 79e4375c1e35a64b1b463b68d40b3dab761ef730 Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Mon, 15 Jun 2026 09:48:59 +0200 Subject: [PATCH 42/43] fix(Work Assignment): delete work ledger entries --- .../doctype/work_assignment/work_assignment.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/landa/organization_management/doctype/work_assignment/work_assignment.py b/landa/organization_management/doctype/work_assignment/work_assignment.py index 02945c7a..a9af8da1 100644 --- a/landa/organization_management/doctype/work_assignment/work_assignment.py +++ b/landa/organization_management/doctype/work_assignment/work_assignment.py @@ -50,4 +50,9 @@ def create_work_ledger_entry(self): work_ledger_entry.insert() def delete_work_ledger_entry(self): - frappe.delete_doc("Work Ledger Entry", {"work_assignment": self.name}) + for name in frappe.get_all( + "Work Ledger Entry", + filters={"work_assignment": self.name}, + pluck="name", + ): + frappe.delete_doc("Work Ledger Entry", name) From 5da3c1ecff849dc5e287a091e3db43a7bc19086d Mon Sep 17 00:00:00 2001 From: Marc-Constantin Enke Date: Thu, 25 Jun 2026 09:18:56 +0200 Subject: [PATCH 43/43] feat(Work Ledger Entry): disable form when connected to work assignment --- .../doctype/work_ledger_entry/work_ledger_entry.js | 6 ++++++ 1 file changed, 6 insertions(+) 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 index faa9bf8c..2997a13c 100644 --- a/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.js +++ b/landa/organization_management/doctype/work_ledger_entry/work_ledger_entry.js @@ -9,4 +9,10 @@ frappe.ui.form.on("Work Ledger Entry", { }; }); }, + + refresh(frm) { + if (!frm.is_new() && frm.doc.work_assignment) { + frm.disable_form(); + } + }, });