180 lines
5.3 KiB
Markdown
180 lines
5.3 KiB
Markdown
# Time Tracking - Billed Via Hub Order ID
|
|
|
|
## Oversigt
|
|
|
|
Implementeret tracking af hvilken Hub ordre (og dermed e-conomic ordre) hver tidsregistrering er blevet faktureret gennem.
|
|
|
|
## Database Ændringer
|
|
|
|
### Migration: `060_add_billed_via_thehub_id.sql`
|
|
|
|
Tilføjet nyt felt til `tmodule_times` tabellen:
|
|
|
|
```sql
|
|
ALTER TABLE tmodule_times ADD COLUMN billed_via_thehub_id INTEGER;
|
|
ALTER TABLE tmodule_times
|
|
ADD CONSTRAINT tmodule_times_billed_via_thehub_id_fkey
|
|
FOREIGN KEY (billed_via_thehub_id)
|
|
REFERENCES tmodule_orders(id)
|
|
ON DELETE SET NULL;
|
|
CREATE INDEX idx_tmodule_times_billed_via_thehub_id ON tmodule_times(billed_via_thehub_id);
|
|
```
|
|
|
|
**Felt beskrivelse:**
|
|
- `billed_via_thehub_id`: Hub ordre ID som tidsregistreringen er faktureret gennem
|
|
- Foreign key til `tmodule_orders.id`
|
|
- Via Hub ordren kan man finde `economic_order_number` som er ordrenummeret i e-conomic
|
|
|
|
## Kode Ændringer
|
|
|
|
### 1. `app/timetracking/backend/models.py`
|
|
|
|
Tilføjet felt til `TModuleTime` Pydantic model:
|
|
|
|
```python
|
|
billed_via_thehub_id: Optional[int] = Field(None, description="Hub order ID this time was billed through")
|
|
is_travel: bool = False # Også tilføjet manglende felt
|
|
```
|
|
|
|
### 2. `app/timetracking/backend/economic_export.py`
|
|
|
|
Opdateret `export_order_to_economic()` til at sætte `billed_via_thehub_id` når ordren eksporteres:
|
|
|
|
```python
|
|
# Marker time entries som billed og opdater billed_via_thehub_id
|
|
execute_update(
|
|
"""UPDATE tmodule_times
|
|
SET status = 'billed',
|
|
billed_via_thehub_id = %s
|
|
WHERE id IN (
|
|
SELECT UNNEST(time_entry_ids)
|
|
FROM tmodule_order_lines
|
|
WHERE order_id = %s
|
|
)""",
|
|
(request.order_id, request.order_id)
|
|
)
|
|
```
|
|
|
|
**Vigtig note:** vTiger opdateres også via `update_timelog_billed()` som sætter `billed_via_thehub_id` i vTiger's Timelog records.
|
|
|
|
### 3. `app/timetracking/backend/order_service.py`
|
|
|
|
**FJERNET** for tidlig status opdatering:
|
|
|
|
```python
|
|
# BEFORE: Time entries blev sat til 'billed' når Hub ordre blev oprettet
|
|
# AFTER: Time entries forbliver 'approved' indtil e-conomic eksporten er succesfuld
|
|
```
|
|
|
|
Nu opdateres `status='billed'` og `billed_via_thehub_id` KUN i `economic_export.py` efter succesfuld eksport.
|
|
|
|
### 4. `app/timetracking/backend/vtiger_sync.py`
|
|
|
|
**BESKYTTELSE MOD OVERSKRIVNING:** Tidsregistreringer med `billed_via_thehub_id` opdateres IKKE ved sync:
|
|
|
|
```python
|
|
# Update only if NOT yet approved AND NOT yet billed
|
|
result = execute_update(
|
|
"""UPDATE tmodule_times
|
|
SET description = %s, original_hours = %s, worked_date = %s,
|
|
user_name = %s, billable = %s, vtiger_data = %s::jsonb,
|
|
sync_hash = %s, last_synced_at = CURRENT_TIMESTAMP
|
|
WHERE vtiger_id = %s
|
|
AND status = 'pending'
|
|
AND billed_via_thehub_id IS NULL""",
|
|
...
|
|
)
|
|
```
|
|
|
|
Dette sikrer at allerede fakturerede tidsregistreringer forbliver låst og ikke overskrevet af vTiger sync.
|
|
|
|
## Workflow
|
|
|
|
### Før ændringerne:
|
|
1. Godkendte tider → `status='approved'`
|
|
2. **Opret ordre** i Hub → `status='billed'` ⚠️ (for tidligt!)
|
|
3. Eksporter til e-conomic → `economic_order_number` sættes på Hub ordre
|
|
|
|
### Efter ændringerne:
|
|
1. Godkendte tider → `status='approved'`
|
|
2. **Opret ordre** i Hub → tider forbliver `status='approved'`
|
|
3. **Eksporter til e-conomic** → `status='billed'` + `billed_via_thehub_id` sættes
|
|
4. vTiger opdateres også med `billed_via_thehub_id`
|
|
|
|
## Data Relations
|
|
|
|
```
|
|
tmodule_times.billed_via_thehub_id
|
|
↓ (foreign key)
|
|
tmodule_orders.id
|
|
→ tmodule_orders.economic_order_number (e-conomic ordre nummer)
|
|
→ tmodule_orders.economic_draft_id (e-conomic kladde ID)
|
|
```
|
|
|
|
## Queries
|
|
|
|
### Find alle tidsregistreringer for en e-conomic ordre:
|
|
|
|
```sql
|
|
SELECT t.*, o.economic_order_number
|
|
FROM tmodule_times t
|
|
JOIN tmodule_orders o ON t.billed_via_thehub_id = o.id
|
|
WHERE o.economic_order_number = '12345';
|
|
```
|
|
|
|
### Find tider der er faktureret via en specifik Hub ordre:
|
|
|
|
```sql
|
|
SELECT * FROM tmodule_times
|
|
WHERE billed_via_thehub_id = 123;
|
|
```
|
|
|
|
### Find tider der IKKE er faktureret endnu:
|
|
|
|
```sql
|
|
SELECT * FROM tmodule_times
|
|
WHERE status = 'approved'
|
|
AND billed_via_thehub_id IS NULL;
|
|
```
|
|
|
|
## vTiger Integration
|
|
|
|
vTiger's `Timelog` records opdateres også via `app/timetracking/backend/vtiger_sync.py`:
|
|
|
|
```python
|
|
async def update_timelog_billed(self, vtiger_ids: List[str], hub_order_id: int):
|
|
payload = {
|
|
"elementType": "Timelog",
|
|
"element": {
|
|
"id": vtiger_id,
|
|
"billed_via_thehub_id": str(hub_order_id),
|
|
"cf_timelog_invoiced": "1"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Note:** `cf_timelog_invoiced` (IS BILLED) feltet i vTiger kan vi IKKE ændre fra Hub (vTiger begrænsning), men vi opdaterer vores eget `billed_via_thehub_id` felt.
|
|
|
|
## Testing
|
|
|
|
Migrationen er kørt og verificeret:
|
|
```bash
|
|
docker exec bmc-hub-postgres psql -U bmc_hub -d bmc_hub -c "\d tmodule_times"
|
|
# Viser: billed_via_thehub_id | integer med foreign key
|
|
```
|
|
|
|
## Deployment
|
|
|
|
1. Migration er kørt på dev (060_add_billed_via_thehub_id.sql)
|
|
2. Kode ændringer deployed i samme commit
|
|
3. Eksisterende tidsregistreringer har `billed_via_thehub_id = NULL`
|
|
4. Fremtidige eksporter vil populere feltet korrekt
|
|
|
|
## Relaterede Filer
|
|
|
|
- `migrations/060_add_billed_via_thehub_id.sql`
|
|
- `app/timetracking/backend/models.py`
|
|
- `app/timetracking/backend/economic_export.py`
|
|
- `app/timetracking/backend/order_service.py`
|
|
- `app/timetracking/backend/vtiger_sync.py`
|