From 94b9aa70de65e46cbdae0ccddbb6e6bf7f1b868a Mon Sep 17 00:00:00 2001 From: Harikrishnan Dhanasekaran Date: Wed, 13 May 2026 02:02:59 +0530 Subject: [PATCH] Added the frappe lending template (#665) * added the frappe lending template * removed the external network --- blueprints/frappe-lending/docker-compose.yml | 550 +++++++++++++++++++ blueprints/frappe-lending/frappe-lending.png | Bin 0 -> 2985 bytes blueprints/frappe-lending/template.toml | 29 + meta.json | 20 + 4 files changed, 599 insertions(+) create mode 100644 blueprints/frappe-lending/docker-compose.yml create mode 100644 blueprints/frappe-lending/frappe-lending.png create mode 100644 blueprints/frappe-lending/template.toml diff --git a/blueprints/frappe-lending/docker-compose.yml b/blueprints/frappe-lending/docker-compose.yml new file mode 100644 index 00000000..60972a3b --- /dev/null +++ b/blueprints/frappe-lending/docker-compose.yml @@ -0,0 +1,550 @@ +x-custom-image: &custom_image + image: ${IMAGE_NAME:-frappe/erpnext}:${VERSION:-v15} + pull_policy: ${PULL_POLICY:-always} + deploy: + restart_policy: + condition: always + +services: + backend: + <<: *custom_image + entrypoint: ["bash", "-c"] + command: + - > + cd /home/frappe/frappe-bench; + if [ -d "apps/lending" ] && ! ./env/bin/pip show lending > /dev/null 2>&1; then + echo "Installing lending app in Python environment..."; + ./env/bin/pip install -e apps/lending || echo "Failed to install lending"; + fi; + echo "Waiting for site to be ready..."; + export start=`date +%s`; + while [ ! -f "sites/sites.txt" ] || [ ! -d "sites/${SITE_NAME}" ] || [ ! -f "sites/${SITE_NAME}/site_config.json" ]; do + echo "Waiting for site ${SITE_NAME} to be created and ready..."; + sleep 2; + if (( `date +%s`-start > 300 )); then + echo "Timeout waiting for site to be ready"; + echo "Checking sites directory:"; + ls -la sites/ || echo "sites directory not found"; + echo "Checking sites.txt:"; + cat sites/sites.txt 2>/dev/null || echo "sites.txt not found"; + break; + fi + done; + if [ -f "sites/sites.txt" ] && [ -d "sites/${SITE_NAME}" ] && [ -f "sites/${SITE_NAME}/site_config.json" ]; then + echo "Site ${SITE_NAME} is ready!"; + echo "sites.txt contents:"; + cat sites/sites.txt; + echo "Verifying site is accessible via bench..."; + bench --site ${SITE_NAME} list-apps > /dev/null 2>&1 && echo "Site is accessible via bench" || echo "Warning: Site accessibility check via bench failed"; + echo "Site directory structure:"; + ls -la sites/${SITE_NAME}/ | head -10; + if [ -n "${MAIN_DOMAIN}" ]; then + echo "Updating host_name and SSL settings to https://${MAIN_DOMAIN} (ensuring correct domain for emails)..."; + bench --site ${SITE_NAME} set-config host_name "https://${MAIN_DOMAIN}" || echo "Warning: Could not update host_name"; + bench --site ${SITE_NAME} set-config host_url "https://${MAIN_DOMAIN}" || echo "Warning: Could not update host_url"; + bench --site ${SITE_NAME} set-config use_ssl 1 || echo "Warning: Could not set use_ssl"; + echo "Verifying configuration..."; + bench --site ${SITE_NAME} get-config host_name 2>/dev/null || echo "Could not read host_name (this is OK if site is not fully initialized)"; + echo "Clearing cache to apply new domain settings..."; + bench --site ${SITE_NAME} clear-cache || echo "Warning: Could not clear cache"; + bench --site ${SITE_NAME} clear-website-cache || echo "Warning: Could not clear website cache"; + fi; + else + echo "Warning: Site may not be fully ready, but starting backend anyway"; + fi; + echo "Starting bench serve (production-ready)"; + export PYTHONUNBUFFERED=1; + bench serve --port 8000 2>&1 | awk '!/127\.0\.0\.1.*400/ {print}' || bench serve --port 8000; + volumes: + - sites:/home/frappe/frappe-bench/sites + - apps:/home/frappe/frappe-bench/apps + environment: + SITE_NAME: ${SITE_NAME} + FRAPPE_SITE_NAME_HEADER: "" + MAIN_DOMAIN: ${MAIN_DOMAIN} + depends_on: + configurator: + condition: service_completed_successfully + required: true + create-site: + condition: service_completed_successfully + required: true + healthcheck: + test: + - CMD + - wait-for-it + - '0.0.0.0:8000' + interval: 2s + timeout: 10s + retries: 30 + + frontend: + <<: *custom_image + entrypoint: ["bash", "-c"] + command: + - > + echo "Starting Nginx with port_in_redirect fix..."; + nginx-entrypoint.sh & + NGINX_PID=$!; + sleep 3; + if [ -f /etc/nginx/conf.d/frappe.conf ]; then + if ! grep -q "port_in_redirect off" /etc/nginx/conf.d/frappe.conf; then + echo "Applying port_in_redirect fix to prevent :8080 in URLs..."; + sed -i 's/listen 8080;/listen 8080;\n port_in_redirect off;\n absolute_redirect off;/' /etc/nginx/conf.d/frappe.conf; + echo "Nginx config updated - reloading..."; + sleep 1; + nginx -s reload 2>/dev/null || echo "Nginx will use updated config on next reload"; + else + echo "Nginx config already has port_in_redirect settings"; + fi + else + echo "Warning: frappe.conf not found yet, will check again"; + sleep 2; + if [ -f /etc/nginx/conf.d/frappe.conf ]; then + if ! grep -q "port_in_redirect off" /etc/nginx/conf.d/frappe.conf; then + sed -i 's/listen 8080;/listen 8080;\n port_in_redirect off;\n absolute_redirect off;/' /etc/nginx/conf.d/frappe.conf; + nginx -s reload 2>/dev/null || true; + fi + fi + fi; + wait $NGINX_PID + depends_on: + backend: + condition: service_started + required: true + websocket: + condition: service_started + required: true + environment: + BACKEND: backend:8000 + FRAPPE_SITE_NAME_HEADER: "" + SOCKETIO: websocket:9000 + UPSTREAM_REAL_IP_ADDRESS: 127.0.0.1 + UPSTREAM_REAL_IP_HEADER: X-Forwarded-For + UPSTREAM_REAL_IP_RECURSIVE: "off" + USE_X_FORWARDED_HOST: "1" + PROXY_FIX: "1" + X_FORWARDED_PROTO: "https" + volumes: + - sites:/home/frappe/frappe-bench/sites + - apps:/home/frappe/frappe-bench/apps + + healthcheck: + test: + - CMD-SHELL + - curl -fsS http://127.0.0.1:8080/login || exit 1 + interval: 30s + timeout: 5s + retries: 3 + + queue-default: + <<: *custom_image + entrypoint: ["bash", "-c"] + command: + - > + cd /home/frappe/frappe-bench; + export start=`date +%s`; + while [ ! -d "apps/lending" ]; do + echo "Waiting for apps to be available..."; + sleep 2; + if (( `date +%s`-start > 300 )); then + echo "Timeout waiting for apps"; + break; + fi; + done; + if [ -d "apps/lending" ] && ! ./env/bin/pip show lending > /dev/null 2>&1; then + echo "Installing lending app in Python environment..."; + ./env/bin/pip install -e apps/lending || echo "Failed to install lending"; + fi; + exec bench worker --queue default + volumes: + - sites:/home/frappe/frappe-bench/sites + - apps:/home/frappe/frappe-bench/apps + healthcheck: + test: + - CMD + - wait-for-it + - 'redis-queue:6379' + interval: 2s + timeout: 10s + retries: 30 + depends_on: + configurator: + condition: service_completed_successfully + required: true + + queue-long: + <<: *custom_image + entrypoint: ["bash", "-c"] + command: + - > + cd /home/frappe/frappe-bench; + export start=`date +%s`; + while [ ! -d "apps/lending" ]; do + echo "Waiting for apps to be available..."; + sleep 2; + if (( `date +%s`-start > 300 )); then + echo "Timeout waiting for apps"; + break; + fi; + done; + if [ -d "apps/lending" ] && ! ./env/bin/pip show lending > /dev/null 2>&1; then + echo "Installing lending app in Python environment..."; + ./env/bin/pip install -e apps/lending || echo "Failed to install lending"; + fi; + exec bench worker --queue long + volumes: + - sites:/home/frappe/frappe-bench/sites + - apps:/home/frappe/frappe-bench/apps + healthcheck: + test: + - CMD + - wait-for-it + - 'redis-queue:6379' + interval: 2s + timeout: 10s + retries: 30 + depends_on: + configurator: + condition: service_completed_successfully + required: true + + queue-short: + <<: *custom_image + entrypoint: ["bash", "-c"] + command: + - > + cd /home/frappe/frappe-bench; + export start=`date +%s`; + while [ ! -d "apps/lending" ]; do + echo "Waiting for apps to be available..."; + sleep 2; + if (( `date +%s`-start > 300 )); then + echo "Timeout waiting for apps"; + break; + fi; + done; + if [ -d "apps/lending" ] && ! ./env/bin/pip show lending > /dev/null 2>&1; then + echo "Installing lending app in Python environment..."; + ./env/bin/pip install -e apps/lending || echo "Failed to install lending"; + fi; + exec bench worker --queue short + volumes: + - sites:/home/frappe/frappe-bench/sites + - apps:/home/frappe/frappe-bench/apps + healthcheck: + test: + - CMD + - wait-for-it + - 'redis-queue:6379' + interval: 2s + timeout: 10s + retries: 30 + depends_on: + configurator: + condition: service_completed_successfully + required: true + + scheduler: + <<: *custom_image + entrypoint: ["bash", "-c"] + command: + - > + cd /home/frappe/frappe-bench; + export start=`date +%s`; + while [ ! -d "apps/lending" ]; do + echo "Waiting for apps to be available..."; + sleep 2; + if (( `date +%s`-start > 300 )); then + echo "Timeout waiting for apps"; + break; + fi; + done; + if [ -d "apps/lending" ] && ! ./env/bin/pip show lending > /dev/null 2>&1; then + echo "Installing lending app in Python environment..."; + ./env/bin/pip install -e apps/lending || echo "Failed to install lending"; + fi; + exec bench schedule + healthcheck: + test: + - CMD + - wait-for-it + - 'redis-queue:6379' + interval: 2s + timeout: 10s + retries: 30 + depends_on: + configurator: + condition: service_completed_successfully + required: true + volumes: + - sites:/home/frappe/frappe-bench/sites + - apps:/home/frappe/frappe-bench/apps + + websocket: + <<: *custom_image + healthcheck: + test: + - CMD + - wait-for-it + - '0.0.0.0:9000' + interval: 2s + timeout: 10s + retries: 30 + command: + - node + - /home/frappe/frappe-bench/apps/frappe/socketio.js + depends_on: + configurator: + condition: service_completed_successfully + required: true + volumes: + - sites:/home/frappe/frappe-bench/sites + - apps:/home/frappe/frappe-bench/apps + + configurator: + <<: *custom_image + deploy: + mode: replicated + replicas: ${CONFIGURE:-0} + restart_policy: + condition: none + entrypoint: ["bash", "-c"] + command: + - > + [[ $${REGENERATE_APPS_TXT} == "1" ]] && ls -1 apps > sites/apps.txt; + [[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".db_host // empty"` ]] && exit 0; + bench set-config -g db_host $$DB_HOST; + bench set-config -gp db_port $$DB_PORT; + bench set-config -g redis_cache "redis://$$REDIS_CACHE"; + bench set-config -g redis_queue "redis://$$REDIS_QUEUE"; + bench set-config -g redis_socketio "redis://$$REDIS_QUEUE"; + bench set-config -gp socketio_port $$SOCKETIO_PORT; + environment: + DB_HOST: "${DB_HOST:-db}" + DB_PORT: "3306" + REDIS_CACHE: redis-cache:6379 + REDIS_QUEUE: redis-queue:6379 + SOCKETIO_PORT: "9000" + REGENERATE_APPS_TXT: "${REGENERATE_APPS_TXT:-0}" + volumes: + - sites:/home/frappe/frappe-bench/sites + - apps:/home/frappe/frappe-bench/apps + + create-site: + <<: *custom_image + deploy: + mode: replicated + replicas: ${CREATE_SITE:-0} + restart_policy: + condition: none + entrypoint: ["bash", "-c"] + command: + - > + wait-for-it -t 120 $$DB_HOST:$$DB_PORT; + wait-for-it -t 120 redis-cache:6379; + wait-for-it -t 120 redis-queue:6379; + export start=`date +%s`; + until [[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".db_host // empty"` ]] && \ + [[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".redis_cache // empty"` ]] && \ + [[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".redis_queue // empty"` ]]; + do + echo "Waiting for sites/common_site_config.json to be created"; + sleep 5; + if (( `date +%s`-start > 120 )); then + echo "could not find sites/common_site_config.json with required keys"; + exit 1 + fi + done; + echo "sites/common_site_config.json found"; + cd /home/frappe/frappe-bench; + if [ -d "sites/${SITE_NAME}" ] && [ -f "sites/${SITE_NAME}/site_config.json" ]; then + echo "Site ${SITE_NAME} already exists, skipping creation"; + bench use $${SITE_NAME} || echo "Warning: Could not set current site"; + echo "$${SITE_NAME}" > sites/sites.txt || echo "Warning: Could not update sites.txt"; + bench set-config -g default_site $${SITE_NAME} || echo "Warning: Could not set default site"; + if [ -n "$${ADMIN_PASSWORD}" ]; then + echo "Updating admin password for existing site..."; + bench --site $${SITE_NAME} set-admin-password $${ADMIN_PASSWORD} || echo "Warning: Could not update admin password (may need to be done manually)"; + fi; + if [ -n "$${MAIN_DOMAIN}" ]; then + echo "Setting host_name and SSL settings to https://${MAIN_DOMAIN} (with HTTPS)..."; + bench --site $${SITE_NAME} set-config host_name "https://$${MAIN_DOMAIN}" || echo "Warning: Could not set host_name"; + bench --site $${SITE_NAME} set-config host_url "https://$${MAIN_DOMAIN}" || echo "Warning: Could not set host_url"; + bench --site $${SITE_NAME} set-config use_ssl 1 || echo "Warning: Could not set use_ssl"; + echo "Clearing cache to apply new domain settings..."; + bench --site $${SITE_NAME} clear-cache || echo "Warning: Could not clear cache"; + bench --site $${SITE_NAME} clear-website-cache || echo "Warning: Could not clear website cache"; + fi; + echo "Verifying existing site is accessible..."; + bench --site $${SITE_NAME} list-apps > /dev/null 2>&1 && echo "Existing site is accessible and working" || echo "Warning: Site accessibility check failed"; + exit 0; + fi; + if [ ! -d "apps/lending" ]; then + echo "Cloning lending app..."; + git clone https://github.com/frappe/lending.git apps/lending || echo "Failed to clone lending app"; + fi; + if [ -d "apps/lending" ]; then + echo "Installing lending app in Python environment..."; + ./env/bin/pip install -e apps/lending || echo "Failed to install lending app"; + fi; + echo "Regenerating apps.txt to include all apps..."; + ls -1 apps > sites/apps.txt || (echo "frappe" > sites/apps.txt && echo "lending" >> sites/apps.txt); + echo "apps.txt contents:"; + cat sites/apps.txt; + bench set-mariadb-host $${DB_HOST:-db}; + bench new-site --mariadb-user-host-login-scope='%' --admin-password=$${ADMIN_PASSWORD} --db-root-username=root --db-root-password=$${DB_ROOT_PASSWORD} $${INSTALL_APP_ARGS} $${SITE_NAME}; + if [ ! -d "sites/${SITE_NAME}" ]; then + echo "ERROR: Site ${SITE_NAME} was not created successfully"; + exit 1; + fi; + echo "Site ${SITE_NAME} created successfully"; + bench use $${SITE_NAME}; + echo "Current site set to: $${SITE_NAME}"; + if [ -d "apps/lending" ]; then + echo "Installing lending app on site..."; + bench --site $${SITE_NAME} install-app lending || echo "Lending app may already be installed or failed to install"; + fi; + echo "Building assets for all apps (this ensures lending JS is available)..."; + bench build --apps lending || echo "Asset build completed"; + echo "Clearing all caches..."; + bench --site $${SITE_NAME} clear-cache || echo "Cache cleared"; + bench --site $${SITE_NAME} clear-website-cache || echo "Website cache cleared"; + echo "Creating sites.txt for site resolution..."; + echo "$${SITE_NAME}" > sites/sites.txt || echo "Warning: Could not create sites.txt"; + echo "Site registered in sites.txt:"; + cat sites/sites.txt || echo "sites.txt not found"; + echo "Verifying site directory and config exist..."; + if [ -d "sites/${SITE_NAME}" ] && [ -f "sites/${SITE_NAME}/site_config.json" ]; then + echo "Site directory and config verified successfully"; + else + echo "Warning: Site directory or config file missing"; + ls -la sites/${SITE_NAME}/ 2>/dev/null || echo "Site directory listing failed"; + fi; + echo "Setting default site in common_site_config.json..."; + bench set-config -g default_site $${SITE_NAME} || echo "Warning: Could not set default site"; + if [ -n "$${MAIN_DOMAIN}" ]; then + echo "Setting host_name and SSL settings to https://${MAIN_DOMAIN} (with HTTPS)..."; + bench --site $${SITE_NAME} set-config host_name "https://$${MAIN_DOMAIN}" || echo "Warning: Could not set host_name"; + bench --site $${SITE_NAME} set-config host_url "https://$${MAIN_DOMAIN}" || echo "Warning: Could not set host_url"; + bench --site $${SITE_NAME} set-config use_ssl 1 || echo "Warning: Could not set use_ssl"; + echo "Clearing cache to apply new domain settings..."; + bench --site $${SITE_NAME} clear-cache || echo "Warning: Could not clear cache"; + bench --site $${SITE_NAME} clear-website-cache || echo "Warning: Could not clear website cache"; + fi; + echo "Verifying site is accessible..."; + bench --site $${SITE_NAME} list-apps > /dev/null 2>&1 && echo "Site is accessible and working" || echo "Warning: Site accessibility check failed"; + volumes: + - sites:/home/frappe/frappe-bench/sites + - apps:/home/frappe/frappe-bench/apps + environment: + SITE_NAME: ${SITE_NAME} + MAIN_DOMAIN: ${main_domain} + ADMIN_PASSWORD: ${ADMIN_PASSWORD} + DB_HOST: ${DB_HOST:-db} + DB_PORT: "${DB_PORT:-3306}" + DB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD} + INSTALL_APP_ARGS: ${INSTALL_APP_ARGS} + + migration: + <<: *custom_image + deploy: + mode: replicated + replicas: ${MIGRATE:-0} + restart_policy: + condition: none + entrypoint: ["bash", "-c"] + command: + - > + curl -f http://${SITE_NAME}:8080/api/method/ping || echo "Site busy" && exit 0; + bench --site all set-config -p maintenance_mode 1; + bench --site all set-config -p pause_scheduler 1; + bench --site all migrate; + bench --site all set-config -p maintenance_mode 0; + bench --site all set-config -p pause_scheduler 0; + volumes: + - sites:/home/frappe/frappe-bench/sites + - apps:/home/frappe/frappe-bench/apps + + db: + image: mariadb:10.6 + deploy: + mode: replicated + replicas: ${ENABLE_DB:-0} + restart_policy: + condition: always + healthcheck: + test: mysqladmin ping -h localhost --password=${DB_ROOT_PASSWORD} + interval: 1s + retries: 20 + command: + - --character-set-server=utf8mb4 + - --collation-server=utf8mb4_unicode_ci + - --skip-character-set-client-handshake + - --skip-innodb-read-only-compressed + environment: + - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD} + - MARIADB_ROOT_PASSWORD=${DB_ROOT_PASSWORD} + volumes: + - db-data:/var/lib/mysql + + redis-cache: + deploy: + restart_policy: + condition: always + image: redis:6.2-alpine + volumes: + - redis-cache-data:/data + healthcheck: + test: + - CMD + - redis-cli + - ping + interval: 5s + timeout: 5s + retries: 3 + + redis-queue: + deploy: + restart_policy: + condition: always + image: redis:6.2-alpine + volumes: + - redis-queue-data:/data + healthcheck: + test: + - CMD + - redis-cli + - ping + interval: 5s + timeout: 5s + retries: 3 + + redis-socketio: + deploy: + restart_policy: + condition: always + image: redis:6.2-alpine + volumes: + - redis-socketio-data:/data + healthcheck: + test: + - CMD + - redis-cli + - ping + interval: 5s + timeout: 5s + retries: 3 + +volumes: + db-data: + redis-cache-data: + redis-queue-data: + redis-socketio-data: + sites: + driver_opts: + type: "${SITE_VOLUME_TYPE}" + o: "${SITE_VOLUME_OPTS}" + device: "${SITE_VOLUME_DEV}" + apps: + diff --git a/blueprints/frappe-lending/frappe-lending.png b/blueprints/frappe-lending/frappe-lending.png new file mode 100644 index 0000000000000000000000000000000000000000..e94e65a6e91233b476d6c394ee356aabb6b133be GIT binary patch literal 2985 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 GHum3@T!&}? literal 0 HcmV?d00001 diff --git a/blueprints/frappe-lending/template.toml b/blueprints/frappe-lending/template.toml new file mode 100644 index 00000000..71612960 --- /dev/null +++ b/blueprints/frappe-lending/template.toml @@ -0,0 +1,29 @@ +[variables] +main_domain = "${domain}" +site_name = "frappe.lending" +db_root_password = "${password:32}" +admin_password = "${password:32}" + +[config] +env = [ + "SITE_NAME=${site_name}", + "ADMIN_PASSWORD=${admin_password}", + "DB_ROOT_PASSWORD=${db_root_password}", + "MIGRATE=1", + "ENABLE_DB=1", + "DB_HOST=db", + "CREATE_SITE=1", + "CONFIGURE=1", + "REGENERATE_APPS_TXT=1", + "INSTALL_APP_ARGS=--install-app erpnext --install-app lending", + "IMAGE_NAME=frappe/erpnext", + "VERSION=latest", + "FRAPPE_SITE_NAME_HEADER=", + "MAIN_DOMAIN=${main_domain}", +] +mounts = [] + +[[config.domains]] +serviceName = "frontend" +port = 8_080 +host = "${main_domain}" diff --git a/meta.json b/meta.json index 3ae0cb5e..5a1dae87 100644 --- a/meta.json +++ b/meta.json @@ -2543,6 +2543,26 @@ "performace" ] }, + { + "id": "frappe-lending", + "name": "Frappe Lending", + "version": "latest", + "description": "A comprehensive loan management system built on Frappe Framework. 100% open source and customizable for managing loans, repayments, and lending operations.", + "logo": "frappe-lending.png", + "links": { + "github": "https://github.com/frappe/lending", + "docs": "https://docs.frappe.io/lending", + "website": "https://frappe.io" + }, + "tags": [ + "lending", + "finance", + "loans", + "payments", + "accounting", + "self-hosted" + ] + }, { "id": "freescout", "name": "FreeScout",