feat(oracle): support per-article id_pol in PACK_IMPORT_COMENZI + deploy docs
- PACK_IMPORT_COMENZI: reads optional "id_pol" per article from JSON, uses it via NVL(v_id_pol_articol, p_id_pol) — enables separate price policy for transport/discount articles vs regular order articles - README.md: add Windows deploy section (deploy.ps1, update.ps1, .env example) - CLAUDE.md: add reference to Windows deploy docs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -134,3 +134,7 @@ ORACLE_PASSWORD=********
|
|||||||
ORACLE_DSN=ROA_ROMFAST
|
ORACLE_DSN=ROA_ROMFAST
|
||||||
TNS_ADMIN=/app
|
TNS_ADMIN=/app
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Deploy & Depanare Windows
|
||||||
|
|
||||||
|
Vezi [README.md](README.md#deploy-windows) pentru instructiuni complete de deploy si depanare pe Windows Server.
|
||||||
|
|||||||
79
README.md
79
README.md
@@ -193,6 +193,85 @@ gomag-vending/
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Deploy Windows
|
||||||
|
|
||||||
|
### Instalare initiala
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Ruleaza ca Administrator
|
||||||
|
.\deploy.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
Scriptul `deploy.ps1` face automat: git clone, venv, dependinte, detectare Oracle, `start.bat`, serviciu NSSM, configurare IIS reverse proxy.
|
||||||
|
|
||||||
|
### Update
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Ca Administrator
|
||||||
|
.\update.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configurare `.env` pe Windows
|
||||||
|
|
||||||
|
```ini
|
||||||
|
# api/.env — exemplu Windows
|
||||||
|
ORACLE_USER=VENDING
|
||||||
|
ORACLE_PASSWORD=****
|
||||||
|
ORACLE_DSN=ROA
|
||||||
|
TNS_ADMIN=C:\roa\instantclient_11_2_0_2
|
||||||
|
INSTANTCLIENTPATH=C:\app\Server\product\18.0.0\dbhomeXE\bin
|
||||||
|
```
|
||||||
|
|
||||||
|
**Important:**
|
||||||
|
- `TNS_ADMIN` = folderul care contine `tnsnames.ora` (NU fisierul in sine)
|
||||||
|
- `ORACLE_DSN` = alias-ul exact din `tnsnames.ora`
|
||||||
|
- `INSTANTCLIENTPATH` = calea catre Oracle bin (thick mode)
|
||||||
|
|
||||||
|
### Serviciu Windows (NSSM)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
nssm restart GoMagVending # restart
|
||||||
|
nssm status GoMagVending # status
|
||||||
|
nssm stop GoMagVending # stop
|
||||||
|
```
|
||||||
|
|
||||||
|
Loguri serviciu: `logs/service_stdout.log`, `logs/service_stderr.log`
|
||||||
|
Loguri aplicatie: `logs/sync_comenzi_*.log`
|
||||||
|
|
||||||
|
### Depanare SSH
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Conectare SSH (PowerShell remote, cheie publica)
|
||||||
|
ssh -p 22122 gomag@79.119.86.134
|
||||||
|
|
||||||
|
# Verificare .env
|
||||||
|
cmd /c type C:\gomag-vending\api\.env
|
||||||
|
|
||||||
|
# Test conexiune Oracle
|
||||||
|
C:\gomag-vending\venv\Scripts\python.exe -c "import oracledb, os; os.environ['TNS_ADMIN']='C:/roa/instantclient_11_2_0_2'; conn=oracledb.connect(user='VENDING', password='ROMFASTSOFT', dsn='ROA'); print('Connected!'); conn.close()"
|
||||||
|
|
||||||
|
# Verificare tnsnames.ora
|
||||||
|
cmd /c type C:\roa\instantclient_11_2_0_2\tnsnames.ora
|
||||||
|
|
||||||
|
# Verificare procese Python
|
||||||
|
Get-Process *python* | Select-Object Id,ProcessName,Path
|
||||||
|
|
||||||
|
# Verificare loguri recente
|
||||||
|
Get-ChildItem C:\gomag-vending\logs\*.log | Sort-Object LastWriteTime -Descending | Select-Object -First 3
|
||||||
|
```
|
||||||
|
|
||||||
|
**Nota SSH:** Userul `gomag` nu are drepturi de admin — `nssm restart` si `net stop/start` necesita PowerShell Administrator direct pe server.
|
||||||
|
|
||||||
|
### Probleme frecvente
|
||||||
|
|
||||||
|
| Eroare | Cauza | Solutie |
|
||||||
|
|--------|-------|---------|
|
||||||
|
| `ORA-12154: TNS:could not resolve` | `TNS_ADMIN` gresit sau `tnsnames.ora` nu contine alias-ul DSN | Verifica `TNS_ADMIN` in `.env` + alias in `tnsnames.ora` |
|
||||||
|
| `ORA-04088: LOGON_AUDIT_TRIGGER` + `Nu aveti licenta pentru PYTHON` | Trigger ROA blocheaza executabile nelicențiate | Adauga `python.exe` (calea completa) in ROASUPORT |
|
||||||
|
| `503 Service Unavailable` pe `/api/articles/search` | Oracle pool nu s-a initializat | Verifica logul `sync_comenzi_*.log` pentru eroarea exacta |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## WSL2 Note
|
## WSL2 Note
|
||||||
|
|
||||||
- `uvicorn --reload` **nu functioneaza** pe `/mnt/e/` (WSL2 limitation) — restarta manual
|
- `uvicorn --reload` **nu functioneaza** pe `/mnt/e/` (WSL2 limitation) — restarta manual
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
-- p_json_articole accepta:
|
-- p_json_articole accepta:
|
||||||
-- - array JSON: [{"sku":"X","quantity":"1","price":"10","vat":"19"}, ...]
|
-- - array JSON: [{"sku":"X","quantity":"1","price":"10","vat":"19"}, ...]
|
||||||
-- - obiect JSON: {"sku":"X","quantity":"1","price":"10","vat":"19"}
|
-- - obiect JSON: {"sku":"X","quantity":"1","price":"10","vat":"19"}
|
||||||
|
-- Optional per articol: "id_pol":"5" — politica de pret specifica
|
||||||
|
-- (pentru transport/discount cu politica separata de cea a comenzii)
|
||||||
-- Valorile sku, quantity, price, vat sunt extrase ca STRING si convertite.
|
-- Valorile sku, quantity, price, vat sunt extrase ca STRING si convertite.
|
||||||
-- Daca comanda exista deja (comanda_externa), nu se dubleaza.
|
-- Daca comanda exista deja (comanda_externa), nu se dubleaza.
|
||||||
-- La eroare ridica RAISE_APPLICATION_ERROR(-20001, mesaj).
|
-- La eroare ridica RAISE_APPLICATION_ERROR(-20001, mesaj).
|
||||||
@@ -113,6 +115,7 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
|||||||
v_codmat VARCHAR2(50);
|
v_codmat VARCHAR2(50);
|
||||||
v_cantitate_roa NUMBER;
|
v_cantitate_roa NUMBER;
|
||||||
v_pret_unitar NUMBER;
|
v_pret_unitar NUMBER;
|
||||||
|
v_id_pol_articol NUMBER; -- id_pol per articol (din JSON), prioritar fata de p_id_pol
|
||||||
|
|
||||||
-- pljson
|
-- pljson
|
||||||
l_json_articole CLOB := p_json_articole;
|
l_json_articole CLOB := p_json_articole;
|
||||||
@@ -189,6 +192,13 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
|||||||
v_pret_web := TO_NUMBER(v_json_obj.get_string('price'));
|
v_pret_web := TO_NUMBER(v_json_obj.get_string('price'));
|
||||||
v_vat := TO_NUMBER(v_json_obj.get_string('vat'));
|
v_vat := TO_NUMBER(v_json_obj.get_string('vat'));
|
||||||
|
|
||||||
|
-- id_pol per articol (optional, pentru transport/discount cu politica separata)
|
||||||
|
BEGIN
|
||||||
|
v_id_pol_articol := TO_NUMBER(v_json_obj.get_string('id_pol'));
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN v_id_pol_articol := NULL;
|
||||||
|
END;
|
||||||
|
|
||||||
-- STEP 3: Gaseste articolele ROA pentru acest SKU
|
-- STEP 3: Gaseste articolele ROA pentru acest SKU
|
||||||
-- Cauta mai intai in ARTICOLE_TERTI (mapari speciale / seturi)
|
-- Cauta mai intai in ARTICOLE_TERTI (mapari speciale / seturi)
|
||||||
v_found_mapping := FALSE;
|
v_found_mapping := FALSE;
|
||||||
@@ -211,7 +221,7 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
|||||||
BEGIN
|
BEGIN
|
||||||
PACK_COMENZI.adauga_articol_comanda(V_ID_COMANDA => v_id_comanda,
|
PACK_COMENZI.adauga_articol_comanda(V_ID_COMANDA => v_id_comanda,
|
||||||
V_ID_ARTICOL => rec.id_articol,
|
V_ID_ARTICOL => rec.id_articol,
|
||||||
V_ID_POL => p_id_pol,
|
V_ID_POL => NVL(v_id_pol_articol, p_id_pol),
|
||||||
V_CANTITATE => v_cantitate_roa,
|
V_CANTITATE => v_cantitate_roa,
|
||||||
V_PRET => v_pret_unitar,
|
V_PRET => v_pret_unitar,
|
||||||
V_ID_UTIL => c_id_util,
|
V_ID_UTIL => c_id_util,
|
||||||
@@ -238,7 +248,7 @@ CREATE OR REPLACE PACKAGE BODY PACK_IMPORT_COMENZI AS
|
|||||||
|
|
||||||
PACK_COMENZI.adauga_articol_comanda(V_ID_COMANDA => v_id_comanda,
|
PACK_COMENZI.adauga_articol_comanda(V_ID_COMANDA => v_id_comanda,
|
||||||
V_ID_ARTICOL => v_id_articol,
|
V_ID_ARTICOL => v_id_articol,
|
||||||
V_ID_POL => p_id_pol,
|
V_ID_POL => NVL(v_id_pol_articol, p_id_pol),
|
||||||
V_CANTITATE => v_cantitate_web,
|
V_CANTITATE => v_cantitate_web,
|
||||||
V_PRET => v_pret_unitar,
|
V_PRET => v_pret_unitar,
|
||||||
V_ID_UTIL => c_id_util,
|
V_ID_UTIL => c_id_util,
|
||||||
|
|||||||
Reference in New Issue
Block a user