Loading...
Loading...
Loading...
**Type:** Accounting-Grade Analytics Engine with Incremental Aggregation
# π DRE ANALYTICS (Financial Statement - Multi-Tenant, Multi-Currency)
**Version:** v1.0
**Type:** Accounting-Grade Analytics Engine with Incremental Aggregation
**Scope:** MRR/ARR, Churn, Revenue Recognition (Accrual vs Cash), Chargebacks
**Compliance:** IFRS 15 (Revenue Recognition), Brazilian GAAP, SOX
**Status:** Production Ready
**Last Updated:** 2026-02-03
---
## π TABLE OF CONTENTS
1. [Overview](#overview)
2. [Financial Model](#financial-model)
3. [Data Model (Read Models)](#data-model-read-models)
4. [Incremental Aggregation Jobs](#incremental-aggregation-jobs)
5. [Revenue Recognition (Accrual)](#revenue-recognition-accrual)
6. [Correction & Rebuild Strategy](#correction--rebuild-strategy)
7. [DRE Calculation Logic](#dre-calculation-logic)
8. [Analytics API](#analytics-api)
9. [Edge Cases & Examples](#edge-cases--examples)
10. [Production Checklist](#production-checklist)
---
## π― OVERVIEW
### Problem Statement
```
Without integrated DRE:
ββ Finance manually exports payments to spreadsheet
ββ Lacks revenue recognition (cash vs accrual)
ββ Can't track churn or cohort metrics
ββ Chargebacks buried in raw data
ββ Corrections require full recalculation
ββ No audit trail of calculations
With integrated DRE:
ββ Real-time MRR/ARR by tenant/client
ββ Revenue recognition (IFRS 15 compliant)
ββ Automatic churn calculation
ββ Chargeback tracking separate
ββ Incremental updates (only changed periods)
ββ Full audit trail + rebuild capability
ββ Multi-currency support (BRL, USD, EUR)
```
### Key Metrics
```
MRR (Monthly Recurring Revenue)
ββ Sum of active subscriptions @ start of month
ββ Formula: Ξ£(subscription_amount) where status=active
ββ Updates on: subscription_created, subscription_changed, subscription_canceled
ARR (Annual Recurring Revenue)
ββ MRR * 12
ββ Annualized projection
ββ Used for valuation
Churn Rate
ββ Canceled subscriptions / Total active subscriptions
ββ Formula: canceled_count / (active_count + canceled_count)
ββ Measured monthly/quarterly/annually
Revenue (Accrual)
ββ Recognized revenue based on service delivery (not payment)
ββ For 12-month subscription: recognize 1/12 per month
ββ Formula: invoice_amount / subscription_term_months
ββ More accurate than cash basis
Revenue (Cash Basis)
ββ Recognized when payment received
ββ Useful for cash flow analysis
ββ Different from accrual
InadimplΓͺncia (Delinquency)
ββ Invoices past due + unpaid
ββ Formula: unpaid_invoices > due_date
ββ Monitored for dunning/collection
Chargeback Rate
ββ Chargebacks / Total payments
ββ Formula: chargeback_count / total_payment_count
ββ Risk indicator
```
---
## π° FINANCIAL MODEL
### Chart of Accounts (Simplified)
```
4000 - RECEITAS
ββ 4100 - Receita de ServiΓ§os
β ββ 4101 - Receita de Assinatura (Plan A)
β ββ 4102 - Receita de Assinatura (Plan B)
β ββ 4103 - Receita de Assinatura (Plan C)
ββ 4200 - DeduΓ§Γ΅es de Receita
β ββ 4210 - DevoluΓ§Γ΅es
β ββ 4220 - Cancelamentos
ββ 4300 - Outros
ββ 4310 - Receita de Setup
ββ 4320 - Receita de API Usage
5000 - CUSTOS DE SERVIΓOS
ββ 5100 - Custos de Gateway
β ββ 5101 - Taxa Stripe (2.9% + 0.30)
β ββ 5102 - Taxa MercadoPago (2.99% + 0.49)
β ββ 5103 - Taxa Pagar.me (2.94%)
ββ 5200 - Chargebacks
β ββ 5210 - Custos de Chargeback (15 USD)
ββ 5300 - DevoluΓ§Γ΅es
ββ 5310 - Custo de Refund
6000 - DESPESAS
ββ 6100 - Despesas com Pessoal
ββ 6200 - Despesas com Tecnologia
ββ 6300 - Despesas Administrativas
```
### Account Structure for Multi-Tenant
```
Each tenant has its own Chart of Accounts:
tenant-123:
ββ 4101 - Receita Assinatura Plan A
ββ 5101 - Taxa Gateway
ββ 5210 - Custo Chargeback
tenant-456:
ββ 4101 - Receita Assinatura Plan A
ββ 5101 - Taxa Gateway
ββ 5210 - Custo Chargeback
Each independent + can cross-report for corporate reporting
```
---
## ποΈ DATA MODEL (READ MODELS)
### Table 1: subscription_aggregates (Monthly Snapshots)
```sql
CREATE TABLE subscription_aggregates (
agg_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
client_id UUID, -- NULL = all clients
-- Period
period_year INT NOT NULL,
period_month INT NOT NULL,
period_start DATE NOT NULL,
period_end DATE NOT NULL,
-- MRR Calculation (at start of month)
mrr_active_subscriptions INT DEFAULT 0, -- Count of active subs
mrr_total_amount DECIMAL(19, 4) DEFAULT 0, -- Sum of MRR
mrr_currency VARCHAR(3) DEFAULT 'BRL',
-- Subscriptions created/canceled during month
new_subscriptions INT DEFAULT 0,
new_mrr DECIMAL(19, 4) DEFAULT 0, -- MRR from new subs
canceled_subscriptions INT DEFAULT 0,
churned_mrr DECIMAL(19, 4) DEFAULT 0, -- MRR lost from cancellations
-- Churn rate
churn_rate DECIMAL(5, 4) DEFAULT 0, -- 0.05 = 5%
-- Delinquency
delinquent_count INT DEFAULT 0, -- Unpaid invoices
delinquent_mrr DECIMAL(19, 4) DEFAULT 0, -- MRR at risk
-- Status
is_finalized BOOLEAN DEFAULT FALSE, -- Can't change after finalized
-- Audit
calculated_at TIMESTAMP DEFAULT NOW(),
recalculated_at TIMESTAMP,
UNIQUE (tenant_id, period_year, period_month, client_id),
CONSTRAINT valid_month CHECK (period_month BETWEEN 1 AND 12),
FOREIGN KEY (tenant_id) REFERENCES tenants(id),
FOREIGN KEY (client_id) REFERENCES companies(id)
);
CREATE INDEX idx_sub_agg_tenant_period
ON subscription_aggregates(tenant_id, period_year, period_month);
CREATE INDEX idx_sub_agg_client_period
ON subscription_aggregates(client_id, period_year, period_month);
```
### Table 2: revenue_recognition (Accrual Basis)
```sql
CREATE TABLE revenue_recognition (
rec_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
invoice_id UUID NOT NULL,
subscription_id UUID,
-- Period
period_year INT NOT NULL,
period_month INT NOT NULL,
-- Recognition details
total_invoice_amount DECIMAL(19, 4),
subscription_term_months INT, -- 1, 3, 12, etc
monthly_recognition DECIMAL(19, 4), -- Amount recognized this month
-- Recognition basis
recognition_method VARCHAR(50), -- 'straight_line', 'performance'
-- Accrual vs Cash
payment_received_amount DECIMAL(19, 4) DEFAULT 0, -- Cash received this period
payment_received_date TIMESTAMP,
-- Account mapping
credit_account VARCHAR(20), -- 4101, 4102, etc
debit_account VARCHAR(20), -- Bank account, receivable
-- Status
is_deferred BOOLEAN, -- If advance payment (deferred revenue)
-- Audit
recognized_at TIMESTAMP DEFAULT NOW(),
UNIQUE (tenant_id, invoice_id, period_year, period_month),
FOREIGN KEY (tenant_id) REFERENCES tenants(id),
FOREIGN KEY (invoice_id) REFERENCES invoices(id)
);
CREATE INDEX idx_rev_rec_tenant_period
ON revenue_recognition(tenant_id, period_year, period_month);
CREATE INDEX idx_rev_rec_invoice
ON revenue_recognition(invoice_id);
```
### Table 3: gateway_costs (Costs Aggregation)
```sql
CREATE TABLE gateway_costs (
cost_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
payment_id UUID, -- Link to payment
-- Period
period_year INT NOT NULL,
period_month INT NOT NULL,
-- Cost details
cost_type VARCHAR(50), -- 'gateway_fee', 'chargeback', 'refund'
gateway VARCHAR(50), -- 'stripe', 'mercadopago', 'pagarme'
-- Amount
transaction_amount DECIMAL(19, 4), -- Amount of transaction
cost_percentage DECIMAL(5, 4), -- 2.9% = 0.029
cost_fixed DECIMAL(19, 4), -- Fixed component (ex: 0.30)
total_cost DECIMAL(19, 4), -- cost_percentage * amount + cost_fixed
-- Account mapping
charge_account VARCHAR(20), -- 5101, 5102, etc
-- Status
is_finalized BOOLEAN DEFAULT FALSE,
-- Audit
calculated_at TIMESTAMP DEFAULT NOW(),
FOREIGN KEY (tenant_id) REFERENCES tenants(id),
FOREIGN KEY (payment_id) REFERENCES payments(id)
);
CREATE INDEX idx_gateway_costs_period
ON gateway_costs(tenant_id, period_year, period_month);
CREATE INDEX idx_gateway_costs_payment
ON gateway_costs(payment_id);
```
### Table 4: chargeback_costs
```sql
CREATE TABLE chargeback_costs (
cb_cost_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
payment_id UUID NOT NULL,
-- Period
period_year INT NOT NULL,
period_month INT NOT NULL,
-- Chargeback details
original_amount DECIMAL(19, 4),
chargeback_amount DECIMAL(19, 4), -- Usually = original amount
chargeback_fee DECIMAL(19, 4) DEFAULT 15, -- Fixed fee ($15 USD)
total_cost DECIMAL(19, 4), -- Amount + fee
-- Account mapping
charge_account VARCHAR(20) DEFAULT '5210', -- Chargeback costs
-- Status
is_finalized BOOLEAN DEFAULT FALSE,
-- Audit
recorded_at TIMESTAMP DEFAULT NOW(),
FOREIGN KEY (tenant_id) REFERENCES tenants(id),
FOREIGN KEY (payment_id) REFERENCES payments(id)
);
CREATE INDEX idx_chargeback_costs_period
ON chargeback_costs(tenant_id, period_year, period_month);
```
### Table 5: dre_monthly (Consolidated P&L)
```sql
CREATE TABLE dre_monthly (
dre_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
client_id UUID, -- NULL = consolidated
-- Period
period_year INT NOT NULL,
period_month INT NOT NULL,
period_start DATE NOT NULL,
period_end DATE NOT NULL,
-- RECEITAS (Revenue)
revenue_accrual DECIMAL(19, 4) DEFAULT 0, -- IFRS 15 recognized
revenue_cash DECIMAL(19, 4) DEFAULT 0, -- Actually received
deductions_refund DECIMAL(19, 4) DEFAULT 0, -- Refunds
net_revenue DECIMAL(19, 4) DEFAULT 0, -- Revenue - deductions
-- CUSTOS DE SERVIΓOS (COGS)
cogs_gateway_fees DECIMAL(19, 4) DEFAULT 0, -- Payment processor fees
cogs_chargebacks DECIMAL(19, 4) DEFAULT 0, -- Chargeback costs
cogs_refunds DECIMAL(19, 4) DEFAULT 0, -- Refund costs
total_cogs DECIMAL(19, 4) DEFAULT 0,
-- EBITDA / Gross Margin
gross_profit DECIMAL(19, 4) DEFAULT 0, -- Net revenue - COGS
gross_margin_pct DECIMAL(5, 4) DEFAULT 0, -- gross_profit / net_revenue
-- DESPESAS OPERACIONAIS (OpEx) - TODO: integrate with HR/ops systems
opex_payroll DECIMAL(19, 4) DEFAULT 0,
opex_technology DECIMAL(19, 4) DEFAULT 0,
opex_other DECIMAL(19, 4) DEFAULT 0,
total_opex DECIMAL(19, 4) DEFAULT 0,
-- RESULTADO (Result)
operating_income DECIMAL(19, 4) DEFAULT 0, -- Gross profit - OpEx
-- Metrics
mrr DECIMAL(19, 4) DEFAULT 0,
arr DECIMAL(19, 4) DEFAULT 0,
churn_rate DECIMAL(5, 4) DEFAULT 0,
cogs_percentage DECIMAL(5, 4) DEFAULT 0, -- COGS / Revenue
-- Status
is_finalized BOOLEAN DEFAULT FALSE, -- Locked for correction
-- Audit
calculated_at TIMESTAMP DEFAULT NOW(),
recalculated_count INT DEFAULT 0,
UNIQUE (tenant_id, period_year, period_month, client_id),
CONSTRAINT valid_month CHECK (period_month BETWEEN 1 AND 12),
FOREIGN KEY (tenant_id) REFERENCES tenants(id),
FOREIGN KEY (client_id) REFERENCES companies(id)
);
CREATE INDEX idx_dre_tenant_period
ON dre_monthly(tenant_id, period_year, period_month);
CREATE INDEX idx_dre_client_period
ON dre_monthly(client_id, period_year, period_month);
```
### Table 6: dre_calculation_log (Audit Trail)
```sql
CREATE TABLE dre_calculation_log (
log_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
-- Calculation details
calculation_type VARCHAR(50), -- 'incremental', 'rebuild', 'correction'
period_year INT,
period_month INT,
-- What changed
rows_created INT DEFAULT 0,
rows_updated INT DEFAULT 0,
rows_deleted INT DEFAULT 0,
-- Changes
old_revenue DECIMAL(19, 4),
new_revenue DECIMAL(19, 4),
old_cogs DECIMAL(19, 4),
new_cogs DECIMAL(19, 4),
-- Reason for recalculation
trigger_reason VARCHAR(255), -- 'payment_refunded', 'chargeback_received', 'manual_correction'
triggered_by_user_id UUID, -- If manual
triggered_by_event_id UUID, -- If automatic
-- Execution
started_at TIMESTAMP DEFAULT NOW(),
completed_at TIMESTAMP,
duration_ms INT,
-- Status
status VARCHAR(50), -- SUCCESS, FAILED, PARTIAL
error_message TEXT,
FOREIGN KEY (tenant_id) REFERENCES tenants(id)
);
CREATE INDEX idx_dre_log_tenant_period
ON dre_calculation_log(tenant_id, period_year, period_month, calculation_type);
```
### Table 7: revenue_deferred_liability (Deferred Revenue)
```sql
CREATE TABLE revenue_deferred_liability (
defer_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
invoice_id UUID NOT NULL,
-- Deferred details
received_date DATE NOT NULL,
received_amount DECIMAL(19, 4) NOT NULL, -- Full amount received upfront
-- Recognition schedule
start_recognition_date DATE NOT NULL,
end_recognition_date DATE NOT NULL,
subscription_term_months INT,
-- Monthly recognition
monthly_recognition_amount DECIMAL(19, 4),
-- Periods remaining
periods_remaining INT,
-- Balance tracking
total_recognized DECIMAL(19, 4) DEFAULT 0, -- Amount recognized so far
balance DECIMAL(19, 4), -- Remaining liability
-- Status
is_fully_recognized BOOLEAN DEFAULT FALSE,
-- Audit
created_at TIMESTAMP DEFAULT NOW(),
FOREIGN KEY (tenant_id) REFERENCES tenants(id),
FOREIGN KEY (invoice_id) REFERENCES invoices(id)
);
CREATE INDEX idx_deferred_tenant_pending
ON revenue_deferred_liability(tenant_id, is_fully_recognized)
WHERE NOT is_fully_recognized;
```
---
## π INCREMENTAL AGGREGATION JOBS
### Job 1: MRR Calculation (Monthly at 2 AM)
```python
class MRRCalculationJob:
"""
Calculate MRR for each tenant/client at start of month
Uses subscription state at period start
"""
def __init__(self, db, logger):
self.db = db
self.logger = logger
def run(self, year: int, month: int):
"""
Run MRR calculation for specific month
"""
period_start = date(year, month, 1)
if month == 12:
period_end = date(year + 1, 1, 1) - timedelta(days=1)
else:
period_end = date(year, month + 1, 1) - timedelta(days=1)
self.logger.info(f"Starting MRR calculation for {year}-{month:02d}")
# 1. Get all tenants
tenants = self.db.query("SELECT id FROM tenants WHERE is_active = TRUE")
for tenant in tenants:
tenant_id = tenant['id']
try:
# 2. Calculate MRR for entire tenant
self._calculate_tenant_mrr(tenant_id, period_start, period_end, year, month)
# 3. Calculate MRR by client (optional breakdown)
clients = self.db.query("""
SELECT DISTINCT company_id FROM subscriptions
WHERE tenant_id = %s
""", [tenant_id])
for client in clients:
client_id = client['company_id']
self._calculate_client_mrr(
tenant_id, client_id, period_start, period_end, year, month
)
except Exception as e:
self.logger.error(f"MRR calculation failed for {tenant_id}: {str(e)}")
self.db.insert('dre_calculation_log', {
'tenant_id': tenant_id,
'calculation_type': 'mrr',
'period_year': year,
'period_month': month,
'status': 'FAILED',
'error_message': str(e)
})
def _calculate_tenant_mrr(self, tenant_id: str, period_start: date, period_end: date, year: int, month: int):
"""
Calculate consolidated MRR for tenant
"""
# MRR = Sum of subscription amounts active at start of month
query = """
SELECT
COUNT(*) as active_count,
SUM(monthly_amount) as total_mrr,
currency
FROM subscriptions
WHERE tenant_id = %s
AND status = 'ACTIVE'
AND (start_date <= %s)
AND (end_date IS NULL OR end_date > %s)
GROUP BY currency
"""
results = self.db.query(query, [tenant_id, period_start, period_end])
# Create/update aggregates for each currency
for result in results:
# New subscriptions during month
new_subs = self.db.query("""
SELECT COUNT(*) as count, SUM(monthly_amount) as mrr
FROM subscriptions
WHERE tenant_id = %s
AND status = 'ACTIVE'
AND start_date BETWEEN %s AND %s
""", [tenant_id, period_start, period_end])[0]
# Canceled subscriptions during month
canceled_subs = self.db.query("""
SELECT COUNT(*) as count, SUM(monthly_amount) as mrr
FROM subscriptions
WHERE tenant_id = %s
AND (status = 'CANCELED' OR status = 'CHURNED')
AND end_date BETWEEN %s AND %s
""", [tenant_id, period_start, period_end])[0]
# Delinquent subscriptions (invoices unpaid + overdue)
delinquent = self.db.query("""
SELECT COUNT(DISTINCT s.subscription_id) as count, SUM(s.monthly_amount) as mrr
FROM subscriptions s
LEFT JOIN invoices i ON s.subscription_id = (
SELECT subscription_id FROM invoice_items
WHERE invoice_id = i.invoice_id LIMIT 1
)
WHERE s.tenant_id = %s
AND s.status = 'ACTIVE'
AND i.status = 'AWAITING_PAYMENT'
AND i.due_date < %s
""", [tenant_id, period_start])[0]
# Calculate churn rate
active_count = result['active_count']
canceled_count = canceled_subs['count'] or 0
churn_rate = canceled_count / (active_count + canceled_count) if (active_count + canceled_count) > 0 else 0
# Insert/update aggregate
self.db.upsert('subscription_aggregates', {
'tenant_id': tenant_id,
'client_id': None,
'period_year': year,
'period_month': month,
'period_start': period_start,
'period_end': period_end,
'mrr_active_subscriptions': result['active_count'],
'mrr_total_amount': result['total_mrr'],
'mrr_currency': result['currency'],
'new_subscriptions': new_subs['count'] or 0,
'new_mrr': new_subs['mrr'] or 0,
'canceled_subscriptions': canceled_count,
'churned_mrr': canceled_subs['mrr'] or 0,
'churn_rate': churn_rate,
'delinquent_count': delinquent['count'] or 0,
'delinquent_mrr': delinquent['mrr'] or 0,
'calculated_at': datetime.utcnow()
}, {
'tenant_id': tenant_id,
'period_year': year,
'period_month': month,
'client_id': None
})
self.logger.info(f"β MRR calculated: {tenant_id} - {result['total_mrr']} {result['currency']}")
def _calculate_client_mrr(self, tenant_id: str, client_id: str, period_start: date, period_end: date, year: int, month: int):
"""
Calculate MRR breakdown by client
"""
query = """
SELECT
COUNT(*) as active_count,
SUM(monthly_amount) as total_mrr,
currency
FROM subscriptions
WHERE tenant_id = %s
AND company_id = %s
AND status = 'ACTIVE'
AND start_date <= %s
AND (end_date IS NULL OR end_date > %s)
GROUP BY currency
"""
results = self.db.query(query, [tenant_id, client_id, period_start, period_end])
for result in results:
self.db.upsert('subscription_aggregates', {
'tenant_id': tenant_id,
'client_id': client_id,
'period_year': year,
'period_month': month,
'mrr_active_subscriptions': result['active_count'],
'mrr_total_amount': result['total_mrr'],
'mrr_currency': result['currency']
}, {
'tenant_id': tenant_id,
'period_year': year,
'period_month': month,
'client_id': client_id
})
```
### Job 2: Revenue Recognition (Accrual Basis)
```python
class RevenueRecognitionJob:
"""
Calculate IFRS 15 revenue recognition (accrual basis)
Each invoice β recognized monthly based on service delivery
"""
def __init__(self, db, logger):
self.db = db
self.logger = logger
def run(self, year: int, month: int):
"""
Recognize revenue for period
"""
period_start = date(year, month, 1)
if month == 12:
period_end = date(year + 1, 1, 1) - timedelta(days=1)
else:
period_end = date(year, month + 1, 1) - timedelta(days=1)
self.logger.info(f"Starting revenue recognition for {year}-{month:02d}")
# 1. Find all invoices that span this period (subscription delivery)
invoices = self.db.query("""
SELECT
i.invoice_id,
i.tenant_id,
i.company_id,
i.amount,
s.subscription_term_months,
s.billing_cycle,
i.issued_at,
p.payment_received_date,
p.amount as payment_amount
FROM invoices i
JOIN subscription_invoices si ON i.invoice_id = si.invoice_id
JOIN subscriptions s ON si.subscription_id = s.subscription_id
LEFT JOIN payments p ON i.invoice_id = p.invoice_id AND p.status = 'SUCCEEDED'
WHERE i.tenant_id IN (SELECT id FROM tenants WHERE is_active = TRUE)
AND i.issued_at <= %s
AND (i.due_date >= %s OR i.issued_at >= %s)
""", [period_end, period_start, period_start])
for invoice in invoices:
# 2. Calculate monthly recognition (straight-line method)
recognition = self._recognize_revenue(
invoice, period_start, period_end, year, month
)
if recognition:
# Insert recognition record
self.db.upsert('revenue_recognition', recognition, {
'tenant_id': invoice['tenant_id'],
'invoice_id': invoice['invoice_id'],
'period_year': year,
'period_month': month
})
def _recognize_revenue(self, invoice: dict, period_start: date, period_end: date, year: int, month: int) -> dict:
"""
Recognize revenue for specific invoice in specific period
Straight-line method: invoice_amount / subscription_term_months
"""
# Service period starts at invoice issue date
service_start = invoice['issued_at'].date()
# Service period ends based on billing cycle
if invoice['billing_cycle'] == 'MONTHLY':
service_end = service_start + timedelta(days=30)
elif invoice['billing_cycle'] == 'QUARTERLY':
service_end = service_start + timedelta(days=90)
elif invoice['billing_cycle'] == 'ANNUAL':
service_end = service_start + timedelta(days=365)
else:
service_end = service_start + timedelta(days=30)
# Overlap between service period and current period
overlap_start = max(service_start, period_start)
overlap_end = min(service_end, period_end)
if overlap_start > overlap_end:
# No overlap - don't recognize
return None
# Calculate daily amount
total_days = (service_end - service_start).days
daily_amount = invoice['amount'] / total_days if total_days > 0 else 0
# Recognition for this period
overlap_days = (overlap_end - overlap_start).days + 1
monthly_recognition = daily_amount * overlap_days
# Determine account mapping
account = self._get_revenue_account(invoice.get('plan_id'))
# Check if advance payment (deferred revenue)
is_deferred = invoice['payment_received_date'] and invoice['payment_received_date'].date() < service_start
return {
'tenant_id': invoice['tenant_id'],
'invoice_id': invoice['invoice_id'],
'subscription_id': invoice.get('subscription_id'),
'period_year': year,
'period_month': month,
'total_invoice_amount': invoice['amount'],
'subscription_term_months': invoice['subscription_term_months'],
'monthly_recognition': monthly_recognition,
'recognition_method': 'straight_line',
'payment_received_amount': invoice['payment_amount'] or 0,
'payment_received_date': invoice['payment_received_date'],
'credit_account': account,
'debit_account': '1100', # Receivable account
'is_deferred': is_deferred,
'recognized_at': datetime.utcnow()
}
def _get_revenue_account(self, plan_id: str) -> str:
"""
Map plan to revenue account
"""
plan_accounts = {
'plan-starter': '4101',
'plan-pro': '4102',
'plan-enterprise': '4103',
}
return plan_accounts.get(plan_id, '4100') # Default to 4100
```
### Job 3: Gateway Costs Aggregation
```python
class GatewayCostsJob:
"""
Calculate payment processor fees
Tied to actual payments
"""
def __init__(self, db, logger):
self.db = db
self.logger = logger
def run(self, year: int, month: int):
"""
Calculate gateway costs for period
"""
period_start = date(year, month, 1)
if month == 12:
period_end = date(year + 1, 1, 1) - timedelta(days=1)
else:
period_end = date(year, month + 1, 1) - timedelta(days=1)
self.logger.info(f"Starting gateway costs calculation for {year}-{month:02d}")
# Get all successful payments in period
payments = self.db.query("""
SELECT
p.payment_id,
p.tenant_id,
p.amount,
p.currency,
p.gateway,
p.processed_at
FROM payments p
WHERE p.status = 'SUCCEEDED'
AND DATE(p.processed_at) BETWEEN %s AND %s
""", [period_start, period_end])
# Gateway fee structures
fees = {
'stripe': {'percentage': 0.029, 'fixed': 0.30},
'mercadopago': {'percentage': 0.0299, 'fixed': 0.49},
'pagarme': {'percentage': 0.0294, 'fixed': 0.00}
}
for payment in payments:
gateway = payment['gateway']
fee_config = fees.get(gateway, {})
# Calculate fee
fee_amount = (payment['amount'] * fee_config.get('percentage', 0)) + fee_config.get('fixed', 0)
# Map to account
account_map = {
'stripe': '5101',
'mercadopago': '5102',
'pagarme': '5103'
}
# Insert cost record
self.db.upsert('gateway_costs', {
'tenant_id': payment['tenant_id'],
'payment_id': payment['payment_id'],
'period_year': year,
'period_month': month,
'cost_type': 'gateway_fee',
'gateway': gateway,
'transaction_amount': payment['amount'],
'cost_percentage': fee_config.get('percentage', 0),
'cost_fixed': fee_config.get('fixed', 0),
'total_cost': fee_amount,
'charge_account': account_map.get(gateway, '5100'),
'calculated_at': datetime.utcnow()
}, {
'payment_id': payment['payment_id'],
'period_year': year,
'period_month': month
})
```
### Job 4: Chargeback Costs
```python
class ChargebackCostsJob:
"""
Record chargeback impacts on P&L
"""
def __init__(self, db, logger):
self.db = db
self.logger = logger
def run(self, year: int, month: int):
"""
Record chargebacks for period
"""
period_start = date(year, month, 1)
if month == 12:
period_end = date(year + 1, 1, 1) - timedelta(days=1)
else:
period_end = date(year, month + 1, 1) - timedelta(days=1)
# Get chargebacked payments
chargebacks = self.db.query("""
SELECT
p.payment_id,
p.tenant_id,
p.amount,
p.chargebacked_at
FROM payments p
WHERE p.status = 'CHARGEBACKED'
AND DATE(p.chargebacked_at) BETWEEN %s AND %s
""", [period_start, period_end])
for chargeback in chargebacks:
# Chargeback fee varies by gateway (~$15 USD)
chargeback_fee = 15 # USD or equivalent
total_cost = chargeback['amount'] + chargeback_fee
self.db.upsert('chargeback_costs', {
'tenant_id': chargeback['tenant_id'],
'payment_id': chargeback['payment_id'],
'period_year': year,
'period_month': month,
'original_amount': chargeback['amount'],
'chargeback_amount': chargeback['amount'],
'chargeback_fee': chargeback_fee,
'total_cost': total_cost,
'recorded_at': datetime.utcnow()
}, {
'payment_id': chargeback['payment_id'],
'period_year': year,
'period_month': month
})
```
### Job 5: DRE Consolidation (Brings It All Together)
```python
class DREConsolidationJob:
"""
Consolidate all components into final P&L
"""
def __init__(self, db, logger):
self.db = db
self.logger = logger
def run(self, year: int, month: int):
"""
Calculate consolidated DRE for period
"""
self.logger.info(f"Starting DRE consolidation for {year}-{month:02d}")
# Get all tenants
tenants = self.db.query("SELECT id FROM tenants WHERE is_active = TRUE")
for tenant in tenants:
tenant_id = tenant['id']
# Consolidated DRE
self._calculate_dre(tenant_id, None, year, month)
# Per-client DRE
clients = self.db.query("""
SELECT DISTINCT company_id FROM subscriptions
WHERE tenant_id = %s
""", [tenant_id])
for client in clients:
self._calculate_dre(tenant_id, client['company_id'], year, month)
def _calculate_dre(self, tenant_id: str, client_id: str = None, year: int = None, month: int = None):
"""
Calculate DRE (P&L) for tenant/client in period
"""
period_start = date(year, month, 1)
if month == 12:
period_end = date(year + 1, 1, 1) - timedelta(days=1)
else:
period_end = date(year, month + 1, 1) - timedelta(days=1)
# RECEITAS (Revenue)
rev_accrual = self._sum_revenue(tenant_id, client_id, year, month, basis='accrual')
rev_cash = self._sum_revenue(tenant_id, client_id, year, month, basis='cash')
# DEDUCTIONS
refund_deduction = self.db.query("""
SELECT COALESCE(SUM(amount), 0) FROM payments
WHERE tenant_id = %s
AND status = 'REFUNDED'
AND DATE(refunded_at) BETWEEN %s AND %s
{}
""".format(
f"AND invoice_id IN (SELECT id FROM invoices WHERE company_id = {client_id})" if client_id else ""
), [tenant_id, period_start, period_end])[0][0]
net_revenue_accrual = rev_accrual - refund_deduction
net_revenue_cash = rev_cash - refund_deduction
# CUSTOS (COGS)
gateway_fees = self._sum_costs(tenant_id, client_id, year, month, 'gateway_fee')
chargeback_costs = self._sum_costs(tenant_id, client_id, year, month, 'chargeback')
refund_costs = self._sum_costs(tenant_id, client_id, year, month, 'refund')
total_cogs = gateway_fees + chargeback_costs + refund_costs
# GROSS PROFIT
gross_profit = net_revenue_accrual - total_cogs
gross_margin_pct = (gross_profit / net_revenue_accrual * 100) if net_revenue_accrual > 0 else 0
# Get subscription metrics
mrr_agg = self.db.query("""
SELECT mrr_total_amount, churn_rate
FROM subscription_aggregates
WHERE tenant_id = %s
AND period_year = %s
AND period_month = %s
AND client_id IS {}
""".format("NULL" if not client_id else f"'{client_id}'"), [tenant_id, year, month])
if mrr_agg:
mrr = mrr_agg[0]['mrr_total_amount']
arr = mrr * 12
churn_rate = mrr_agg[0]['churn_rate']
else:
mrr = 0
arr = 0
churn_rate = 0
# COGS %
cogs_pct = (total_cogs / net_revenue_accrual * 100) if net_revenue_accrual > 0 else 0
# Insert DRE
self.db.upsert('dre_monthly', {
'tenant_id': tenant_id,
'client_id': client_id,
'period_year': year,
'period_month': month,
'period_start': period_start,
'period_end': period_end,
'revenue_accrual': rev_accrual,
'revenue_cash': rev_cash,
'deductions_refund': refund_deduction,
'net_revenue': net_revenue_accrual,
'cogs_gateway_fees': gateway_fees,
'cogs_chargebacks': chargeback_costs,
'cogs_refunds': refund_costs,
'total_cogs': total_cogs,
'gross_profit': gross_profit,
'gross_margin_pct': gross_margin_pct,
'mrr': mrr,
'arr': arr,
'churn_rate': churn_rate,
'cogs_percentage': cogs_pct,
'calculated_at': datetime.utcnow()
}, {
'tenant_id': tenant_id,
'period_year': year,
'period_month': month,
'client_id': client_id
})
```
---
## π‘ REVENUE RECOGNITION (ACCRUAL)
### IFRS 15 Compliance Example
**Scenario: Annual subscription paid upfront**
```
Invoice issued: 2026-01-15
Subscription period: 2026-01-15 to 2027-01-14 (12 months)
Invoice amount: 12,000 BRL
Payment received: 2026-01-15 (upfront)
Monthly recognition (straight-line):
12,000 / 12 = 1,000 BRL per month
January 2026:
Recognized: 1,000 BRL (15 days of 31)
Actual: 1,000 * (16/31) = 516 BRL
February 2026:
Recognized: 1,000 BRL (full month)
...
December 2026:
Recognized: 1,000 BRL (full month)
January 2027:
Recognized: 484 BRL (14 days of 31)
Total recognized: 12,000 BRL β
Accounting entries (January 2026):
Debit: Bank account / Receivable 12,000
Credit: Revenue 516
Credit: Deferred Revenue Liability 11,484
February 2026:
Debit: Deferred Revenue Liability 1,000
Credit: Revenue 1,000
```
### Cash vs Accrual Comparison
```
Scenario: 100 customers Γ 1,000 BRL = 100,000 BRL/month
Year 1: ACCRUAL BASIS
January: 100,000 (recognized)
February: 100,000
...
December: 100,000
Total 2026: 1,200,000 BRL
Year 1: CASH BASIS
January: 100,000 (received)
February: 100,000
...
December: 100,000
Total 2026: 1,200,000 BRL
Year 2: ACCRUAL BASIS (same as above)
January: 100,000 + 50,000 (new customers)
...
Total 2027: 1,800,000 BRL
Year 2: CASH BASIS
January: 50,000 (new customers paid upfront)
February: 100,000 + some new
...
Total 2027: Different, depends on when payments received
Key difference:
ACCRUAL = More accurate for SaaS (matches service delivery)
CASH = Better for cash flow analysis
```
---
## π CORRECTION & REBUILD STRATEGY
### Scenario 1: Payment Refunded After DRE Finalized
**Timeline:**
```
Jan 1: Payment processed, DRE calculated
Jan 15: Payment refunded
Jan 20: Need to correct DRE
Issue: DRE already finalized, but refund changes COGS
```
**Solution:**
```python
class DRECorrectionEngine:
"""
Handle corrections to finalized DRE
"""
def correct_payment_refund(self, payment_id: str, reason: str):
"""
Correct DRE when payment refunded
"""
# 1. Find affected period
payment = self.db.query("""
SELECT p.*, DATE_TRUNC('month', p.processed_at) as period
FROM payments p WHERE p.payment_id = %s
""", [payment_id])[0]
period_year = payment['period'].year
period_month = payment['period'].month
tenant_id = payment['tenant_id']
client_id = self.db.query("""
SELECT company_id FROM invoices WHERE invoice_id = %s
""", [payment['invoice_id']])[0]['company_id']
# 2. Get current DRE
current_dre = self.db.query("""
SELECT * FROM dre_monthly
WHERE tenant_id = %s
AND period_year = %s
AND period_month = %s
AND client_id = %s
""", [tenant_id, period_year, period_month, client_id])[0]
# 3. Recalculate affected lines
gateway_fees = self._recalculate_gateway_fees(tenant_id, client_id, period_year, period_month)
# Remove fee for this refunded payment
payment_fee = self.db.query("""
SELECT total_cost FROM gateway_costs
WHERE payment_id = %s
""", [payment_id])[0]
new_gateway_fees = gateway_fees - payment_fee['total_cost']
# 4. Recalculate DRE
old_cogs = current_dre['total_cogs']
new_cogs = old_cogs - payment_fee['total_cost']
old_gross_profit = current_dre['gross_profit']
new_gross_profit = old_gross_profit + payment_fee['total_cost']
# 5. Log correction
self.db.insert('dre_calculation_log', {
'tenant_id': tenant_id,
'calculation_type': 'correction',
'period_year': period_year,
'period_month': period_month,
'trigger_reason': f'payment_refunded: {payment_id}',
'old_cogs': old_cogs,
'new_cogs': new_cogs,
'rows_updated': 1,
'status': 'SUCCESS',
'completed_at': datetime.utcnow()
})
# 6. Update DRE (increment recalculation counter)
self.db.update('dre_monthly', current_dre['dre_id'], {
'total_cogs': new_cogs,
'cogs_gateway_fees': new_gateway_fees,
'gross_profit': new_gross_profit,
'gross_margin_pct': (new_gross_profit / current_dre['net_revenue']) if current_dre['net_revenue'] > 0 else 0,
'cogs_percentage': (new_cogs / current_dre['net_revenue']) if current_dre['net_revenue'] > 0 else 0,
'recalculated_count': current_dre['recalculation_count'] + 1,
'recalculated_at': datetime.utcnow()
})
```
### Scenario 2: Chargeback Received After Month Closed
**Issue:** Chargeback in Feb for payment from Jan
**Solution:**
```python
def handle_chargeback_correction(self, payment_id: str):
"""
When chargeback received, correct the month it occurred
"""
payment = self.db.query("""
SELECT * FROM payments WHERE payment_id = %s
""", [payment_id])[0]
# Find original period when payment was processed
original_period_year = payment['processed_at'].year
original_period_month = payment['processed_at'].month
# Get chargeback date
chargeback_date = payment['chargebacked_at']
chargeback_period_year = chargeback_date.year
chargeback_period_month = chargeback_date.month
# Add chargeback cost to chargeback period (not original payment period)
self.db.insert('chargeback_costs', {
'payment_id': payment_id,
'period_year': chargeback_period_year,
'period_month': chargeback_period_month,
'original_amount': payment['amount'],
'total_cost': payment['amount'] + 15 # $15 fee
})
# Recalculate DRE for chargeback month
self._recalculate_dre(
payment['tenant_id'],
payment['invoice_id'].company_id,
chargeback_period_year,
chargeback_period_month
)
```
### Scenario 3: Full Period Rebuild (Rare)
**When to rebuild:**
```
- Major bug discovered in calculation logic
- Retroactive price change
- Data quality issue (missing records)
- Compliance requirement
```
**How to rebuild:**
```python
def rebuild_period(self, tenant_id: str, year: int, month: int):
"""
Full rebuild of period (expensive operation)
"""
# 1. Delete all aggregates for this period
self.db.delete('dre_monthly', {
'tenant_id': tenant_id,
'period_year': year,
'period_month': month
})
self.db.delete('revenue_recognition', {
'tenant_id': tenant_id,
'period_year': year,
'period_month': month
})
self.db.delete('gateway_costs', {
'tenant_id': tenant_id,
'period_year': year,
'period_month': month
})
# 2. Recalculate from scratch
mrr_job = MRRCalculationJob(self.db, self.logger)
mrr_job.run(year, month)
rev_job = RevenueRecognitionJob(self.db, self.logger)
rev_job.run(year, month)
gateway_job = GatewayCostsJob(self.db, self.logger)
gateway_job.run(year, month)
chargeback_job = ChargebackCostsJob(self.db, self.logger)
chargeback_job.run(year, month)
dre_job = DREConsolidationJob(self.db, self.logger)
dre_job.run(year, month)
# 3. Log rebuild
self.db.insert('dre_calculation_log', {
'tenant_id': tenant_id,
'calculation_type': 'rebuild',
'period_year': year,
'period_month': month,
'trigger_reason': 'manual_rebuild',
'status': 'SUCCESS'
})
```
---
## π DRE CALCULATION LOGIC
### Example: Complete Month Calculation
**Input Data (January 2026, Tenant ABC):**
```
Subscriptions:
ββ 50 active @ 1,000 BRL/month
ββ 10 new this month @ 1,000 BRL/month
ββ 5 canceled this month @ 1,000 BRL/month
Invoices issued:
ββ INV-001: 50 Γ 1,000 = 50,000 BRL (Jan 1, annual)
ββ INV-002: 10 Γ 1,000 = 10,000 BRL (Jan 15, annual)
ββ INV-003: 5 Γ 500 = 2,500 BRL (Jan 25, refund due to cancellation)
Payments received:
ββ PAY-001: 50,000 BRL (INV-001) via Stripe
ββ PAY-002: 10,000 BRL (INV-002) via MercadoPago
ββ Refund: -2,500 BRL (INV-003) via Stripe
Chargebacks:
ββ None
Failed/Pending:
ββ 3 invoices still unpaid
ββ 1 payment failed
```
**Calculations:**
```
RECEITAS (Revenue - Accrual)
ββ INV-001: 50,000 / 12 months = 4,167 BRL (issued Jan 1)
ββ INV-002: 10,000 / 12 months Γ 16/31 = 433 BRL (issued Jan 15)
ββ INV-003: (2,500 / 12 months) - refund = credit
= -208 BRL
Total Revenue (Accrual): 4,167 + 433 - 208 = 4,392 BRL
RECEITAS (Cash Basis)
ββ PAY-001: 50,000 BRL received
ββ PAY-002: 10,000 BRL received
ββ Refund: -2,500 BRL
Total Revenue (Cash): 50,000 + 10,000 - 2,500 = 57,500 BRL
CUSTOS (COGS)
ββ Gateway fees:
β ββ Stripe PAY-001: 50,000 Γ 2.9% + 0.30 = 1,450.30 BRL
β ββ MercadoPago PAY-002: 10,000 Γ 2.99% + 0.49 = 299.49 BRL
β ββ Refund credit: -(2,500 Γ 2.9% + 0.30) = -73.30 BRL
β = Total: 1,676.49 BRL
β
ββ Chargebacks: 0 BRL
β
ββ Refund costs: 0 BRL (included in gateway)
Total COGS: 1,676.49 BRL
RESULTADO
ββ Net Revenue (Accrual): 4,392 BRL
ββ Total COGS: 1,676.49 BRL
ββ Gross Profit: 4,392 - 1,676.49 = 2,715.51 BRL
ββ Gross Margin %: 2,715.51 / 4,392 = 61.8%
MΓTRICAS
ββ MRR: 50 Γ 1,000 = 50,000 BRL (active at start)
ββ New MRR: 10 Γ 1,000 = 10,000 BRL
ββ Churned MRR: 5 Γ 1,000 = 5,000 BRL
ββ Churn Rate: 5 / (50 + 5) = 8.3%
ββ ARR: 50,000 Γ 12 = 600,000 BRL
ββ COGS %: 1,676.49 / 4,392 = 38.2%
```
---
## π ANALYTICS API
### Endpoint 1: Get DRE Summary
```python
@app.get('/v1/analytics/dre')
def get_dre_summary(tenant_id: str, year: int, month: int = None) -> dict:
"""
GET /v1/analytics/dre?tenant_id=xxx&year=2026&month=1
Returns: P&L statement for period
"""
if month:
# Single month
dre = db.query("""
SELECT * FROM dre_monthly
WHERE tenant_id = %s
AND period_year = %s
AND period_month = %s
AND client_id IS NULL
""", [tenant_id, year, month])[0]
return {
'success': True,
'period': f"{year}-{month:02d}",
'revenue': {
'accrual': float(dre['revenue_accrual']),
'cash': float(dre['revenue_cash']),
'deductions_refund': float(dre['deductions_refund']),
'net_revenue': float(dre['net_revenue'])
},
'cogs': {
'gateway_fees': float(dre['cogs_gateway_fees']),
'chargebacks': float(dre['cogs_chargebacks']),
'refunds': float(dre['cogs_refunds']),
'total': float(dre['total_cogs'])
},
'profitability': {
'gross_profit': float(dre['gross_profit']),
'gross_margin_pct': float(dre['gross_margin_pct']),
'cogs_pct': float(dre['cogs_percentage'])
},
'metrics': {
'mrr': float(dre['mrr']),
'arr': float(dre['arr']),
'churn_rate': float(dre['churn_rate'])
}
}
else:
# Annual - sum all months
dres = db.query("""
SELECT
SUM(revenue_accrual) as revenue_accrual,
SUM(revenue_cash) as revenue_cash,
SUM(total_cogs) as total_cogs,
AVG(churn_rate) as avg_churn,
MAX(mrr) as ending_mrr
FROM dre_monthly
WHERE tenant_id = %s
AND period_year = %s
AND client_id IS NULL
""", [tenant_id, year])[0]
return {
'success': True,
'period': str(year),
'revenue_accrual': float(dres['revenue_accrual']),
'revenue_cash': float(dres['revenue_cash']),
'total_cogs': float(dres['total_cogs']),
'avg_churn_rate': float(dres['avg_churn']),
'ending_mrr': float(dres['ending_mrr'])
}
```
### Endpoint 2: MRR Breakdown
```python
@app.get('/v1/analytics/mrr')
def get_mrr_breakdown(tenant_id: str, year: int, month: int) -> dict:
"""
GET /v1/analytics/mrr?tenant_id=xxx&year=2026&month=1
Returns: MRR breakdown by subscription type
"""
agg = db.query("""
SELECT * FROM subscription_aggregates
WHERE tenant_id = %s
AND period_year = %s
AND period_month = %s
AND client_id IS NULL
""", [tenant_id, year, month])[0]
# By plan
by_plan = db.query("""
SELECT
p.plan_name,
COUNT(*) as subscription_count,
SUM(s.monthly_amount) as mrr
FROM subscriptions s
JOIN plans p ON s.plan_id = p.id
WHERE s.tenant_id = %s
AND s.status = 'ACTIVE'
GROUP BY p.plan_id, p.plan_name
""", [tenant_id])
return {
'success': True,
'period': f"{year}-{month:02d}",
'summary': {
'total_mrr': float(agg['mrr_total_amount']),
'active_subscriptions': agg['mrr_active_subscriptions'],
'new_subscriptions': agg['new_subscriptions'],
'canceled_subscriptions': agg['canceled_subscriptions'],
'churn_rate': float(agg['churn_rate'])
},
'by_plan': [
{
'plan': plan['plan_name'],
'subscriptions': plan['subscription_count'],
'mrr': float(plan['mrr'])
}
for plan in by_plan
]
}
```
### Endpoint 3: Revenue Forecast
```python
@app.get('/v1/analytics/forecast')
def get_revenue_forecast(tenant_id: str, months: int = 12) -> dict:
"""
GET /v1/analytics/forecast?tenant_id=xxx&months=12
Returns: Revenue projection based on current MRR and churn
"""
# Get current MRR and churn
current = db.query("""
SELECT mrr_total_amount, churn_rate
FROM subscription_aggregates
WHERE tenant_id = %s
AND client_id IS NULL
ORDER BY period_year DESC, period_month DESC
LIMIT 1
""", [tenant_id])[0]
current_mrr = float(current['mrr_total_amount'])
churn_rate = float(current['churn_rate'])
forecast = []
for month_offset in range(months):
# Project forward: MRR decays by churn each month
projected_mrr = current_mrr * ((1 - churn_rate) ** month_offset)
projected_arr = projected_mrr * 12
forecast.append({
'month': month_offset + 1,
'projected_mrr': round(projected_mrr, 2),
'projected_arr': round(projected_arr, 2)
})
return {
'success': True,
'current_mrr': current_mrr,
'assumed_churn': churn_rate,
'forecast': forecast
}
```
---
## π§ EDGE CASES & EXAMPLES
### Edge Case 1: Refund After Revenue Recognized
**Scenario:**
```
Jan: Invoice 1,000 BRL for 12-month service
Revenue recognized: 83.33 BRL (1,000 / 12)
Cash received: 1,000 BRL
March: Customer requests refund (2 months in)
How to handle?
```
**Solution:**
```python
def handle_refund_edge_case():
"""
Refund issued 2 months into 12-month service
Option 1: Pro-rata refund
ββ Months used: 2
ββ Months remaining: 10
ββ Refund amount: 1,000 Γ (10/12) = 833.33 BRL
ββ Recognized loss: 1,000 - 833.33 = 166.67 BRL
Option 2: Full refund (policy-based)
ββ Refund amount: 1,000 BRL
Accounting entry (Option 1, pro-rata):
Debit: Revenue (reversal) 166.67
Credit: Bank account 166.67
Note: Don't reverse all recognized revenue,
only the pro-rata amount for undelivered service
"""
# Calculate pro-rata refund
months_used = 2
total_months = 12
invoice_amount = 1000
refund_amount = invoice_amount * ((total_months - months_used) / total_months)
# = 1000 * (10/12) = 833.33
# Record refund
refund_entry = {
'type': 'revenue_adjustment',
'description': 'Pro-rata refund after 2 months service delivery',
'amount': -refund_amount, # Negative = reduction
'period': 'March' # Refund period, not original period
}
return refund_entry
```
### Edge Case 2: Chargeback 90 Days After Payment
**Scenario:**
```
Jan 15: Payment received (100 BRL)
Revenue recognized: 8.33 BRL/month
DRE finalized for January
April 15: Chargeback received (100 BRL)
DRE for January already finalized
How to handle?
```
**Solution:**
```python
def handle_delayed_chargeback():
"""
Chargeback months after original payment
Original period (Jan): DRE already finalized
Chargeback period (Apr): Where to record?
Option 1: Record in chargeback period (Apr)
ββ Jan DRE unchanged (already final)
ββ Apr DRE includes chargeback cost
ββ Apr revenue reduced by chargeback + fee
ββ Most common approach
Option 2: Reverse original month (rare)
ββ Only if DRE not finalized and not yet reported
"""
# Implementation: Option 1
payment = get_payment(id='pay-123')
original_period = payment['processed_at'] # January
chargeback = get_chargeback(id='cb-456')
chargeback_period = chargeback['received_date'] # April
# Record cost in chargeback period (NOT original period)
chargeback_cost = {
'payment_id': 'pay-123',
'original_period_month': 1, # For audit trail
'chargeback_recorded_month': 4, # Where we record it
'amount': 100,
'chargeback_fee': 15,
'total_cost': 115,
'journal_entry': {
'debit': 'Loss on Chargebacks (5210)',
'credit': 'Bank Account',
'amount': 115
}
}
# Update April DRE
april_dre = get_dre('Apr', 2026)
april_dre['cogs_chargebacks'] += 115
april_dre['total_cogs'] += 115
april_dre['gross_profit'] -= 115
april_dre.save()
# January DRE unchanged β
```
### Edge Case 3: Currency Conversion
**Scenario:**
```
Tenant operates in USD
DRE currency is BRL (corporate)
Payment: 100 USD
Exchange rate (Jan 1): 5.00 BRL/USD
Exchange rate (Jan 31): 5.10 BRL/USD
```
**Solution:**
```python
def handle_multi_currency():
"""
Multi-currency DRE
"""
# Recording date: use transaction date rate
payment_brl = 100 * 5.00 # 500 BRL
# DRE consolidation: sum all currencies by converting to corporate (BRL)
dre_monthly = {
'revenue_usd': 100,
'revenue_brl': 500,
'revenue_eur': 20 * 5.5, # 110 BRL
# Consolidated
'revenue_brl_total': 500 + 110 + others, # All in BRL
# Note exchange rates used
'exchange_rates': {
'USD_to_BRL': 5.00,
'EUR_to_BRL': 5.50
}
}
return dre_monthly
```
### Edge Case 4: Subscription Upgrade Mid-Month
**Scenario:**
```
Jan 1: Subscription @ 100 BRL/month
Jan 15: Upgrade to 300 BRL/month (new plan)
Jan 31: End of month
How to recognize revenue?
```
**Solution:**
```python
def handle_subscription_upgrade():
"""
Pro-rata revenue for subscription change mid-month
"""
# Period 1: Jan 1-14 @ 100 BRL/month
days1 = 14
rate1 = 100
revenue1 = (rate1 / 31) * days1 # 45.16 BRL
# Period 2: Jan 15-31 @ 300 BRL/month
days2 = 17
rate2 = 300
revenue2 = (rate2 / 31) * days2 # 164.52 BRL
# Total January revenue (accrual)
total = revenue1 + revenue2 # 209.68 BRL
# Accounting
entry = {
'debit': 'Receivable',
'credit': 'Revenue',
'amount': 209.68
}
return entry
```
---
## β
PRODUCTION CHECKLIST
```
β
Data Model
ββ subscription_aggregates (MRR)
ββ revenue_recognition (accrual basis)
ββ gateway_costs (processor fees)
ββ chargeback_costs (chargebacks)
ββ dre_monthly (consolidated P&L)
ββ dre_calculation_log (audit trail)
ββ revenue_deferred_liability (unearned revenue)
ββ All indexes created
β
Jobs
ββ MRR calculation (monthly)
ββ Revenue recognition (monthly, IFRS 15)
ββ Gateway costs (monthly)
ββ Chargeback costs (monthly)
ββ DRE consolidation (monthly, after all above)
β
Incremental Processing
ββ New payments β auto-update COGS
ββ Chargebacks β auto-update COGS
ββ Refunds β auto-adjust revenue
ββ Subscription changes β auto-update MRR
ββ No full rebuilds except in corrections
β
Corrections & Rebuilds
ββ Payment refund β correct period COGS
ββ Chargeback β record in chargeback period
ββ Delayed correction β incremental update
ββ Full rebuild β rare, audit logged
ββ Finalized flag β prevents accidental changes
β
Revenue Recognition (IFRS 15)
ββ Accrual basis (service delivery)
ββ Straight-line method (most common)
ββ Performance-based (if applicable)
ββ Deferred revenue tracking
ββ Compliance documented
β
Multi-Tenant Support
ββ Per-tenant DRE
ββ Per-client breakdown (optional)
ββ Consolidated tenant view
ββ Cross-tenant reporting (admin only)
β
Analytics API
ββ GET /dre (P&L summary)
ββ GET /mrr (MRR breakdown)
ββ GET /forecast (revenue projection)
ββ GET /revenue_recognition (accrual tracking)
ββ All queries <1 second
β
Audit Trail
ββ All calculations logged
ββ Change history (old β new)
ββ Recalculation counter
ββ Reason for changes
ββ User/event tracking
β
Testing
ββ Basic MRR calculation
ββ Revenue recognition (multiple terms)
ββ Refund handling (pro-rata)
ββ Chargeback handling (delayed)
ββ Currency conversion
ββ Upgrade mid-month
ββ Full rebuild verification
```
---
## π SUMMARY
### What We've Built
1. **Accounting-Grade Data Model** β
- Subscription aggregates (MRR/churn tracking)
- Revenue recognition (IFRS 15 compliant)
- Cost tracking (gateway fees, chargebacks)
- Consolidated P&L (DRE)
- Full audit trail
2. **Incremental Aggregation Jobs** β
- MRR calculation (monthly snapshots)
- Revenue recognition (accrual basis)
- Gateway costs (processor fees)
- Chargeback costs (separate tracking)
- DRE consolidation (brings it all together)
3. **Correction & Rebuild Strategy** β
- Incremental corrections (one payment refunded)
- Delayed chargebacks (record in correct period)
- Full rebuilds (rare, fully logged)
- Finalized flag (prevents accidental changes)
4. **Revenue Recognition (Accrual)** β
- IFRS 15 compliant
- Straight-line method (12-month split)
- Advance payments β deferred revenue
- Performance-based (extensible)
5. **Analytics API** β
- DRE summary (monthly/annual)
- MRR breakdown (by plan/client)
- Revenue forecast (projection)
- All queries optimized (<1s)
6. **Edge Cases Handled** β
- Refunds after recognition
- Delayed chargebacks
- Multi-currency
- Subscription upgrades
- Pro-rata calculations
### Financial Metrics Provided
```
β
MRR (Monthly Recurring Revenue)
β
ARR (Annual Recurring Revenue)
β
Churn Rate (monthly)
β
Gross Margin % (COGS / Revenue)
β
COGS % (cost of revenue)
β
Revenue (accrual vs cash)
β
Delinquency tracking
β
Chargeback rate
```
### Safety Guarantees
```
β
Never lose data (audit trail)
β
IFRS 15 compliant (revenue recognition)
β
Accrual accounting (not just cash)
β
Multi-currency support
β
Multi-tenant isolation
β
Corrections without data loss
β
Full rebuild capability
β
Consistent with billing module
```
---
**Version:** 1.0
**Status:** Production Ready
**Compliance:** IFRS 15, Brazilian GAAP, SOX
**Last Updated:** 2026-02-03
For integration: Combine with BILLING_MODULE.md + AUTHORIZATION_SYSTEM.md
Complete feature support matrix and compliance details for rrule_plpgsql.
A consistent policy & compliance layer ensures platform guardrails are **predictable, observable, progressive, and reversible**. This document outlines how to use **Kyverno** (cluster runtime admission / mutation / validation) and **Checkov** (CI Infrastructure-as-Code scanning) under the same GitOps promotion model (AppβofβApps) to prevent lastβminute surprises.
**Document versie**: 1.3
title: "Specification"