Agency Flow · Prezentare de flux
G · Budget overlay — factură fixă, servicii ca actuals
Singurul caz care nu e un billing type. Bugetul e un overlay la nivel de client
(Client.budget, spec §1.11b): clientul primește o factură fixă = bugetul,
iar serviciile lui rulează normal, doar că devin actuals — referință pentru reconciliere,
nu sursa facturii. Un singur loc din sistem se comportă diferit: generatorul de factură.
O singură dată · la nivel de client
Setup: Billing mode = Budget, pe client
Account manager
Nu atingi niciun serviciu. În drawerul de editare al clientului comuti
Billing mode pe Budget și scrii plafonul lunar. Clientul primește
badge-ul „Budget client". Atât — restul e neschimbat.
brand = clientul (spec §1.5): billing_mode alege
strategia de asamblare a facturii, iar budget + budget_currency sunt
parametrii ei când modul e 'budget'. Nicio modificare în service sau în
tabelele de pricing — serviciile își păstrează billing type-urile lor reale.
Monthly budget e condiționat de mod —
ascuns când billing_mode = per_service, vizibil și obligatoriu când
= budget (spec §1.11b: „required when billing_mode = budget"). Altfel s-ar putea salva
un buget pe un client fără mod buget → dată moartă. Implementat în prototip: drawerul comută câmpul la
schimbarea modului (agency-flow-pages/*.html, drawer #drawer-client).
budget_currency, iar toate serviciile billabile ale clientului-buget moștenesc automat acea monedă.
La adăugarea/editarea unui serviciu sub un client-buget, service.currency e locked la
brand.budget_currency (nu e editable manual). Așa, variația de scop și net_profit rămân un singur
număr curat — consistent cu „o factură = o monedă" (§1.13) și cu „adnotează mixt, nu converti". Pentru clienți
per-service, moneda serviciilor rămâne editable independent.
În fiecare lună · neschimbat
Serviciile rulează normal — ca actuals
Serviciile (orice tip)
Fiecare serviciu al clientului își păstrează propriul billing type și-și trăiește
ciclul normal (cost_entry → ready → invoiced, snapshot-uri). Nimic nu știe că
clientul are buget. Suma valorilor lor facturabile = actual-ul lunii.
| serviciu | billing | billable value (snapshot_client_amount) |
|---|---|---|
| SEO retainer | A2 · Hourly flat | 8.000,00 |
| Content production | A1 · Fixed fee | 5.000,00 |
| Outreach placements | F1 · Supplier deliverables | 4.500,00 |
| Actual = Σ billable value | 17.500,00 | |
snapshot_client_amount al serviciilor lunii — exact suma pe care
fiecare serviciu ar fi facturat-o normal (A1 fix · A2/B ore×rată · C/E pass-through · D/F cost+fee).
Fără calcul nou — se refolosește același snapshot per serviciu.
La închiderea lunii · reconciliere
Variația de scop: buget − actual
Finance / ManagementDiferența dintre bugetul fix și actual e variația de scop (over/under-serviced) — o măsură de efort-vs-fee, nu de profitabilitate. Se ține intern, ca sold curent: o lună „under" compensează o lună „over". Clientul nu o vede niciodată.
| lună | buget (invoiced) | actual (billable) | variație | sold curent |
|---|---|---|---|---|
| iun 2024 | 20.000,00 | 21.200,00 | −1.200,00 | −1.200,00 |
| iul 2024 | 20.000,00 | 18.500,00 | +1.500,00 | +300,00 |
| aug 2024 · curent | 20.000,00 | 17.500,00 | +2.500,00 | +2.800,00 |
budget − Σ actual.
1 septembrie · batch lunar
Factura către client (AR — Accounts Receivable) — o singură linie
Finance modulul Billing — urmează
În fluxul ghidat (select clients → assets → services → generate → review → issue),
când generatorul dă de un client cu budget setat, produce o singură linie =
bugetul — nu câte o linie per serviciu. Singurul caz în care factura nu e suma serviciilor.
| linie | amount | TVA 21% | total |
|---|---|---|---|
| Northwind Retail — buget lunar · aug 2024 | 20.000,00 | 4.200,00 | 24.200,00 |
net_profit = budget − supplier_cost − labour_cost. Venitul-titlu e bugetul fix;
costurile rămân cele reale, agregate din serviciile lunii.
Cele două cifre paralele — nu se amestecă
Un client cu buget raportează mereu două numere pentru aceeași lună. În raportul de profitabilitate apar unul lângă altul, etichetate distinct (spec §1.12).
| cifră | ce e | de unde | o vede clientul? |
|---|---|---|---|
| invoiced | bugetul, o linie fixă | Client.budget | da — singura cifră |
| delivered_value | valoarea reală livrată | Σ snapshot_client_amount | nu — doar intern |
variance = budget − delivered_value se raportează separat. net_profit
e întotdeauna față de buget. A confunda cele două cifre = a rupe atât factura, cât și raportul.
Ce se schimbă în schemă — aproape nimic
Puterea cazului G e că nu cere entități noi. Trei câmpuri pe client + o strategie explicită de asamblare a facturii.
if budget IS NULL ascuns: billing_mode
e un selector de nivel-client, testabil și extensibil (un al treilea mod de asamblare ar avea unde intra).
E o strategie de factură, distinctă de billing type-ul (per-serviciu) — două niveluri diferite.
service, service_billing_period, service_cost_line,
snapshot-urile — toate neatinse. Serviciile clientului cu buget sunt indistinctibile,
la nivel de schemă, de ale oricărui alt client. Doar consumatorul (factura + raportul) le citește diferit.
budget (if budget IS NULL). Prototipul modelează deja un
toggle explicit Billing mode: Per service / Budget în toate drawerele. Direcția recomandată e
a prototipului: un enum billing_mode pe client, cu budget ca parametru —
strategia devine un lucru numit, nu o consecință a unui câmp nul.
billing_mode='budget',
client_invoice al lunii = Client.budget (constant), indiferent de
Σ snapshot_client_amount. Egalitatea dintre ele e o coincidență, nu o regulă.
Unde stă variația — derivată, nu stocată
Variația și soldul curent nu se scriu într-un tabel dedicat. Sunt un raport, exact ca
profitabilitatea: un SUM peste snapshot-uri deja înghețate (spec §1.11b — „no new computation").
snapshot_client_amount e înghețat la ready/invoiced și nu se mai mișcă —
de-aia diff-ul lunar e stabil: aceeași lună, același număr, oricând îl citești.
Diff-urile lunare le ai „pe gratis", fără stocare nouă.
sold_curent — deja e suma cumulată a diff-urilor lunare.
settlement (dată + sumă decontată), fiindcă un pur derivat nu poate reprezenta
„am decontat până în luna X, soldul repornește". Nedecis încă — până atunci: doar diff-uri lunare + sold derivat.
Simulare · buget vs. actual
interactiv · doar vizualMișcă bugetul (ce facturezi, fix) și actual-ul (ce livrezi, suma serviciilor). Vezi cum factura rămâne mereu = bugetul, iar diferența devine variația de scop (under/over-serviced) care intră în soldul curent. Nimic nu se salvează — e o schiță.
budget, mereu. variance = budget − actual:
pozitiv → under-serviced, negativ → over-serviced. Clientul vede doar bugetul.
client_invoice nu se mișcă cu actual-ul — doar cu bugetul.
Asta e toată ideea overlay-ului: o factură previzibilă pentru client, adevărul livrării ținut separat, intern.