Merge pull request #99 from meichthys/develop

Add Person Details in portal
    Show family members on family form
    Add task tracking
    Add asset tracking (items, locations, etc)
    Update documentation for adding email account
    Add basic Church Directory print format
    Allow inviting of Church People to become users
This commit is contained in:
MeIchthys 2026-02-13 00:33:08 -05:00 committed by GitHub
commit 549a5e5a1c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
49 changed files with 1223 additions and 240 deletions

View File

@ -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)
@ -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
@ -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.

View File

@ -0,0 +1,3 @@
frappe.ready(function() {
// bind events here
})

View File

@ -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
}
]
}

View File

@ -0,0 +1,5 @@
import frappe
def get_context(context):
# do your magic here
pass

View File

@ -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.")

View File

@ -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"
},

View File

@ -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,

View File

@ -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",

View File

@ -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",

View File

@ -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
}

View File

@ -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",

View File

@ -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,

View File

@ -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
}

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{
"charts": [],
"content": "[{\"id\":\"nnvMTG5Sl5\",\"type\":\"paragraph\",\"data\":{\"text\":\"<span class=\\\"h1\\\" style=\\\"font-weight: normal;\\\">\ud83c\udf10Website&nbsp;Manual</span>\",\"col\":12}},{\"id\":\"B-CtTCmVDX\",\"type\":\"paragraph\",\"data\":{\"text\":\"<span style=\\\"font-weight: normal;\\\">The website module manages and configures a public facing website for the church using data from other modules (i.e. Foundations, Missions, Ministries, etc).</span>\",\"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 <a href=\\\"https://github.com/meichthys/church#%EF%B8%8F-feature-roadmap\\\">roadmap</a>.\",\"col\":12}}]",
"content": "[{\"id\":\"nnvMTG5Sl5\",\"type\":\"paragraph\",\"data\":{\"text\":\"<span class=\\\"h1\\\" style=\\\"font-weight: normal;\\\">\ud83c\udf10Website&nbsp;Manual</span>\",\"col\":12}},{\"id\":\"B-CtTCmVDX\",\"type\":\"paragraph\",\"data\":{\"text\":\"<span style=\\\"font-weight: normal;\\\">The website module consists of two main features: a public website, and a user portal.</span>\",\"col\":12}},{\"id\":\"kHbqzTGDhX\",\"type\":\"paragraph\",\"data\":{\"text\":\"\u26a0\ufe0f&nbsp;The website and portal 'features' have not been fully developed but the features are on the <a href=\\\"https://github.com/meichthys/church#%EF%B8%8F-feature-roadmap\\\" draggable=\\\"false\\\">roadmap</a>.\",\"col\":12}},{\"id\":\"fAFxFk8rny\",\"type\":\"header\",\"data\":{\"text\":\"\ud83c\udf0e<span class=\\\"h4\\\"><b>Website</b></span>\",\"col\":12}},{\"id\":\"WCW6FzkHwB\",\"type\":\"paragraph\",\"data\":{\"text\":\"<span style=\\\"font-weight: normal;\\\">The public facing website is accessible by anyone and can be dynamically updated based on information in the Church App </span>(i.e. Beliefs, Missionaries, Ministries, etc).<br><span style=\\\"font-weight: normal;\\\">User accounts with \\\"Church Manager\\\" permissions can <i>modify</i> the website.<br>No user account is required to <i>view</i> the website - anyone with an internet connection and a web browser can view the public website.</span>\",\"col\":12}},{\"id\":\"nZdduTPzRH\",\"type\":\"header\",\"data\":{\"text\":\"\ud83d\udc64<span class=\\\"h4\\\"><b>User Portal</b></span>\",\"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).<br>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",

View File

@ -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\":\"<span class=\\\"h1\\\" style=\\\"font-weight: normal;\\\">\ud83d\udc4bWelcome</span>\",\"col\":12}},{\"id\":\"3y9XjWNIDH\",\"type\":\"paragraph\",\"data\":{\"text\":\"<span style=\\\"font-weight: normal;\\\">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: <i>\\\"Freely you have received; freely give. ~Jesus\\\"</i></span>\",\"col\":12}},{\"id\":\"eyx_vzvkgN\",\"type\":\"paragraph\",\"data\":{\"text\":\"<span style=\\\"font-weight: normal;\\\">\ud83d\udc49To get started using the `Church` app, see the <a href=\\\"/app/getting-started\\\">Getting Started</a> page.</span>\",\"col\":12}},{\"id\":\"Kh8eExzLKr\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h1\\\" style=\\\"font-weight: normal;\\\">\ud83d\udcd8User Manual</span>\",\"col\":12}},{\"id\":\"RubIh0IucA\",\"type\":\"paragraph\",\"data\":{\"text\":\"<span style=\\\"font-weight: normal;\\\">Each `Module` in the left hand menu has it's own help pages. If you need more help than what is provided there, see&nbsp;<a href=\\\"http://development.localhost/app/support\\\">Support</a>.</span>\",\"col\":12}},{\"id\":\"8fQ8usz33T\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h1\\\" style=\\\"font-weight: normal;\\\">\ud83e\udd1dContribute</span>\",\"col\":12}},{\"id\":\"dBcYsyF07e\",\"type\":\"paragraph\",\"data\":{\"text\":\"<span style=\\\"font-weight: normal;\\\">If you have technical expertise and would like to contribute to the development of this project, please join us on <a href=\\\"https://github.com/meichthys/church\\\">github</a>.<br>If you would like to support the project financially, don't. Instead, pray for the developers and for the churches using the software.</span>\",\"col\":12}},{\"id\":\"JQvQ237QXM\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h1\\\" style=\\\"font-weight: normal;\\\">\ud83d\udce2Credits</span>\",\"col\":12}},{\"id\":\"Fbdz2raOGi\",\"type\":\"paragraph\",\"data\":{\"text\":\"<span style=\\\"font-weight: normal;\\\">- All the <a href=\\\"https://github.com/meichthys/church/graphs/contributors\\\">contributors</a> of this project. Thank You!<br>-&nbsp;<a href=\\\"https://frappe.io/\\\">Frappe</a>&nbsp;Framework - This application is built on top of this great open source software.<br>- Your IT Administrator - They set this application up for you!</span>\",\"col\":12}}]",
"content": "[{\"id\":\"a0vkPmhn3y\",\"type\":\"custom_block\",\"data\":{\"custom_block_name\":\"Workspace Cover Photo\",\"col\":12}},{\"id\":\"qv6aLVY432\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h1\\\" style=\\\"font-weight: normal;\\\">\ud83d\udc4bWelcome</span>\",\"col\":12}},{\"id\":\"3y9XjWNIDH\",\"type\":\"paragraph\",\"data\":{\"text\":\"<span style=\\\"font-weight: normal;\\\">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: <i>\\\"Freely you have received; freely give. ~Jesus\\\"</i></span>\",\"col\":12}},{\"id\":\"eyx_vzvkgN\",\"type\":\"paragraph\",\"data\":{\"text\":\"<span style=\\\"font-weight: normal;\\\">\ud83d\udc49To get started using the `Church` app, see the <a href=\\\"/app/getting-started\\\">Getting Started</a> page.</span>\",\"col\":12}},{\"id\":\"Kh8eExzLKr\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h1\\\" style=\\\"font-weight: normal;\\\">\ud83d\udcd8User Manual</span>\",\"col\":12}},{\"id\":\"RubIh0IucA\",\"type\":\"paragraph\",\"data\":{\"text\":\"<span style=\\\"font-weight: normal;\\\">Each `Module` in the left hand menu has it's own help pages. If you need more help than what is provided there, see&nbsp;<a href=\\\"http://development.localhost/app/support\\\">Support</a>.</span>\",\"col\":12}},{\"id\":\"8fQ8usz33T\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h1\\\" style=\\\"font-weight: normal;\\\">\ud83e\udd1dContribute</span>\",\"col\":12}},{\"id\":\"dBcYsyF07e\",\"type\":\"paragraph\",\"data\":{\"text\":\"<span style=\\\"font-weight: normal;\\\">If you have technical expertise and would like to contribute to the development of this project, please join us on <a href=\\\"https://github.com/meichthys/church\\\">github</a>.<br>If you would like to support the project financially, don't. Instead, pray for the developers and for the churches using the software.</span>\",\"col\":12}},{\"id\":\"JQvQ237QXM\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h1\\\" style=\\\"font-weight: normal;\\\">\ud83d\udce2Credits</span>\",\"col\":12}},{\"id\":\"Fbdz2raOGi\",\"type\":\"paragraph\",\"data\":{\"text\":\"<span style=\\\"font-weight: normal;\\\">- All the <a href=\\\"https://github.com/meichthys/church/graphs/contributors\\\">contributors</a> of this project. Thank You!<br>-&nbsp;<a href=\\\"https://frappe.io/\\\">Frappe</a>&nbsp;Framework - This application is built on top of this great open source software.<br>- Your IT Administrator - They set this application up for you!<br>- Our Lord and Savior Jesus Christ - without whom this app would not exist.</span>\",\"col\":12}}]",
"creation": "2025-08-22 00:39:02.127277",
"custom_blocks": [
{
@ -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": "2025-11-01 23:09:26.643807",
"modified": "2026-02-12 22:03:11.277791",
"modified_by": "Administrator",
"module": "Church Foundations",
"name": "Welcome",

View File

@ -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) {
// },
// });

View File

@ -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": []
}

View File

@ -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

View File

@ -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

View File

@ -1,19 +1,23 @@
{
"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",
"title",
"status",
"due_date",
"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 +49,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 +62,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 +113,55 @@
"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 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-15 00:59:25.234829",
"modified": "2025-12-20 22:59:11.776100",
"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": [
{
@ -165,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"
}

View File

@ -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": []
}

View File

@ -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

View File

@ -1,6 +1,6 @@
{
"charts": [],
"content": "[{\"id\":\"nnvMTG5Sl5\",\"type\":\"paragraph\",\"data\":{\"text\":\"<span class=\\\"h1\\\" style=\\\"font-weight: normal;\\\">\ud83d\udee0\ufe0f Operations Manual</span>\",\"col\":12}},{\"id\":\"B-CtTCmVDX\",\"type\":\"paragraph\",\"data\":{\"text\":\"<span style=\\\"font-weight: normal;\\\">The operations module contains features related to the operation of the church (maintenance, assets, etc).</span>\",\"col\":12}},{\"id\":\"w8oEjl0tNc\",\"type\":\"paragraph\",\"data\":{\"text\":\"<span class=\\\"h2\\\" style=\\\"font-weight: normal;\\\">\ud83d\udce6Assets</span>\",\"col\":12}},{\"id\":\"6IlcMu_Ikb\",\"type\":\"paragraph\",\"data\":{\"text\":\"Assets of the church.\",\"col\":12}},{\"id\":\"0J08Yp0qsz\",\"type\":\"paragraph\",\"data\":{\"text\":\"When adding a&nbsp;<a href=\\\"/app/church-asset/new-church-asset\\\">new asset</a>, note the following:<br>- Try to give the asset a short but descriptive title<br>- Additional details can be added in the 'Notes' field\",\"col\":12}},{\"id\":\"8zFlGyC4XI\",\"type\":\"paragraph\",\"data\":{\"text\":\"<span class=\\\"h2\\\" style=\\\"font-weight: normal;\\\">\u2705Tasks</span>\",\"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 <a href=\\\"/app/church-task/new-church-task\\\">new task</a>, note the following:<br>- To add sub-tasks, check the 'Is Group' option, then create new tasks and select the 'group' task in the 'Parent Task' field.<br>- \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\":\"<span class=\\\"h1\\\" style=\\\"font-weight: normal;\\\">\ud83d\udee0\ufe0f Operations Manual</span>\",\"col\":12}},{\"id\":\"B-CtTCmVDX\",\"type\":\"paragraph\",\"data\":{\"text\":\"<span style=\\\"font-weight: normal;\\\">The operations module contains features related to the operation of the church (maintenance, assets, etc).</span>\",\"col\":12}},{\"id\":\"w8oEjl0tNc\",\"type\":\"paragraph\",\"data\":{\"text\":\"<span class=\\\"h2\\\" style=\\\"font-weight: normal;\\\">\ud83d\udce6Assets</span>\",\"col\":12}},{\"id\":\"6IlcMu_Ikb\",\"type\":\"paragraph\",\"data\":{\"text\":\"Property of the church.\",\"col\":12}},{\"id\":\"0J08Yp0qsz\",\"type\":\"paragraph\",\"data\":{\"text\":\"When adding a&nbsp;<a href=\\\"/app/church-asset/new-church-asset\\\">new asset</a>, note the following:<br>- Try to give the asset a short but descriptive title<br>- Additional details can be added in the 'Notes' field<br>- The location of the asset can be set (or added) in the \\\"Location\\\" field.\",\"col\":12}},{\"id\":\"8zFlGyC4XI\",\"type\":\"paragraph\",\"data\":{\"text\":\"<span class=\\\"h2\\\" style=\\\"font-weight: normal;\\\">\u2705Tasks</span>\",\"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 <a href=\\\"/app/church-task/new-church-task\\\">new task</a>, note the following:<br>- To add sub-tasks, check the 'Is Group' option, then create new tasks and select the 'group' task in the 'Parent Task' field.<br>- \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",

View File

@ -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"
@ -32,6 +32,16 @@
"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"
},
{
"hidden": 0,
"is_query_report": 0,
@ -43,7 +53,7 @@
"type": "Link"
}
],
"modified": "2025-12-15 01:14:50.411941",
"modified": "2026-01-05 23:54:03.614596",
"modified_by": "Administrator",
"module": "Church Operations",
"name": "Operations",

View File

@ -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,12 @@
{
"fieldname": "section_break_acrr",
"fieldtype": "Section Break"
},
{
"fieldname": "members",
"fieldtype": "Table",
"label": "Family Members",
"options": "Church Family Members"
}
],
"grid_page_length": 50,
@ -70,7 +77,7 @@
"link_fieldname": "recipient"
}
],
"modified": "2025-11-15 22:55:14.237301",
"modified": "2025-12-20 23:03:58.407158",
"modified_by": "Administrator",
"module": "Church People",
"name": "Church Family",

View File

@ -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() 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)
# 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
)

View File

@ -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",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"member"
],
"fields": [
{
"fieldname": "member",
"fieldtype": "Link",
"in_list_view": 1,
"in_preview": 1,
"label": "Family Member",
"options": "Church Person",
"reqd": 1
}
],
"grid_page_length": 50,
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2025-12-20 23:04:31.049341",
"modified_by": "Administrator",
"module": "Church People",
"name": "Church Family Members",
"owner": "Administrator",
"permissions": [],
"row_format": "Dynamic",
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}

View File

@ -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

View File

@ -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", {
},
});

View File

@ -18,6 +18,7 @@
"photo",
"birthday",
"alergies",
"portal_user",
"church_records_section",
"is_member",
"membership_date",
@ -293,6 +294,12 @@
"label": "Letters to the Church",
"options": "Church Letter",
"print_hide": 1
},
{
"fieldname": "portal_user",
"fieldtype": "Link",
"label": "Portal User",
"options": "User"
}
],
"grid_page_length": 50,
@ -320,7 +327,7 @@
"link_fieldname": "recipient"
}
],
"modified": "2025-11-18 23:43:11.668299",
"modified": "2026-02-02 22:55:22.764479",
"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,

View File

@ -5,14 +5,50 @@ from datetime import datetime
import frappe
from frappe.model.document import Document
from frappe.utils import get_link_to_form
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()
# 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:
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:
@ -77,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):
@ -90,3 +127,42 @@ class ChurchPerson(Document):
role.is_current_role = 1
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: <a href='/app/user/{new_user.name}'>{self.full_name}</a>"
)
else:
# User already exists, just update the portal_user field
self.portal_user = user
self.save(ignore_permissions=True)
frappe.msgprint(
f"⚠️ Portal user <a href='/app/user/{user}'>{user}</a> already exists. User is now linked to this person."
)
def get_list_context(context):
# Only show documents related to the active user
context.filters = {"portal_user": frappe.session.user}
# Sort the portal list view by status descending
context.order_by = "modified desc"
return context

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,3 @@
frappe.ready(function() {
// bind events here
})

View File

@ -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
}
]
}

View File

@ -0,0 +1,5 @@
import frappe
def get_context(context):
# do your magic here
pass

File diff suppressed because one or more lines are too long

View File

@ -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": "<div class=\"ql-editor read-mode\"><blockquote>Be anxious for nothing, but in everything, by prayer and petition, with thanksgiving, present your requests to God.</blockquote><blockquote>~ Philipians 4:6 (BSB)</blockquote></div>",
"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": "<div class=\"ql-editor read-mode\"><blockquote>Be anxious for nothing, but in everything, by prayer and petition, with thanksgiving, present your requests to God.</blockquote><blockquote>~ Philipians 4:6 (BSB)</blockquote></div>",
"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": ""
}

View File

@ -51,6 +51,7 @@
"options": "Church Bible Translation"
},
{
"description": "Text fetched courtesy of <a href=\"bible.helloao.org\">bible.helloao.org</a>",
"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",

View File

@ -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,

View File

@ -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
# ----------

View File

@ -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"]: