Categories
Moon ERP provides two category systems: Product Categories for organizing products and services, and Partner Categories for classifying business partners (customers and suppliers). Product categories are hierarchical (tree structure), while partner categories are flat.
Product Categories
Purpose
- Organize products and services into a hierarchical tree
- Support unlimited nesting depth via parent-child relationships
- Enable filtering and reporting by category
- Provide a tree endpoint for building navigation UI
Entity Attributes
| Field | Type | Description |
|---|---|---|
id | integer | Primary key |
company_id | integer | Foreign key to the company |
parent_id | integer? | Foreign key to parent category (null for root) |
code | string | Category code (e.g., ELEC, FOOD) |
name | string | Category name (English) |
name_ar | string | Category name (Arabic) |
level | integer | Depth in the tree (0 for root) |
has_children | boolean | Whether this category has sub-categories |
is_active | boolean | Whether the category is active |
description | string? | Description (English) |
description_ar | string? | Description (Arabic) |
created_at | datetime | Creation timestamp |
updated_at | datetime | Last update timestamp |
deleted_at | datetime? | Soft-delete timestamp |
Relationships
API Endpoints
| Method | Path | Description |
|---|---|---|
GET | /api/core/product-categories | List categories (paginated, flat) |
GET | /api/core/product-categories/tree | Get full category tree |
POST | /api/core/product-categories | Create a category |
GET | /api/core/product-categories/{id} | Get a specific category |
PUT | /api/core/product-categories/{id} | Update a category |
DELETE | /api/core/product-categories/{id} | Soft-delete a category |
Query Parameters for GET /api/core/product-categories
| Parameter | Type | Description |
|---|---|---|
search | string | Search by code, name, or name_ar |
page | integer | Page number for pagination |
Request/Response Examples
GET /api/core/product-categories/tree
Retrieve the full category hierarchy as a nested tree.
bash
curl -X GET https://moon-erp.test/api/core/product-categories/tree \
-H "Accept: application/json" \
-H "Accept-Language: ar" \
-H "Authorization: Bearer {token}"dart
final response = await http.get(
Uri.parse('https://moon-erp.test/api/core/product-categories/tree'),
headers: {
'Accept': 'application/json',
'Accept-Language': 'ar',
'Authorization': 'Bearer $token',
},
);Response 200 OK
json
{
"data": [
{
"id": 1,
"code": "ELEC",
"name": "إلكترونيات",
"name_en": "Electronics",
"name_ar": "إلكترونيات",
"level": 0,
"has_children": true,
"is_active": true,
"children": [
{
"id": 2,
"code": "ELEC-COMP",
"name": "حواسيب",
"name_en": "Computers",
"name_ar": "حواسيب",
"level": 1,
"has_children": false,
"is_active": true,
"children": []
},
{
"id": 3,
"code": "ELEC-PHONE",
"name": "هواتف",
"name_en": "Phones",
"name_ar": "هواتف",
"level": 1,
"has_children": false,
"is_active": true,
"children": []
}
]
},
{
"id": 4,
"code": "FOOD",
"name": "مواد غذائية",
"name_en": "Food Items",
"name_ar": "مواد غذائية",
"level": 0,
"has_children": false,
"is_active": true,
"children": []
}
]
}POST /api/core/product-categories
Create a new category. To create a sub-category, provide the parent_id.
bash
curl -X POST https://moon-erp.test/api/core/product-categories \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}" \
-d '{
"code": "ELEC-TAB",
"name": "Tablets",
"name_ar": "أجهزة لوحية",
"parent_id": 1,
"is_active": true
}'dart
final response = await http.post(
Uri.parse('https://moon-erp.test/api/core/product-categories'),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token',
},
body: jsonEncode({
'code': 'ELEC-TAB',
'name': 'Tablets',
'name_ar': 'أجهزة لوحية',
'parent_id': 1,
'is_active': true,
}),
);Response 201 Created
json
{
"data": {
"id": 5,
"code": "ELEC-TAB",
"name": "Tablets",
"name_en": "Tablets",
"name_ar": "أجهزة لوحية",
"parent_id": 1,
"level": 1,
"has_children": false,
"is_active": true,
"description": null,
"description_ar": null,
"created_at": "2026-02-16T10:00:00.000000Z",
"updated_at": "2026-02-16T10:00:00.000000Z"
}
}Business Rules
- Automatic level calculation -- when a
parent_idis provided, thelevelis automatically set toparent.level + 1. has_childrenflag -- automatically set totrueon the parent when a child category is created.- Cannot delete with children -- attempting to delete a category that has
has_children: truereturns a422error. Delete child categories first. - Company scoping -- categories are scoped to the authenticated user's company.
Partner Categories
Purpose
- Classify business partners into groups for reporting and filtering
- Support scope-based categorization (customer-only, supplier-only, or both)
Entity Attributes
| Field | Type | Description |
|---|---|---|
id | integer | Primary key |
company_id | integer | Foreign key to the company |
name | string | Category name (English) |
name_ar | string | Category name (Arabic) |
scope | enum | Applicability: customer, supplier, both |
is_active | boolean | Whether the category is active |
description | string? | Description (English) |
description_ar | string? | Description (Arabic) |
created_at | datetime | Creation timestamp |
updated_at | datetime | Last update timestamp |
deleted_at | datetime? | Soft-delete timestamp |
API Endpoints
| Method | Path | Description |
|---|---|---|
GET | /api/core/partner-categories | List partner categories (paginated) |
POST | /api/core/partner-categories | Create a partner category |
GET | /api/core/partner-categories/{id} | Get a specific partner category |
PUT | /api/core/partner-categories/{id} | Update a partner category |
DELETE | /api/core/partner-categories/{id} | Soft-delete a partner category |
Query Parameters for GET /api/core/partner-categories
| Parameter | Type | Description |
|---|---|---|
scope | string | Filter by scope: customer, supplier, both |
page | integer | Page number for pagination |
Request/Response Examples
POST /api/core/partner-categories
bash
curl -X POST https://moon-erp.test/api/core/partner-categories \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer {token}" \
-d '{
"name": "Wholesale Suppliers",
"name_ar": "موردين بالجملة",
"scope": "supplier",
"is_active": true,
"description": "Large-volume wholesale suppliers",
"description_ar": "موردين بكميات كبيرة بالجملة"
}'dart
final response = await http.post(
Uri.parse('https://moon-erp.test/api/core/partner-categories'),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token',
},
body: jsonEncode({
'name': 'Wholesale Suppliers',
'name_ar': 'موردين بالجملة',
'scope': 'supplier',
'is_active': true,
}),
);Response 201 Created
json
{
"data": {
"id": 1,
"name": "Wholesale Suppliers",
"name_en": "Wholesale Suppliers",
"name_ar": "موردين بالجملة",
"scope": "supplier",
"is_active": true,
"description": "Large-volume wholesale suppliers",
"description_ar": "موردين بكميات كبيرة بالجملة",
"created_at": "2026-02-16T10:00:00.000000Z",
"updated_at": "2026-02-16T10:00:00.000000Z"
}
}Business Rules
- Flat structure -- partner categories have no parent-child hierarchy, unlike product categories.
- Scope filtering -- the
scopefield determines whether a category applies to customers, suppliers, or both. Use this to filter categories when displaying them in a customer or supplier form. - Company scoping -- categories are scoped to the authenticated user's company.