300 lines
9.5 KiB
Markdown
300 lines
9.5 KiB
Markdown
# 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 <parola-root-db> \
|
|
--admin-password <parola-admin> \
|
|
--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<parola-root-db> -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 <modul.functie>`.
|
|
|
|
```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<parola-root-db> $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.
|