Agency Flow · Prezentare de flux

A2 · Hourly flat — factura crește cu fiecare pontaj

Ca A1, dar cu o răsturnare: factura însăși e variabilă — o singură rată pe serviciu, înmulțită cu toate orele lunii. De aceea perioada A2 nu se poate naște ready: suma finală se află abia când luna se închide.

Account manager — setup Engine — automat Echipa — pontaje Finance — facturare
1

O singură dată · la vânzarea serviciului

Setup: o rată, nu o sumă

Account manager

Diferența față de A1 e un singur câmp: în loc de sumă fixă, o rată orară facturată — una singură pe serviciu, nu per persoană și nu per task (decizie de spec v6: rata a urcat de pe task pe serviciu). Costul intern rămâne per angajat, din payroll.

Drawer · New service
Made by society RO — Website · madebysociety.ro
client derivat din asset
Linkbuilding
grup derivat: SEO
Hourly — flat rate (A2)
150 RON/h — una pe serviciu
40 h / mo — estimare, nu cap
nume compus → Made by society RO — SEO — Linkbuilding
În baza de date · la Save
INSERT service
billing_type: 'hourly_flat' supplier_id: NULL status: 'active'
INSERT service_pricing_hourly_flat
billed_rate: 150.00 planning_hours: 40.00
2

1 august · automat

Luna se deschide — dar nu îngheață nimic

Engine

Aici A2 se desparte de A1: factura depinde de orele care abia urmează, deci perioada se naște cost_entry (acumulare), cu ready_at NULL. Sumele de pe rând sunt valori curente, nu snapshot-uri finale — se rescriu la fiecare pontaj.

În baza de date
INSERT service_billing_period
period: 2024-08-01 state: 'cost_entry' ready_at: NULL — orele nu-s finale snapshot_client_amount: 0.00 snapshot_labour_cost: 0.00
De ce nu ready, ca A1? ready_at înseamnă „sumele facturabile sunt înghețate". La A1 suma e o constantă din setup — poate îngheța din ziua 1. La A2 suma e rată × orele lunii, iar orele există abia la final. Stare = câtă încredere ai în cifre, nu câtă muncă ai depus.
3

Pe parcursul lui august

Fiecare pontaj mișcă ambele talere

Echipa task & time_entry — pasul următor de implementare

La A1, pontajul mișca doar costul. La A2 mișcă și factura, și costul: orele intră în client_amount cu rata serviciului (150) și în labour_cost cu costul per angajat din payroll. Marja pe oră diferă per om — de-asta cele două coloane evoluează diferit.

Time entries · august
angajattaskorefacturat @150cost/h interncost
Ana — SEO LeadOutreach parteneri30,04.5001003.000
Radu — SEO JuniorProspectare linkuri12,01.80080960
total august (planificat: 40 h)42,06.3003.960
În baza de date · după fiecare pontaj
UPDATE service_billing_period · 2024-08
snapshot_client_amount: 0 → 4.500 → 6.300 snapshot_labour_cost: 0 → 3.000 → 3.960
strategia recalculează ambele primitive la fiecare pontaj — permis, pentru că ready_at e NULL.
GENERATED DB-ul urmează automat
snapshot_net_profit: 0 → 1.500 → 2.340
Calculul · HourlyFlatStrategy
ƒ
HourlyFlatStrategy::calculate(ctx) → BillingBreakdown {
  clientInvoice: 150 × ctx.hours,  // 150 × 42 = 6.300
  supplierCost: 0, labourCost: ctx.labour  // 3.960 din payroll
}
4

31 august → 1 septembrie

Închiderea lunii, apoi factura

Finance modulul Billing — urmează

La închiderea lunii orele sunt declarate finale: perioada trece ready și cele 6.300 îngheață. Fluxul de facturare o preia ca pe orice altă perioadă ready — de aici încolo A2 e identic cu A1.

În baza de date · închidere + issue
UPDATE service_billing_period · închiderea lunii
state: 'cost_entry' → 'ready' ready_at: 2024-09-01 06:00
de acum, un pontaj pe august nu mai poate schimba factura — doar labour-ul, până la invoiced_at.
INSERT client_invoice_line · DR-2024-0132
description: MBS RO — SEO — Linkbuilding · aug (42 h) amount: 6300.00 + TVA 21%: 1.323 → total 7.623
UPDATE service_billing_period · la Issue
state: 'ready' → 'invoiced' invoiced_at: 2024-09-01 10:14
5

Oricând după aceea

Rezultatul lunii

Engine
client_invoice
6.300
42 h × 150 · înghețat la ready
labour_cost
3.960
per angajat, din payroll
net_profit
2.340
calculat de DB
margin
37,1%
doar ratio de afișare
Estimarea de planificare (40 h) nu limitează nimic — s-au lucrat 42 h și toate s-au facturat. Dacă vrei ore incluse + tarif de depășire, acela e B · hourly tiered, fluxul următor.
DB

service_billing_period — ce se scrie și ce se actualizează

A2 se naște cost_entry și se umple pe măsură ce se pontează; factura = rate × ore, finală abia la închiderea lunii (ready).

service_billing_period · ciclul de scriere al rândului lunar
INSERT service_billing_period · la generare
state: 'cost_entry' input_supplier_cost: NULL input_supplier_hours: NULL input_amount_spend: NULL snapshot_client_amount: NULL snapshot_labour_cost: NULL snapshot_labour_hours: NULL ready_at: NULL invoiced_at: NULL
A2 nu folosește inputuri de perioadă — coloanele input_* rămân NULL; toate snapshot_* sunt încă necalculate.
UPDATE service_billing_period · la fiecare pontaj (recompute cât ready_at IS NULL)
snapshot_client_amount: = billed_rate × Σ ore snapshot_labour_cost: Σ ore × cost/h snapshot_labour_hours: Σ ore snapshot_supplier_cost: 0 snapshot_direct_profit: 0 snapshot_fee_profit: 0 snapshot_labour_recovery: 0 snapshot_net_profit: DB
cât ready_at e NULL, strategia rescrie snapshot-urile la fiecare pontaj; net_profit e coloană generată de DB.
UPDATE service_billing_period · la închiderea lunii
state: 'cost_entry' → 'ready' ready_at: setat
îngheață client_amount + supplier + bucket-urile; orele sunt declarate finale pentru facturare.
UPDATE service_billing_period · la emitere
state: 'ready' → 'invoiced' invoiced_at: setat
îngheață labour_cost + labour_hours. Între ready și invoiced labour-ul (cost + hours) încă se recalculează la pontaje întârziate; client_amount e deja înghețat.
DB

service_cost_line — niciuna la acest tip

A1/A2/B sunt labor pur (supplier_id NULL, impus de CHECK) — nu există cost de furnizor, deci zero linii în service_cost_line. Rândul lunar din service_billing_period e singura evidență: factura clientului + profitabilitatea din pontaje.

Contrast: la C–Platform engine-ul materializează o linie de cost (ancora AP (Accounts Payable) a facturii furnizorului); la F1 liniile sunt introduse de oameni, una per livrabil. Aici nu e cazul — nu ai către cine să emiți o factură de furnizor.

Simulare · pontează tu luna

interactiv · doar vizual

Exact cum funcționează A2: o singură rată pe serviciu, înmulțită cu toate orele lunii. Echipa adaugă pontaje (ore + cost intern/h) și factura crește cu fiecare oră — spre deosebire de A1, unde suma e fixă din setup. Finance închide luna (ready) și abia atunci suma îngheață, apoi emite. Nimic nu se salvează — e o schiță.

Echipa — pontaje (ore, cost/h) Finance — închide luna & emite
Setup · rata serviciului rol: Account manager
una singură pe serviciu — nu per angajat, nu per task
Add pontaj rol: Echipa
rata facturată e a serviciului — aici doar orele și costul intern
Pontaje · august starea perioadei: cost_entry
angajatorecost/h cost linieacțiune
total august 0 0
ore_total
0
Σ ore pontate
client_invoice
0
rată × ore_total
labour_cost
0
Σ ore × cost/h
net_profit
0
client − labour
Ce ilustrează: o singură rată pe serviciu — nu per angajat, nu per task; factura crește cu fiecare oră pontată, spre deosebire de A1 unde suma e fixă din setup; și e finală abia la închiderea lunii (→ ready). Cât perioada e cost_entry, orice pontaj nou rescrie ambele coloane; după invoiced, luna e blocată.