Agency Flow · Prezentare de flux
F2 · Cost/h + fee/h — orele furnizorului, nu ale echipei
Arată ca un tip „hourly", dar e supplier sadea: orele sunt ale furnizorului, nu vin
din pontaje interne. Ratele (cost/h și fee/h) se fixează la setup, specialistul introduce
lunar doar orele — de aceea F2 sare peste awaiting_fee: fee-ul e decis dinainte.
Account manager — setup
Engine — automat
Specialist — orele lunare
Finance — facturi
1
O singură dată · la vânzarea serviciului
Setup: două rate, fixate o dată
Account manager
Negocierea se întâmplă aici, nu lunar: cât ne costă ora furnizorului (100) și cât
adăugăm noi peste (50). Din momentul ăsta, singura variabilă a lunii sunt orele.
În baza de date · la Save
INSERT service + service_pricing_supplier_hourly
billing_type: 'supplier_hourly'
supplier_id: → Webify
cost_per_hour: 100.00
fee_per_hour: 50.00
2
1 august → sfârșitul lunii
Perioada așteaptă orele
Engine
Specialist
Perioada se naște cost_entry, ca la E — dar inputul e altul: orele
raportate de furnizor. La „Enter hours", strategia calculează tot lanțul din cele
două rate de setup, iar perioada trece direct ready.
Formular · Enter hours — August 2024 rol: Specialist
În baza de date · la salvare
UPDATE service_billing_period
input_supplier_hours: 26.00
snapshot_supplier_cost: 2600.00
snapshot_fee_profit: 1300.00
snapshot_client_amount: 3900.00
state: 'cost_entry' → 'ready'
whitelist: la F2 doar input_supplier_hours e scriibil.
INSERT service_cost_line · materializată
line_type: 'supplier_hours'
quantity: 26 — orele sunt cantitatea
unit_cost: 100.00
unit_fee: 50.00
client_amount: 3900.00
aceeași anatomie ca o linie F1 — doar că aici o scrie engine-ul, cu ratele din setup.
De ce nu există awaiting_fee la F2? Pentru că fee-ul nu se decide lunar — e în
contract (50/h, la setup). Ce rămâne lunar e doar o cifră factuală (orele), deci un
singur rol e de ajuns. Exact asta separă F2 de F1.
3
1 septembrie + la sosirea facturii Webify
Facturile: 3.900 în AR (Accounts Receivable), 2.600 în AP (Accounts Payable)
Finance
modulul Billing — urmează
Clientul primește o linie de 3.900 (echivalent 150/h, fără split). Webify facturează
2.600, legat de linia de cost. Istoricul lunar arată variația orelor: iulie 31 h → 4.650,
august 26 h → 3.900.
Istoricul perioadelor
| period | ore | cost (×100) | fee (×50) | client | state |
| 2024-07-01 | 31,0 | 3.100 | 1.550 | 4.650 | invoiced |
| 2024-08-01 | 26,0 | 2.600 | 1.300 | 3.900 | ready |
client_invoice · aug
3.900
26 × 150 combinat
supplier_cost
2.600
AP → linia de cost
fee_profit
1.300
50 × 26 — marjă curată
margin
33,3%
constantă prin construcție
Observație de business pe care schema o face vizibilă: la F2 marja procentuală e
constantă (50 / 150 = 33,3% indiferent de ore) — profitul absolut crește cu volumul.
La F3, procentul e fixat direct; la F1, fiecare linie are marja ei.
DB
service_billing_period — ce se scrie și ce se actualizează
F2 se naște cost_entry; la introducerea orelor furnizorului derivă tot din ratele de setup și sare DIRECT în ready (fee-ul e în contract, fără awaiting_fee).
service_billing_period · ciclul de scriere al rândului lunar
INSERT service_billing_period · la generarea perioadei
state: 'cost_entry'
input_supplier_hours: NULL — se așteaptă
input_supplier_cost: NULL — nu aparține F2
input_amount_spend: NULL — nu aparține F2
snapshot_*: NULL — toate
ready_at: NULL
invoiced_at: NULL
rândul se naște gol în afară de state — singurul input al lunii sunt orele furnizorului.
UPDATE service_billing_period · specialistul introduce orele (input + recompute)
input_supplier_hours: 26 — scris de specialist
snapshot_client_amount: 3.900 = (cost/h + fee/h) × ore
snapshot_supplier_cost: 2.600 = cost/h × ore
snapshot_fee_profit: 1.300 = fee/h × ore
snapshot_labour_cost: 0
snapshot_labour_hours: 0
snapshot_direct_profit: 0
snapshot_labour_recovery: 0
state: 'cost_entry' → 'ready'
ready_at: setat
engine-ul materializează linia supplier_hours, quantity = orele (26).
UPDATE service_billing_period · reeditare ore înainte de facturare (reset)
input_supplier_hours: valoare nouă
state: 'ready' → 'cost_entry'
ready_at: NULL
orele schimbate readuc perioada la cost_entry — trebuie reconfirmată.
UPDATE service_billing_period · la emitere
state: 'ready' → 'invoiced'
invoiced_at: setat
DB
service_cost_line — linia materializată de engine
La F2, engine-ul materializează linia la introducerea orelor. Particularitatea: quantity NU e 1 — e chiar numărul de ore, iar unit_cost/unit_fee sunt ratele de setup.
service_cost_line · linia lunii (materializată la input)
INSERT service_cost_line · la introducerea orelor (input_supplier_hours 26 → materializare)
billing_period_id: → perioada
supplier_id: → service.supplier_id
line_type: 'supplier_hours'
description: auto
quantity: 26 — ORELE, nu 1
unit_cost: = cost/h (100)
unit_fee: = fee/h (50)
supplier_cost_amount: 2.600 (= 100 × 26)
fee_amount: 1.300 (= 50 × 26)
client_amount: 3.900
state: 'ready' — oglindește perioada
position: 1
o singură linie pe lună: quantity = orele, ratele de setup stau pe unit_cost/unit_fee.
UPDATE service_cost_line · reeditare ore înainte de facturare (reset)
quantity: recalculat la noile ore
supplier_cost_amount: recalculat la noile ore
fee_amount: recalculat la noile ore
client_amount: recalculat la noile ore
state: 'ready' → 'cost_entry'
orele schimbate rescriu linia și readuc perioada la cost_entry.
UPDATE service_cost_line · la emitere
state: 'ready' → 'invoiced' (Locked)
La F2, quantity = orele furnizorului — aici e cheia, nu e 1 ca la o linie clasică.
Linia e ancora AP a facturii furnizorului pe cost (2.600), iar fee_amount (1.300)
e marja noastră adăugată peste.
Simulare · orele decid tot
interactiv · doar vizual
Exact cum funcționează F2: cele două rate se fixează o dată, la setup (cost/h și fee/h),
apoi specialistul introduce lunar doar orele furnizorului. Restul se derivă:
client = (cost/h + fee/h) × ore. Fee-ul fiind decis dinainte, perioada sare peste
awaiting_fee și trece direct în ready. Nimic nu se salvează — e o schiță.
Specialist — orele lunii
Setup · rate din contract fixate o dată
ratele nu se schimbă lunar — negocierea e la vânzarea serviciului.
Enter hours starea perioadei: cost_entry
| line_type | quantity (ore) | unit_cost |
unit_fee | client | state |
client_invoice
0
(cost/h + fee/h) × ore
supplier_cost
0
cost/h × ore — AP
net_profit
0
= fee_profit (labour 0)
Ce ilustrează: fee-ul e fix în contract (la setup) — de aceea F2 nu folosește
awaiting_fee, un singur rol lunar e de ajuns. quantity pe linia de cost
e chiar orele furnizorului, iar tot fee-ul e marjă curată: nu există cost de manoperă internă,
deci net_profit = fee_profit.