feat(ocr): Add modular store profiles with hot-reload support
## Store Profiles System
- Add ProfileRegistry for CUI-based profile lookup
- Add BaseStoreProfile with generic extraction patterns
- Implement hot-reload via POST /api/data-entry/ocr/profiles/reload
## 12 Store Profiles
- LIDL: Multi-rate TVA (A, B, C, D codes)
- OMV, SOCAR: B2B with client CUI, YYYY.MM.DD dates
- BRICK, DEDEMAN: Standard TVA, e-factura support
- KINETERRA, BEST PRINT: Non-VAT payers (returns [])
- STEPOUT MARKET: TVA 5% (books/reduced rate)
- UNLIMITED KEYS: NUMERAR payment detection
- GAMA INK, ELECTROBERING, PICTUS VELUM: Standard TVA
## Flexible TVA Patterns
- All patterns use (\d{1,2})% to accept any rate
- Supports historical (19%, 9%, 5%) and current (21%, 11%)
## Payment Methods Fix
- Fixed base.py to support multiple payments of same type
- Changed deduplication from method-only to (method, amount) tuple
- Returns separate entries for split payments
## Tools
- Add generate_store_profile.py for automatic profile generation
- Analyzes PDFs via OCR API and detects patterns
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
106
.claude/rules/claude-learn-backend.md
Normal file
106
.claude/rules/claude-learn-backend.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# Claude Learn: Backend
|
||||
|
||||
**Domain**: backend
|
||||
**Last updated**: 2026-01-06
|
||||
**Sessions recorded**: 1
|
||||
|
||||
Knowledge about FastAPI, Python services, Oracle DB, and backend architecture.
|
||||
|
||||
---
|
||||
|
||||
## Patterns
|
||||
|
||||
### ProfileRegistry cu Hot-Reload pentru Store Profiles
|
||||
**Discovered**: 2026-01-06 (feature: ocr-store-profiles)
|
||||
**Description**: Sistem de înregistrare profile OCR folosind decorator `@ProfileRegistry.register` cu hot-reload via `importlib.reload()`. Permite adăugarea/modificarea profilelor fără restart server.
|
||||
|
||||
**Example** (`backend/modules/data_entry/services/ocr/profiles/__init__.py`):
|
||||
```python
|
||||
class ProfileRegistry:
|
||||
_profiles: Dict[str, Type["BaseStoreProfile"]] = {}
|
||||
_instances: Dict[str, "BaseStoreProfile"] = {}
|
||||
|
||||
@classmethod
|
||||
def register(cls, profile_class):
|
||||
"""Decorator to register a store profile class."""
|
||||
for cui in profile_class.CUI_LIST:
|
||||
cls._profiles[cls._normalize_cui(cui)] = profile_class
|
||||
return profile_class
|
||||
|
||||
@classmethod
|
||||
def reload_all(cls):
|
||||
"""Hot-reload all profile modules via importlib.reload()."""
|
||||
cls._instances.clear()
|
||||
for module_name in cls._get_profile_module_names():
|
||||
importlib.reload(sys.modules[f"backend...profiles.{module_name}"])
|
||||
```
|
||||
|
||||
**Usage**:
|
||||
```python
|
||||
@ProfileRegistry.register
|
||||
class LidlProfile(BaseStoreProfile):
|
||||
CUI_LIST = ["22891860"]
|
||||
STORE_NAME = "LIDL DISCOUNT S.R.L."
|
||||
|
||||
# Lookup
|
||||
profile = ProfileRegistry.get_profile("22891860")
|
||||
|
||||
# Hot-reload (endpoint)
|
||||
POST /api/data-entry/ocr/profiles/reload
|
||||
```
|
||||
|
||||
**Tags**: registry-pattern, hot-reload, decorator, ocr, singleton
|
||||
|
||||
---
|
||||
|
||||
### Script generare cod Python din analiză PDF
|
||||
**Discovered**: 2026-01-06 (feature: ocr-store-profiles)
|
||||
**Description**: Script care analizează PDF-uri via OCR API, detectează pattern-uri (TVA format, date format, payment) și generează automat cod Python pentru profile noi. Include JWT auth, async polling, și verificare sintaxă.
|
||||
|
||||
**Example** (`scripts/generate_store_profile.py`):
|
||||
```python
|
||||
def analyze_tva_patterns(results: List[Dict]) -> Dict:
|
||||
"""Detectează format TVA dominant din rezultatele OCR."""
|
||||
tva_formats = defaultdict(int)
|
||||
for text in raw_texts:
|
||||
if re.search(r'TVA\s+[A-D]\s+\d{1,2}', text_upper):
|
||||
tva_formats["lidl_multi_rate"] += 1
|
||||
if re.search(r'BAZA\s+TVA', text_upper):
|
||||
tva_formats["table"] += 1
|
||||
return {"dominant_format": max(tva_formats, key=tva_formats.get)}
|
||||
|
||||
def generate_profile_code(store_name, cui, tva_analysis, ...):
|
||||
"""Generează cod Python pentru clasa de profil."""
|
||||
# Template-based generation cu OCR error variants
|
||||
```
|
||||
|
||||
**Usage**:
|
||||
```bash
|
||||
# Dry-run pentru preview
|
||||
python scripts/generate_store_profile.py \
|
||||
--name "Magazin Nou" --cui "12345678" \
|
||||
--receipts "docs/data-entry/MagazinNou*.pdf" --dry-run
|
||||
|
||||
# Generează și salvează
|
||||
python scripts/generate_store_profile.py \
|
||||
--name "Magazin Nou" --cui "12345678" \
|
||||
--receipts "docs/data-entry/MagazinNou*.pdf" \
|
||||
--output backend/.../profiles/magazin_nou.py
|
||||
```
|
||||
|
||||
**Tags**: code-generation, ocr, automation, cli-tool
|
||||
|
||||
---
|
||||
|
||||
## Gotchas
|
||||
|
||||
_(None recorded yet)_
|
||||
|
||||
---
|
||||
|
||||
## Statistics
|
||||
|
||||
- **Total Patterns**: 2
|
||||
- **Total Gotchas**: 0
|
||||
- **Last Session**: 2026-01-06
|
||||
- **Sessions Recorded**: 1
|
||||
28
.claude/rules/claude-learn-database.md
Normal file
28
.claude/rules/claude-learn-database.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Claude Learn: Database
|
||||
|
||||
**Domain**: database
|
||||
**Last updated**: -
|
||||
**Sessions recorded**: 0
|
||||
|
||||
Knowledge about Oracle DB, SQLite, SQLModel, migrations, and data modeling.
|
||||
|
||||
---
|
||||
|
||||
## Patterns
|
||||
|
||||
_(None recorded yet)_
|
||||
|
||||
---
|
||||
|
||||
## Gotchas
|
||||
|
||||
_(None recorded yet)_
|
||||
|
||||
---
|
||||
|
||||
## Statistics
|
||||
|
||||
- **Total Patterns**: 0
|
||||
- **Total Gotchas**: 0
|
||||
- **Last Session**: -
|
||||
- **Sessions Recorded**: 0
|
||||
55
.claude/rules/claude-learn-deployment.md
Normal file
55
.claude/rules/claude-learn-deployment.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Claude Learn: Deployment
|
||||
|
||||
**Domain**: deployment
|
||||
**Last updated**: 2026-01-06
|
||||
**Sessions recorded**: 1
|
||||
|
||||
Knowledge about IIS, Docker, deployment scripts, and infrastructure.
|
||||
|
||||
---
|
||||
|
||||
## Patterns
|
||||
|
||||
### IIS URL Rewrite Rules for SPA with Multiple API Backends
|
||||
**Discovered**: 2025-12-22 (feature: unified-app)
|
||||
**Description**: Configure IIS web.config to proxy different API paths to different backend ports while serving SPA for all other routes. Enables single IIS site to route to multiple microservices.
|
||||
|
||||
**Example** (`public/web.config:5-28`):
|
||||
```xml
|
||||
<rewrite>
|
||||
<rules>
|
||||
<rule name="Proxy Reports API" stopProcessing="true">
|
||||
<match url="^api/reports/(.*)" />
|
||||
<action type="Rewrite" url="http://localhost:8001/api/{R:1}" />
|
||||
</rule>
|
||||
<rule name="Proxy Data Entry API" stopProcessing="true">
|
||||
<match url="^api/data-entry/(.*)" />
|
||||
<action type="Rewrite" url="http://localhost:8003/api/{R:1}" />
|
||||
</rule>
|
||||
<rule name="SPA Fallback" stopProcessing="true">
|
||||
<match url=".*" />
|
||||
<conditions logicalGrouping="MatchAll">
|
||||
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
||||
</conditions>
|
||||
<action type="Rewrite" url="/index.html" />
|
||||
</rule>
|
||||
</rules>
|
||||
</rewrite>
|
||||
```
|
||||
|
||||
**Tags**: iis, deployment, spa, microservices, proxy
|
||||
|
||||
---
|
||||
|
||||
## Gotchas
|
||||
|
||||
_(None recorded yet)_
|
||||
|
||||
---
|
||||
|
||||
## Statistics
|
||||
|
||||
- **Total Patterns**: 1
|
||||
- **Total Gotchas**: 0
|
||||
- **Last Session**: 2026-01-06
|
||||
- **Sessions Recorded**: 1
|
||||
83
.claude/rules/claude-learn-domains.md
Normal file
83
.claude/rules/claude-learn-domains.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# Claude Learn Domains Configuration
|
||||
|
||||
**Last updated**: 2026-01-06
|
||||
|
||||
This file defines available knowledge domains and their file path patterns.
|
||||
|
||||
---
|
||||
|
||||
## Domains
|
||||
|
||||
### frontend
|
||||
**File**: `claude-learn-frontend.md`
|
||||
**Patterns**:
|
||||
- `src/**/*.vue`
|
||||
- `src/**/*.js`
|
||||
- `src/**/*.ts`
|
||||
- `src/**/*.css`
|
||||
- `vite.config.*`
|
||||
- `package.json`
|
||||
|
||||
---
|
||||
|
||||
### backend
|
||||
**File**: `claude-learn-backend.md`
|
||||
**Patterns**:
|
||||
- `backend/**/*.py`
|
||||
- `backend/modules/**/*`
|
||||
- `requirements.txt`
|
||||
|
||||
---
|
||||
|
||||
### database
|
||||
**File**: `claude-learn-database.md`
|
||||
**Patterns**:
|
||||
- `**/*.sql`
|
||||
- `**/models.py`
|
||||
- `**/schemas.py`
|
||||
- `backend/**/db/**/*`
|
||||
|
||||
---
|
||||
|
||||
### testing
|
||||
**File**: `claude-learn-testing.md`
|
||||
**Patterns**:
|
||||
- `tests/**/*`
|
||||
- `**/*.test.*`
|
||||
- `**/*.spec.*`
|
||||
- `pytest.ini`
|
||||
- `vitest.config.*`
|
||||
|
||||
---
|
||||
|
||||
### deployment
|
||||
**File**: `claude-learn-deployment.md`
|
||||
**Patterns**:
|
||||
- `deployment/**/*`
|
||||
- `public/web.config`
|
||||
- `Dockerfile*`
|
||||
- `docker-compose*.yml`
|
||||
- `*.sh`
|
||||
- `ansible/**/*`
|
||||
|
||||
---
|
||||
|
||||
### global
|
||||
**File**: `claude-learn-global.md`
|
||||
**Patterns**:
|
||||
- `*` (catch-all for cross-cutting concerns)
|
||||
|
||||
---
|
||||
|
||||
## Statistics
|
||||
|
||||
| Domain | Patterns | Gotchas | Last Updated |
|
||||
|--------|----------|---------|--------------|
|
||||
| frontend | 8 | 10 | 2026-01-06 |
|
||||
| deployment | 1 | 0 | 2026-01-06 |
|
||||
| global | 0 | 1 | 2026-01-06 |
|
||||
| backend | 2 | 0 | 2026-01-06 |
|
||||
| database | 0 | 0 | - |
|
||||
| testing | 0 | 0 | - |
|
||||
|
||||
**Total**: 11 patterns, 11 gotchas across 4 domains
|
||||
@@ -1,9 +1,10 @@
|
||||
# Learned Patterns & Gotchas
|
||||
# Claude Learn: Frontend
|
||||
|
||||
**Last updated**: 2025-12-24
|
||||
**Maintained**: Manually (add new patterns/gotchas as discovered)
|
||||
**Domain**: frontend
|
||||
**Last updated**: 2026-01-06
|
||||
**Sessions recorded**: 3
|
||||
|
||||
This file contains insights learned during feature implementations. Claude Code auto-loads this file to prevent repeating past mistakes.
|
||||
Knowledge about Vue.js, Vite, Pinia, CSS, and frontend architecture.
|
||||
|
||||
---
|
||||
|
||||
@@ -130,37 +131,6 @@ resolve: {
|
||||
|
||||
---
|
||||
|
||||
### IIS URL Rewrite Rules for SPA with Multiple API Backends
|
||||
**Discovered**: 2025-12-22 (feature: unified-app)
|
||||
**Description**: Configure IIS web.config to proxy different API paths to different backend ports while serving SPA for all other routes. Enables single IIS site to route to multiple microservices.
|
||||
|
||||
**Example** (`public/web.config:5-28`):
|
||||
```xml
|
||||
<rewrite>
|
||||
<rules>
|
||||
<rule name="Proxy Reports API" stopProcessing="true">
|
||||
<match url="^api/reports/(.*)" />
|
||||
<action type="Rewrite" url="http://localhost:8001/api/{R:1}" />
|
||||
</rule>
|
||||
<rule name="Proxy Data Entry API" stopProcessing="true">
|
||||
<match url="^api/data-entry/(.*)" />
|
||||
<action type="Rewrite" url="http://localhost:8003/api/{R:1}" />
|
||||
</rule>
|
||||
<rule name="SPA Fallback" stopProcessing="true">
|
||||
<match url=".*" />
|
||||
<conditions logicalGrouping="MatchAll">
|
||||
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
||||
</conditions>
|
||||
<action type="Rewrite" url="/index.html" />
|
||||
</rule>
|
||||
</rules>
|
||||
</rewrite>
|
||||
```
|
||||
|
||||
**Tags**: iis, deployment, spa, microservices, proxy
|
||||
|
||||
---
|
||||
|
||||
### Vue Watcher for Auto-Loading Dependent Data
|
||||
**Discovered**: 2025-12-24 (feature: unified-app-ux)
|
||||
**Description**: Use Vue watch() to automatically trigger data loading when dependent selections change. Watch company selection changes to auto-load accounting periods, ensuring UI stays synchronized without manual intervention.
|
||||
@@ -248,15 +218,6 @@ const getStorageKey = () => {
|
||||
|
||||
---
|
||||
|
||||
### Sed Command Quote Mismatch in Bulk Find-Replace
|
||||
**Discovered**: 2025-12-22 (feature: unified-app)
|
||||
**Problem**: Bulk sed commands using single quotes in pattern didn't match imports using double quotes, and vice versa. Commands like sed 's|from '@/stores/'|...' didn't replace from "@/stores/" lines.
|
||||
**Solution**: Always use the quote style that matches the target files. For Vue/JS files with ESLint using double quotes, use double quotes in sed patterns. Better yet: use find -exec with separate sed for each file to handle both quote styles.
|
||||
|
||||
**Tags**: sed, regex, scripting, find-replace, migration
|
||||
|
||||
---
|
||||
|
||||
### Circular Reference in API Wrapper
|
||||
**Discovered**: 2025-12-22 (feature: unified-app)
|
||||
**Problem**: receiptsStore.js failed to build with 'Identifier api has already been declared' because it imported api and then declared const api = { ... } wrapper object using the same name.
|
||||
@@ -287,7 +248,7 @@ const getStorageKey = () => {
|
||||
### Vite Build Transform Count is Progress Indicator
|
||||
**Discovered**: 2025-12-22 (feature: unified-app)
|
||||
**Problem**: Hard to tell if build is making progress when fixing import issues. Each fix revealed new errors, causing frustration.
|
||||
**Solution**: Watch the 'transforming... ✓ N modules transformed' count - it increases with each successful fix even if build ultimately fails. Going from 200→573→1490→1492 modules meant we were getting close to success. Use this as encouragement!
|
||||
**Solution**: Watch the 'transforming... N modules transformed' count - it increases with each successful fix even if build ultimately fails. Going from 200->573->1490->1492 modules meant we were getting close to success. Use this as encouragement!
|
||||
|
||||
**Tags**: vite, build, debugging, progress-tracking, developer-experience
|
||||
|
||||
@@ -329,9 +290,9 @@ const getStorageKey = () => {
|
||||
|
||||
---
|
||||
|
||||
## Memory Statistics
|
||||
## Statistics
|
||||
|
||||
- **Total Patterns**: 9
|
||||
- **Total Gotchas**: 11
|
||||
- **Last Session**: 2025-12-24 (unified-app-ux)
|
||||
- **Sessions Recorded**: 2
|
||||
- **Total Patterns**: 8
|
||||
- **Total Gotchas**: 10
|
||||
- **Last Session**: 2026-01-06
|
||||
- **Sessions Recorded**: 3
|
||||
33
.claude/rules/claude-learn-global.md
Normal file
33
.claude/rules/claude-learn-global.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Claude Learn: Global
|
||||
|
||||
**Domain**: global
|
||||
**Last updated**: 2026-01-06
|
||||
**Sessions recorded**: 1
|
||||
|
||||
Cross-cutting knowledge applicable to multiple domains (scripting, tooling, workflow).
|
||||
|
||||
---
|
||||
|
||||
## Patterns
|
||||
|
||||
_(None recorded yet)_
|
||||
|
||||
---
|
||||
|
||||
## Gotchas
|
||||
|
||||
### Sed Command Quote Mismatch in Bulk Find-Replace
|
||||
**Discovered**: 2025-12-22 (feature: unified-app)
|
||||
**Problem**: Bulk sed commands using single quotes in pattern didn't match imports using double quotes, and vice versa. Commands like sed 's|from '@/stores/'|...' didn't replace from "@/stores/" lines.
|
||||
**Solution**: Always use the quote style that matches the target files. For Vue/JS files with ESLint using double quotes, use double quotes in sed patterns. Better yet: use find -exec with separate sed for each file to handle both quote styles.
|
||||
|
||||
**Tags**: sed, regex, scripting, find-replace, migration
|
||||
|
||||
---
|
||||
|
||||
## Statistics
|
||||
|
||||
- **Total Patterns**: 0
|
||||
- **Total Gotchas**: 1
|
||||
- **Last Session**: 2026-01-06
|
||||
- **Sessions Recorded**: 1
|
||||
28
.claude/rules/claude-learn-testing.md
Normal file
28
.claude/rules/claude-learn-testing.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Claude Learn: Testing
|
||||
|
||||
**Domain**: testing
|
||||
**Last updated**: -
|
||||
**Sessions recorded**: 0
|
||||
|
||||
Knowledge about pytest, Vitest, test patterns, and validation strategies.
|
||||
|
||||
---
|
||||
|
||||
## Patterns
|
||||
|
||||
_(None recorded yet)_
|
||||
|
||||
---
|
||||
|
||||
## Gotchas
|
||||
|
||||
_(None recorded yet)_
|
||||
|
||||
---
|
||||
|
||||
## Statistics
|
||||
|
||||
- **Total Patterns**: 0
|
||||
- **Total Gotchas**: 0
|
||||
- **Last Session**: -
|
||||
- **Sessions Recorded**: 0
|
||||
Reference in New Issue
Block a user