Skip to content

Units

Moon ERP provides a two-tier measurement system: Unit Groups (e.g., Weight, Length, Volume) and Units (e.g., kg, g, lb). Each unit belongs to a group and has a conversion factor relative to the group's base unit. This system is used throughout the product catalog, inventory, and purchasing modules.

Unit Groups

Purpose

  • Group related units of measure together (e.g., all weight units in one group)
  • Provide an organizational structure for the unit catalog

Entity Attributes

FieldTypeDescription
idintegerPrimary key
company_idintegerForeign key to the company
namestringGroup name (English, e.g., Weight)
name_arstringGroup name (Arabic, e.g., الوزن)
is_activebooleanWhether the group is active
created_atdatetimeCreation timestamp
updated_atdatetimeLast update timestamp
deleted_atdatetime?Soft-delete timestamp

API Endpoints

MethodPathDescription
GET/api/core/unit-groupsList unit groups with their units (paginated)
POST/api/core/unit-groupsCreate a unit group
GET/api/core/unit-groups/{id}Get a unit group with its units
PUT/api/core/unit-groups/{id}Update a unit group
DELETE/api/core/unit-groups/{id}Soft-delete a unit group

Units

Purpose

  • Define individual units of measure with symbols and conversion factors
  • Enable unit conversion via the base unit within each group
  • Support product-level unit assignments for purchasing and selling

Entity Attributes

FieldTypeDescription
idintegerPrimary key
company_idintegerForeign key to the company
unit_group_idintegerForeign key to the unit group
namestringUnit name (English, e.g., Kilogram)
name_arstringUnit name (Arabic, e.g., كيلوغرام)
symbolstringShort symbol (e.g., kg, g, lb)
conversion_factordecimal(6)Factor relative to the base unit
is_basebooleanWhether this is the base unit of its group
is_activebooleanWhether the unit is active
created_atdatetimeCreation timestamp
updated_atdatetimeLast update timestamp
deleted_atdatetime?Soft-delete timestamp

Conversion Factor Explained

The conversion_factor represents how many base units equal one of this unit. The base unit always has a factor of 1.000000.

Example: Weight group (base unit = Kilogram)

UnitSymbolConversion FactorMeaning
Kilogramkg1.000000Base unit
Gramg0.0010001 g = 0.001 kg
Poundlb0.4535921 lb = 0.453592 kg
Tonton1000.0000001 ton = 1000 kg

To convert from unit A to unit B: value_in_B = value_in_A * (factor_A / factor_B)

Relationships

API Endpoints

MethodPathDescription
GET/api/core/unitsList units (paginated, filterable by group)
POST/api/core/unitsCreate a unit
GET/api/core/units/{id}Get a specific unit with its group
PUT/api/core/units/{id}Update a unit
DELETE/api/core/units/{id}Soft-delete a unit

Query Parameters for GET /api/core/units

ParameterTypeDescription
unit_group_idintegerFilter by unit group
pageintegerPage number for pagination

Request/Response Examples

GET /api/core/unit-groups

Retrieve unit groups with their units.

bash
curl -X GET https://moon-erp.test/api/core/unit-groups \
  -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/unit-groups'),
  headers: {
    'Accept': 'application/json',
    'Accept-Language': 'ar',
    'Authorization': 'Bearer $token',
  },
);

Response 200 OK

json
{
  "data": [
    {
      "id": 1,
      "name": "الوزن",
      "name_en": "Weight",
      "name_ar": "الوزن",
      "is_active": true,
      "units": [
        {
          "id": 1,
          "name": "كيلوغرام",
          "name_en": "Kilogram",
          "name_ar": "كيلوغرام",
          "symbol": "kg",
          "conversion_factor": "1.000000",
          "is_base": true,
          "is_active": true
        },
        {
          "id": 2,
          "name": "غرام",
          "name_en": "Gram",
          "name_ar": "غرام",
          "symbol": "g",
          "conversion_factor": "0.001000",
          "is_base": false,
          "is_active": true
        }
      ],
      "created_at": "2026-01-01T00:00:00.000000Z",
      "updated_at": "2026-01-01T00:00:00.000000Z"
    }
  ],
  "links": { "first": "...?page=1", "last": "...?page=1", "prev": null, "next": null },
  "meta": { "current_page": 1, "from": 1, "last_page": 1, "per_page": 25, "to": 1, "total": 1 }
}

POST /api/core/unit-groups

Create a new unit group.

bash
curl -X POST https://moon-erp.test/api/core/unit-groups \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer {token}" \
  -d '{
    "name": "Length",
    "name_ar": "الطول",
    "is_active": true
  }'
dart
final response = await http.post(
  Uri.parse('https://moon-erp.test/api/core/unit-groups'),
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'Authorization': 'Bearer $token',
  },
  body: jsonEncode({
    'name': 'Length',
    'name_ar': 'الطول',
    'is_active': true,
  }),
);

Response 201 Created

json
{
  "data": {
    "id": 2,
    "name": "Length",
    "name_en": "Length",
    "name_ar": "الطول",
    "is_active": true,
    "units": [],
    "created_at": "2026-02-16T10:00:00.000000Z",
    "updated_at": "2026-02-16T10:00:00.000000Z"
  }
}

POST /api/core/units

Create a new unit within a group.

bash
curl -X POST https://moon-erp.test/api/core/units \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer {token}" \
  -d '{
    "unit_group_id": 2,
    "name": "Meter",
    "name_ar": "متر",
    "symbol": "m",
    "conversion_factor": 1.000000,
    "is_base": true,
    "is_active": true
  }'
dart
final response = await http.post(
  Uri.parse('https://moon-erp.test/api/core/units'),
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'Authorization': 'Bearer $token',
  },
  body: jsonEncode({
    'unit_group_id': 2,
    'name': 'Meter',
    'name_ar': 'متر',
    'symbol': 'm',
    'conversion_factor': 1.000000,
    'is_base': true,
    'is_active': true,
  }),
);

Response 201 Created

json
{
  "data": {
    "id": 3,
    "unit_group_id": 2,
    "name": "Meter",
    "name_en": "Meter",
    "name_ar": "متر",
    "symbol": "m",
    "conversion_factor": "1.000000",
    "is_base": true,
    "is_active": true,
    "unit_group": { "id": 2, "name": "Length" },
    "created_at": "2026-02-16T10:00:00.000000Z",
    "updated_at": "2026-02-16T10:00:00.000000Z"
  }
}

Business Rules

  • One base unit per group -- each unit group must have exactly one unit with is_base: true and conversion_factor: 1.000000.
  • Conversion factor required -- every unit must specify a conversion_factor relative to the base unit.
  • Company scoping -- unit groups and units are scoped to the authenticated user's company.
  • Units depend on groups -- every unit must belong to a unit_group_id. Deleting a group that still has units should be prevented.
  • Used by products -- units are referenced by the Product.base_unit_id field and by ProductUnit records. Deleting a unit in use may cause referential integrity issues.
  • Symbol is for display -- the symbol field (e.g., kg, m, pcs) is used for UI display alongside quantities.

Moon ERP API Documentation