From 531c545d5f0db6ca66f4a4d2fbcee0e1972a8957 Mon Sep 17 00:00:00 2001 From: meichthys Date: Fri, 19 Dec 2025 05:18:42 +0000 Subject: [PATCH 01/28] add church person details to portal. --- .../doctype/church_person/church_person.json | 15 +- .../doctype/church_person/church_person.py | 8 + church/church_people/web_form/__init__.py | 0 .../web_form/personal_details/__init__.py | 0 .../personal_details/personal_details.js | 3 + .../personal_details/personal_details.json | 352 ++++++++++++++++++ .../personal_details/personal_details.py | 5 + .../prayer_request/prayer_request.json | 345 ++++++++--------- 8 files changed, 555 insertions(+), 173 deletions(-) create mode 100644 church/church_people/web_form/__init__.py create mode 100644 church/church_people/web_form/personal_details/__init__.py create mode 100644 church/church_people/web_form/personal_details/personal_details.js create mode 100644 church/church_people/web_form/personal_details/personal_details.json create mode 100644 church/church_people/web_form/personal_details/personal_details.py diff --git a/church/church_people/doctype/church_person/church_person.json b/church/church_people/doctype/church_person/church_person.json index e8afa0a..bcbd074 100644 --- a/church/church_people/doctype/church_person/church_person.json +++ b/church/church_people/doctype/church_person/church_person.json @@ -18,6 +18,7 @@ "photo", "birthday", "alergies", + "app_user", "church_records_section", "is_member", "membership_date", @@ -293,6 +294,12 @@ "label": "Letters to the Church", "options": "Church Letter", "print_hide": 1 + }, + { + "fieldname": "app_user", + "fieldtype": "Link", + "label": "App User", + "options": "User" } ], "grid_page_length": 50, @@ -320,7 +327,7 @@ "link_fieldname": "recipient" } ], - "modified": "2025-11-18 23:43:11.668299", + "modified": "2025-12-18 23:37:10.065945", "modified_by": "Administrator", "module": "Church People", "name": "Church Person", @@ -352,9 +359,15 @@ "select": 1, "share": 1, "write": 1 + }, + { + "read": 1, + "role": "Church User", + "write": 1 } ], "quick_entry": 1, + "route": "church-personz", "row_format": "Dynamic", "search_fields": "last_name, first_name", "show_preview_popup": 1, diff --git a/church/church_people/doctype/church_person/church_person.py b/church/church_people/doctype/church_person/church_person.py index d2b6ef4..d770497 100644 --- a/church/church_people/doctype/church_person/church_person.py +++ b/church/church_people/doctype/church_person/church_person.py @@ -90,3 +90,11 @@ class ChurchPerson(Document): role.is_current_role = 1 else: role.is_current_role = 0 + + +def get_list_context(context): + # Only show documents related to the active user + context.filters = {"app_user": frappe.session.user} + # Sort the portal list view by status descending + context.order_by = "modified desc" + return context diff --git a/church/church_people/web_form/__init__.py b/church/church_people/web_form/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/church/church_people/web_form/personal_details/__init__.py b/church/church_people/web_form/personal_details/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/church/church_people/web_form/personal_details/personal_details.js b/church/church_people/web_form/personal_details/personal_details.js new file mode 100644 index 0000000..699703c --- /dev/null +++ b/church/church_people/web_form/personal_details/personal_details.js @@ -0,0 +1,3 @@ +frappe.ready(function() { + // bind events here +}) \ No newline at end of file diff --git a/church/church_people/web_form/personal_details/personal_details.json b/church/church_people/web_form/personal_details/personal_details.json new file mode 100644 index 0000000..02adb74 --- /dev/null +++ b/church/church_people/web_form/personal_details/personal_details.json @@ -0,0 +1,352 @@ +{ + "allow_comments": 0, + "allow_delete": 0, + "allow_edit": 1, + "allow_incomplete": 0, + "allow_multiple": 1, + "allow_print": 1, + "anonymous": 0, + "apply_document_permissions": 1, + "button_label": "Save", + "condition_json": "[]", + "creation": "2025-11-19 00:10:47.226042", + "doc_type": "Church Person", + "docstatus": 0, + "doctype": "Web Form", + "idx": 0, + "is_standard": 1, + "list_columns": [ + { + "fieldname": "first_name", + "fieldtype": "Data", + "label": "First Name" + }, + { + "fieldname": "last_name", + "fieldtype": "Data", + "label": "Last Name" + }, + { + "fieldname": "gender", + "fieldtype": "Select", + "label": "Gender" + }, + { + "fieldname": "birthday", + "fieldtype": "Date", + "label": "Birthday" + }, + { + "fieldname": "photo", + "fieldtype": "Attach Image", + "label": "Photo" + }, + { + "fieldname": "alergies", + "fieldtype": "Data", + "label": "Alergies" + }, + { + "fieldname": "primary_phone", + "fieldtype": "Phone", + "label": "Primary Phone" + }, + { + "fieldname": "email", + "fieldtype": "Data", + "label": "Email" + }, + { + "fieldname": "home_address", + "fieldtype": "Link", + "label": "Home Address" + }, + { + "fieldname": "mailing_address", + "fieldtype": "Link", + "label": "Mailing Address" + } + ], + "list_title": "Your Personal Information", + "login_required": 1, + "max_attachment_size": 0, + "modified": "2025-12-18 23:45:41.183820", + "modified_by": "Administrator", + "module": "Church People", + "name": "personal-details", + "owner": "Administrator", + "published": 1, + "route": "personal-details", + "show_attachments": 0, + "show_list": 1, + "show_sidebar": 0, + "title": "Personal Details", + "web_form_fields": [ + { + "allow_read_on_all_link_options": 0, + "fieldname": "personal_information_section", + "fieldtype": "Section Break", + "hidden": 0, + "label": "Personal Information", + "max_length": 0, + "max_value": 0, + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "first_name", + "fieldtype": "Data", + "hidden": 0, + "label": "First Name", + "max_length": 0, + "max_value": 0, + "precision": "", + "read_only": 0, + "reqd": 1, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "last_name", + "fieldtype": "Data", + "hidden": 0, + "label": "Last Name", + "max_length": 0, + "max_value": 0, + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "default": "Unknown", + "fieldname": "gender", + "fieldtype": "Select", + "hidden": 0, + "label": "Gender", + "max_length": 0, + "max_value": 0, + "options": "Female\nMale\nUnknown", + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "column_break_agva", + "fieldtype": "Column Break", + "hidden": 0, + "max_length": 0, + "max_value": 0, + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "photo", + "fieldtype": "Attach Image", + "hidden": 0, + "label": "Photo", + "max_length": 0, + "max_value": 0, + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "birthday", + "fieldtype": "Date", + "hidden": 0, + "label": "Birthday", + "max_length": 0, + "max_value": 0, + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "alergies", + "fieldtype": "Data", + "hidden": 0, + "label": "Alergies", + "max_length": 0, + "max_value": 0, + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "contact_information_section", + "fieldtype": "Section Break", + "hidden": 0, + "label": "Contact Information", + "max_length": 0, + "max_value": 0, + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "home_address", + "fieldtype": "Link", + "hidden": 0, + "label": "Home Address", + "max_length": 0, + "max_value": 0, + "options": "Address", + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "mailing_address", + "fieldtype": "Link", + "hidden": 0, + "label": "Mailing Address", + "max_length": 0, + "max_value": 0, + "options": "Address", + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "column_break_vzrz", + "fieldtype": "Column Break", + "hidden": 0, + "max_length": 0, + "max_value": 0, + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "primary_phone", + "fieldtype": "Phone", + "hidden": 0, + "label": "Primary Phone", + "max_length": 0, + "max_value": 0, + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "email", + "fieldtype": "Data", + "hidden": 0, + "label": "Email", + "max_length": 0, + "max_value": 0, + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "section_break_eqre", + "fieldtype": "Section Break", + "hidden": 0, + "label": "Family Information", + "max_length": 0, + "max_value": 0, + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "column_break_gwhd", + "fieldtype": "Column Break", + "hidden": 0, + "max_length": 0, + "max_value": 0, + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "default": "0", + "fieldname": "is_married", + "fieldtype": "Check", + "hidden": 0, + "label": "Is Married", + "max_length": 0, + "max_value": 0, + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "depends_on": "eval:doc.is_married;", + "fieldname": "anniversary", + "fieldtype": "Date", + "hidden": 0, + "label": "Anniversary", + "max_length": 0, + "max_value": 0, + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "depends_on": "eval:doc.is_married;", + "fieldname": "spouse", + "fieldtype": "Link", + "hidden": 0, + "label": "Spouse", + "max_length": 0, + "max_value": 0, + "options": "Church Person", + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "relationships", + "fieldtype": "Table", + "hidden": 0, + "label": "Notable Relationships", + "max_length": 0, + "max_value": 0, + "options": "Church Person Relation", + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + } + ] +} \ No newline at end of file diff --git a/church/church_people/web_form/personal_details/personal_details.py b/church/church_people/web_form/personal_details/personal_details.py new file mode 100644 index 0000000..e1ada61 --- /dev/null +++ b/church/church_people/web_form/personal_details/personal_details.py @@ -0,0 +1,5 @@ +import frappe + +def get_context(context): + # do your magic here + pass diff --git a/church/church_prayers/web_form/prayer_request/prayer_request.json b/church/church_prayers/web_form/prayer_request/prayer_request.json index 173c30a..bc521ce 100644 --- a/church/church_prayers/web_form/prayer_request/prayer_request.json +++ b/church/church_prayers/web_form/prayer_request/prayer_request.json @@ -1,173 +1,174 @@ { - "allow_comments": 1, - "allow_delete": 1, - "allow_edit": 1, - "allow_incomplete": 0, - "allow_multiple": 1, - "allow_print": 1, - "anonymous": 0, - "apply_document_permissions": 0, - "button_label": "Save", - "condition_json": "[]", - "creation": "2025-09-13 22:28:01.939717", - "doc_type": "Church Prayer Request", - "docstatus": 0, - "doctype": "Web Form", - "idx": 0, - "introduction_text": "
Be anxious for nothing, but in everything, by prayer and petition, with thanksgiving, present your requests to God.
~ Philipians 4:6 (BSB)
", - "is_standard": 1, - "list_columns": [ - { - "fieldname": "status", - "fieldtype": "Link", - "label": "" - }, - { - "fieldname": "type", - "fieldtype": "Link", - "label": "" - }, - { - "fieldname": "column_break_ynvf", - "fieldtype": "Column Break", - "label": "" - }, - { - "fieldname": "related_person", - "fieldtype": "Link", - "label": "" - }, - { - "fieldname": "section_break_usaz", - "fieldtype": "Section Break", - "label": "" - }, - { - "fieldname": "request", - "fieldtype": "Small Text", - "label": "" - }, - { - "fieldname": "is_private", - "fieldtype": "Check", - "label": "" - } - ], - "list_title": "Your Prayer Requests", - "login_required": 1, - "max_attachment_size": 0, - "modified": "2025-11-16 00:10:38.455309", - "modified_by": "Administrator", - "module": "Church Prayers", - "name": "prayer-request", - "owner": "Administrator", - "published": 1, - "route": "prayer-request", - "show_attachments": 0, - "show_list": 1, - "show_sidebar": 1, - "title": "Prayer Request ", - "web_form_fields": [ - { - "allow_read_on_all_link_options": 1, - "default": "Requested", - "fieldname": "status", - "fieldtype": "Link", - "hidden": 0, - "label": "Status", - "max_length": 0, - "max_value": 0, - "options": "Church Prayer Request Status", - "precision": "", - "read_only": 0, - "reqd": 1, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 1, - "default": "", - "fieldname": "type", - "fieldtype": "Link", - "hidden": 0, - "label": "Type", - "max_length": 0, - "max_value": 0, - "options": "Church Prayer Request Type", - "precision": "", - "read_only": 0, - "reqd": 1, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "column_break_ynvf", - "fieldtype": "Column Break", - "hidden": 0, - "label": "", - "max_length": 0, - "max_value": 0, - "precision": "", - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 1, - "default": "", - "depends_on": "eval:frappe.session.user!='Guest';", - "description": "If this request is for a specific person and the person is in this list, please select the person.", - "fieldname": "related_person", - "fieldtype": "Link", - "hidden": 0, - "label": "Related Person", - "max_length": 0, - "max_value": 0, - "options": "Church Person", - "precision": "", - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "section_break_usaz", - "fieldtype": "Section Break", - "hidden": 0, - "label": "", - "max_length": 0, - "max_value": 0, - "precision": "", - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "fieldname": "request", - "fieldtype": "Small Text", - "hidden": 0, - "label": "Request", - "max_length": 0, - "max_value": 0, - "precision": "", - "read_only": 0, - "reqd": 1, - "show_in_filter": 0 - }, - { - "allow_read_on_all_link_options": 0, - "default": "", - "description": "Check this if you don't want this shared with the church body.", - "fieldname": "is_private", - "fieldtype": "Check", - "hidden": 0, - "label": "Is Private", - "max_length": 0, - "max_value": 0, - "precision": "", - "read_only": 0, - "reqd": 0, - "show_in_filter": 0 - } - ] -} + "allow_comments": 1, + "allow_delete": 1, + "allow_edit": 1, + "allow_incomplete": 0, + "allow_multiple": 1, + "allow_print": 1, + "anonymous": 0, + "apply_document_permissions": 1, + "button_label": "Save", + "condition_json": "[]", + "creation": "2025-09-13 22:28:01.939717", + "doc_type": "Church Prayer Request", + "docstatus": 0, + "doctype": "Web Form", + "idx": 0, + "introduction_text": "
Be anxious for nothing, but in everything, by prayer and petition, with thanksgiving, present your requests to God.
~ Philipians 4:6 (BSB)
", + "is_standard": 1, + "list_columns": [ + { + "fieldname": "status", + "fieldtype": "Link", + "label": "" + }, + { + "fieldname": "type", + "fieldtype": "Link", + "label": "" + }, + { + "fieldname": "column_break_ynvf", + "fieldtype": "Column Break", + "label": "" + }, + { + "fieldname": "related_person", + "fieldtype": "Link", + "label": "" + }, + { + "fieldname": "section_break_usaz", + "fieldtype": "Section Break", + "label": "" + }, + { + "fieldname": "request", + "fieldtype": "Small Text", + "label": "" + }, + { + "fieldname": "is_private", + "fieldtype": "Check", + "label": "" + } + ], + "list_title": "Your Prayer Requests", + "login_required": 1, + "max_attachment_size": 0, + "modified": "2025-12-18 23:45:59.150941", + "modified_by": "Administrator", + "module": "Church Prayers", + "name": "prayer-request", + "owner": "Administrator", + "published": 1, + "route": "prayer-request", + "show_attachments": 0, + "show_list": 1, + "show_sidebar": 1, + "title": "Prayer Request ", + "web_form_fields": [ + { + "allow_read_on_all_link_options": 1, + "default": "Requested", + "fieldname": "status", + "fieldtype": "Link", + "hidden": 0, + "label": "Status", + "max_length": 0, + "max_value": 0, + "options": "Church Prayer Request Status", + "precision": "", + "read_only": 0, + "reqd": 1, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 1, + "default": "", + "fieldname": "type", + "fieldtype": "Link", + "hidden": 0, + "label": "Type", + "max_length": 0, + "max_value": 0, + "options": "Church Prayer Request Type", + "precision": "", + "read_only": 0, + "reqd": 1, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "column_break_ynvf", + "fieldtype": "Column Break", + "hidden": 0, + "label": "", + "max_length": 0, + "max_value": 0, + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 1, + "default": "", + "depends_on": "eval:frappe.session.user!='Guest';", + "description": "If this request is for a specific person and the person is in this list, please select the person.", + "fieldname": "related_person", + "fieldtype": "Link", + "hidden": 0, + "label": "Related Person", + "max_length": 0, + "max_value": 0, + "options": "Church Person", + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "section_break_usaz", + "fieldtype": "Section Break", + "hidden": 0, + "label": "", + "max_length": 0, + "max_value": 0, + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "request", + "fieldtype": "Small Text", + "hidden": 0, + "label": "Request", + "max_length": 0, + "max_value": 0, + "precision": "", + "read_only": 0, + "reqd": 1, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "default": "", + "description": "Check this if you don't want this shared with the church body.", + "fieldname": "is_private", + "fieldtype": "Check", + "hidden": 0, + "label": "Is Private", + "max_length": 0, + "max_value": 0, + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + } + ], + "website_sidebar": "" +} \ No newline at end of file From 830334e3d7906bb3d0943b357128d8f501eb2b7c Mon Sep 17 00:00:00 2001 From: meichthys Date: Sat, 20 Dec 2025 06:54:31 +0000 Subject: [PATCH 02/28] Display family members on Family form. --- .../doctype/church_family/church_family.json | 14 +++++-- .../doctype/church_family_members/__init__.py | 0 .../church_family_members.json | 38 +++++++++++++++++++ .../church_family_members.py | 9 +++++ .../doctype/church_person/church_person.py | 31 +++++++++++++++ .../manual:_people/manual:_people.json | 4 +- 6 files changed, 91 insertions(+), 5 deletions(-) create mode 100644 church/church_people/doctype/church_family_members/__init__.py create mode 100644 church/church_people/doctype/church_family_members/church_family_members.json create mode 100644 church/church_people/doctype/church_family_members/church_family_members.py diff --git a/church/church_people/doctype/church_family/church_family.json b/church/church_people/doctype/church_family/church_family.json index 2621769..958c9dc 100644 --- a/church/church_people/doctype/church_family/church_family.json +++ b/church/church_people/doctype/church_family/church_family.json @@ -11,9 +11,10 @@ "section_break_acrr", "family_name", "head_of_household", - "column_break_pmch", "home_address", - "photo" + "photo", + "column_break_pmch", + "members" ], "fields": [ { @@ -55,6 +56,13 @@ { "fieldname": "section_break_acrr", "fieldtype": "Section Break" + }, + { + "fieldname": "members", + "fieldtype": "Table", + "label": "Family Members", + "options": "Church Family Members", + "read_only": 1 } ], "grid_page_length": 50, @@ -70,7 +78,7 @@ "link_fieldname": "recipient" } ], - "modified": "2025-11-15 22:55:14.237301", + "modified": "2025-12-20 01:46:01.200249", "modified_by": "Administrator", "module": "Church People", "name": "Church Family", diff --git a/church/church_people/doctype/church_family_members/__init__.py b/church/church_people/doctype/church_family_members/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/church/church_people/doctype/church_family_members/church_family_members.json b/church/church_people/doctype/church_family_members/church_family_members.json new file mode 100644 index 0000000..40d3c4a --- /dev/null +++ b/church/church_people/doctype/church_family_members/church_family_members.json @@ -0,0 +1,38 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2025-12-20 00:48:57.168497", + "description": "People who are part of a `Church Family`", + "doctype": "DocType", + "documentation": "/app/manual%3A-people#family", + "engine": "InnoDB", + "field_order": [ + "member" + ], + "fields": [ + { + "fieldname": "member", + "fieldtype": "Link", + "in_list_view": 1, + "in_preview": 1, + "label": "Family Member", + "options": "Church Person", + "read_only": 1, + "reqd": 1 + } + ], + "grid_page_length": 50, + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2025-12-20 01:48:38.401634", + "modified_by": "Administrator", + "module": "Church People", + "name": "Church Family Members", + "owner": "Administrator", + "permissions": [], + "row_format": "Dynamic", + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/church/church_people/doctype/church_family_members/church_family_members.py b/church/church_people/doctype/church_family_members/church_family_members.py new file mode 100644 index 0000000..d16651c --- /dev/null +++ b/church/church_people/doctype/church_family_members/church_family_members.py @@ -0,0 +1,9 @@ +# Copyright (c) 2025, meichthys and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class ChurchFamilyMembers(Document): + pass diff --git a/church/church_people/doctype/church_person/church_person.py b/church/church_people/doctype/church_person/church_person.py index d770497..5bf5963 100644 --- a/church/church_people/doctype/church_person/church_person.py +++ b/church/church_people/doctype/church_person/church_person.py @@ -8,11 +8,42 @@ from frappe.model.document import Document class ChurchPerson(Document): + def on_update(self): + # Update Family Member list in Church Family + if self.family: + family = frappe.get_doc("Church Family", self.family) + found = False + for member in family.members: + if member.member == self.name: + found = True + break + if not found: + family.append("members", {"member": self.name}) + family.save() + # Remove person from Church Family if family is removed + if not self.family and hasattr(self.get_doc_before_save(), "family"): + family = frappe.get_doc("Church Family", self.get_doc_before_save().family) + for member in family.members: + if member.member == self.name: + family.remove(member) + break + family.save() + def before_save(self): # We set this here since virtual fields do not work with # View Settings -> Title Field as of 2025-08-26 self.full_name = f"{self.first_name}" + ((" " + self.last_name) if self.last_name else "") + def before_delete(self): + # Remove person from Church Family + if self.family: + family = frappe.get_doc("Church Family", self.family) + for member in family.members: + if member.name == self.name: + family.remove(member) + break + family.save() + def validate(self): # Remove head of household status when family is removed if not self.family and self.is_head_of_household: diff --git a/church/church_people/workspace/manual:_people/manual:_people.json b/church/church_people/workspace/manual:_people/manual:_people.json index eec731c..abaaeb9 100644 --- a/church/church_people/workspace/manual:_people/manual:_people.json +++ b/church/church_people/workspace/manual:_people/manual:_people.json @@ -1,6 +1,6 @@ { "charts": [], - "content": "[{\"id\":\"nnvMTG5Sl5\",\"type\":\"paragraph\",\"data\":{\"text\":\"\ud83d\udc65People Manual\",\"col\":12}},{\"id\":\"B-CtTCmVDX\",\"type\":\"paragraph\",\"data\":{\"text\":\"The people module contains features relating to the people of the church (i.e. Members, Families, Leadership. etc).\",\"col\":12}},{\"id\":\"Htx875Wd1w\",\"type\":\"paragraph\",\"data\":{\"text\":\"The People workspace contains number cards and graphs indicating the current count of people/families/members. there are also links to various reports (Birthdays, Roles, Letters, etc).\",\"col\":12}},{\"id\":\"qI9ZNpJJX4\",\"type\":\"paragraph\",\"data\":{\"text\":\"\ud83d\udc64Person\",\"col\":12}},{\"id\":\"RZThk3_x4O\",\"type\":\"paragraph\",\"data\":{\"text\":\"Church people include guests, members, leadership, and other people who interact or are associated with the church.\",\"col\":12}},{\"id\":\"UJEDTpYJIM\",\"type\":\"paragraph\",\"data\":{\"text\":\"When adding a person, note the following:
- Church membership and baptism status can be indicated.
    - If needed, additional member status types can be created.
- If the person has any roles in the church, they should be indicated in the 'Church Roles' section. 
   - If a role type does not exist, you can create new role types as needed.
- Photos should be added for members. The photos will be used in a member directory in a future versions.
- Letters from this person can be added in the 'Contact' tab
- Family relationships can be defined in the 'Family' tab.
    - When a spouse is added, the spouse's document will also be updated accordingly.
    - Additional relationships can be defined in the 'Notable Relationships' section - these relationships are not auto-updated on the other person's document.
    - A Family can be automatically created from a person by clicking the 'New Family From Person' button. This requires a 'Last Name' to be set, and will set the person as the Family's head-of-household.\",\"col\":12}},{\"id\":\"0a0Yfbfao3\",\"type\":\"paragraph\",\"data\":{\"text\":\"Person Directory\",\"col\":12}},{\"id\":\"aIL5EgTGiJ\",\"type\":\"paragraph\",\"data\":{\"text\":\"To generate a Church Directory:
1. Navigate to the church person list.
2. (Optionally) Check the Is Member filter to only show members.
3. Select all the people by checking the top left checkbox in the list.
4. Click the Actions button and choose Print.
5. Select your print options and click Print to generate a member directory pdf file.
    - Tip: To make each person page smaller when printing the pdf, you can use the print multiple pages per sheet option in your system print dialog (if your system supports this feature).
\",\"col\":12}},{\"id\":\"A37CU_rUFj\",\"type\":\"paragraph\",\"data\":{\"text\":\"\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc66Family\",\"col\":12}},{\"id\":\"_wxytNqTX4\",\"type\":\"paragraph\",\"data\":{\"text\":\"Families are groups of people who are related.\",\"col\":12}},{\"id\":\"qQr_8PsoeH\",\"type\":\"paragraph\",\"data\":{\"text\":\"When adding a family, note the following:
- After adding a family, you may want to link people to the family.
- Only one person can be set as the head of household. To set the head-of-household, go to the person's document and check 'Is Head of Household' on the 'Family' tab.
\",\"col\":12}}]", + "content": "[{\"id\":\"nnvMTG5Sl5\",\"type\":\"paragraph\",\"data\":{\"text\":\"\ud83d\udc65People Manual\",\"col\":12}},{\"id\":\"B-CtTCmVDX\",\"type\":\"paragraph\",\"data\":{\"text\":\"The people module contains features relating to the people of the church (i.e. Members, Families, Leadership. etc).\",\"col\":12}},{\"id\":\"Htx875Wd1w\",\"type\":\"paragraph\",\"data\":{\"text\":\"The People workspace contains number cards and graphs indicating the current count of people/families/members. there are also links to various reports (Birthdays, Roles, Letters, etc).\",\"col\":12}},{\"id\":\"qI9ZNpJJX4\",\"type\":\"paragraph\",\"data\":{\"text\":\"\ud83d\udc64Person\",\"col\":12}},{\"id\":\"RZThk3_x4O\",\"type\":\"paragraph\",\"data\":{\"text\":\"Church people include guests, members, leadership, and other people who interact or are associated with the church.\",\"col\":12}},{\"id\":\"UJEDTpYJIM\",\"type\":\"paragraph\",\"data\":{\"text\":\"When adding a person, note the following:
- Church membership and baptism status can be indicated.
    - If needed, additional member status types can be created.
- If the person has any roles in the church, they should be indicated in the 'Church Roles' section. 
   - If a role type does not exist, you can create new role types as needed.
- Photos should be added for members. The photos will be used in a member directory in a future versions.
- Letters from this person can be added in the 'Contact' tab
- If a family has been selected, the person will be displayed in the \\\"Family Members\\\" section on the `Church Family` form.
- Family relationships can be defined in the 'Family' tab.
    - When a spouse is added, the spouse's document will also be updated accordingly.
    - Additional relationships can be defined in the 'Notable Relationships' section - these relationships are not auto-updated on the other person's document.
    - A Family can be automatically created from a person by clicking the 'New Family From Person' button. This requires a 'Last Name' to be set, and will set the person as the Family's head-of-household.\",\"col\":12}},{\"id\":\"0a0Yfbfao3\",\"type\":\"paragraph\",\"data\":{\"text\":\"Person/Member Directory\",\"col\":12}},{\"id\":\"aIL5EgTGiJ\",\"type\":\"paragraph\",\"data\":{\"text\":\"To generate a Church Directory:
1. Navigate to the church person list.
2. (Optionally) Check the Is Member filter to only show members.
3. Select all the people by checking the top left checkbox in the list.
4. Click the Actions button and choose Print.
5. Select your print options and click Print to generate a member directory pdf file.
    - Tip: To make each person page smaller when printing the pdf, you can use the print multiple pages per sheet option in your system print dialog (if your system supports this feature).
\",\"col\":12}},{\"id\":\"A37CU_rUFj\",\"type\":\"paragraph\",\"data\":{\"text\":\"\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc66Family\",\"col\":12}},{\"id\":\"_wxytNqTX4\",\"type\":\"paragraph\",\"data\":{\"text\":\"Families are groups of people who are related.\",\"col\":12}},{\"id\":\"qQr_8PsoeH\",\"type\":\"paragraph\",\"data\":{\"text\":\"When adding a family, note the following:
- After adding a family, you may want to link people to the family. When a person is linked to a family, that person will be displayed in the \\\"Family Members\\\" list.
- Only one person can be set as the head of household. To set the head-of-household, go to the person's document and check 'Is Head of Household' on the 'Family' tab.
\",\"col\":12}}]", "creation": "2025-10-26 22:59:15.251142", "custom_blocks": [], "docstatus": 0, @@ -13,7 +13,7 @@ "is_hidden": 0, "label": "Manual: People", "links": [], - "modified": "2025-11-10 00:37:02.650282", + "modified": "2025-12-20 01:52:41.918887", "modified_by": "Administrator", "module": "Church People", "name": "Manual: People", From b15cfdb77261579ac866a0c314ce206cfe0f17d3 Mon Sep 17 00:00:00 2001 From: meichthys Date: Sun, 21 Dec 2025 03:47:56 +0000 Subject: [PATCH 03/28] Allow linking app items to tasks --- .../doctype/church_task/church_task.json | 49 ++++++++---- .../doctype/church_task_item/__init__.py | 0 .../church_task_item/church_task_item.json | 75 +++++++++++++++++++ .../church_task_item/church_task_item.py | 9 +++ 4 files changed, 117 insertions(+), 16 deletions(-) create mode 100644 church/church_operations/doctype/church_task_item/__init__.py create mode 100644 church/church_operations/doctype/church_task_item/church_task_item.json create mode 100644 church/church_operations/doctype/church_task_item/church_task_item.py diff --git a/church/church_operations/doctype/church_task/church_task.json b/church/church_operations/doctype/church_task/church_task.json index 9d737ae..3d38edb 100644 --- a/church/church_operations/doctype/church_task/church_task.json +++ b/church/church_operations/doctype/church_task/church_task.json @@ -1,10 +1,11 @@ { "actions": [], "allow_import": 1, - "autoname": "autoincrement", + "autoname": "format:Task {#}", "creation": "2025-12-15 00:41:21.858015", "description": "Things that need to get done (Like a checklist or ToDo list)", "doctype": "DocType", + "documentation": "/app/manual%3A-operations", "engine": "InnoDB", "field_order": [ "section_break_fgnk", @@ -13,7 +14,9 @@ "assigned_person", "column_break_yrnx", "is_group", - "parent_church_task", + "parent_task", + "section_break_kwag", + "task_items", "section_break_ysry", "notes", "hidden_fields_section", @@ -45,6 +48,7 @@ { "allow_in_quick_entry": 1, "default": "0", + "description": "Checking this box allows you to add 'generic' sub-tasks and link them to this task. For items that already exist in the system, use the 'Task Items' table below.", "fieldname": "is_group", "fieldtype": "Check", "in_preview": 1, @@ -57,17 +61,6 @@ "label": "Old Parent", "options": "Church Task" }, - { - "allow_in_quick_entry": 1, - "fieldname": "parent_church_task", - "fieldtype": "Link", - "ignore_user_permissions": 1, - "in_list_view": 1, - "in_preview": 1, - "in_standard_filter": 1, - "label": "Parent Task", - "options": "Church Task" - }, { "allow_in_quick_entry": 1, "fieldname": "title", @@ -119,18 +112,42 @@ "fieldtype": "Section Break", "hidden": 1, "label": "Hidden Fields" + }, + { + "allow_in_quick_entry": 1, + "description": "If this task is a sub-task, select the parent task here.", + "fieldname": "parent_task", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "in_list_view": 1, + "in_preview": 1, + "in_standard_filter": 1, + "label": "Parent Task", + "options": "Church Task" + }, + { + "fieldname": "section_break_kwag", + "fieldtype": "Section Break" + }, + { + "allow_in_quick_entry": 1, + "description": "For generic items that do not exist in the system, you can create sub-tasks by checking 'Is Group' and then creating new tasks wit hthis task selected in the new task's 'Parent Task' field. ", + "fieldname": "task_items", + "fieldtype": "Table", + "label": "Task Items", + "options": "Church Task Item" } ], "grid_page_length": 50, "index_web_pages_for_search": 1, "is_tree": 1, "links": [], - "modified": "2025-12-15 00:59:25.234829", + "modified": "2025-12-20 22:43:14.677845", "modified_by": "Administrator", "module": "Church Operations", "name": "Church Task", - "naming_rule": "Autoincrement", - "nsm_parent_field": "parent_church_task", + "naming_rule": "Expression", + "nsm_parent_field": "parent_task", "owner": "Administrator", "permissions": [ { diff --git a/church/church_operations/doctype/church_task_item/__init__.py b/church/church_operations/doctype/church_task_item/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/church/church_operations/doctype/church_task_item/church_task_item.json b/church/church_operations/doctype/church_task_item/church_task_item.json new file mode 100644 index 0000000..530b07d --- /dev/null +++ b/church/church_operations/doctype/church_task_item/church_task_item.json @@ -0,0 +1,75 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2025-12-20 22:28:50.886444", + "description": "A reference to a document in the Church App that is part of a Church Task", + "doctype": "DocType", + "documentation": "/app/manual%3A-operations", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "completed", + "item_type", + "item", + "notes" + ], + "fields": [ + { + "allow_in_quick_entry": 1, + "default": "0", + "fieldname": "completed", + "fieldtype": "Check", + "in_filter": 1, + "in_list_view": 1, + "in_preview": 1, + "in_standard_filter": 1, + "label": "Completed?" + }, + { + "allow_in_quick_entry": 1, + "fieldname": "item_type", + "fieldtype": "Link", + "in_filter": 1, + "in_list_view": 1, + "in_preview": 1, + "in_standard_filter": 1, + "label": "Item Type", + "link_filters": "[[\"DocType\",\"name\",\"like\",\"Church%\"]]", + "options": "DocType", + "reqd": 1 + }, + { + "allow_in_quick_entry": 1, + "fieldname": "item", + "fieldtype": "Dynamic Link", + "in_filter": 1, + "in_list_view": 1, + "in_preview": 1, + "in_standard_filter": 1, + "label": "Item", + "options": "item_type", + "reqd": 1 + }, + { + "fieldname": "notes", + "fieldtype": "Text Editor", + "in_list_view": 1, + "in_preview": 1, + "label": "Notes" + } + ], + "grid_page_length": 50, + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2025-12-20 22:36:42.050521", + "modified_by": "Administrator", + "module": "Church Operations", + "name": "Church Task Item", + "owner": "Administrator", + "permissions": [], + "row_format": "Dynamic", + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/church/church_operations/doctype/church_task_item/church_task_item.py b/church/church_operations/doctype/church_task_item/church_task_item.py new file mode 100644 index 0000000..dacb108 --- /dev/null +++ b/church/church_operations/doctype/church_task_item/church_task_item.py @@ -0,0 +1,9 @@ +# Copyright (c) 2025, meichthys and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class ChurchTaskItem(Document): + pass From d6def96e670f46feec63b573bfaf794b14e9a6f3 Mon Sep 17 00:00:00 2001 From: meichthys Date: Sun, 21 Dec 2025 03:59:53 +0000 Subject: [PATCH 04/28] Add status field with pre-defined states. --- .../doctype/church_task/church_task.json | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/church/church_operations/doctype/church_task/church_task.json b/church/church_operations/doctype/church_task/church_task.json index 3d38edb..bc42070 100644 --- a/church/church_operations/doctype/church_task/church_task.json +++ b/church/church_operations/doctype/church_task/church_task.json @@ -10,6 +10,7 @@ "field_order": [ "section_break_fgnk", "title", + "status", "due_date", "assigned_person", "column_break_yrnx", @@ -131,18 +132,31 @@ }, { "allow_in_quick_entry": 1, - "description": "For generic items that do not exist in the system, you can create sub-tasks by checking 'Is Group' and then creating new tasks wit hthis task selected in the new task's 'Parent Task' field. ", + "description": "For generic items that do not exist in the system, you can create a checklist in the notes section below or create sub-tasks by checking 'Is Group' and then creating new tasks wit hthis task selected in the new task's 'Parent Task' field. ", "fieldname": "task_items", "fieldtype": "Table", "label": "Task Items", "options": "Church Task Item" + }, + { + "allow_in_quick_entry": 1, + "default": "Open", + "fieldname": "status", + "fieldtype": "Select", + "in_filter": 1, + "in_list_view": 1, + "in_preview": 1, + "in_standard_filter": 1, + "label": "Status", + "options": "Open\nAssigned\nIn Progress\nCompleted", + "reqd": 1 } ], "grid_page_length": 50, "index_web_pages_for_search": 1, "is_tree": 1, "links": [], - "modified": "2025-12-20 22:43:14.677845", + "modified": "2025-12-20 22:59:11.776100", "modified_by": "Administrator", "module": "Church Operations", "name": "Church Task", @@ -182,6 +196,23 @@ "show_title_field_in_link": 1, "sort_field": "modified", "sort_order": "DESC", - "states": [], + "states": [ + { + "color": "Red", + "title": "Open" + }, + { + "color": "Purple", + "title": "Assigned" + }, + { + "color": "Yellow", + "title": "In Progress" + }, + { + "color": "Green", + "title": "Completed" + } + ], "title_field": "title" } \ No newline at end of file From 1bc8886b0ee27ed37b0bbe337cf1996336fcf2b9 Mon Sep 17 00:00:00 2001 From: meichthys Date: Sun, 21 Dec 2025 04:32:55 +0000 Subject: [PATCH 05/28] Resolves #92 --- .../doctype/church_family/church_family.json | 5 ++--- .../doctype/church_family/church_family.py | 14 ++++++++++++++ .../church_family_members.json | 4 ++-- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/church/church_people/doctype/church_family/church_family.json b/church/church_people/doctype/church_family/church_family.json index 958c9dc..450ac5b 100644 --- a/church/church_people/doctype/church_family/church_family.json +++ b/church/church_people/doctype/church_family/church_family.json @@ -61,8 +61,7 @@ "fieldname": "members", "fieldtype": "Table", "label": "Family Members", - "options": "Church Family Members", - "read_only": 1 + "options": "Church Family Members" } ], "grid_page_length": 50, @@ -78,7 +77,7 @@ "link_fieldname": "recipient" } ], - "modified": "2025-12-20 01:46:01.200249", + "modified": "2025-12-20 23:03:58.407158", "modified_by": "Administrator", "module": "Church People", "name": "Church Family", diff --git a/church/church_people/doctype/church_family/church_family.py b/church/church_people/doctype/church_family/church_family.py index 2461946..f608e12 100644 --- a/church/church_people/doctype/church_family/church_family.py +++ b/church/church_people/doctype/church_family/church_family.py @@ -21,3 +21,17 @@ class ChurchFamily(Document): return doc_dict[0]["doctype"] = "Church Person" return frappe.get_doc(doc_dict[0]).name + + def before_save(self): + # Remove family from Church Person records when Person is removed from ChurchFamily + if self.get_doc_before_save().members: + for member in self.get_doc_before_save().members: + if member not in self.members: + frappe.db.set_value("Church Person", member.member, "family", None, update_modified=False) + # Update Church Person records when ChurchFamily is updated + if self.members: + for member in self.members: + if member.member: + frappe.db.set_value( + "Church Person", member.member, "family", self.name, update_modified=False + ) diff --git a/church/church_people/doctype/church_family_members/church_family_members.json b/church/church_people/doctype/church_family_members/church_family_members.json index 40d3c4a..9211f5a 100644 --- a/church/church_people/doctype/church_family_members/church_family_members.json +++ b/church/church_people/doctype/church_family_members/church_family_members.json @@ -5,6 +5,7 @@ "description": "People who are part of a `Church Family`", "doctype": "DocType", "documentation": "/app/manual%3A-people#family", + "editable_grid": 1, "engine": "InnoDB", "field_order": [ "member" @@ -17,7 +18,6 @@ "in_preview": 1, "label": "Family Member", "options": "Church Person", - "read_only": 1, "reqd": 1 } ], @@ -25,7 +25,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2025-12-20 01:48:38.401634", + "modified": "2025-12-20 23:04:31.049341", "modified_by": "Administrator", "module": "Church People", "name": "Church Family Members", From 052dca5fe41586e20f133bf0569641b657abe0cb Mon Sep 17 00:00:00 2001 From: meichthys Date: Tue, 6 Jan 2026 04:53:27 +0000 Subject: [PATCH 06/28] Add location tracking --- README.md | 2 +- .../doctype/church_location/__init__.py | 0 .../church_location/church_location.js | 8 + .../church_location/church_location.json | 139 ++++++++++++++++++ .../church_location/church_location.py | 9 ++ .../church_location/test_church_location.py | 9 ++ .../workspace/operations/operations.json | 14 +- 7 files changed, 178 insertions(+), 3 deletions(-) create mode 100644 church/church_operations/doctype/church_location/__init__.py create mode 100644 church/church_operations/doctype/church_location/church_location.js create mode 100644 church/church_operations/doctype/church_location/church_location.json create mode 100644 church/church_operations/doctype/church_location/church_location.py create mode 100644 church/church_operations/doctype/church_location/test_church_location.py diff --git a/README.md b/README.md index 478248e..eea35b7 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ The following features have been implemented in this app (see the [πŸ—ΊοΈ Roadm - Bank reconciliation report - Fund balance tracking - Collections automatically update funds when saved -- Basic Asset Tracking +- Basic Asset Tracking (location, details) - Church Belief tracking - Basic Church Website - About Page diff --git a/church/church_operations/doctype/church_location/__init__.py b/church/church_operations/doctype/church_location/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/church/church_operations/doctype/church_location/church_location.js b/church/church_operations/doctype/church_location/church_location.js new file mode 100644 index 0000000..c7589a4 --- /dev/null +++ b/church/church_operations/doctype/church_location/church_location.js @@ -0,0 +1,8 @@ +// Copyright (c) 2026, meichthys and contributors +// For license information, please see license.txt + +// frappe.ui.form.on("Church Location", { +// refresh(frm) { + +// }, +// }); diff --git a/church/church_operations/doctype/church_location/church_location.json b/church/church_operations/doctype/church_location/church_location.json new file mode 100644 index 0000000..eb6f50d --- /dev/null +++ b/church/church_operations/doctype/church_location/church_location.json @@ -0,0 +1,139 @@ +{ + "actions": [], + "allow_import": 1, + "allow_rename": 1, + "autoname": "format:{title}", + "creation": "2026-01-05 23:28:09.404374", + "default_view": "Tree", + "description": "A physical location associated with the Church. (i.e. Office, Library, etc)", + "doctype": "DocType", + "engine": "InnoDB", + "field_order": [ + "title", + "notes", + "column_break_djot", + "parent_church_location", + "is_group", + "photo", + "hidden_fields_section", + "lft", + "rgt", + "old_parent" + ], + "fields": [ + { + "allow_in_quick_entry": 1, + "fieldname": "title", + "fieldtype": "Data", + "in_list_view": 1, + "in_preview": 1, + "in_standard_filter": 1, + "label": "Title", + "reqd": 1 + }, + { + "allow_in_quick_entry": 1, + "fieldname": "notes", + "fieldtype": "Text Editor", + "in_list_view": 1, + "in_preview": 1, + "label": "Notes" + }, + { + "fieldname": "lft", + "fieldtype": "Int", + "hidden": 1, + "label": "Left", + "no_copy": 1, + "read_only": 1 + }, + { + "fieldname": "rgt", + "fieldtype": "Int", + "hidden": 1, + "label": "Right", + "no_copy": 1, + "read_only": 1 + }, + { + "default": "0", + "description": "Check this if other locations are located within this location.", + "fieldname": "is_group", + "fieldtype": "Check", + "label": "Is Group" + }, + { + "fieldname": "old_parent", + "fieldtype": "Link", + "label": "Old Parent", + "options": "Church Location" + }, + { + "description": "If this location is located within another location, choose the other location here.", + "fieldname": "parent_church_location", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "label": "Parent Location", + "options": "Church Location" + }, + { + "fieldname": "column_break_djot", + "fieldtype": "Column Break" + }, + { + "fieldname": "hidden_fields_section", + "fieldtype": "Section Break", + "hidden": 1, + "label": "Hidden Fields" + }, + { + "fieldname": "photo", + "fieldtype": "Attach Image", + "label": "Photo" + } + ], + "grid_page_length": 50, + "image_field": "photo", + "index_web_pages_for_search": 1, + "is_tree": 1, + "links": [], + "modified": "2026-01-05 23:51:38.123146", + "modified_by": "Administrator", + "module": "Church Operations", + "name": "Church Location", + "naming_rule": "Expression", + "nsm_parent_field": "parent_church_location", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "write": 1 + }, + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "import": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Church Manager", + "share": 1, + "write": 1 + } + ], + "quick_entry": 1, + "row_format": "Dynamic", + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/church/church_operations/doctype/church_location/church_location.py b/church/church_operations/doctype/church_location/church_location.py new file mode 100644 index 0000000..75a8f52 --- /dev/null +++ b/church/church_operations/doctype/church_location/church_location.py @@ -0,0 +1,9 @@ +# Copyright (c) 2026, meichthys and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class ChurchLocation(Document): + pass diff --git a/church/church_operations/doctype/church_location/test_church_location.py b/church/church_operations/doctype/church_location/test_church_location.py new file mode 100644 index 0000000..36754d4 --- /dev/null +++ b/church/church_operations/doctype/church_location/test_church_location.py @@ -0,0 +1,9 @@ +# Copyright (c) 2026, meichthys and Contributors +# See license.txt + +# import frappe +from frappe.tests.utils import FrappeTestCase + + +class TestChurchLocation(FrappeTestCase): + pass diff --git a/church/church_operations/workspace/operations/operations.json b/church/church_operations/workspace/operations/operations.json index ac6c013..55c35ba 100644 --- a/church/church_operations/workspace/operations/operations.json +++ b/church/church_operations/workspace/operations/operations.json @@ -17,7 +17,7 @@ "hidden": 0, "is_query_report": 0, "label": "Operations Documents", - "link_count": 2, + "link_count": 3, "link_type": "DocType", "onboard": 0, "type": "Card Break" @@ -41,9 +41,19 @@ "link_type": "DocType", "onboard": 0, "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Church Locations", + "link_count": 0, + "link_to": "Church Location", + "link_type": "DocType", + "onboard": 0, + "type": "Link" } ], - "modified": "2025-12-15 01:14:50.411941", + "modified": "2026-01-05 23:51:05.865566", "modified_by": "Administrator", "module": "Church Operations", "name": "Operations", From 7afe97c0ec623d8f8115111aa71df52840f8db14 Mon Sep 17 00:00:00 2001 From: meichthys Date: Tue, 6 Jan 2026 04:55:56 +0000 Subject: [PATCH 07/28] rearrange church operations worksapce --- .../workspace/operations/operations.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/church/church_operations/workspace/operations/operations.json b/church/church_operations/workspace/operations/operations.json index 55c35ba..481beda 100644 --- a/church/church_operations/workspace/operations/operations.json +++ b/church/church_operations/workspace/operations/operations.json @@ -35,9 +35,9 @@ { "hidden": 0, "is_query_report": 0, - "label": "Church Tasks", + "label": "Church Locations", "link_count": 0, - "link_to": "Church Task", + "link_to": "Church Location", "link_type": "DocType", "onboard": 0, "type": "Link" @@ -45,15 +45,15 @@ { "hidden": 0, "is_query_report": 0, - "label": "Church Locations", + "label": "Church Tasks", "link_count": 0, - "link_to": "Church Location", + "link_to": "Church Task", "link_type": "DocType", "onboard": 0, "type": "Link" } ], - "modified": "2026-01-05 23:51:05.865566", + "modified": "2026-01-05 23:54:03.614596", "modified_by": "Administrator", "module": "Church Operations", "name": "Operations", From 6ae782a866bf322ec022df476b3658cea3204801 Mon Sep 17 00:00:00 2001 From: meichthys Date: Wed, 7 Jan 2026 03:35:17 +0000 Subject: [PATCH 08/28] Add church location note to asset documentation --- .../workspace/manual:_operations/manual:_operations.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/church/church_operations/workspace/manual:_operations/manual:_operations.json b/church/church_operations/workspace/manual:_operations/manual:_operations.json index f4804b3..04425d7 100644 --- a/church/church_operations/workspace/manual:_operations/manual:_operations.json +++ b/church/church_operations/workspace/manual:_operations/manual:_operations.json @@ -1,6 +1,6 @@ { "charts": [], - "content": "[{\"id\":\"nnvMTG5Sl5\",\"type\":\"paragraph\",\"data\":{\"text\":\"\ud83d\udee0\ufe0f Operations Manual\",\"col\":12}},{\"id\":\"B-CtTCmVDX\",\"type\":\"paragraph\",\"data\":{\"text\":\"The operations module contains features related to the operation of the church (maintenance, assets, etc).\",\"col\":12}},{\"id\":\"w8oEjl0tNc\",\"type\":\"paragraph\",\"data\":{\"text\":\"\ud83d\udce6Assets\",\"col\":12}},{\"id\":\"6IlcMu_Ikb\",\"type\":\"paragraph\",\"data\":{\"text\":\"Assets of the church.\",\"col\":12}},{\"id\":\"0J08Yp0qsz\",\"type\":\"paragraph\",\"data\":{\"text\":\"When adding a new asset, note the following:
- Try to give the asset a short but descriptive title
- Additional details can be added in the 'Notes' field\",\"col\":12}},{\"id\":\"8zFlGyC4XI\",\"type\":\"paragraph\",\"data\":{\"text\":\"\u2705Tasks\",\"col\":12}},{\"id\":\"kDsKUF3xl2\",\"type\":\"paragraph\",\"data\":{\"text\":\"Items that need to be completed. (Like a checklist or todo-list)\",\"col\":12}},{\"id\":\"t5oHSN8It-\",\"type\":\"paragraph\",\"data\":{\"text\":\"When adding a new task, note the following:
- To add sub-tasks, check the 'Is Group' option, then create new tasks and select the 'group' task in the 'Parent Task' field.
- \u26a0\ufe0f Assigning a person is only for documentation purposes, no additional 'reminder' or 'notification' functionality exists yet.\",\"col\":12}}]", + "content": "[{\"id\":\"nnvMTG5Sl5\",\"type\":\"paragraph\",\"data\":{\"text\":\"\ud83d\udee0\ufe0f Operations Manual\",\"col\":12}},{\"id\":\"B-CtTCmVDX\",\"type\":\"paragraph\",\"data\":{\"text\":\"The operations module contains features related to the operation of the church (maintenance, assets, etc).\",\"col\":12}},{\"id\":\"w8oEjl0tNc\",\"type\":\"paragraph\",\"data\":{\"text\":\"\ud83d\udce6Assets\",\"col\":12}},{\"id\":\"6IlcMu_Ikb\",\"type\":\"paragraph\",\"data\":{\"text\":\"Property of the church.\",\"col\":12}},{\"id\":\"0J08Yp0qsz\",\"type\":\"paragraph\",\"data\":{\"text\":\"When adding a new asset, note the following:
- Try to give the asset a short but descriptive title
- Additional details can be added in the 'Notes' field
- The location of the asset can be set (or added) in the \\\"Location\\\" field.\",\"col\":12}},{\"id\":\"8zFlGyC4XI\",\"type\":\"paragraph\",\"data\":{\"text\":\"\u2705Tasks\",\"col\":12}},{\"id\":\"kDsKUF3xl2\",\"type\":\"paragraph\",\"data\":{\"text\":\"Items that need to be completed. (Like a checklist or todo-list)\",\"col\":12}},{\"id\":\"t5oHSN8It-\",\"type\":\"paragraph\",\"data\":{\"text\":\"When adding a new task, note the following:
- To add sub-tasks, check the 'Is Group' option, then create new tasks and select the 'group' task in the 'Parent Task' field.
- \u26a0\ufe0f Assigning a person is only for documentation purposes, no additional 'reminder' or 'notification' functionality exists yet.\",\"col\":12}}]", "creation": "2025-12-15 00:05:45.766085", "custom_blocks": [], "docstatus": 0, @@ -13,7 +13,7 @@ "is_hidden": 0, "label": "Manual: Operations", "links": [], - "modified": "2025-12-15 01:13:52.662574", + "modified": "2026-01-06 22:23:53.967818", "modified_by": "Administrator", "module": "Church Operations", "name": "Manual: Operations", From cd37ee9f57b124449ffeafc6da4c2a6cfc6ecc2e Mon Sep 17 00:00:00 2001 From: meichthys Date: Sat, 10 Jan 2026 05:01:41 +0000 Subject: [PATCH 09/28] Give credit to Jesus --- church/church_foundations/workspace/welcome/welcome.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/church/church_foundations/workspace/welcome/welcome.json b/church/church_foundations/workspace/welcome/welcome.json index 8725c1f..d25c5b0 100644 --- a/church/church_foundations/workspace/welcome/welcome.json +++ b/church/church_foundations/workspace/welcome/welcome.json @@ -1,6 +1,6 @@ { "charts": [], - "content": "[{\"id\":\"a0vkPmhn3y\",\"type\":\"custom_block\",\"data\":{\"custom_block_name\":\"Workspace Cover Photo\",\"col\":12}},{\"id\":\"qv6aLVY432\",\"type\":\"header\",\"data\":{\"text\":\"\ud83d\udc4bWelcome\",\"col\":12}},{\"id\":\"3y9XjWNIDH\",\"type\":\"paragraph\",\"data\":{\"text\":\"Thank you for installing the `Church` app. `Church` is a completely free and open-source church management application that we hope will edify your church. We develop the application completely free of charge: \\\"Freely you have received; freely give. ~Jesus\\\"\",\"col\":12}},{\"id\":\"eyx_vzvkgN\",\"type\":\"paragraph\",\"data\":{\"text\":\"\ud83d\udc49To get started using the `Church` app, see the Getting Started page.\",\"col\":12}},{\"id\":\"Kh8eExzLKr\",\"type\":\"header\",\"data\":{\"text\":\"\ud83d\udcd8User Manual\",\"col\":12}},{\"id\":\"RubIh0IucA\",\"type\":\"paragraph\",\"data\":{\"text\":\"Each `Module` in the left hand menu has it's own help pages. If you need more help than what is provided there, see Support.\",\"col\":12}},{\"id\":\"8fQ8usz33T\",\"type\":\"header\",\"data\":{\"text\":\"\ud83e\udd1dContribute\",\"col\":12}},{\"id\":\"dBcYsyF07e\",\"type\":\"paragraph\",\"data\":{\"text\":\"If you have technical expertise and would like to contribute to the development of this project, please join us on github.
If you would like to support the project financially, don't. Instead, pray for the developers and for the churches using the software.
\",\"col\":12}},{\"id\":\"JQvQ237QXM\",\"type\":\"header\",\"data\":{\"text\":\"\ud83d\udce2Credits\",\"col\":12}},{\"id\":\"Fbdz2raOGi\",\"type\":\"paragraph\",\"data\":{\"text\":\"- All the contributors of this project. Thank You!
Frappe Framework - This application is built on top of this great open source software.
- Your IT Administrator - They set this application up for you!
\",\"col\":12}}]", + "content": "[{\"id\":\"a0vkPmhn3y\",\"type\":\"custom_block\",\"data\":{\"custom_block_name\":\"Workspace Cover Photo\",\"col\":12}},{\"id\":\"qv6aLVY432\",\"type\":\"header\",\"data\":{\"text\":\"\ud83d\udc4bWelcome\",\"col\":12}},{\"id\":\"3y9XjWNIDH\",\"type\":\"paragraph\",\"data\":{\"text\":\"Thank you for installing the `Church` app. `Church` is a completely free and open-source church management application that we hope will edify your church. We develop the application completely free of charge: \\\"Freely you have received; freely give. ~Jesus\\\"\",\"col\":12}},{\"id\":\"eyx_vzvkgN\",\"type\":\"paragraph\",\"data\":{\"text\":\"\ud83d\udc49To get started using the `Church` app, see the Getting Started page.\",\"col\":12}},{\"id\":\"Kh8eExzLKr\",\"type\":\"header\",\"data\":{\"text\":\"\ud83d\udcd8User Manual\",\"col\":12}},{\"id\":\"RubIh0IucA\",\"type\":\"paragraph\",\"data\":{\"text\":\"Each `Module` in the left hand menu has it's own help pages. If you need more help than what is provided there, see Support.\",\"col\":12}},{\"id\":\"8fQ8usz33T\",\"type\":\"header\",\"data\":{\"text\":\"\ud83e\udd1dContribute\",\"col\":12}},{\"id\":\"dBcYsyF07e\",\"type\":\"paragraph\",\"data\":{\"text\":\"If you have technical expertise and would like to contribute to the development of this project, please join us on github.
If you would like to support the project financially, don't. Instead, pray for the developers and for the churches using the software.
\",\"col\":12}},{\"id\":\"JQvQ237QXM\",\"type\":\"header\",\"data\":{\"text\":\"\ud83d\udce2Credits\",\"col\":12}},{\"id\":\"Fbdz2raOGi\",\"type\":\"paragraph\",\"data\":{\"text\":\"- All the contributors of this project. Thank You!
Frappe Framework - This application is built on top of this great open source software.
- Your IT Administrator - They set this application up for you!
- Our Lord and Savior Jesus Christ - without whom this app would not exist.
\",\"col\":12}}]", "creation": "2025-08-22 00:39:02.127277", "custom_blocks": [ { @@ -18,7 +18,7 @@ "is_hidden": 0, "label": "Welcome", "links": [], - "modified": "2025-11-01 23:09:26.643807", + "modified": "2026-01-10 00:00:59.501803", "modified_by": "Administrator", "module": "Church Foundations", "name": "Welcome", From a109a0a9124d239c14c44609db0738e8e7d1f8eb Mon Sep 17 00:00:00 2001 From: meichthys Date: Mon, 12 Jan 2026 02:00:00 +0000 Subject: [PATCH 10/28] refactor install.py after_install scripts --- church/install.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/church/install.py b/church/install.py index 39d6a0f..525e46a 100644 --- a/church/install.py +++ b/church/install.py @@ -4,13 +4,15 @@ import frappe def before_install(): # Ensure ERPNext is installed if "erpnext" not in frappe.get_installed_apps(): - raise FileNotFoundError( - f"ERPNext must be installed before installing this app." - ) + raise FileNotFoundError("ERPNext must be installed before installing this app.") def after_install(): - # Remove non-biblical Genders + adjust_gender_options() + + +def adjust_gender_options(): + """Remove non-biblical Genders from default gender list""" genders = frappe.db.get_all("Gender") for gender in genders: if gender.name not in ["Male", "Female", "Unknown"]: From 468e395a7992886166898df86bee2d94bac51cb6 Mon Sep 17 00:00:00 2001 From: meichthys Date: Mon, 12 Jan 2026 04:24:19 +0000 Subject: [PATCH 11/28] Credit the source of the fetched Bible text --- .../doctype/church_bible_reference/church_bible_reference.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/church/church_study/doctype/church_bible_reference/church_bible_reference.json b/church/church_study/doctype/church_bible_reference/church_bible_reference.json index 55fe746..a02dc67 100644 --- a/church/church_study/doctype/church_bible_reference/church_bible_reference.json +++ b/church/church_study/doctype/church_bible_reference/church_bible_reference.json @@ -51,6 +51,7 @@ "options": "Church Bible Translation" }, { + "description": "Text fetched courtesy of bible.helloao.org", "fieldname": "import_reference_text", "fieldtype": "Button", "label": "Import Reference Text" @@ -76,7 +77,7 @@ "table_fieldname": "bible_references" } ], - "modified": "2025-11-18 23:52:19.026266", + "modified": "2026-01-11 23:23:16.779117", "modified_by": "Administrator", "module": "Church Study", "name": "Church Bible Reference", From a77a6b140c0c976064477a88011ab3043e259fd8 Mon Sep 17 00:00:00 2001 From: meichthys Date: Mon, 12 Jan 2026 04:48:18 +0000 Subject: [PATCH 12/28] fix alms request expense creation --- .../doctype/church_alms_request/church_alms_request.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/church/church_finances/doctype/church_alms_request/church_alms_request.py b/church/church_finances/doctype/church_alms_request/church_alms_request.py index 0d33700..81e04ba 100644 --- a/church/church_finances/doctype/church_alms_request/church_alms_request.py +++ b/church/church_finances/doctype/church_alms_request/church_alms_request.py @@ -21,7 +21,7 @@ def create_expense(alms_request_name): expense = frappe.new_doc("Church Expense") expense.amount = alms.amount expense.notes = f"Church Alms Request: {alms.name}" - expense.type = frappe.db.get_value("Church Expense Type", {"name": "Alms"}, "name") + expense.type = frappe.db.get_value("Church Expense Type", alms.expense_type, "type") expense.date = frappe.utils.now() expense.insert(ignore_permissions=True) frappe.msgprint(f"βœ… {expense.type} expense created.") From 63558ef751253a400d2a6f0458e795026ba152a7 Mon Sep 17 00:00:00 2001 From: meichthys Date: Mon, 12 Jan 2026 04:52:32 +0000 Subject: [PATCH 13/28] Add mvp presentation doctype --- .../web_form/presentations/__init__.py | 0 .../web_form/presentations/presentations.js | 3 + .../web_form/presentations/presentations.json | 80 +++++++++++++++++++ .../web_form/presentations/presentations.py | 5 ++ 4 files changed, 88 insertions(+) create mode 100644 church/church_communications/web_form/presentations/__init__.py create mode 100644 church/church_communications/web_form/presentations/presentations.js create mode 100644 church/church_communications/web_form/presentations/presentations.json create mode 100644 church/church_communications/web_form/presentations/presentations.py diff --git a/church/church_communications/web_form/presentations/__init__.py b/church/church_communications/web_form/presentations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/church/church_communications/web_form/presentations/presentations.js b/church/church_communications/web_form/presentations/presentations.js new file mode 100644 index 0000000..699703c --- /dev/null +++ b/church/church_communications/web_form/presentations/presentations.js @@ -0,0 +1,3 @@ +frappe.ready(function() { + // bind events here +}) \ No newline at end of file diff --git a/church/church_communications/web_form/presentations/presentations.json b/church/church_communications/web_form/presentations/presentations.json new file mode 100644 index 0000000..c261e70 --- /dev/null +++ b/church/church_communications/web_form/presentations/presentations.json @@ -0,0 +1,80 @@ +{ + "allow_comments": 0, + "allow_delete": 0, + "allow_edit": 0, + "allow_incomplete": 0, + "allow_multiple": 0, + "allow_print": 1, + "anonymous": 0, + "apply_document_permissions": 1, + "button_label": "Save", + "condition_json": "[]", + "creation": "2025-12-19 23:50:47.255475", + "doc_type": "Church Presentation", + "docstatus": 0, + "doctype": "Web Form", + "idx": 0, + "is_standard": 1, + "list_columns": [ + { + "fieldname": "title", + "fieldtype": "Data", + "label": "Title" + } + ], + "list_title": "Presentations", + "login_required": 1, + "max_attachment_size": 0, + "modified": "2025-12-20 00:20:51.007813", + "modified_by": "Administrator", + "module": "Church Communications", + "name": "presentations", + "owner": "Administrator", + "published": 1, + "route": "presentations", + "show_attachments": 1, + "show_list": 1, + "show_sidebar": 0, + "title": "Presentations", + "web_form_fields": [ + { + "allow_read_on_all_link_options": 0, + "fieldname": "title", + "fieldtype": "Data", + "hidden": 0, + "label": "Title", + "max_length": 0, + "max_value": 0, + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "section_break_hgry", + "fieldtype": "Section Break", + "hidden": 0, + "max_length": 0, + "max_value": 0, + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "slides", + "fieldtype": "Table", + "hidden": 0, + "label": "Slides", + "max_length": 0, + "max_value": 0, + "options": "Church Presentation Slide", + "precision": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + } + ] +} \ No newline at end of file diff --git a/church/church_communications/web_form/presentations/presentations.py b/church/church_communications/web_form/presentations/presentations.py new file mode 100644 index 0000000..e1ada61 --- /dev/null +++ b/church/church_communications/web_form/presentations/presentations.py @@ -0,0 +1,5 @@ +import frappe + +def get_context(context): + # do your magic here + pass From 8d34475a6ae141b6e3cf1242b2e376925ec7c036 Mon Sep 17 00:00:00 2001 From: meichthys Date: Mon, 12 Jan 2026 05:05:31 +0000 Subject: [PATCH 14/28] Update typos in getting started doc --- .../workspace/getting_started/getting_started.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/church/church_foundations/workspace/getting_started/getting_started.json b/church/church_foundations/workspace/getting_started/getting_started.json index 29ff159..d413b99 100644 --- a/church/church_foundations/workspace/getting_started/getting_started.json +++ b/church/church_foundations/workspace/getting_started/getting_started.json @@ -1,6 +1,6 @@ { "charts": [], - "content": "[{\"id\":\"jBOqYlrUKi\",\"type\":\"header\",\"data\":{\"text\":\"Getting Started\",\"col\":12}},{\"id\":\"G96Ym-p_M3\",\"type\":\"onboarding\",\"data\":{\"onboarding_name\":\"Church\",\"col\":12}},{\"id\":\"-4rZfnKx88\",\"type\":\"paragraph\",\"data\":{\"text\":\"\ud83d\udcacTerminology\",\"col\":12}},{\"id\":\"DbBYvDiV8I\",\"type\":\"paragraph\",\"data\":{\"text\":\"- Workspace: Each menu item to the left is called a 'Workspace'. Workspaces show the Documents, Reports, and other ways you can with in the module.
- Module: A group of related functions in the app (i.e, Donations, Funds, Expenses).
- Document: Data that describes an object (i.e. Song, Fund, Person, etc). Documents are composed of 'Fields', are created via 'Forms', and can be viewed in a Document 'List' or 'Report'.
    - Name: The title given to a document. Some documents may have a number after the name to prevent documents from having the same name (document names must be unique).
    - State: When a Document is created, it can be in various states:
        - Not Saved: A new document is in this state until it is saved. No data is retained until the document is saved.
        - Draft: The document has not been submitted yet. Submittable documents will be in the 'draft' state after they are saved and before they are submitted. In this state the document can still be modified.
        - Submitted: A finalized document which cannot be edited unless it is cancelled and amended.
        - Cancelled: A document that has been cancelled (as opposed to deleted). Cancelled documents remain in the system for reference, and can be amended and re-submitted.
        - Amended: If a cancelled document needs to be changed, it can be amended. This will create a new document which will be linked to the original (cancelled) document.
- Fields: Pieces of data that make up a document (i.e. Name, Age, etc). Fields with a red * are mandatory.
- Form: A way to enter data into the system. A form consists of any number of fields, that (when saved) create a document.
- List
: A view that shows documents in a vertical layout. You can view a list of any type of document by typing `DocumentName List` in the search bar at the top of the page.
- Report: A view that shows documents in an easy-to-filter view. Every column can be filtered individually. Additional filters and groupings can be added to easily retrieve a subset of documents.\",\"col\":12}},{\"id\":\"Yx5-uyqasy\",\"type\":\"paragraph\",\"data\":{\"text\":\"\ud83d\udcccGeneral App Tips\",\"col\":12}},{\"id\":\"oyG93LCEUd\",\"type\":\"paragraph\",\"data\":{\"text\":\"The general layout of the application is the same for most modules & documents. Once you learn how to interact with the system in one module, it will be almost identical in other modules. Some tips that will work across the application are:\",\"col\":12}},{\"id\":\"d9OEtT2hpG\",\"type\":\"paragraph\",\"data\":{\"text\":\"Awesome Bar (keyboard shortcut of `ctrl-g`)
The search bar at the top of the page is called the `Awesome Bar` because it can be used for many purposes:
\u2795 Creating a new document: (i.e. `New Church Person` to add a new church person into the app)
\ud83d\udccbListing all documents of a specific type: (i.e. `Church Person List` to show a list of existing church people)
\ud83d\udcc4Report of a specific document type: (i.e. `Church Person Report` \\nto show a filter-able and group-able report containing church people)
\ud83d\udd0dFind an individual document: (i.e. `Marjorie May` to search for this person. Most documents are searchable this way)
\",\"col\":12}},{\"id\":\"MJLiY1t4dT\",\"type\":\"paragraph\",\"data\":{\"text\":\"Navigation
To navigate the system you can use the following:
\u2754Look for the 'question mark in a circle' icon. Clicking this icon will take you to the documentation relevant for the field or document you are working on.
\u2b05\ufe0f The sidebar items on the left will take you to a workspace for the given module
\u2196\ufe0f Clicking on the icon on the top left will take you back to the default workspace page.
\u2197\ufe0f Using the search bar, you can navigate to almost any page in the app.
\",\"col\":12}},{\"id\":\"wDz7rjHAKG\",\"type\":\"paragraph\",\"data\":{\"text\":\"Keyboard Shortcuts
After using the app for a while, keyboard shortcuts can help speed up your workflow significantly. To view a list of keyboard shortcuts, click the `Help > Keyboard Shortcuts` at the top right of the page. Some common shortcuts that may be useful are:
\ud83d\udcbe `ctrl-s` Saves a loaded document/form
\ud83d\udccd`ctrl-j` Locates a specific field in a form
\ud83d\udd0d`ctrl-g` Focuses the AwesomeBar for quick access to almost any action in the app.
\ud83d\udd03`ctrl-shift-r` Reloads the page - Useful if something didn't seem to load correctly.
\",\"col\":12}}]", + "content": "[{\"id\":\"jBOqYlrUKi\",\"type\":\"header\",\"data\":{\"text\":\"Getting Started\",\"col\":12}},{\"id\":\"G96Ym-p_M3\",\"type\":\"onboarding\",\"data\":{\"onboarding_name\":\"Church\",\"col\":12}},{\"id\":\"-4rZfnKx88\",\"type\":\"paragraph\",\"data\":{\"text\":\"\ud83d\udcacTerminology\",\"col\":12}},{\"id\":\"DbBYvDiV8I\",\"type\":\"paragraph\",\"data\":{\"text\":\"- Workspace: Each menu item to the left is called a 'Workspace'. Workspaces show the Documents, Reports, Charts, and links to features in a given module.
- Module: A group of related functions in the app (i.e, Finances, Communications, Missions, etc).
- Document: Data that describes an object (i.e. Song, Fund, Person, etc). Documents are composed of 'Fields', are created via 'Forms', and can be viewed in a Document 'List' or 'Report'.
    - Name: The title given to a document. Some documents may have a number after the name to prevent documents from having the same name (document names must be unique).
    - State: When a Document is created, it can be in various states:
        - Not Saved: A new document is in this state until it is saved. No data is retained until the document is saved.
        - Draft: The document has not been submitted yet. Submittable documents will be in the 'draft' state after they are saved and before they are submitted. In this state the document can still be modified.
        - Submitted: A finalized document which cannot be edited unless it is cancelled and amended.
        - Cancelled: A document that has been cancelled (as opposed to deleted). Cancelled documents remain in the system for reference, and can be amended and re-submitted.
        - Amended: If a cancelled document needs to be changed, it can be amended. This will create a new document which will be linked to the original (cancelled) document.
- Fields: Pieces of data that make up a document (i.e. Name, Age, etc). Fields with a red * are mandatory.
- Form: A way to enter data into the system. A form consists of any number of fields, that (when saved) create a document.
- List
: A view that shows documents in a vertical layout. You can view a list of any type of document by typing `<document name> List` in the search bar at the top of the page.
- Report: A view that shows documents in an easy-to-filter view. Every column can be filtered individually. Additional filters and groupings can be added to easily retrieve a subset of documents.\",\"col\":12}},{\"id\":\"Yx5-uyqasy\",\"type\":\"paragraph\",\"data\":{\"text\":\"\ud83d\udcccGeneral App Tips\",\"col\":12}},{\"id\":\"oyG93LCEUd\",\"type\":\"paragraph\",\"data\":{\"text\":\"The general layout of the application is the same for most modules & documents. Once you learn how to interact with the system in one module, it will be almost identical in other modules. Some tips that will work across the application are:\",\"col\":12}},{\"id\":\"d9OEtT2hpG\",\"type\":\"paragraph\",\"data\":{\"text\":\"Awesome Bar (keyboard shortcut of `ctrl-g`)
The search bar at the top of the page is called the `Awesome Bar` because it can be used for many purposes:
\u2795 Creating a new document: (i.e. `New Church Person` to add a new church person into the app)
\ud83d\udccbListing all documents of a specific type: (i.e. `Church Person List` to show a list of existing church people)
\ud83d\udcc4Report of a specific document type: (i.e. `Church Person Report` \\nto show a filter-able and group-able report containing church people)
\ud83d\udd0dFind an individual document: (i.e. `Marjorie May` to search for this person. Most documents are searchable this way)
\",\"col\":12}},{\"id\":\"MJLiY1t4dT\",\"type\":\"paragraph\",\"data\":{\"text\":\"Navigation
To navigate the system you can use the following:
\u2754Look for the 'question mark in a circle' icon. Clicking this icon will take you to the documentation relevant for the field or document you are working on.
\u2b05\ufe0f The sidebar items on the left will take you to a workspace for the given module
\u2196\ufe0f Clicking on the icon on the top left will take you back to the default workspace page.
\u2197\ufe0f Using the search bar, you can navigate to almost any page in the app.
\",\"col\":12}},{\"id\":\"wDz7rjHAKG\",\"type\":\"paragraph\",\"data\":{\"text\":\"Keyboard Shortcuts
After using the app for a while, keyboard shortcuts can help speed up your workflow significantly. To view a list of keyboard shortcuts, click the `Help > Keyboard Shortcuts` at the top right of the page. Some common shortcuts that may be useful are:
\ud83d\udcbe `ctrl-s` Saves a loaded document/form
\ud83d\udccd`ctrl-j` Locates a specific field in a form
\ud83d\udd0d`ctrl-g` Focuses the AwesomeBar for quick access to almost any action in the app.
\ud83d\udd03`ctrl-shift-r` Reloads the page - Useful if something didn't seem to load correctly.
\",\"col\":12}}]", "creation": "2025-10-20 23:30:01.238945", "custom_blocks": [], "docstatus": 0, @@ -13,7 +13,7 @@ "is_hidden": 0, "label": "Getting Started", "links": [], - "modified": "2025-11-12 23:57:05.744160", + "modified": "2026-01-12 00:05:13.303545", "modified_by": "Administrator", "module": "Church Foundations", "name": "Getting Started", From 48ba2530db9fa3f700003bac38fde73fbff8acfd Mon Sep 17 00:00:00 2001 From: meichthys Date: Thu, 15 Jan 2026 05:38:07 +0000 Subject: [PATCH 15/28] fix app_include_icon path --- church/hooks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/church/hooks.py b/church/hooks.py index ac71e45..7aacb30 100644 --- a/church/hooks.py +++ b/church/hooks.py @@ -267,7 +267,7 @@ app_include_js = "/assets/church/js/help_icon_on_form.js" # Svg Icons # ------------------ # include app icons in desk -app_include_icons = ["church/icons/church.svg"] +app_include_icons = ["/assets/church/icons/church.svg"] # Home Pages # ---------- From bf968686718428ae3e30785a5f875abd2f8f05b1 Mon Sep 17 00:00:00 2001 From: meichthys Date: Mon, 2 Feb 2026 04:43:10 +0000 Subject: [PATCH 16/28] bump readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eea35b7..82e4aec 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ # β›ͺ Church -A fully open-source church management app built on the [Frappe Framework](https://frappe.io/framework). +A fully open-source church management system built on the [Frappe Framework](https://frappe.io/framework). ![](./church/public/media/feature_image.png) From a439baa339f3032e0b0b86511eb069dec0d441c9 Mon Sep 17 00:00:00 2001 From: meichthys Date: Tue, 3 Feb 2026 03:00:05 +0000 Subject: [PATCH 17/28] fix family creation from person --- church/church_people/doctype/church_family/church_family.py | 2 +- church/church_people/doctype/church_person/church_person.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/church/church_people/doctype/church_family/church_family.py b/church/church_people/doctype/church_family/church_family.py index f608e12..58ecad9 100644 --- a/church/church_people/doctype/church_family/church_family.py +++ b/church/church_people/doctype/church_family/church_family.py @@ -24,7 +24,7 @@ class ChurchFamily(Document): def before_save(self): # Remove family from Church Person records when Person is removed from ChurchFamily - if self.get_doc_before_save().members: + if self.get_doc_before_save() and self.get_doc_before_save().members: for member in self.get_doc_before_save().members: if member not in self.members: frappe.db.set_value("Church Person", member.member, "family", None, update_modified=False) diff --git a/church/church_people/doctype/church_person/church_person.py b/church/church_people/doctype/church_person/church_person.py index 5bf5963..8b36da3 100644 --- a/church/church_people/doctype/church_person/church_person.py +++ b/church/church_people/doctype/church_person/church_person.py @@ -21,7 +21,7 @@ class ChurchPerson(Document): family.append("members", {"member": self.name}) family.save() # Remove person from Church Family if family is removed - if not self.family and hasattr(self.get_doc_before_save(), "family"): + if not self.family and self.get_doc_before_save().family is not None: family = frappe.get_doc("Church Family", self.get_doc_before_save().family) for member in family.members: if member.member == self.name: From 9a22802a6a8c41a28c57b6b0af80d612b5f1f022 Mon Sep 17 00:00:00 2001 From: meichthys Date: Tue, 3 Feb 2026 04:51:09 +0000 Subject: [PATCH 18/28] Add Email Configuration Onboarding Step --- .../module_onboarding/church/church.json | 7 +++++-- .../email_configuration.json | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 church/church_foundations/onboarding_step/email_configuration/email_configuration.json diff --git a/church/church_foundations/module_onboarding/church/church.json b/church/church_foundations/module_onboarding/church/church.json index ed69720..674818e 100644 --- a/church/church_foundations/module_onboarding/church/church.json +++ b/church/church_foundations/module_onboarding/church/church.json @@ -10,13 +10,13 @@ "role": "Church User" } ], - "creation": "2025-09-26 23:06:43.733904", + "creation": "2026-01-15 00:35:14.121463", "docstatus": 0, "doctype": "Module Onboarding", "documentation_url": "https://github.com/meichthys/church", "idx": 0, "is_complete": 0, - "modified": "2025-09-30 21:21:52.088048", + "modified": "2026-02-02 23:21:50.768671", "modified_by": "Administrator", "module": "Church Foundations", "name": "Church", @@ -25,6 +25,9 @@ { "step": "Church Manager" }, + { + "step": "Email Configuration" + }, { "step": "Church Information" }, diff --git a/church/church_foundations/onboarding_step/email_configuration/email_configuration.json b/church/church_foundations/onboarding_step/email_configuration/email_configuration.json new file mode 100644 index 0000000..2e022c1 --- /dev/null +++ b/church/church_foundations/onboarding_step/email_configuration/email_configuration.json @@ -0,0 +1,18 @@ +{ + "action": "Create Entry", + "creation": "2026-02-02 23:21:46.133462", + "docstatus": 0, + "doctype": "Onboarding Step", + "idx": 0, + "is_complete": 0, + "is_single": 0, + "is_skipped": 0, + "modified": "2026-02-02 23:21:46.133462", + "modified_by": "Administrator", + "name": "Email Configuration", + "owner": "Administrator", + "show_form_tour": 0, + "show_full_form": 0, + "title": "Email Configuration", + "validate_action": 1 +} \ No newline at end of file From 7c1b2c5c9de8873e11b347bfc50b2ee2a788069b Mon Sep 17 00:00:00 2001 From: meichthys Date: Tue, 3 Feb 2026 04:53:58 +0000 Subject: [PATCH 19/28] update misc --- .../onboarding_step/church_event/church_event.json | 4 ++-- .../onboarding_step/church_family/church_family.json | 2 +- .../church_information/church_information.json | 8 ++++---- .../church_manager/church_manager.json | 11 ++++++----- .../onboarding_step/church_person/church_person.json | 4 ++-- .../church_prayer_request/church_prayer_request.json | 4 ++-- 6 files changed, 17 insertions(+), 16 deletions(-) diff --git a/church/church_foundations/onboarding_step/church_event/church_event.json b/church/church_foundations/onboarding_step/church_event/church_event.json index 64f5392..ac3367e 100644 --- a/church/church_foundations/onboarding_step/church_event/church_event.json +++ b/church/church_foundations/onboarding_step/church_event/church_event.json @@ -1,11 +1,11 @@ { "action": "Create Entry", "action_label": "Add a Church Event", - "creation": "2025-09-01 01:22:18.857151", + "creation": "2026-01-15 11:02:52.715557", "description": "Events can be used to track `Church Person` attendance and to link to `Church Collection`s", "docstatus": 0, "doctype": "Onboarding Step", - "idx": 1, + "idx": 0, "is_complete": 0, "is_single": 0, "is_skipped": 0, diff --git a/church/church_foundations/onboarding_step/church_family/church_family.json b/church/church_foundations/onboarding_step/church_family/church_family.json index a0b8832..df981eb 100644 --- a/church/church_foundations/onboarding_step/church_family/church_family.json +++ b/church/church_foundations/onboarding_step/church_family/church_family.json @@ -1,7 +1,7 @@ { "action": "Create Entry", "action_label": "Add a Church Family", - "creation": "2025-09-01 01:21:35.262713", + "creation": "2026-01-15 11:02:52.691072", "description": "Adding a `Church Family` allows you to track which `Church Person`s belong to specific families.", "docstatus": 0, "doctype": "Onboarding Step", diff --git a/church/church_foundations/onboarding_step/church_information/church_information.json b/church/church_foundations/onboarding_step/church_information/church_information.json index 8e4d9ef..436e6cd 100644 --- a/church/church_foundations/onboarding_step/church_information/church_information.json +++ b/church/church_foundations/onboarding_step/church_information/church_information.json @@ -1,16 +1,16 @@ { "action": "Create Entry", "action_label": "Add Church Information", - "creation": "2025-09-18 00:37:00.347151", - "description": "Church information is used across the application to populate parts of the church website, letterheads, reports, etc.", + "creation": "2026-01-15 11:02:52.730907", + "description": "Church information is used across the application to populate parts of the church website, letterheads, reports, etc.\n\n\u26a0\ufe0f Only `Church Manager`s can edit `Church Information`.", "docstatus": 0, "doctype": "Onboarding Step", "form_tour": "Church Information", - "idx": 1, + "idx": 0, "is_complete": 0, "is_single": 1, "is_skipped": 0, - "modified": "2025-09-28 22:44:13.743291", + "modified": "2025-09-30 21:28:41.144848", "modified_by": "Administrator", "name": "Church Information", "owner": "Administrator", diff --git a/church/church_foundations/onboarding_step/church_manager/church_manager.json b/church/church_foundations/onboarding_step/church_manager/church_manager.json index 2c71272..7bba04b 100644 --- a/church/church_foundations/onboarding_step/church_manager/church_manager.json +++ b/church/church_foundations/onboarding_step/church_manager/church_manager.json @@ -1,21 +1,22 @@ { "action": "Create Entry", "action_label": "Create Church Manager User", - "creation": "2025-09-30 20:52:59.340570", - "description": "Before you get started, you should create a new user. The 'Administrator' user should not be used on a daily basis and should be reserved for troubleshooting and system configuration. At least one separate user should be created with the 'Church Manager' RoleProfile and the 'Church' ModuleProfile permissions. These users will have full access to the Church app.\n\nAdditional users can also be created with the 'Church User' RoleProfile and 'Church' ModuleProfile permissions. These users will have access to most of the Church app, but will be restricted from modifying, or even seeing sensitive portions of the app. To see the exact permissions that these users have, you can (with the 'Administrator' account) use the seach bar at the top to search for 'Role Permissions Manager' and select the 'Church User' role to see what is accessible by those types of users.", + "creation": "2026-01-15 11:02:52.707437", + "description": "Before you get started, you should create a new user. The `Administrator` user should not be used on a daily basis and should be reserved for setting up new users, troubleshooting and system configuration. At least one separate user should be created with the `Church Manager` RoleProfile and the `Church` ModuleProfile permissions. These users will have full access to the Church app.\n\nAdditional users can also be created with the `Church User` RoleProfile and no ModuleProfile permissions. These users will only have access to specific forms. \n\nTo see the exact permissions that a user has, you can (with the `Administrator` account) use the seach bar at the top to search for `Role Permissions Manager` and select the `Church Manager` or `Church User` role to see what is accessible by eacy type of user.\n\nTo summarize:\n- Only the `Administrator` user has permission to create new users.\n- `Church Managers` have full access to the Church app - This is best for church leadership.\n- `Church Users` have limited (portal) access - This is best for church members/attendees.", "docstatus": 0, "doctype": "Onboarding Step", + "form_tour": "Church Manager", "idx": 0, "is_complete": 0, "is_single": 0, "is_skipped": 0, - "modified": "2025-09-30 20:53:20.314286", + "modified": "2025-11-15 23:32:10.480849", "modified_by": "Administrator", "name": "Church Manager", "owner": "Administrator", "reference_document": "User", - "show_form_tour": 0, - "show_full_form": 0, + "show_form_tour": 1, + "show_full_form": 1, "title": "Church Manager", "validate_action": 1 } \ No newline at end of file diff --git a/church/church_foundations/onboarding_step/church_person/church_person.json b/church/church_foundations/onboarding_step/church_person/church_person.json index 8137d80..42c00d9 100644 --- a/church/church_foundations/onboarding_step/church_person/church_person.json +++ b/church/church_foundations/onboarding_step/church_person/church_person.json @@ -1,7 +1,7 @@ { "action": "Create Entry", "action_label": "Add Church Person", - "creation": "2025-09-26 23:06:43.748709", + "creation": "2026-01-15 11:02:52.699437", "description": "Adding `Church Person`s allows you to track the person's roles, attendance, donations, etc.", "docstatus": 0, "doctype": "Onboarding Step", @@ -10,7 +10,7 @@ "is_complete": 0, "is_single": 0, "is_skipped": 0, - "modified": "2025-09-07 00:57:18.263385", + "modified": "2025-09-30 21:56:12.070093", "modified_by": "Administrator", "name": "Church Person", "owner": "Administrator", diff --git a/church/church_foundations/onboarding_step/church_prayer_request/church_prayer_request.json b/church/church_foundations/onboarding_step/church_prayer_request/church_prayer_request.json index dfdf3d5..9868853 100644 --- a/church/church_foundations/onboarding_step/church_prayer_request/church_prayer_request.json +++ b/church/church_foundations/onboarding_step/church_prayer_request/church_prayer_request.json @@ -1,10 +1,10 @@ { "action": "Create Entry", "action_label": "Add Prayer Request", - "creation": "2025-09-13 01:20:43.693886", + "creation": "2026-01-15 11:02:52.722337", "docstatus": 0, "doctype": "Onboarding Step", - "idx": 1, + "idx": 0, "is_complete": 0, "is_single": 0, "is_skipped": 0, From 29253393479b6abc0a12181bd723a3336b28bc60 Mon Sep 17 00:00:00 2001 From: meichthys Date: Tue, 3 Feb 2026 04:54:30 +0000 Subject: [PATCH 20/28] Invite Church Persons to be Portal Users --- .../manual:_website/manual:_website.json | 4 +-- .../doctype/church_person/church_person.js | 13 ++++++-- .../doctype/church_person/church_person.json | 8 ++--- .../doctype/church_person/church_person.py | 33 ++++++++++++++++++- .../manual:_people/manual:_people.json | 4 +-- 5 files changed, 50 insertions(+), 12 deletions(-) diff --git a/church/church_foundations/workspace/manual:_website/manual:_website.json b/church/church_foundations/workspace/manual:_website/manual:_website.json index 7caeeec..2811ea1 100644 --- a/church/church_foundations/workspace/manual:_website/manual:_website.json +++ b/church/church_foundations/workspace/manual:_website/manual:_website.json @@ -1,6 +1,6 @@ { "charts": [], - "content": "[{\"id\":\"nnvMTG5Sl5\",\"type\":\"paragraph\",\"data\":{\"text\":\"\ud83c\udf10Website Manual\",\"col\":12}},{\"id\":\"B-CtTCmVDX\",\"type\":\"paragraph\",\"data\":{\"text\":\"The website module manages and configures a public facing website for the church using data from other modules (i.e. Foundations, Missions, Ministries, etc).\",\"col\":12}},{\"id\":\"8qBfIl0adi\",\"type\":\"paragraph\",\"data\":{\"text\":\"Various information in the system (i.e. Beliefs, Missionaries, Ministries, etc), may be used to populate the public facing website.\",\"col\":12}},{\"id\":\"kHbqzTGDhX\",\"type\":\"paragraph\",\"data\":{\"text\":\"The website 'feature' has not been fully developed but is on the roadmap.\",\"col\":12}}]", + "content": "[{\"id\":\"nnvMTG5Sl5\",\"type\":\"paragraph\",\"data\":{\"text\":\"\ud83c\udf10Website Manual\",\"col\":12}},{\"id\":\"B-CtTCmVDX\",\"type\":\"paragraph\",\"data\":{\"text\":\"The website module consists of two main features: a public website, and a user portal.\",\"col\":12}},{\"id\":\"kHbqzTGDhX\",\"type\":\"paragraph\",\"data\":{\"text\":\"\u26a0\ufe0f The website and portal 'features' have not been fully developed but the features are on the roadmap.\",\"col\":12}},{\"id\":\"fAFxFk8rny\",\"type\":\"header\",\"data\":{\"text\":\"\ud83c\udf0eWebsite\",\"col\":12}},{\"id\":\"WCW6FzkHwB\",\"type\":\"paragraph\",\"data\":{\"text\":\"The public facing website is accessible by anyone and can be dynamically updated based on information in the Church App (i.e. Beliefs, Missionaries, Ministries, etc).
User accounts with \\\"Church Manager\\\" permissions can modify the website.
No user account is required to view the website - anyone with an internet connection and a web browser can view the public website.
\",\"col\":12}},{\"id\":\"nZdduTPzRH\",\"type\":\"header\",\"data\":{\"text\":\"\ud83d\udc64User Portal\",\"col\":12}},{\"id\":\"8qBfIl0adi\",\"type\":\"paragraph\",\"data\":{\"text\":\"The user portal requires login credentials and provides users a personalized interface for accessing church information (i.e. Personal Profile, Prayer Requests, Alms Requests, etc).
Portal users cannot access all information in the Church App, they can only access information related to their 'Church Person', or information shared with them (i.e. non-private prayer requests).\",\"col\":12}}]", "creation": "2025-10-26 22:57:00.373845", "custom_blocks": [], "docstatus": 0, @@ -13,7 +13,7 @@ "is_hidden": 0, "label": "Manual: Website", "links": [], - "modified": "2025-11-02 01:31:42.840957", + "modified": "2026-02-02 23:18:28.432425", "modified_by": "Administrator", "module": "Church Foundations", "name": "Manual: Website", diff --git a/church/church_people/doctype/church_person/church_person.js b/church/church_people/doctype/church_person/church_person.js index 80e4084..6c0c536 100644 --- a/church/church_people/doctype/church_person/church_person.js +++ b/church/church_people/doctype/church_person/church_person.js @@ -8,11 +8,20 @@ frappe.ui.form.on("Church Person", { frm.add_custom_button(__('New Family From Person'), function () { frm.call("new_family_from_person") }) - }; + } + + // Add 'Invite to Portal' button if email is provided and no Portal User is linked + if (frm.doc.email && !frm.doc.portal_user) { + frm.add_custom_button(__('Invite to Portal'), function () { + frm.call("invite_to_portal") + }); + } + // Add 'Church Person Tour' button frm.add_custom_button(__('Tutorial'), function () { frm.tour.init("Church Person").then(() => frm.tour.start()); }); + }, after_save(frm) { @@ -20,5 +29,3 @@ frappe.ui.form.on("Church Person", { }, }); - - diff --git a/church/church_people/doctype/church_person/church_person.json b/church/church_people/doctype/church_person/church_person.json index bcbd074..4cad6f4 100644 --- a/church/church_people/doctype/church_person/church_person.json +++ b/church/church_people/doctype/church_person/church_person.json @@ -18,7 +18,7 @@ "photo", "birthday", "alergies", - "app_user", + "portal_user", "church_records_section", "is_member", "membership_date", @@ -296,9 +296,9 @@ "print_hide": 1 }, { - "fieldname": "app_user", + "fieldname": "portal_user", "fieldtype": "Link", - "label": "App User", + "label": "Portal User", "options": "User" } ], @@ -327,7 +327,7 @@ "link_fieldname": "recipient" } ], - "modified": "2025-12-18 23:37:10.065945", + "modified": "2026-02-02 22:55:22.764479", "modified_by": "Administrator", "module": "Church People", "name": "Church Person", diff --git a/church/church_people/doctype/church_person/church_person.py b/church/church_people/doctype/church_person/church_person.py index 8b36da3..45ea7d3 100644 --- a/church/church_people/doctype/church_person/church_person.py +++ b/church/church_people/doctype/church_person/church_person.py @@ -122,10 +122,41 @@ class ChurchPerson(Document): else: role.is_current_role = 0 + @frappe.whitelist() + def invite_to_portal(self): + # Check if user already exists with this email + user = frappe.db.exists("User", {"email": self.email}) + + if not user: + # Create a new portal user + new_user = frappe.new_doc("User") + new_user.email = self.email + new_user.first_name = self.first_name + new_user.last_name = self.last_name + new_user.send_welcome_email = 1 + new_user.enabled = 1 + new_user.role_profile_name = "Church User" + new_user.save(ignore_permissions=True) + + # Update Church Person to mark as portal user + self.portal_user = new_user.name + self.save(ignore_permissions=True) + + frappe.msgprint( + f"πŸ‘€ Portal user created and linked: {self.full_name}" + ) + else: + # User already exists, just update the portal_user field + self.portal_user = user + self.save(ignore_permissions=True) + frappe.msgprint( + f"⚠️ Portal user {user} already exists. User is now linked to this person." + ) + def get_list_context(context): # Only show documents related to the active user - context.filters = {"app_user": frappe.session.user} + context.filters = {"portal_user": frappe.session.user} # Sort the portal list view by status descending context.order_by = "modified desc" return context diff --git a/church/church_people/workspace/manual:_people/manual:_people.json b/church/church_people/workspace/manual:_people/manual:_people.json index abaaeb9..19d3c8a 100644 --- a/church/church_people/workspace/manual:_people/manual:_people.json +++ b/church/church_people/workspace/manual:_people/manual:_people.json @@ -1,6 +1,6 @@ { "charts": [], - "content": "[{\"id\":\"nnvMTG5Sl5\",\"type\":\"paragraph\",\"data\":{\"text\":\"\ud83d\udc65People Manual\",\"col\":12}},{\"id\":\"B-CtTCmVDX\",\"type\":\"paragraph\",\"data\":{\"text\":\"The people module contains features relating to the people of the church (i.e. Members, Families, Leadership. etc).\",\"col\":12}},{\"id\":\"Htx875Wd1w\",\"type\":\"paragraph\",\"data\":{\"text\":\"The People workspace contains number cards and graphs indicating the current count of people/families/members. there are also links to various reports (Birthdays, Roles, Letters, etc).\",\"col\":12}},{\"id\":\"qI9ZNpJJX4\",\"type\":\"paragraph\",\"data\":{\"text\":\"\ud83d\udc64Person\",\"col\":12}},{\"id\":\"RZThk3_x4O\",\"type\":\"paragraph\",\"data\":{\"text\":\"Church people include guests, members, leadership, and other people who interact or are associated with the church.\",\"col\":12}},{\"id\":\"UJEDTpYJIM\",\"type\":\"paragraph\",\"data\":{\"text\":\"When adding a person, note the following:
- Church membership and baptism status can be indicated.
    - If needed, additional member status types can be created.
- If the person has any roles in the church, they should be indicated in the 'Church Roles' section. 
   - If a role type does not exist, you can create new role types as needed.
- Photos should be added for members. The photos will be used in a member directory in a future versions.
- Letters from this person can be added in the 'Contact' tab
- If a family has been selected, the person will be displayed in the \\\"Family Members\\\" section on the `Church Family` form.
- Family relationships can be defined in the 'Family' tab.
    - When a spouse is added, the spouse's document will also be updated accordingly.
    - Additional relationships can be defined in the 'Notable Relationships' section - these relationships are not auto-updated on the other person's document.
    - A Family can be automatically created from a person by clicking the 'New Family From Person' button. This requires a 'Last Name' to be set, and will set the person as the Family's head-of-household.\",\"col\":12}},{\"id\":\"0a0Yfbfao3\",\"type\":\"paragraph\",\"data\":{\"text\":\"Person/Member Directory\",\"col\":12}},{\"id\":\"aIL5EgTGiJ\",\"type\":\"paragraph\",\"data\":{\"text\":\"To generate a Church Directory:
1. Navigate to the church person list.
2. (Optionally) Check the Is Member filter to only show members.
3. Select all the people by checking the top left checkbox in the list.
4. Click the Actions button and choose Print.
5. Select your print options and click Print to generate a member directory pdf file.
    - Tip: To make each person page smaller when printing the pdf, you can use the print multiple pages per sheet option in your system print dialog (if your system supports this feature).
\",\"col\":12}},{\"id\":\"A37CU_rUFj\",\"type\":\"paragraph\",\"data\":{\"text\":\"\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc66Family\",\"col\":12}},{\"id\":\"_wxytNqTX4\",\"type\":\"paragraph\",\"data\":{\"text\":\"Families are groups of people who are related.\",\"col\":12}},{\"id\":\"qQr_8PsoeH\",\"type\":\"paragraph\",\"data\":{\"text\":\"When adding a family, note the following:
- After adding a family, you may want to link people to the family. When a person is linked to a family, that person will be displayed in the \\\"Family Members\\\" list.
- Only one person can be set as the head of household. To set the head-of-household, go to the person's document and check 'Is Head of Household' on the 'Family' tab.
\",\"col\":12}}]", + "content": "[{\"id\":\"nnvMTG5Sl5\",\"type\":\"paragraph\",\"data\":{\"text\":\"\ud83d\udc65People Manual\",\"col\":12}},{\"id\":\"B-CtTCmVDX\",\"type\":\"paragraph\",\"data\":{\"text\":\"The people module contains features relating to the people of the church (i.e. Members, Families, Leadership. etc).\",\"col\":12}},{\"id\":\"Htx875Wd1w\",\"type\":\"paragraph\",\"data\":{\"text\":\"The People workspace contains number cards and graphs indicating the current count of people/families/members. there are also links to various reports (Birthdays, Roles, Letters, etc).\",\"col\":12}},{\"id\":\"qI9ZNpJJX4\",\"type\":\"paragraph\",\"data\":{\"text\":\"\ud83d\udc64Person\",\"col\":12}},{\"id\":\"RZThk3_x4O\",\"type\":\"paragraph\",\"data\":{\"text\":\"Church people include guests, members, leadership, and other people who interact or are associated with the church.\",\"col\":12}},{\"id\":\"UJEDTpYJIM\",\"type\":\"paragraph\",\"data\":{\"text\":\"When adding a person, note the following:
- Church membership and baptism status can be indicated.
    - If needed, additional member status types can be created.
- If the person has any roles in the church, they should be indicated in the 'Church Roles' section. 
   - If a role type does not exist, you can create new role types as needed.
- Photos should be added for members. The photos will be used in a member directory in a future versions.
- Letters from this person can be added in the 'Contact' tab
- If a family has been selected, the person will be displayed in the \\\"Family Members\\\" section on the `Church Family` form.
- Family relationships can be defined in the 'Family' tab.
    - When a spouse is added, the spouse's document will also be updated accordingly.
    - Additional relationships can be defined in the 'Notable Relationships' section - these relationships are not auto-updated on the other person's document.
    - A Family can be automatically created from a person by clicking the 'New Family From Person' button. This requires a 'Last Name' to be set, and will set the person as the Family's head-of-household.\",\"col\":12}},{\"id\":\"IqJm62Jfo2\",\"type\":\"paragraph\",\"data\":{\"text\":\"To give a person access to the Church App Portal, the church person must have an associated email address. 
Click the \\\"Invite to Portal\\\" button on the 'Church Person' form to create and associate a new user with the 'Church Person'.
    - The user will be created with 'Church User' permissions and linked with the 'Church Person' (This should give the user access to their own information as well as information that is shared with them).
    - The user should receive an invitation/welcome email (assuming email settings have been setup correctly).\",\"col\":12}},{\"id\":\"0a0Yfbfao3\",\"type\":\"paragraph\",\"data\":{\"text\":\"Person/Member Directory\",\"col\":12}},{\"id\":\"aIL5EgTGiJ\",\"type\":\"paragraph\",\"data\":{\"text\":\"To generate a Church Directory:
1. Navigate to the church person list.
2. (Optionally) Check the Is Member filter to only show members.
3. Select all the people by checking the top left checkbox in the list.
4. Click the Actions button and choose Print.
5. Select your print options and click Print to generate a member directory pdf file.
    - Tip: To make each person page smaller when printing the pdf, you can use the print multiple pages per sheet option in your system print dialog (if your system supports this feature).
\",\"col\":12}},{\"id\":\"A37CU_rUFj\",\"type\":\"paragraph\",\"data\":{\"text\":\"\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc66Family\",\"col\":12}},{\"id\":\"_wxytNqTX4\",\"type\":\"paragraph\",\"data\":{\"text\":\"Families are groups of people who are related.\",\"col\":12}},{\"id\":\"qQr_8PsoeH\",\"type\":\"paragraph\",\"data\":{\"text\":\"When adding a family, note the following:
- After adding a family, you may want to link people to the family. When a person is linked to a family, that person will be displayed in the \\\"Family Members\\\" list.
- Only one person can be set as the head of household. To set the head-of-household, go to the person's document and check 'Is Head of Household' on the 'Family' tab.
\",\"col\":12}}]", "creation": "2025-10-26 22:59:15.251142", "custom_blocks": [], "docstatus": 0, @@ -13,7 +13,7 @@ "is_hidden": 0, "label": "Manual: People", "links": [], - "modified": "2025-12-20 01:52:41.918887", + "modified": "2026-02-02 23:53:05.514800", "modified_by": "Administrator", "module": "Church People", "name": "Manual: People", From c41cdc36cc811e690f7873adec1874f32b8acf4b Mon Sep 17 00:00:00 2001 From: meichthys Date: Fri, 6 Feb 2026 04:44:54 +0000 Subject: [PATCH 21/28] support versions 15 & 16 --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 82e4aec..a44bb6e 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,11 @@ The following features have been implemented in this app (see the [πŸ—ΊοΈ Roadm ## πŸ“₯ Installing Frappe -To use the 'Church' app, you must have a working Frappe environment first. There are a variety of ways to install a Frappe instance. The recommended ways for this project are: +To use the 'Church' app, you must have a working Frappe environment first. There are a variety of ways to install a Frappe instance. + If you are running a Frappe v15 environment, then use the `version-15` branch. + If you are running a Frappe v16 environment, then use the `version-16` branch + +The recommended ways for installig this project are: ### ☁️ In the Cloud The easiest (but not free) way to get a working Frappe environment is to use [Frappe Cloud](https://frappe.io/cloud). For a few dollars per month you can run an instance in the cloud. You get your choice of support options and shouldn't need to worry about data loss yourself. From d650bb7b009166f336b63b965efe50c042d51ee8 Mon Sep 17 00:00:00 2001 From: meichthys Date: Fri, 13 Feb 2026 03:03:45 +0000 Subject: [PATCH 22/28] use star icon instead of church for welcome workspace --- church/church_foundations/workspace/welcome/welcome.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/church/church_foundations/workspace/welcome/welcome.json b/church/church_foundations/workspace/welcome/welcome.json index d25c5b0..a634a0b 100644 --- a/church/church_foundations/workspace/welcome/welcome.json +++ b/church/church_foundations/workspace/welcome/welcome.json @@ -12,13 +12,13 @@ "doctype": "Workspace", "for_user": "", "hide_custom": 0, - "icon": "church", + "icon": "star", "idx": 0, "indicator_color": "", "is_hidden": 0, "label": "Welcome", "links": [], - "modified": "2026-01-10 00:00:59.501803", + "modified": "2026-02-12 22:03:11.277791", "modified_by": "Administrator", "module": "Church Foundations", "name": "Welcome", From d5d7516ffef508fd96abd3bc6567ad5eb25c025f Mon Sep 17 00:00:00 2001 From: meichthys Date: Fri, 13 Feb 2026 03:53:32 +0000 Subject: [PATCH 23/28] Fix person creation without family --- church/church_people/doctype/church_person/church_person.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/church/church_people/doctype/church_person/church_person.py b/church/church_people/doctype/church_person/church_person.py index 45ea7d3..fb33a13 100644 --- a/church/church_people/doctype/church_person/church_person.py +++ b/church/church_people/doctype/church_person/church_person.py @@ -20,6 +20,10 @@ class ChurchPerson(Document): if not found: family.append("members", {"member": self.name}) family.save() + + # Return if person doesn't have family + if not self.family and not self.get_doc_before_save().family: + return # Remove person from Church Family if family is removed if not self.family and self.get_doc_before_save().family is not None: family = frappe.get_doc("Church Family", self.get_doc_before_save().family) From f11bcdf45d4ce61b4f62daf662b91a3631297529 Mon Sep 17 00:00:00 2001 From: meichthys Date: Fri, 13 Feb 2026 04:02:02 +0000 Subject: [PATCH 24/28] Add link to family in family creation message --- church/church_people/doctype/church_person/church_person.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/church/church_people/doctype/church_person/church_person.py b/church/church_people/doctype/church_person/church_person.py index fb33a13..1ec9bcd 100644 --- a/church/church_people/doctype/church_person/church_person.py +++ b/church/church_people/doctype/church_person/church_person.py @@ -5,6 +5,7 @@ from datetime import datetime import frappe from frappe.model.document import Document +from frappe.utils import get_link_to_form class ChurchPerson(Document): @@ -112,7 +113,8 @@ class ChurchPerson(Document): self.set("is_head_of_household", True) self.save() self.reload() - frappe.msgprint(f"New family created: {doc.family_name}") + family_link = get_link_to_form("Church Family", doc.name, doc.family_name) + frappe.msgprint(f"πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘¦ New family created: {family_link}") @frappe.whitelist() def update_is_current_role(self): From 8d81bcd81d580e7412b2f91ea00f0cbb4a460049 Mon Sep 17 00:00:00 2001 From: meichthys Date: Fri, 13 Feb 2026 05:17:27 +0000 Subject: [PATCH 25/28] Add basic directory print format for Church Person --- .../church_directory/church_directory.json | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 church/church_people/print_format/church_directory/church_directory.json diff --git a/church/church_people/print_format/church_directory/church_directory.json b/church/church_people/print_format/church_directory/church_directory.json new file mode 100644 index 0000000..d3945b7 --- /dev/null +++ b/church/church_people/print_format/church_directory/church_directory.json @@ -0,0 +1,34 @@ +{ + "absolute_value": 0, + "align_labels_right": 0, + "creation": "2026-02-12 22:19:13.599699", + "css": "/* Improve typography */\nbody {\n font-family: \"Georgia\", \"Times New Roman\", serif;\n letter-spacing: 0.2px;\n}\n\n/* Name styling enhancement */\n.name {\n letter-spacing: 0.5px;\n border-bottom: 2px solid #eaeaea;\n padding-bottom: 6px;\n}\n\n/* Add subtle divider between photo and content */\n.details-cell {\n border-left: 1px solid #e6e6e6;\n}\n\n/* Improve pill appearance */\n.pill {\n box-shadow: 0 1px 2px rgba(0,0,0,0.08);\n}\n\n/* Improve role badge contrast */\n.role-badge {\n background: #f0f7f4;\n border: 1px solid #d6ebe2;\n}\n\n/* Add subtle background tone to page */\nbody {\n background-color: #fcfcfc;\n}\n", + "custom_format": 1, + "default_print_language": "en", + "disabled": 0, + "doc_type": "Church Person", + "docstatus": 0, + "doctype": "Print Format", + "font_size": 14, + "html": "\n\n
\n

Church Directory

\n
\n\n\n \n \n\n \n \n
\n {% if doc.photo %}\n \n {% else %}\n \n {% endif %}\n \n\n
\n {{ doc.full_name or (doc.first_name + \" \" + doc.last_name) }}\n
\n\n \n {% if doc.church_roles %}\n {% for role in doc.church_roles %}\n
\n Role\n {{ role.role }}\n
\n {% endfor %}\n {% endif %}\n\n {% if doc.primary_phone %}\n
\n Phone\n {{ doc.primary_phone }}\n
\n {% endif %}\n\n {% if doc.email %}\n
\n Email\n {{ doc.email }}\n
\n {% endif %}\n\n {% if doc.home_address %}\n
\n Address\n {{ doc.home_address }}\n
\n {% endif %}\n\n {% if doc.birthday %}\n
\n Birthday\n \n {{ frappe.utils.formatdate(doc.birthday, \"MMMM d\") }}\n \n
\n {% endif %}\n\n {% if doc.anniversary %}\n
\n Anniversary\n \n {{ frappe.utils.formatdate(doc.anniversary, \"MMMM d, yyyy\") }}\n \n
\n {% endif %}\n\n {% if doc.membership_date %}\n
\n Member Since\n \n {{ frappe.utils.formatdate(doc.membership_date, \"MMMM d, yyyy\") }}\n \n
\n {% endif %}\n\n \n {% if doc.family %}\n {% for fam in doc.family %}\n
\n Family\n {{ fam.family_member_name }}{% if fam.relationship %} ({{ fam.relationship }}){% endif %}\n
\n {% endfor %}\n {% endif %}\n\n
\n\n
\n {{ frappe.utils.formatdate(frappe.utils.nowdate(), \"MMMM yyyy\") }}\n
\n", + "idx": 0, + "line_breaks": 0, + "margin_bottom": 15.0, + "margin_left": 15.0, + "margin_right": 15.0, + "margin_top": 15.0, + "modified": "2026-02-13 00:16:34.957246", + "modified_by": "Administrator", + "module": "Church People", + "name": "Church Directory", + "owner": "Administrator", + "page_number": "Hide", + "pdf_generator": "wkhtmltopdf", + "print_format_builder": 0, + "print_format_builder_beta": 0, + "print_format_for": "DocType", + "print_format_type": "Jinja", + "raw_printing": 0, + "show_section_headings": 0, + "standard": "Yes" +} \ No newline at end of file From 765c84fa7bf1d7f9b17a7750abc23b86f2e5057c Mon Sep 17 00:00:00 2001 From: meichthys Date: Fri, 13 Feb 2026 05:18:00 +0000 Subject: [PATCH 26/28] add __init__.py for print format --- church/church_people/print_format/church_directory/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 church/church_people/print_format/church_directory/__init__.py diff --git a/church/church_people/print_format/church_directory/__init__.py b/church/church_people/print_format/church_directory/__init__.py new file mode 100644 index 0000000..e69de29 From 7376cb99dde8da1e91ef8c4a0c230b09982e1429 Mon Sep 17 00:00:00 2001 From: meichthys Date: Fri, 13 Feb 2026 05:23:45 +0000 Subject: [PATCH 27/28] better handle new Church Person setup --- church/church_people/doctype/church_person/church_person.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/church/church_people/doctype/church_person/church_person.py b/church/church_people/doctype/church_person/church_person.py index 1ec9bcd..b5f4b0a 100644 --- a/church/church_people/doctype/church_person/church_person.py +++ b/church/church_people/doctype/church_person/church_person.py @@ -22,8 +22,8 @@ class ChurchPerson(Document): family.append("members", {"member": self.name}) family.save() - # Return if person doesn't have family - if not self.family and not self.get_doc_before_save().family: + # Return if this is a new person + if not self.get_doc_before_save(): return # Remove person from Church Family if family is removed if not self.family and self.get_doc_before_save().family is not None: From eee02c173d2748560203537f52986e0f08314b27 Mon Sep 17 00:00:00 2001 From: meichthys Date: Fri, 13 Feb 2026 05:24:38 +0000 Subject: [PATCH 28/28] remove app logo for now --- church/fixtures/website_settings.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/church/fixtures/website_settings.json b/church/fixtures/website_settings.json index ba6f01b..45bd2bc 100644 --- a/church/fixtures/website_settings.json +++ b/church/fixtures/website_settings.json @@ -1,7 +1,7 @@ [ { "address": null, - "app_logo": "/files/church_logo.png", + "app_logo": "", "app_name": "Church", "auto_account_deletion": 72, "banner_html": null, @@ -29,7 +29,7 @@ "home_page": "", "indexing_authorization_code": null, "indexing_refresh_token": null, - "modified": "2025-10-24 00:15:21.027630", + "modified": "2026-02-12 22:06:39.776572", "name": "Website Settings", "navbar_search": 0, "navbar_template": null,