Skip to main content

getStockLevel

getStockLevel returns the current inventory document for one store + product combination โ€” quantity, min/max thresholds, batch info, location, and the embedded store / product relations. It works on the inventory model. You need it to answer "how much of X do we have in store Y right now?" and, thanks to the minQuantity / maxQuantity fields, to drive low-stock / over-stock alerts.

The validator (getStockLevel.val.ts)โ€‹

Two required ObjectIds in set (storeId, productId) plus the activeRoleMixin. The get is object({}) โ€” an empty projection, because this act returns the full stock-level document regardless of what the client asks for. Any read role can call it: Manager, Admin, StoreHead, UnitHead, and Employee.

import { object, objectIdValidation } from "lesan";
import { activeRoleMixin } from "@lib";

export const getStockLevelValidator = () => {
return object({
set: object({
...activeRoleMixin,
storeId: objectIdValidation,
productId: objectIdValidation,
}),
get: object({}),
});
};
note

About the imports All framework imports in this repo use the "lesan" alias. In your own app, import the same names from @hemedani/lesan (npm/Bun) or jsr:@hemedani/lesan (Deno). @lib points at the app's utils/ folder.

The implementation (getStockLevel.fn.ts)โ€‹

Even thinner than the mutators: it reads the two ids from set and forwards them to the shared getStockLevel helper in utils/inventoryManager.ts. No context lookup โ€” reads don't need the acting user.

import { type ActFn } from "lesan";
import { getStockLevel as getStockLevelUtil } from "@lib";

export const getStockLevelFn: ActFn = async (body) => {
const {
set: { storeId, productId },
} = body.details;

return await getStockLevelUtil(storeId as string, productId as string);
};

The helper (see inventoryManager) does a findOne on the inventory collection filtering by store._id and product._id, and returns the document โ€” or { quantity: 0 } when nothing exists yet. That fallback is why this act never throws for a missing record; it simply reports zero.

How it's registered (mod.ts)โ€‹

import { grantAccess, setTokens, setUser } from "@lib";
import { coreApp } from "../../../mod.ts";
import { getStockLevelFn } from "./getStockLevel.fn.ts";
import { getStockLevelValidator } from "./getStockLevel.val.ts";

export const getStockLevelSetup = () =>
coreApp.acts.setAct({
schema: "inventory",
actName: "getStockLevel",
preAct: [setTokens, setUser, grantAccess([{ roles: ["Manager", "Admin", "StoreHead", "UnitHead", "Employee"] }])],
validator: getStockLevelValidator(),
fn: getStockLevelFn,
});

In the workflowโ€‹

This is the primary point-of-sale read for inventory: one product in one store. The broader reads are getInventories (many rows, filterable, sortable) and getStockMovements (the history). Writing stock goes through addStock, removeStock, and transferStock. See the overview for the big picture.

Run itโ€‹

curl -X POST http://localhost:1380/lesan \
-H "Content-Type: application/json" \
-H "token: <your-token>" \
-d '{
"service": "main",
"model": "inventory",
"act": "getStockLevel",
"details": {
"set": {
"activeRoleId": "<role-id>",
"storeId": "<store-id>",
"productId": "<product-id>"
},
"get": {}
}
}'

The body is the inventory document (_id, quantity, minQuantity, maxQuantity, batchNo, expirationDate, location, store, product) or { quantity: 0 }.

Errors & fixesโ€‹

ErrorWhat it meansHow to fix
you should send your id with token key in req headersetTokens found no token headerAdd -H "token: <your-jwt>" to the request
Invalid or expired tokenJWT verification failedLog in again and use the fresh token
Invalid or missing token dataToken payload has no _idUse a token produced by the app's login act
user not existsetUser couldn't find the user docThe token references a deleted user โ€” log in again
activeRoleId is requiredgrantAccess needs the active roleSend activeRoleId in details.set (unless the user isGhost)
Active role not foundThe activeRoleId isn't among the user's rolesPass one of the role ids on the user document
You cant do thisThe active role isn't in the allowed read rolesSwitch to an allowed role or use a ghost admin
Invalid ObjectId / validator failurestoreId / productId isn't a valid 24-char hex stringCheck the ids you're sending