# Instalare ERP/CRM DiDi de la 0 Ghid complet pentru a porni stack-ul ERPNext + DiDi custom de la o masina goala. ## Prerequisite ### Software pe host ```bash docker --version # >= 24.0 docker compose version # >= v2 ``` Toata logica de setup ruleaza IN containerul ERPNext prin `bench execute` pe functiile din app-ul `didi_custom` — nu e nevoie de Python pe host. ### Resurse - 4 GB RAM disponibili - 10 GB spatiu disc - Port 8080 liber (sau schimba ERPNEXT_PORT) ### Retea Docker ERPNext-ul ruleaza pe reteaua `didi-network` (impartita cu website-ul). Creeaz-o: ```bash docker network create didi-network 2>/dev/null || true ``` ## Build automat (recomandat) Ruleaza: ```bash cd ~/erp_crm bash build-from-zero.sh ``` Scriptul face urmatoarele (~5 min): 1. Verifica `docker network` si `.env` 2. Porneste containerele (`docker compose up -d`) 3. Asteapta MariaDB sa fie healthy 4. Configureaza Redis in `common_site_config.json` 5. Creeaza site-ul `didi-erp` cu ERPNext instalat 6. Instaleaza app-ul `didi_custom` 7. Creeaza Company `TOP CLOSSERS SRL` + plan de conturi RO + An Fiscal curent 8. Ruleaza setup-ul complet din `didi_custom` prin `bench execute` (doctypes, campuri custom, CMS, items DIDI + user API, print format, email, workspace + scurtaturi) 9. Build assets (`bench build`) 10. Verifica accesul HTTP ## Build manual (pas cu pas) Daca preferi sa rulezi fiecare pas individual: ### Pas 1. Containere ```bash cd ~/erp_crm docker compose up -d ``` Asteapta ~30 secunde pana MariaDB e healthy: ```bash docker compose ps # Toate trebuie sa fie Up; mariadb cu (healthy) ``` ### Pas 2. Configurare Redis ```bash docker exec didi-erpnext bash -c ' cd /home/frappe/frappe-bench && bench set-config -g redis_cache "redis://redis-cache:6379" && bench set-config -g redis_queue "redis://redis-queue:6379" && bench set-config -g redis_socketio "redis://redis-queue:6379" ' ``` ### Pas 3. Creare site + instalare ERPNext ```bash docker exec didi-erpnext bash -c ' cd /home/frappe/frappe-bench && bench new-site didi-erp \ --mariadb-root-password \ --admin-password \ --db-host mariadb \ --install-app erpnext ' ``` Dureaza ~3 minute. ### Pas 4. Fix MariaDB user pentru orice host Userul DB creat de Frappe e restrictionat la host-ul curent. Pentru ca containerele cu workers/scheduler sa se conecteze, schimba la wildcard: ```bash DB_NAME=$(docker exec didi-erpnext python3 -c " import json with open('/home/frappe/frappe-bench/sites/didi-erp/site_config.json') as f: print(json.load(f)['db_name']) ") DB_PWD=$(docker exec didi-erpnext python3 -c " import json with open('/home/frappe/frappe-bench/sites/didi-erp/site_config.json') as f: print(json.load(f)['db_password']) ") docker exec didi-mariadb mariadb -uroot -p -e " DROP USER IF EXISTS '$DB_NAME'@'%'; CREATE USER '$DB_NAME'@'%' IDENTIFIED BY '$DB_PWD'; GRANT ALL PRIVILEGES ON \`$DB_NAME\`.* TO '$DB_NAME'@'%'; FLUSH PRIVILEGES; " ``` ### Pas 5. Instalare didi_custom ```bash docker exec didi-erpnext bash -c ' cd /home/frappe/frappe-bench && printf "frappe\nerpnext\ndidi_custom\n" > sites/apps.txt && env/bin/pip install -e apps/didi_custom && bench --site didi-erp install-app didi_custom ' ``` ### Pas 6. Patch ERPNext (portal_users compatibility) Frappe v15 are un bug minor cu campul `portal_users` pe Customer (referinta la modul lipsa). Patch: ```bash docker exec didi-erpnext sed -i \ 's|for portal_user in self.portal_users:|for portal_user in (getattr(self, "portal_users", None) or []):|' \ /home/frappe/frappe-bench/apps/erpnext/erpnext/selling/doctype/customer/customer.py ``` ### Pas 7. Companie + plan de conturi Romania + An Fiscal ⚠️ **NU rula logica frappe cu `python3` pe host sau cu python-ul de sistem din container** — esueaza tacut (frappe e instalat doar in venv-ul bench). Foloseste `bench --site didi-erp execute `. ```bash BE='docker exec didi-erpnext bash -c' # Warehouse Type "Transit" — cerut la crearea companiei, lipseste in instalarea curata $BE 'cd /home/frappe/frappe-bench && bench --site didi-erp execute frappe.client.insert \ --kwargs "{\"doc\":{\"doctype\":\"Warehouse Type\",\"name\":\"Transit\"}}"' || true # Company TOP CLOSSERS SRL (cu patch-uri country fixtures incluse in modul) $BE 'cd /home/frappe/frappe-bench && bench --site didi-erp execute didi_custom.make_company_ro3.execute' # Plan de conturi RO complet (447 conturi: TVA 4426/4427/4423/4424, venituri 704/707, # default-uri companie, template TVA 21%) $BE 'cd /home/frappe/frappe-bench && bench --site didi-erp execute didi_custom.setup_ro_coa.execute' # An Fiscal curent — lipseste complet dupa instalarea curata; facturile pica fara el YEAR=$(date +%Y) $BE "cd /home/frappe/frappe-bench && bench --site didi-erp execute frappe.client.insert \ --kwargs '{\"doc\":{\"doctype\":\"Fiscal Year\",\"year\":\"$YEAR\",\"year_start_date\":\"$YEAR-01-01\",\"year_end_date\":\"$YEAR-12-31\"}}'" # Price list implicit in RON $BE 'cd /home/frappe/frappe-bench && bench --site didi-erp execute frappe.client.set_value \ --kwargs "{\"doctype\":\"Price List\",\"name\":\"Standard Selling\",\"fieldname\":\"currency\",\"value\":\"RON\"}"' ``` ### Pas 8. Doctypes custom, campuri si continut CMS ```bash for fn in didi_custom.setup_doctypes.execute \ didi_custom.integrations.migrations.setup_custom_fields.execute \ didi_custom.fix_sa.execute \ didi_custom.populate_content.execute; do docker exec didi-erpnext bash -c "cd /home/frappe/frappe-bench && bench --site didi-erp execute $fn" done ``` Creeaza: doctype-urile Service Agreement / Payment Log / Website Content, campurile custom pe Customer / Sales Invoice / Lead (didi_user_id, iam_role, active_plan, sales_invoice „Factura asociata" pe Service Agreement etc.) si continutul CMS. ### Pas 9. Integrare website, print format, email, workspace ```bash for fn in didi_custom.setup_website_integration.execute \ didi_custom.setup_phase2_final.setup_print_format \ didi_custom.setup_website_integration.fix_print_format \ didi_custom.setup_email.execute \ didi_custom.setup_workspaces.execute \ didi_custom.setup_shortcuts.execute; do docker exec didi-erpnext bash -c "cd /home/frappe/frappe-bench && bench --site didi-erp execute $fn" done ``` - `setup_website_integration.execute` creeaza items DIDI, rolul „Website Integration" (cu toate permisiunile read necesare validarii facturilor) si userul API `website_api@didi-erp.local` — **noteaza api_key/api_secret afisate**, intra in `.env.production`-ul website-ului. - `fix_print_format` repara print formatul „DiDi Invoice" si seteaza `host_name` (altfel wkhtmltopdf da `HostNotFoundError` la logo). - `setup_email.execute` configureaza contul SMTP „DiDi Outgoing" (Mailpit in test; in productie se schimba doar host/port/credentiale in Email Account). ### Pas 10. Scripturile legacy (scripts/setup/) — NU se mai folosesc Directorul `scripts/setup/` contine prima generatie de scripturi (rulate pe host). Sunt pastrate doar ca referinta istorica — totul a fost mutat in module `didi_custom` rulabile cu `bench execute` (pasii 7-9 de mai sus). ### Pas 11. Build assets + restart ```bash docker exec didi-erpnext bash -c 'cd /home/frappe/frappe-bench && bench build --force' docker restart didi-erpnext sleep 8 curl -s -o /dev/null -w "ERPNext: %{http_code}\n" http://localhost:8080 ``` ## Verificare instalare Daca totul a mers, deschide http://localhost:8080: - Login: `Administrator` / `admin` - Sidebar trebuie sa contina: Home, Facturi, Clienti, CRM, Servicii, Plati, Contabilitate, Financial Reports, Website CMS - Pagina `/app/customer` arata Customer-ul `Test User` (daca ai rulat seed) Curl rapid de verificare: ```bash # Login + verifica company curl -s -c /tmp/c -X POST http://localhost:8080/api/method/login \ -d 'usr=Administrator&pwd=admin' && echo curl -s -b /tmp/c http://localhost:8080/api/resource/Company | python3 -m json.tool ``` ## Date de test (seed) Pentru smoke testing dupa instalare: ```bash bash seed-data.sh ``` Creeaza: - 1 Customer (`Test User`) - 3 Sales Invoices submitted + paid - 1 Payment Log (Stripe simulat) - 1 Service Agreement ## Probleme frecvente ### "Module Selling not found" `installed_apps` global value nu contine `erpnext`. Fix: ```bash DB=$(docker exec didi-erpnext cat /home/frappe/frappe-bench/sites/didi-erp/site_config.json | python3 -c "import sys,json; print(json.load(sys.stdin)['db_name'])") docker exec didi-mariadb mariadb -uroot -p $DB -e " UPDATE tabDefaultValue SET defvalue='[\"frappe\",\"erpnext\",\"didi_custom\"]' WHERE defkey='installed_apps'; " docker exec didi-redis-cache redis-cli FLUSHALL docker restart didi-erpnext ``` ### "wkhtmltopdf reported an error: HostNotFoundError" `host_name` lipseste in Website Settings. Fix: ```bash docker exec didi-erpnext bash -c 'cd /home/frappe/frappe-bench && bench --site didi-erp set-config -g host_name "http://didi-erpnext:8080"' docker restart didi-erpnext ``` ### "Access denied for user '_xxxx'@'host'" User DB are host limitat. Vezi Pas 4 mai sus pentru fix. ### Site ramane la 500 pe `/app/home` `setup_complete` e 0 si lipsesc accounts. Treci prin Setup Wizard manual din browser, SAU re-ruleaza Pasul 7 + 8. ## Reset complet Pentru a reseta totul si a porni de la 0: ```bash cd ~/erp_crm docker compose down -v # -v sterge volumele! docker network rm didi-network 2>/dev/null docker network create didi-network bash build-from-zero.sh ``` ATENTIE: `down -v` sterge IREVERSIBIL toate datele din MariaDB. Faci backup intai daca ai date importante.