Subledgerele vânzătorilor din marketplace: venituri versus datorii
Un ghid practic pentru separarea numerarului de la clienți, a comisionului platformei, a datoriilor către vânzători, a rezervelor și a plăților, utilizând înregistrări contabile echilibrate și un model de date de la comandă la plată.
Cea mai întâlnită greșeală în contabilitatea de marketplace este tratarea încasării brute de la cumpărător drept venit al platformei. Un client plătește 100 €, suma intră în contul procesatorului de plăți, iar cineva înregistrează totul la vânzări. Contabilitatea se balansează pentru moment, veniturile arată excelent, iar la un moment dat un auditor întreabă unde este datoria față de vânzător. Aceasta nu există, deoarece cota de 90 € a vânzătorului nu a fost niciodată înregistrată ca sumă datorată.
Soluția este una structurală, nu cosmetică. Un marketplace are nevoie de un model de registru care să separe cinci fonduri distincte încă de la prima înregistrare: numerarul clienților aflat în tranzit, venitul din comisionul platformei, datoriile către vânzători, comisioanele și rezervele. Plățile (payouts) reprezintă un al șaselea eveniment care stinge datoria, nu un eveniment de venituri sau cheltuieli în sine. Acest ghid prezintă înregistrările contabile echilibrate și modelul de date care mențin aceste fonduri separate.
Începeți cu concluzia privind calitatea de principal versus agent
Înainte ca orice structură de conturi să conteze, platforma trebuie să stabilească ce anume vinde. Conform ASC 606, acest lucru se evaluează pentru fiecare bun sau serviciu specificat, iar concluzia determină dacă veniturile sunt înregistrate la valoarea brută sau netă. O platformă poate fi principal pentru un flux și agent pentru altul.
Pentru o vânzare tipică de marketplace care implică produsele unui vânzător, platforma acționează de obicei ca agent. Aceasta facilitează livrarea produsului către cumpărător, nu își asumă riscul legat de stocuri, iar contraprestația sa este un comision. Ghidul Deloitte privind calitatea de principal versus agent conform ASC 606 plasează testul în jurul controlului: responsabilitatea pentru îndeplinirea promisiunii, riscul legat de stocuri și libertatea de stabilire a prețurilor sunt indicatori, nu o listă de verificare care anulează evaluarea de fond a controlului.
Motivul pentru care acest aspect aparține designului registrului, și nu doar unei note interne, este că respectiva concluzie generează fiecare înregistrare ulterioară. Dacă platforma este agent, cota vânzătorului reprezintă o datorie din momentul în care a fost câștigată. Dacă platforma este principal pentru un serviciu de livrare sau de garanție, acea parte constituie venit al platformei. Stocați concluzia sub formă de date:
principal_agent_rolespecified_good_or_servicecommission_rule_idcontrol_assessment_versioneffective_from/effective_to
Un revizor care analizează o linie de comision net doi ani mai târziu trebuie să poată vedea de ce nu s-a folosit valoarea brută. Așa cum subliniază BillingPlatform referitor la ASC 606 privind principalul și agentul, eticheta de „marketplace” nu tranșează chestiunea. O face analiza controlului.
Definiți soldul vânzătorului înainte de a scrie o singură regulă contabilă
„Soldul vânzătorului” nu este o singură cifră. Un vânzător poate avea un sold general favorabil și totuși nicio sumă disponibilă pentru plată, deoarece banii sunt încă în curs de clarificare sau sunt reținuți într-un fond de rezervă. Dacă anulați aceste distincții, veți raporta greșit suma pe care vânzătorul o poate retrage și suma pe care platforma încă o datorează.
Urmăriți cel puțin următoarele stări:
- În așteptare (Pending): câștigați sau colectați, dar neeligibili încă pentru plată
- Disponibili (Available): eligibili pentru plată conform regulilor platformei
- Rezervați (Reserved): reținuți în așteptarea unor retururi, contestații sau refuzuri de plată (chargebacks)
- Plătiți (Paid out): transferați sau trmiși spre decontare
- Negativi: suma pe care vânzătorul o datorează, recuperabilă din încasările viitoare
- În suspans (Suspense): primiți, dar vânzătorul sau tratamentul contabil nu a fost încă stabilit
Furnizorii de plăți modelează deja această distincție. Stripe separă fiecare cont conectat în solduri în așteptare și disponibile, și păstrează un sold de rezervă la nivelul platformei pentru anumite solduri negative ale vânzătorilor. Dacă procesatorul separă aceste sume, registrul trebuie să facă același lucru, altfel reconcilierea nu se va încheia niciodată cu succes.
Planul de conturi și dimensiunile relevante
O structură inițială funcțională menține separate conturile de decontare (clearing), datoriile și veniturile, și include o dimensiune pentru vânzător la fiecare înregistrare semnificativă.
| Scop | Cont sau dimensiune | Tratament contabil |
|---|---|---|
| Fonduri la procesator în așteptarea decontării | Decontare procesator de plăți | Activ de încasare (clearing) |
| Plată de la procesator ajunsă în bancă | Bancă | Activ |
| Sumă câștigată de vânzător, dar neplătită | Datorii către vânzători | Pasiv (Datorie) |
| Detaliu la nivel de vânzător | Dimensiunea seller_id |
Detaliu de pasiv, nu venit |
| Comisionul platformei | Venituri din comisioane | Venit |
| TVA sau taxă pe vânzări | Taxe de plată | Pasiv (Datorie) |
| Comisioanele procesatorului | Cheltuieli cu procesarea plăților | Cheltuială |
| Rezerve ale vânzătorului | Pasiv din rezerve | În funcție de contract |
| Retururi | Corectie de venituri sau retururi | Inversează tratamentul inițial |
| Refuzuri de plată (Chargebacks) | Pierdere, creanță sau recuperare de la vânzător | Depinde cine suportă pierderea |
| Plăți în așteptarea confirmării bancare | Decontare plăți către vânzători | Cont de încasare (clearing) |
| Sumă nealocată | Suspens | Excepție temporară |
Fiecare înregistrare contabilă importantă ar trebui să conțină vânzătorul, comanda, lotul de plăți, procesatorul, moneda, entitatea juridică, tratamentul fiscal, tipul de eveniment, referința externă și orice link de stornare. Fără acestea, subledgerul vânzătorilor nu poate justifica un sold individual, iar registrul general nu poate justifica totalul.
Puteți implementa subledgerul ca un cont de datorie per vânzător, un cont global de datorii cu seller_id drept dimensiune sau o divizare între datorii, rezerve și decontare plăți. Abordarea cu un cont agregat plus dimensiune scalează mai bine după ce depășiți câteva zeci de vânzători. Alegeți modelul împreună cu contabilul dumneavoastră, deoarece regulile de protecție a fondurilor și reglementările locale privind plățile pot influența modul în care trebuie prezentate aceste sume. Pentru mecanica din spatele înregistrărilor, articolul nostru despre API-urile pentru registre în partidă dublă în contabilitatea de marketplace acoperă elementele fundamentale pe care se sprijină acest model.
Înregistrați vânzarea cu linii separate pentru vânzător și platformă
Să luăm exemplul unei vânzări prin agent: clientul plătește 100 €, comisionul platformei este 10 €, vânzătorul câștigă 90 €. În momentul în care comisionul și dreptul vânzătorului sunt câștigate:
| Cont | Debit | Credit |
|---|---|---|
| Decontare procesator de plăți | 100 € | |
| Datorii către vânzători - Vânzătorul A | 90 € | |
| Venituri din comisioane | 10 € |
Controlul esențial: suma de 90 € se înregistrează în creditul unei datorii, nu ca venit. Platforma recunoaște 10 €. Acesta este rezultatul pe care exemplul de marketplace din standardul ASC 606 îl indică pentru un agent, unde platforma își recunoaște comisionul în loc de valoarea totală a vânzărilor vânzătorului.
Dacă taxa este colectată separat, adăugați linia pentru taxa de plată și reduceți suma aferentă vânzătorului sau platformei, conform concluziei fiscale. Nu includeți taxa în comision sau în datoria către vânzător doar din motive de comoditate.
Nu amestecați comisioanele procesatorului cu matematica veniturilor și a datoriilor
Trei aspecte sunt confundate în mod constant: comisionul platformei, comisionul procesatorului de plăți și suma plătită. Ele sunt diferite și afectează conturi diferite.
Clientul plătește 100 €, comisionul este 10 €, procesatorul reține 3 €.
- Venitul din comision rămâne 10 €, dacă așa prevede contractul.
- Comisionul de 3 € al procesatorului reprezintă o cheltuială.
- Datoria către vânzător este de 90 €, cu excepția cazului în care contractul specifică faptul că vânzătorul suportă comisionul de procesare. Doar în acest caz suma scade la 87 €, cu o înregistrare corespunzătoare de 3 € imputată vânzătorului.
Înregistrarea exclusivă a sumei nete de 97 € care intră în bancă șterge dintr-o singură mișcare vânzarea brută, comisionul și comisionul de procesare. Materialul nostru de referință privind reconcilierea plăților punctează același lucru: descompuneți decontarea, tratați comisioanele procesatorului drept cheltuieli și nu lăsați niciodată depozitul net să țină locul veniturilor.
Modelați disponibilitatea, rezervele și plățile ca evenimente separate
Banii își schimbă statutul de mai multe ori între încasare și decontarea finală. Fiecare tranziție merită propria înregistrare, iar o rezervă nu reprezintă niciodată o reducere neexplicată a veniturilor.
Când fondurile disponibile sunt mutate în rezervă:
| Cont | Debit | Credit |
|---|---|---|
| Datorii către vânzători - Vânzătorul A | 15 € | |
| Pasiv din rezerve pentru vânzători | 15 € |
Atunci când rezerva este eliberată, anulați această înregistrare. Obligația totală față de vânzător nu s-a schimbat, ci doar statutul ei. Stripe documentează tranzacțiile cu rezerve care cresc și eliberează fondurile de rezervă, plus transferurile de colectare pentru soldurile negative pe termen lung, motiv pentru care acestea necesită conturi identificabile în locul unei singure înregistrări de compensare netă.
Plățile au propriul tratament în doi pași. La aprobare:
| Cont | Debit | Credit |
|---|---|---|
| Datorii către vânzători - Vânzătorul A | 90 € | |
| Decontare plăți către vânzători | 90 € |
La confirmarea decontării bancare:
| Cont | Debit | Credit |
|---|---|---|
| Decontare plăți către vânzători | 90 € | |
| Bancă | 90 € |
Dacă plata eșuează, transferați suma înapoi din contul de decontare în datoria către vânzător. O plată reprezintă stingerea unei datorii, nu o cheltuială. Tratarea ei drept cheltuială dublează contorizarea față de vânzarea care a înregistrat deja datoria. Stripe separă starea plății (pending, in_transit, paid, failed, canceled) și data estimată a sosirii de momentul inițierii, iar aceste date nu trebuie comasate într-un singur marcaj temporal.
Modelul de date de la comandă la plată
Subledgerul funcționează pe baza evenimentelor, nu pe baza stării curente a comenzii în aplicație. Orice eveniment care afectează un vânzător poartă același format standard (envelope):
seller_id,event_id,order_idevent_type(sale, refund, chargeback, reserve_hold, reserve_release, payout, adjustment)effective_date,posting_datecurrency,direction,gross,commission,fees,reserverefund_ref/dispute_refpayout_batch_idreversal_ofsource_status,idempotency_key
Din aceste evenimente calculați soldul final în loc să stocați un câmp care se poate modifica:
Sold final vânzător
= sold inițial
+ credite vânzător
− debitări vânzător
− plăți efectuate
± mișcări de rezerve
± corecții
Fiecare eveniment extern are nevoie de o cheie de idempotență durabilă, astfel încât reîncercările și webhook-urile duplicate să nu crediteze sau să plătească în dublu exemplar un vânzător. Modele care funcționează:
- Eveniment în jurnalul vânzătorului:
seller_id:order_id:event_type:version - Lot de plăți:
processor:payout_id - Eveniment de la procesator:
processor:event_type:processor_event_id
Ghidul privind webhook-urile emis de Stripe avertizează că apar evenimente duplicate, prin urmare detectarea duplicatelor nu este opțională. Înregistrările validate rămân imuabile. Corecțiile se fac printr-o înregistrare de stornare urmată de o înregistrare corectată, iar propriul dumneavoastră pachet de evenimente este cel care poartă referința reversal_of și motivul. Registrul stochează înregistrările contabile, nu acea legătură: Nordlet oferă funcțiile de creare, interogare și listare pentru tranzacțiile din jurnal în documentația API și nu include funcții de actualizare sau ștergere, astfel încât o corecție reprezintă întotdeauna o tranzacție nouă, nu o editare.
Retururile și refuzurile de plată se leagă direct de tranzacție, nu plutesc izolate
Un retur care apare în plata de săptămâna viitoare nu trebuie să devină niciodată o vânzare negativă nouă atașată acelei plăți. Conectați-l la tranzacția originală și păstrați alocarea inițială către vânzător. În funcție de contract:
- Anulați comisionul dacă respectivul contract prevede că acesta este rambursabil
- Debitați datoria vânzătorului dacă acesta suportă retururile
- Debitați un cont de pierderi al platformei dacă aceasta le suportă
- Măriți o rezervă în timp ce o dispută este deschisă; eliberați-o sau utilizați-o la soluționare
Refuzurile de plată (chargebacks) survenite după efectuarea plății sunt situațiile în care apar soldurile negative. Banii vânzătorului sunt deja plecați, așa că platforma fie îi recuperează din încasările viitoare, fie absoarbe pierderea. Modelul trebuie să permită solduri negative pentru vânzători și să definească regula de recuperare. Raportarea de marketplace a celor de la Adyen arată retururi și refuzuri de plată care generează rânduri de debit separate pentru fiecare titular de cont, aceasta fiind granularitatea pe care trebuie să o urmăriți.
Reconciliați per plată, nu per lună
Descompuneți fiecare decontare a procesatorului înainte de înregistrare și reconciliați fiecare plată în parte, în loc să agregați o lună întreagă:
Încasări brute
− retururi
− comisioane procesator
− refuzuri de plată (chargebacks)
± rezerve și corecții
= plată netă de la procesator
Apoi demonstrați că patru solduri coincid pentru fiecare vânzător și monedă: subledgerul vânzătorului, soldul vânzătorului la procesator, raportul de plăți și decontarea bancară. Atunci când acestea difere, clasificați diferența (decalaj temporal, eveniment lipsă, duplicat, atribuire greșită, monedă greșită, plată eșuată, refuz de plată înregistrat în contul greșit). Compensarea automată a diferențelor este modalitatea prin care erorile se maschează reciproc și supraviețuiesc până la închiderea următoare.
Agregarea unei luni întregi permite decalajelor temporare să se anuleze reciproc și maschează discrepanțele reale. Corelarea per plată, bazată pe ID-ul plății și referința tranzacției în loc de sumă și dată, scoate la iveală aceste probleme.
Erori frecvente
| Mod de eșec | De ce dăunează | Control |
|---|---|---|
| Înregistrarea încasării brute de la client drept venit | Umflă veniturile, ascunde datoria față de vânzător | Separați datoria și comisionul în momentul obținerii |
| Înregistrarea exclusivă a depozitelor nete | Se pierd valoarea brută, comisioanele, retururile, rezervele | Descompuneți fiecare decontare |
| Înregistrarea plății drept cheltuială | Prezintă greșit stingerea unei datorii | Debitați datoria vânzătorului la efectuarea plății |
| Un singur câmp pentru soldul vânzătorului | Amestecă sumele în așteptare, disponibile, rezervate, plătite | Urmăriți stările soldului în mod explicit |
| Comision calculat la momentul plății | Veniturile urmează programul de plată | Recunoașteți comisionul în momentul câștigării |
| Rezervă tratată ca reducere de venit | Oprește vizibilitatea asupra calendarului și riscului | Urmăriți reținerea, eliberarea și utilizarea separat |
| Retur aplicat la ultima plată | Distruge atribuirea către comandă | Conectați returul la tranzacția originală |
| Editarea înregistrărilor validate | Distruge pista de audit (audit trail) | Stornați și reintroduceți |
| Webhook-uri retrimise | Credite și plăți duplicate | Chei de idempotență, detectarea duplicatelor |
| Corelare bazată doar pe sumă și dată | Elemente diferite se suprapun | Corelați după ID-ul plății, ID-ul tranzacției, vânzător, monedă |
Ce aș face prima oară
Mapați fluxul banilor înainte de a atinge planul de conturi. Notați fiecare eveniment, de la încasarea plății până la eliberarea rezervei, și marcați care dintre ele generează venituri, care creează o datorie și care doar schimbă starea fondurilor.
Apoi construiți un flux complet, de la cap la coadă, și dovediți că se echilibrează: o vânzare normală, un retur parțial, un refuz de plată survenit după plată, o rezervă reținută și eliberată, și o plată eșuată. Rulați aceste scenarii cu solduri așteptate cunoscute. Dacă contul de control pentru datoriile către vânzători este egal cu suma subledgerelor, contul de decontare al procesatorului se potrivește cu raportul de decontare, iar depozitul bancar se leagă de ID-ul plății, aveți o coloană vertebrală funcțională.
Activați blocarea perioadelor contabile doar după ce prima lună se închide corect, cu un sold în suspans egal cu zero. Blocarea prematură nu face decât să înghețe greșelile.
Nordlet înregistrează decontările urmărind aceste principii în mod nativ: comisionul platformei merge în veniturile din comisioane, cota vânzătorului în datoriile către vânzători, comisioanele procesatorului în cheltuielile de procesare a plăților, iar tot ce nu a fost încă atribuit ajunge într-un cont de suspans. Perioadele contabile rămân deschise până când le blocați în mod explicit, astfel încât prima lună poate fi închisă odată ce contul de suspans este gol. Pagina de funcționalități prezintă elementele incluse.
FAQ
Este plata cumpărătorului vreodată venit pentru platformă?
Doar pentru acele bunuri sau servicii specifice unde platforma acționează ca principal. Pentru o vânzare de marketplace în regim de agent care implică produsele unui vânzător, venitul este reprezentat de comision, iar cota vânzătorului este o datorie. O platformă poate fi principal pentru un serviciu de livrare și agent pentru bunurile de bază în cadrul aceleiași comenzi, astfel încât evaluarea se face per bun sau serviciu specific, nu la nivel de companie.
Ar trebui rezervele să reducă veniturile?
Nu. O rezervă este o alocare bazată pe riscuri și pe decalaje temporare, nu o ajustare de venituri. Mutați fondurile din datoriile către vânzători într-un pasiv din rezerve atunci când le rețineți și anulați operațiunea când le eliberați. Veniturile și comisionul nu sunt afectate de faptul că banii vânzătorului sunt reținuți în prezent.
Cum opresc plățile duplicate generate de reîncercările de webhook?
Atașați o cheie de idempotență fiecărui eveniment extern, cum ar fi processor:payout_id pentru loturile de plăți, și detectați evenimentele duplicate la scriere. Furnizorii avertizează în mod explicit că livrările duplicate de webhook-uri pot apărea, așa că registrul trebuie să respingă a doua încercare în loc să o înregistreze din nou.
Poate un sold de vânzător să devină negativ?
Da, iar modelul trebuie să permită acest lucru. Un refuz de plată (chargeback) care sosește după ce vânzătorul a fost deja plătit lasă platforma fie cu o creanță de la vânzător, fie cu o pierdere pe care o absoarbe. Suprimarea soldurilor negative nu face decât să ascundă o obligație neînregistrată.
De ce să reconciliez fiecare plată în loc de totalul lunar?
Deoarece diferențele temporare și erorile se anulează reciproc atunci când agregați o lună, astfel încât totalurile se pot potrivi în timp ce tranzacțiile individuale sunt greșite. Reconcilierea per plată, corelată pe baza ID-urilor de plată și de tranzacție, scoate la iveală evenimentele lipsă, duplicatele și refuzurile de plată atribuite greșit înainte de închiderea perioadei.