Revenues
Revenues provide a simplified entry form for recording company income. Each revenue is linked to a revenue category, a receiving account, and optionally a tax rate, cost center, and business partner. When approved, the system automatically creates a balanced journal entry. Cancellation reverses the journal entry.
Purpose
- Record revenue transactions with a streamlined single-entry form
- Auto-calculate tax amounts when a tax rate is assigned
- Auto-generate document numbers via the sequence service
- Create journal entries automatically on approval
- Reverse journal entries on cancellation
- Support filtering and reporting by category, partner, branch, and date range
Entity Attributes
Revenue
| Field | Type | Description |
|---|---|---|
id | bigint | Primary key |
company_id | bigint | FK to companies |
branch_id | bigint? | FK to branches |
document_number | string | Auto-generated sequence number (e.g., REV-2026-0001) |
date | date | Revenue date |
revenue_category_id | bigint | FK to transaction_categories (type=revenue) |
description | string | English description |
description_ar | string? | Arabic description |
amount | decimal(12,3) | Base revenue amount (before tax) |
tax_rate_id | bigint? | FK to tax_rates |
tax_amount | decimal(12,3) | Auto-calculated tax amount |
total_amount | decimal(12,3) | amount + tax_amount |
payment_method | enum | cash, check, bank_transfer, card, mixed |
receiving_account_id | bigint | FK to accounts (cash or bank GL account receiving funds) |
bank_account_id | bigint? | FK to bank_accounts (required for check/bank_transfer) |
check_number | string? | Check number (if payment by check) |
cost_center_id | bigint? | FK to cost_centers |
partner_id | bigint? | FK to business_partners |
status | enum | draft, approved, cancelled |
journal_entry_id | bigint? | FK to journal_entries (set on approval) |
notes | text? | Additional notes |
created_by | bigint | FK to users |
approved_by | bigint? | FK to users |
approved_at | datetime? | Approval timestamp |
created_at | timestamp | Creation timestamp |
updated_at | timestamp | Last update timestamp |
deleted_at | timestamp? | Soft-delete timestamp |
Relationships
Lifecycle
API Endpoints
| Method | Path | Description |
|---|---|---|
GET | /api/accounting/revenues | List revenues (paginated) |
POST | /api/accounting/revenues | Create a new revenue (draft) |
GET | /api/accounting/revenues/{id} | Get a single revenue |
PUT | /api/accounting/revenues/{id} | Update a revenue (draft only) |
DELETE | /api/accounting/revenues/{id} | Soft-delete a revenue (draft only) |
POST | /api/accounting/revenues/{id}/approve | Approve and create journal entry |
POST | /api/accounting/revenues/{id}/cancel | Cancel and reverse journal entry |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
status | string | No | Filter by status: draft, approved, cancelled |
revenue_category_id | integer | No | Filter by revenue category |
partner_id | integer | No | Filter by business partner |
branch_id | integer | No | Filter by branch |
date_from | date | No | Filter revenues on or after this date |
date_to | date | No | Filter revenues on or before this date |
page | integer | No | Page number (25 per page) |
Request/Response Examples
Create Revenue
Request POST /api/accounting/revenues
bash
curl -X POST https://moon-erp.test/api/accounting/revenues \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"date": "2026-02-23",
"revenue_category_id": 3,
"description": "Consulting service fee",
"description_ar": "رسوم خدمات استشارية",
"amount": "5000.000",
"payment_method": "bank_transfer",
"receiving_account_id": 15,
"bank_account_id": 1,
"tax_rate_id": 1,
"cost_center_id": 1,
"partner_id": 8,
"branch_id": 1,
"notes": "Project Alpha consulting"
}'dart
final response = await http.post(
Uri.parse('https://moon-erp.test/api/accounting/revenues'),
headers: {
'Authorization': 'Bearer $token',
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: jsonEncode({
'date': '2026-02-23',
'revenue_category_id': 3,
'description': 'Consulting service fee',
'description_ar': 'رسوم خدمات استشارية',
'amount': '5000.000',
'payment_method': 'bank_transfer',
'receiving_account_id': 15,
'bank_account_id': 1,
'tax_rate_id': 1,
'cost_center_id': 1,
'partner_id': 8,
'branch_id': 1,
'notes': 'Project Alpha consulting',
}),
);Response 201 Created
json
{
"data": {
"id": 1,
"company_id": 1,
"branch_id": 1,
"document_number": "REV-2026-0001",
"date": "2026-02-23",
"revenue_category_id": 3,
"expense_category": {
"id": 3,
"code": "REV-CONSULT",
"name": "Consulting Revenue",
"name_ar": "إيرادات الاستشارات"
},
"description": "Consulting service fee",
"description_ar": "رسوم خدمات استشارية",
"amount": "5000.000",
"tax_rate_id": 1,
"tax_rate": {
"id": 1,
"name": "VAT 5%",
"rate": "5.0000"
},
"tax_amount": "250.000",
"total_amount": "5250.000",
"payment_method": "bank_transfer",
"payment_method_label": "Bank Transfer",
"receiving_account_id": 15,
"receiving_account": {
"id": 15,
"code": "1201001",
"name": "NBK Main Account"
},
"bank_account_id": 1,
"check_number": null,
"cost_center_id": 1,
"partner_id": 8,
"partner": {
"id": 8,
"name": "Al Safat Trading",
"name_ar": "شركة الصفاة التجارية"
},
"status": "draft",
"status_label": "Draft",
"journal_entry_id": null,
"notes": "Project Alpha consulting",
"created_by": 1,
"approved_by": null,
"approved_at": null,
"created_at": "2026-02-23T10:00:00.000000Z",
"updated_at": "2026-02-23T10:00:00.000000Z"
}
}Approve Revenue
Request POST /api/accounting/revenues/1/approve
Response 200 OK
json
{
"data": {
"id": 1,
"document_number": "REV-2026-0001",
"status": "approved",
"status_label": "Approved",
"journal_entry_id": 43,
"approved_by": 1,
"approved_at": "2026-02-23T11:00:00.000000Z"
}
}List Revenues
Request GET /api/accounting/revenues?status=approved&date_from=2026-01-01&date_to=2026-12-31
Response 200 OK
json
{
"data": [
{
"id": 1,
"document_number": "REV-2026-0001",
"date": "2026-02-23",
"revenue_category": {
"id": 3,
"name": "إيرادات الاستشارات"
},
"amount": "5000.000",
"tax_amount": "250.000",
"total_amount": "5250.000",
"payment_method": "bank_transfer",
"receiving_account": {
"id": 15,
"code": "1201001",
"name": "NBK Main Account"
},
"partner": {
"id": 8,
"name": "شركة الصفاة التجارية"
},
"status": "approved"
}
],
"links": { "first": "...", "last": "...", "prev": null, "next": null },
"meta": { "current_page": 1, "last_page": 1, "per_page": 25, "total": 1 }
}Generated Journal Entry
When a revenue is approved, the system creates a posted journal entry:
| Line | Account | Debit | Credit | Description |
|---|---|---|---|---|
| 1 | Receiving account (e.g., NBK Main Account) | 5,250.000 | -- | Total received |
| 2 | Revenue category GL account (e.g., Consulting Revenue) | -- | 5,000.000 | Revenue amount |
| 3 | Tax Payable account (from tax rate) | -- | 250.000 | Tax amount (if applicable) |
Business Rules
| Rule | Description |
|---|---|
| Draft-only edits | Revenues can only be updated or deleted while in draft status |
| Auto document number | document_number is auto-generated via the sequence service on creation |
| Tax auto-calculation | If tax_rate_id is provided, tax_amount = amount * rate / 100 and total_amount = amount + tax_amount |
| Tax recalculation | On update, tax is recalculated if amount or tax_rate_id changes |
| Approval creates JE | Approving a draft revenue creates a posted journal entry and sets approved_by and approved_at |
| Cancel reverses JE | Cancelling an approved revenue reverses the associated journal entry |
| Company scoped | All revenues are filtered by the authenticated user's company |
| Bank details required | bank_account_id is required when payment_method is check or bank_transfer |
Permissions
| Permission | Description |
|---|---|
accounting.revenues.view | View revenues |
accounting.revenues.create | Create new revenues |
accounting.revenues.update | Update draft revenues |
accounting.revenues.approve | Approve draft revenues |
accounting.revenues.cancel | Cancel approved revenues |