Unit
unit is a department or warehouse inside an organization. Every unit belongs to exactly one organization (required), can have a head user and a parent unit (a tree), and is the scope object for step approvals and inventory ownership โ approval steps assign units, and stores are owned by units.
// models/unit.ts (definition, trimmed of the doc comment)
import { coreApp } from "../mod.ts";
import {
coerce, defaulted, enums, optional,
type RelationDataType, type RelationSortOrderType, string,
} from "lesan";
import { createUpdateAt } from "@lib";
import { organization_excludes, unit_excludes, user_excludes } from "./excludes.ts";
export const unit_type_array = ["Department", "Warehouse", "Finance", "Store"];
export const unit_type_emums = enums(unit_type_array);
export const unit_pure = {
name: string(),
code: string(),
type: defaulted(
coerce(unit_type_emums, string(), (value) => value as typeof unit_type_array[number]),
"Department",
),
description: optional(string()),
...createUpdateAt,
};
export const unit_relations = {
organization: {
schemaName: "organization",
type: "single" as RelationDataType,
optional: false,
excludes: organization_excludes,
relatedRelations: {
units: { type: "multiple" as RelationDataType, limit: 50, sort: { field: "_id", order: "desc" as RelationSortOrderType } },
},
},
head: {
schemaName: "user",
type: "single" as RelationDataType,
optional: true,
excludes: user_excludes,
relatedRelations: {
headedUnits: { type: "multiple" as RelationDataType, limit: 50, sort: { field: "_id", order: "desc" as RelationSortOrderType } },
},
},
parentUnit: {
schemaName: "unit",
type: "single" as RelationDataType,
optional: true,
excludes: unit_excludes,
relatedRelations: {
children: { type: "multiple" as RelationDataType, limit: 50, sort: { field: "_id", order: "desc" as RelationSortOrderType } },
},
},
};
Pure fieldsโ
| Field | Type | Notes |
|---|---|---|
name | string() | |
code | string() | e.g. UNIT-PUR |
type | coerce(enums([Department, Warehouse, Finance, Store]), "Department") | a free-form-ish bucket with a default |
description | optional(string()) | |
createdAt / updatedAt | spread from createUpdateAt |
Relationsโ
| Relation | Target | Type | Back-reference |
|---|---|---|---|
organization | organization | single (required) | organization.units |
head | user | single (optional) | user.headedUnits |
parentUnit | unit (self) | single (optional) | unit.children |
organization is the only relation in this model marked optional: false โ a unit without an organization is meaningless here.
Factoryโ
export const units = () =>
coreApp.odm.newModel("unit", unit_pure, unit_relations);
No unique index at the model level โ code uniqueness is enforced by the calling act if the business needs it.
In the workflowโ
Units are the approval scope. An approval step's assigneeGroups list unit ids, and a stepApproval is created per unit. See:
Catalog acts: add-unit, get-units, remove-unit, update-unit-relations.
Run itโ
curl -X POST http://localhost:1380/lesan \
-H "Content-Type: application/json" \
-H "token: <jwt>" \
-d '{
"service": "main",
"model": "unit",
"act": "getUnits",
"details": {
"set": { "page": 1 },
"get": { "name": true, "code": true, "type": true, "organization": { "name": true } }
}
}'
Errors & fixesโ
| Error | Cause | Fix |
|---|---|---|
unit not found | removeUnit/updateUnitRelations given an unknown _id | pass a real _id |
please clear below relations status before deletion | removeUnit on a unit still referenced by members/stores/etc. | remove those relations first (see the remove-unit page) |
Runtime
On npm/Bun import the framework from @hemedani/lesan; on Deno from jsr:@hemedani/lesan. The repo app itself uses the lesan path alias.