kcommons 18.26.1 → 18.26.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -67,6 +67,8 @@ export declare enum VEHICLE_TYPE {
67
67
  TRAILER = "TRAILER",
68
68
  TEMPO = "TEMPO",
69
69
  CONTAINER = "CONTAINER",
70
+ TANKER = "TANKER",
71
+ TWO_WHEELER = "TWO_WHEELER",
70
72
  OTHER = "OTHER"
71
73
  }
72
74
  export declare enum COURIER_SERVICE_TYPE {
@@ -389,3 +391,4 @@ export interface IFastagTrackingEvent {
389
391
  vehicleType: string | null;
390
392
  vehicleRegNo: string | null;
391
393
  }
394
+ export declare const VEHICLE_TYPE_ICONS: Record<VEHICLE_TYPE, string>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ASN_METAFIELDS_INCLUDE = exports.ASN_SORTING_ORDER = exports.ASN_VIEW_PAGE_TYPE = exports.ASN_ITEM_INCLUDE = exports.ASN_HAND_DELIVERY_TRANSPORT_FIELD_PREFIX = exports.ASN_COURIER_TRANSPORT_FIELD_PREFIX = exports.ASN_AIR_TRANSPORT_FIELD_PREFIX = exports.ASN_SEA_TRANSPORT_FIELD_PREFIX = exports.ASN_RAIL_TRANSPORT_FIELD_PREFIX = exports.ASN_ROAD_TRANSPORT_FIELD_PREFIX = exports.ASN_MODE_OF_TRANSPORT_FIELDS = exports.ASN_INCLUDE = exports.IDENTIFICATION_DOCUMENT_TYPE = exports.COURIER_SERVICE_TYPE = exports.VEHICLE_TYPE = exports.MODE_OF_TRANSPORT = exports.SHIPMENT_TYPE = exports.ASN_STATUS = exports.ASN_LIST_TYPES = exports.ASN_APPROVALS_TABS = exports.ASN_VIEW_TABS = exports.ASN_CANCELLED_BY_ENTITY = void 0;
3
+ exports.VEHICLE_TYPE_ICONS = exports.ASN_METAFIELDS_INCLUDE = exports.ASN_SORTING_ORDER = exports.ASN_VIEW_PAGE_TYPE = exports.ASN_ITEM_INCLUDE = exports.ASN_HAND_DELIVERY_TRANSPORT_FIELD_PREFIX = exports.ASN_COURIER_TRANSPORT_FIELD_PREFIX = exports.ASN_AIR_TRANSPORT_FIELD_PREFIX = exports.ASN_SEA_TRANSPORT_FIELD_PREFIX = exports.ASN_RAIL_TRANSPORT_FIELD_PREFIX = exports.ASN_ROAD_TRANSPORT_FIELD_PREFIX = exports.ASN_MODE_OF_TRANSPORT_FIELDS = exports.ASN_INCLUDE = exports.IDENTIFICATION_DOCUMENT_TYPE = exports.COURIER_SERVICE_TYPE = exports.VEHICLE_TYPE = exports.MODE_OF_TRANSPORT = exports.SHIPMENT_TYPE = exports.ASN_STATUS = exports.ASN_LIST_TYPES = exports.ASN_APPROVALS_TABS = exports.ASN_VIEW_TABS = exports.ASN_CANCELLED_BY_ENTITY = void 0;
4
4
  var ASN_CANCELLED_BY_ENTITY;
5
5
  (function (ASN_CANCELLED_BY_ENTITY) {
6
6
  ASN_CANCELLED_BY_ENTITY["COMPANY"] = "COMPANY";
@@ -60,6 +60,8 @@ var VEHICLE_TYPE;
60
60
  VEHICLE_TYPE["TRAILER"] = "TRAILER";
61
61
  VEHICLE_TYPE["TEMPO"] = "TEMPO";
62
62
  VEHICLE_TYPE["CONTAINER"] = "CONTAINER";
63
+ VEHICLE_TYPE["TANKER"] = "TANKER";
64
+ VEHICLE_TYPE["TWO_WHEELER"] = "TWO_WHEELER";
63
65
  VEHICLE_TYPE["OTHER"] = "OTHER";
64
66
  })(VEHICLE_TYPE || (exports.VEHICLE_TYPE = VEHICLE_TYPE = {}));
65
67
  var COURIER_SERVICE_TYPE;
@@ -184,3 +186,14 @@ var ASN_METAFIELDS_INCLUDE;
184
186
  ASN_METAFIELDS_INCLUDE["approval_logs"] = "approval_logs";
185
187
  ASN_METAFIELDS_INCLUDE["approval_chain_stage_names"] = "approval_chain_stage_names";
186
188
  })(ASN_METAFIELDS_INCLUDE || (exports.ASN_METAFIELDS_INCLUDE = ASN_METAFIELDS_INCLUDE = {}));
189
+ exports.VEHICLE_TYPE_ICONS = {
190
+ [VEHICLE_TYPE.TRUCK]: "mdi:truck",
191
+ [VEHICLE_TYPE.MINI_TRUCK]: "mdi:truck-delivery",
192
+ [VEHICLE_TYPE.PICKUP]: "mdi:car-pickup",
193
+ [VEHICLE_TYPE.TRAILER]: "mdi:truck-trailer",
194
+ [VEHICLE_TYPE.TEMPO]: "mdi:rickshaw",
195
+ [VEHICLE_TYPE.CONTAINER]: "andrsrxn:container-cuboid",
196
+ [VEHICLE_TYPE.TANKER]: "mdi:fuel-truck",
197
+ [VEHICLE_TYPE.TWO_WHEELER]: "mdi:motorbike",
198
+ [VEHICLE_TYPE.OTHER]: "mdi:dots-horizontal-circle-outline",
199
+ };
@@ -90,6 +90,17 @@ export interface IHSFPL_HaltingVehiclesMaterialRow {
90
90
  is_others: boolean;
91
91
  others_materials: string[];
92
92
  }
93
+ export interface IHSFPL_HaltingVehiclesMaterialStockRow {
94
+ material: string;
95
+ material_code: string | null;
96
+ uom: string;
97
+ vehicles_at_nly: number;
98
+ in_transit: number | null;
99
+ at_nly: number | null;
100
+ standing_at_plant: number | null;
101
+ in_inventory: number | null;
102
+ total_incoming: number;
103
+ }
93
104
  export interface IHSFPL_HaltingVehiclesInvalidInvoiceRow {
94
105
  ves_no: string;
95
106
  plant_name: string;
@@ -144,6 +155,7 @@ export interface IHSFPL_HaltingVehiclesReport {
144
155
  plants_without_vehicles: string[];
145
156
  agewise: IHSFPL_HaltingVehiclesAgewise;
146
157
  materialwise: IHSFPL_HaltingVehiclesMaterialRow[];
158
+ material_stock: IHSFPL_HaltingVehiclesMaterialStockRow[];
147
159
  invoice_status: IHSFPL_HaltingVehiclesInvoiceSection;
148
160
  vehicles_by_plant: IHSFPL_HaltingVehiclesPlantGroup[];
149
161
  consistency: IHSFPL_HaltingVehiclesConsistency;
@@ -70,8 +70,13 @@ export interface IQueueJobMetadata extends Pick<IQueueJob, "job_type"> {
70
70
  }
71
71
  export interface IHaldiramsPurchaseOrderItems {
72
72
  item_code: string | null;
73
+ po_line_item_number: string | null;
73
74
  remark: string | null;
74
75
  quantity: string | null;
76
+ price_per_unit: string | null;
77
+ po_uom: string | null;
78
+ base_uom: string | null;
79
+ qty_converted_to_base_uom: string | null;
75
80
  gst_percentage: string | null;
76
81
  total: string | null;
77
82
  per_unit_rate: string | null;
@@ -82,6 +87,7 @@ export interface IHaldiramsPurchaseOrderItems {
82
87
  under_tolerance_percentage: string | null;
83
88
  line_item_number: number | null;
84
89
  Delivery_Completed: string | null;
90
+ Control_code: string | null;
85
91
  }
86
92
  export interface IHaldiramsPODataFetchedFromERPData {
87
93
  purchase_order_number: number | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kcommons",
3
- "version": "18.26.1",
3
+ "version": "18.26.3",
4
4
  "description": "",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",
package/readme.md CHANGED
@@ -1,6 +1,534 @@
1
- TO publish:
1
+ # kcommons
2
2
 
3
- 1. tsc
4
- 2. push to github
5
- 3. npm version patch
6
- 4. npm publish
3
+ > Who is this for? Anyone who is new to this project.
4
+ > Read it once from top to bottom. After that, you should be able to build the package, find your way around it, add new types and helpers the same way everyone else does, and get your change into the projects that use it.
5
+
6
+ ---
7
+
8
+ ## Table of Contents
9
+
10
+ 1. What is this project?
11
+ 2. Words you will see everywhere
12
+ 3. Tools we use
13
+ 4. Getting started on your machine
14
+ 5. The folder map
15
+ 6. How a change travels to the other projects
16
+ 7. The big ideas
17
+ 8. Naming rules
18
+ 9. Coding rules and style
19
+ 10. Recipes: step-by-step guides
20
+ 11. Testing
21
+ 12. Using your local copy in another project
22
+ 13. Publishing a new version
23
+ 14. Git and teamwork
24
+ 15. Troubleshooting and FAQ
25
+ 16. Things that don't follow the rules yet
26
+ 17. Cheat sheet
27
+
28
+ ---
29
+
30
+ ## 1. What is this project?
31
+
32
+ Kraya is made of several projects:
33
+
34
+ | Project | What it is |
35
+ | -------------------------- | -------------------------------------------------- |
36
+ | Kraya backend | The main server (NestJS) |
37
+ | Company panel (frontend) | The website companies use |
38
+ | Vendor panel (frontend) | The website vendors use |
39
+ | ERP Integration Server | Talks to company ERPs, builds and mails reports |
40
+ | Report Generation Engine | Turns report data into PDFs |
41
+
42
+ All of them talk about the same things: a PO, a GRN, a vendor, a report schedule. If every project wrote its own `IPo` type, they would slowly drift apart, and one day the backend would send a field the frontend doesn't know about.
43
+
44
+ kcommons (this repo, `kraya_common`) is the one place where those shared things live. It is an npm package called `kcommons`. It holds:
45
+
46
+ - Types (TypeScript interfaces) for every table and API response
47
+ - Enums and constants (statuses, permissions, routes, upload paths, …)
48
+ - Small helper functions that must work the same everywhere (taxes, dates, IDs, validators, report scheduling)
49
+
50
+ ```
51
+ ┌───────────────────┐
52
+ │ kcommons │
53
+ │ types · enums · │
54
+ │ constants · utils│
55
+ └─────────┬─────────┘
56
+ ┌──────────────┬─────────┼──────────────┬───────────────────┐
57
+ ▼ ▼ ▼ ▼ ▼
58
+ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌──────────────┐ ┌──────────────┐
59
+ │ Kraya │ │ Company │ │ Vendor │ │ ERP │ │ Report │
60
+ │ backend │ │ panel FE │ │ panel FE │ │ Integration │ │ Generation │
61
+ │ │ │ │ │ │ │ Server │ │ Engine │
62
+ └────────────┘ └────────────┘ └────────────┘ └──────────────┘ └──────────────┘
63
+ ```
64
+
65
+ kcommons has no server, no database and no UI. It is only code that other projects import:
66
+
67
+ ```ts
68
+ import { IPo, STATUSES, calculateNextRunAt } from 'kcommons';
69
+ ```
70
+
71
+ Because the frontends import it too, everything in here must run in a browser as well as in Node (see section 9).
72
+
73
+ ---
74
+
75
+ ## 2. Words you will see everywhere
76
+
77
+ | Word | What it means in simple words |
78
+ | ------------------- | ----------------------------------------------------------------------------------------------------------------- |
79
+ | Typing | A TypeScript interface or type. It describes the shape of data. It doesn't exist at runtime. |
80
+ | `I<Name>` | The full shape of one table row, including its relations. Example: `IGRN`. |
81
+ | `INested<Name>` | The same row without its relations. Used when the row appears inside another row. Example: `INestedGRN`. |
82
+ | `<NAME>_INCLUDE` | An enum listing the relations you can ask the backend to include. Example: `REPORTS_PLUGIN_CONFIG_COMPANY_INCLUDE`. |
83
+ | Barrel (`index.ts`) | The one file that re-exports everything. If something isn't exported there, other projects can't import it. |
84
+ | Build | The compiled JavaScript + `.d.ts` files in `build/`. This is what other projects actually load. |
85
+ | Publish | Uploading a new version of the package to npm so other projects can install it. |
86
+ | Link / symlink | Pointing another project's `node_modules/kcommons` at your local folder, so it uses your code without publishing. |
87
+ | Report plugin | One kind of report, for example `HALTING_VEHICLES_REPORTS` (`REPORTS_PLUGIN` enum). |
88
+ | Company code | Short name of a customer company. Company-specific types use it as a prefix. Example: `IABC_HaltingVehiclesReport`. |
89
+
90
+ > Examples in this guide use `ABC` as the company code, the same as the ERP server and engine READMEs. In the real code you will see the real company prefix (for example `HSFPL_`).
91
+
92
+ ---
93
+
94
+ ## 3. Tools we use
95
+
96
+ | Tool | What it does for us |
97
+ | ----------------- | -------------------------------------------------------------------------------------- |
98
+ | TypeScript 5 | Everything is written in TypeScript and compiled with `tsc` (CommonJS, ES2017). |
99
+ | Jest + ts-jest | Unit tests for the helper functions. |
100
+ | date-fns | Date helpers. kcommons re-exports the whole library, so `import { format } from 'kcommons'` works. |
101
+ | zod | Schema validation, used by the extra-form helpers and `zod.constant.ts`. |
102
+ | uuid | ID generation (`generateId.util.ts`). |
103
+ | npm | Package manager and the registry we publish to. |
104
+
105
+ There is no ESLint or Prettier config in this repo. Match the style of the files around you (double quotes, 2 spaces, trailing commas).
106
+
107
+ ---
108
+
109
+ ## 4. Getting started on your machine
110
+
111
+ ### 4.1 What you need
112
+
113
+ - Node.js 22 and npm
114
+ - Git access to `Kraya-Vkraya/kraya_common`
115
+ - npm publish rights, only if you will publish (ask the team)
116
+
117
+ ### 4.2 First-time setup
118
+
119
+ Clone it next to the other projects. The other repos link to it with the relative path `../../kraya_common`, so the folder name and place matter:
120
+
121
+ ```bash
122
+ cd ~/code/kraya/code # the folder that also holds backend/, erp-integration-server/, ...
123
+ git clone https://github.com/Kraya-Vkraya/kraya_common.git
124
+ cd kraya_common
125
+ npm install # also runs "prepare", which builds into build/
126
+ ```
127
+
128
+ ### 4.3 npm commands
129
+
130
+ | Command | What it does |
131
+ | ------------------- | -------------------------------------------------------------------- |
132
+ | `npx tsc` | Compiles everything into `build/`. Run it after every change. |
133
+ | `npm run prepare` | Same as above (runs `npx tsc`). npm also runs it on `install` and before `publish`. |
134
+ | `npm test` | Runs all `*.spec.ts` tests. |
135
+ | `npm run test:watch`| Runs tests again on every save. |
136
+ | `npm run test:cov` | Runs tests and shows coverage. |
137
+
138
+ ### 4.4 Is it working?
139
+
140
+ - `npx tsc` finishes with no errors.
141
+ - `build/index.js` and `build/index.d.ts` exist and have today's time.
142
+ - `npm test` passes.
143
+
144
+ ---
145
+
146
+ ## 5. The folder map
147
+
148
+ There is no `src/` folder. The source folders sit at the top level, and `tsc` writes the output to `build/`.
149
+
150
+ ```
151
+ kraya_common/
152
+ ├── index.ts ← THE BARREL. Re-exports everything. package.json "main"/"types" point at build/index.*
153
+ ├── typings/ ← Types for tables, API responses and reports (~180 files). Most of your work is here.
154
+ │ ├── <entity>.typings.ts ← Older entities live at the top level (grn, mrn, vendor, …)
155
+ │ ├── company/ ← Company-side entities
156
+ │ │ ├── masters/ ← po, ves, checkpoints, …
157
+ │ │ ├── inventory/ istd/ iad/ settings/ _junctions/ vendorOnboardingRequest/
158
+ │ ├── vendor/ ← Vendor-panel types
159
+ │ ├── system/ ← System config tables (erp plugins, report schedules, recipients)
160
+ │ ├── plugins/ ← Plugin enums (REPORTS_PLUGIN, REPORT_FREQUENCY)
161
+ │ ├── reports/<company>/ ← Report data shapes, one folder per company (e.g. reports/hsfpl/)
162
+ │ ├── integrations/erp/ ← ERP integration types
163
+ │ ├── kpis/ ← Dashboard KPI types, grouped by dashboard
164
+ │ ├── settings/form/ ← Extra (configurable) form types
165
+ │ ├── verification_apis/ ← GST / PAN / … verification responses
166
+ │ └── common/ ← Shared pieces (pagination, ULIP, configurable forms)
167
+ ├── enums/ ← Stand-alone enums (priority, upload)
168
+ ├── constants/ ← Fixed values: statuses, permissions, routes, upload paths, socket events, UOMs, …
169
+ ├── configs/ ← response.typings.ts (shape of every API response)
170
+ ├── classes/ ← The few real classes (ASNWrapper, vendor quote ➜ quote item adapter)
171
+ ├── helpers/ ← Tiny generic helpers (padNumber)
172
+ ├── utils/ ← Helper functions with real logic, each with a .spec.ts next to it
173
+ │ ├── validators/ ← gst, pan, cin, udyam
174
+ │ └── extra-form/ ← Build/parse configurable forms
175
+ ├── build/ ← Compiled output. Generated by tsc, but committed (see section 16)
176
+ ├── jest.config.js
177
+ ├── tsconfig.json ← strict, commonjs, ES2017, declaration: true, outDir: ./build
178
+ └── package.json
179
+ ```
180
+
181
+ ---
182
+
183
+ ## 6. How a change travels to the other projects
184
+
185
+ ```
186
+ 1. Change a file in kraya_common (for example add a field to IGRN)
187
+ │
188
+ ▼
189
+ 2. Export it from index.ts (if it's a new file)
190
+ │
191
+ ▼
192
+ 3. npx tsc ──► build/ (JavaScript + .d.ts)
193
+ │
194
+ ├──────────────► 4a. Local: projects that link to ../../kraya_common
195
+ │ see the new build straight away (section 12)
196
+ │
197
+ ▼
198
+ 4b. Commit, push, npm version patch, npm publish (section 13)
199
+ │
200
+ ▼
201
+ 5. In each project that needs it: npm install kcommons@<new version>
202
+ and commit "CHORE: updated kcommons to <version>"
203
+ ```
204
+
205
+ Most features touch kcommons plus one or more projects. Use the same branch name in every repo (for example `feat/plugins-for-reports`) and merge kcommons first, because the other projects depend on it.
206
+
207
+ ---
208
+
209
+ ## 7. The big ideas
210
+
211
+ ### 7.1 One table = one typings file with three parts
212
+
213
+ Every database table gets a typings file with the same three parts. Example, `typings/system/reportScheduleRecipient.typings.ts`:
214
+
215
+ ```ts
216
+ import { INestedReportsPluginConfigCompany } from "./reportsPluginConfigCompany.typings";
217
+
218
+ // Part 1 — which relations can be included
219
+ export enum REPORT_SCHEDULE_RECIPIENT_INCLUDE {
220
+ schedule = "schedule",
221
+ }
222
+
223
+ // Part 2 — the full row, WITH its relations
224
+ export interface IReportScheduleRecipient {
225
+ id: string;
226
+ schedule_id: string;
227
+ to_emails: string[];
228
+ // ...
229
+ created_at: string;
230
+ updated_at: string;
231
+
232
+ schedule: INestedReportsPluginConfigCompany; // relation
233
+ }
234
+
235
+ // Part 3 — the row WITHOUT relations, for use inside other types
236
+ export interface INestedReportScheduleRecipient
237
+ extends Omit<IReportScheduleRecipient, "schedule"> {}
238
+ ```
239
+
240
+ Rules:
241
+
242
+ - Field names are snake_case and match the database columns exactly.
243
+ - Relations inside `I<Name>` always use the other table's `INested<...>` type. This stops types from nesting forever.
244
+ - `INested<Name>` = `Omit<I<Name>, every relation key>`. When you add a relation, add it to the `Omit` list too.
245
+ - Dates are `string` (they arrive as JSON). Nullable columns are `T | null`.
246
+
247
+ ### 7.2 The types follow the database, not the other way round
248
+
249
+ The Kraya backend's Prisma schema owns the database. When a column, table or enum value changes there, update the matching typing here in the same feature branch. Enums that exist in Prisma (for example `REPORTS_PLUGIN`, `REPORT_FREQUENCY`) must have exactly the same values here.
250
+
251
+ ### 7.3 The barrel (`index.ts`)
252
+
253
+ Other projects only ever import from `'kcommons'`, never from a deep path. So:
254
+
255
+ - Every new file must get an `export * from "./path/to/file";` line in `index.ts`, under the right comment heading (`// Constants`, `// Utils`, `// For Reports`, …).
256
+ - Export names must be unique across the whole package. Two files exporting the same name will clash in the barrel.
257
+ - `index.ts` also re-exports all of `date-fns`, so don't create exports with date-fns names (`format`, `addDays`, …).
258
+
259
+ ### 7.4 Report data types
260
+
261
+ Report data is built by the ERP Integration Server and drawn by the Report Generation Engine. Both import the shape from here, so the shape is the contract between them.
262
+
263
+ - Folder: `typings/reports/<company>/`, file `<company>_<reportName>.typings.ts`. Example: `reports/hsfpl/hsfpl_haltingVehicles.typings.ts`.
264
+ - Every type and enum in it gets the company prefix: `IABC_HaltingVehiclesReport`, `ABC_HALTING_VEHICLE_APPROVAL`.
265
+ - The top-level type is `I<COMPANY>_<Name>Report`. That is what the ERP server returns as `report_data`.
266
+ - Change the shape here first, then the ERP server (data), then the engine (PDF).
267
+
268
+ Schedules and their history are typed in `typings/system/` (`IReportsPluginConfigCompany`, `IReportScheduleRecipient`), and the plugin enums are in `typings/plugins/reports.plugins.ts`.
269
+
270
+ ### 7.5 Shared logic lives in `utils/`
271
+
272
+ Put a function here only when more than one project needs the exact same answer. Good examples:
273
+
274
+ - `calculateNextRunAt(schedule, after)`: the next time a report schedule should run. `send_time`, `day_of_week` and `date_of_month` are read as IST; the result is a UTC `Date`. MONTHLY clamps day 31 to the last day of shorter months. Returns `null` for an unknown frequency. The ERP server's scheduler uses it.
275
+ - `taxes.util.ts`: tax and discount maths, so the frontend total matches the backend total.
276
+ - `businessTime.util.ts`, `convertDurationToreadableFormat.util.ts`, `toFixedDecimal.util.ts`, `convertToINS.util.ts`: formatting that must look the same everywhere.
277
+ - `validators/`: GST, PAN, CIN and Udyam format checks.
278
+
279
+ Every util must be a pure function: same input, same output, no database, no network, no global state.
280
+
281
+ ---
282
+
283
+ ## 8. Naming rules
284
+
285
+ > The golden rule: look at the files next to yours and name things the same way.
286
+
287
+ ### 8.1 Files
288
+
289
+ Format: `<name>.<type>.ts`, with `<name>` in camelCase.
290
+
291
+ | Suffix | What is inside | Example |
292
+ | ---------------- | --------------------------------- | ---------------------------------------- |
293
+ | `.typings.ts` | Interfaces, types, `_INCLUDE` enums | `grn.typings.ts` |
294
+ | `.constants.ts` | Fixed values | `statuses.constants.ts` |
295
+ | `.enum.ts` | A stand-alone enum | `priority.enum.ts` |
296
+ | `.util.ts` | A helper function with logic | `calculateNextRunAt.util.ts` |
297
+ | `.validator.ts` | A format validator | `gst.validator.ts` |
298
+ | `.helper.ts` | A tiny generic helper | `padNumber.helper.ts` |
299
+ | `.class.ts` | A class | `asnWrapper.class.ts` |
300
+ | `.spec.ts` | Tests, next to the file they test | `calculateNextRunAt.util.spec.ts` |
301
+
302
+ Company-specific files get a lowercase company prefix: `abc_haltingVehicles.typings.ts`.
303
+
304
+ ### 8.2 Names inside files
305
+
306
+ | Kind | Pattern | Example |
307
+ | ------------------------- | -------------------------------- | ----------------------------------------- |
308
+ | Full row type | `I<Name>` | `IReportsPluginConfigCompany` |
309
+ | Row without relations | `INested<Name>` | `INestedReportsPluginConfigCompany` |
310
+ | Include enum | `<NAME>_INCLUDE` | `REPORT_SCHEDULE_RECIPIENT_INCLUDE` |
311
+ | Other interfaces | `I<Name>` | `IScheduleShape`, `ITaxRelatedItemInputs` |
312
+ | Enums and constant objects| `UPPER_SNAKE_CASE` | `REPORTS_PLUGIN`, `STATUSES` |
313
+ | Enum values | `UPPER_SNAKE_CASE` = same string | `DAILY = "DAILY"` |
314
+ | Include enum values | the relation name | `schedule = "schedule"` |
315
+ | Company-specific type | `I<COMPANY>_<Name>` | `IABC_HaltingVehiclesReport` |
316
+ | Company-specific enum | `<COMPANY>_<NAME>` | `ABC_HALTING_VEHICLE_APPROVAL` |
317
+ | Functions | camelCase, starts with a verb | `calculateNextRunAt`, `getContactPerson` |
318
+ | Fields | snake_case, same as the DB column| `next_run_at`, `to_emails` |
319
+
320
+ ---
321
+
322
+ ## 9. Coding rules and style
323
+
324
+ - It must run in the browser. The frontends import this package. Don't import Node-only modules (`fs`, `path`, `crypto`, `node:*`), NestJS, Prisma or React. Use only TypeScript, `date-fns`, `zod` and `uuid`.
325
+ - No side effects. A file must not do anything when imported (no `console.log`, no timers, no reading `process.env`).
326
+ - Use relative imports (`../typings/...`). There are no path aliases here.
327
+ - Strict TypeScript is on. Avoid `any`; if you must use it, keep it small and local.
328
+ - Don't add a new dependency unless every project can live with it. Each one ends up in the frontends' bundles.
329
+ - Prefer enums over plain strings for statuses and kinds, and use string enums (`A = "A"`) so values survive JSON.
330
+ - When you change an existing type, remember it is used in five projects. Adding an optional field is safe. Renaming or removing a field, or making one required, breaks other projects; search them first and fix them in the same branch.
331
+ - Don't leave test or sample types in `index.ts` (see `ITesting` in section 16).
332
+
333
+ ---
334
+
335
+ ## 10. Recipes: step-by-step guides
336
+
337
+ ### 10.1 Add types for a new table
338
+
339
+ Example: a new table `report_delivery_log`.
340
+
341
+ 1. Backend first: add the model and migration in the Kraya backend.
342
+ 2. Create `typings/system/reportDeliveryLog.typings.ts` with the three parts from section 7.1 (`REPORT_DELIVERY_LOG_INCLUDE`, `IReportDeliveryLog`, `INestedReportDeliveryLog`).
343
+ 3. If another table has a relation to it, add the field to that table's `I<Name>` and to its `INested<Name>` `Omit` list.
344
+ 4. Export the file from `index.ts`.
345
+ 5. `npx tsc`, then link or publish (sections 12 and 13).
346
+
347
+ ### 10.2 Add a field to an existing type
348
+
349
+ 1. Add the field with its exact column name and nullability: `max_halt_days_for_halting_vehicles_report: number | null;`.
350
+ 2. If it is a relation, also add it to the `INested<Name>` `Omit` list.
351
+ 3. `npx tsc`, and build the projects that use the type to make sure nothing broke.
352
+
353
+ ### 10.3 Add a report data type for a company
354
+
355
+ 1. Create `typings/reports/<company>/<company>_<reportName>.typings.ts`.
356
+ 2. Write the pieces (`IABC_<Name>Kpis`, `IABC_<Name>Row`, …) and one top-level `IABC_<Name>Report`.
357
+ 3. If it's a new report kind, add the value to `REPORTS_PLUGIN` in `typings/plugins/reports.plugins.ts`, with the same value as the backend's Prisma enum.
358
+ 4. Export it under `// For Reports` in `index.ts`.
359
+ 5. Then follow "Add a new report" in the ERP server's README (data) and the engine's README (PDF).
360
+
361
+ ### 10.4 Add a helper function
362
+
363
+ 1. Create `utils/<name>.util.ts` with one exported pure function. Write the return type.
364
+ 2. Create `utils/<name>.util.spec.ts` next to it. Cover normal cases, `null`/`undefined`/`NaN` inputs, and edge cases (for dates: month ends, IST midnight).
365
+ 3. `npm test`.
366
+ 4. Export it under `// Utils` in `index.ts`.
367
+
368
+ ### 10.5 Add a constant or enum value
369
+
370
+ 1. Add it to the right `constants/*.constants.ts` (or `enums/*.enum.ts`).
371
+ 2. If the value also exists in Prisma, it must match the backend exactly.
372
+ 3. Check the projects that `switch` on that enum. A new value may need a new `case` there.
373
+
374
+ ---
375
+
376
+ ## 11. Testing
377
+
378
+ - Tests use Jest with `ts-jest`. Test files end with `.spec.ts` and sit next to the code (`utils/taxes.util.spec.ts`).
379
+ - Run them with `npm test`.
380
+ - Every function in `utils/` and `helpers/` should have a spec. Types and constants don't need tests.
381
+ - Keep tests free of network and dates that change: pass a fixed `Date` instead of using `new Date()` inside the test.
382
+
383
+ ```ts
384
+ import { padNumber } from "./padNumber.helper";
385
+
386
+ describe("padNumber", () => {
387
+ it("pads single digits", () => {
388
+ expect(padNumber(7)).toBe("07");
389
+ });
390
+ it("returns non-numeric strings as they are", () => {
391
+ expect(padNumber("abc")).toBe("abc");
392
+ });
393
+ });
394
+ ```
395
+
396
+ ---
397
+
398
+ ## 12. Using your local copy in another project
399
+
400
+ While you work on a feature, you want the backend or the ERP server to use your local kcommons, not the published one. We do this with a symlink:
401
+
402
+ ```bash
403
+ # from the other project, e.g. erp-integration-server/
404
+ rm -rf node_modules/kcommons
405
+ ln -s ../../kraya_common node_modules/kcommons
406
+ ```
407
+
408
+ Then, every time you change kcommons, run `npx tsc` in `kraya_common`. The other project reads `build/` straight away (restart its dev server if it doesn't notice).
409
+
410
+ Things to know:
411
+
412
+ - `npm install` in the other project can replace or delete the link. Check `ls -la node_modules/kcommons` after installing and link again if needed.
413
+ - The link only exists on your machine. Before you merge, the other project's `package.json` must point to a published version that has your change (section 13).
414
+ - Today the backend, the vendor panel, the ERP server and the engine are all linked like this on the main dev machine. The company panel uses the published package.
415
+
416
+ ---
417
+
418
+ ## 13. Publishing a new version
419
+
420
+ Only publish from `master` (or with the team's agreement), after your changes are merged.
421
+
422
+ ```bash
423
+ cd kraya_common
424
+ git checkout master && git pull
425
+ npx tsc # build/ must match the source
426
+ git add . && git commit -m "CHORE: did npm run prepare" # build/ is committed (see section 16)
427
+ git push
428
+ npm version patch # bumps package.json, makes a commit and a tag, e.g. 18.25.7
429
+ git push --follow-tags
430
+ npm publish # runs "prepare" (tsc) again, then uploads build/
431
+ ```
432
+
433
+ Which number to bump:
434
+
435
+ | Change | Command |
436
+ | --------------------------------------------------------- | ------------------- |
437
+ | New types, fields, utils, enum values (nothing breaks) | `npm version patch` |
438
+ | A type or function changed in a way that breaks a project | `npm version minor` and tell the team |
439
+ | Big rework | `npm version major` (agree with the team first) |
440
+
441
+ Then, in each project that needs the change:
442
+
443
+ ```bash
444
+ npm install kcommons@<new version>
445
+ ```
446
+
447
+ and commit it as `CHORE: updated kcommons to <version>`.
448
+
449
+ ---
450
+
451
+ ## 14. Git and teamwork
452
+
453
+ Same as the other projects:
454
+
455
+ - Branches: `master` ← `dev` ← `feat/...`, `hotfix/...`, `refactor/...`. Branch from `dev`.
456
+ - Commits: `FEAT:`, `FIX:`, `CHORE:`, `REFACTOR:` followed by what changed in plain words. Version bumps made by `npm version` are just the number (for example `18.25.6`).
457
+ - Use the same branch name as the matching branches in the backend / ERP server / engine, and merge kcommons first.
458
+
459
+ Before you open a PR:
460
+
461
+ - [ ] `npx tsc` passes
462
+ - [ ] `npm test` passes, and new utils have specs
463
+ - [ ] New files are exported from `index.ts`
464
+ - [ ] Types match the backend's Prisma schema
465
+ - [ ] No Node-only, NestJS, Prisma or React imports
466
+ - [ ] You searched the other projects for any type you renamed or removed
467
+
468
+ ---
469
+
470
+ ## 15. Troubleshooting and FAQ
471
+
472
+ | Problem | What it means / what to do |
473
+ | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
474
+ | `Module 'kcommons' has no exported member 'X'` | X isn't in `index.ts`, you didn't run `npx tsc`, or the project uses an older published version. Check `node_modules/kcommons`. |
475
+ | `Cannot find module 'kcommons'` | The project's link was removed (often by `npm install`), or `kcommons` isn't in its `package.json`. Link again (section 12). |
476
+ | My change works locally but CI / the server breaks | Your local link hides the problem. Publish a version and install it in the project. |
477
+ | `Module "./x" has already exported a member named 'Y'` | Two files export the same name. Rename one. |
478
+ | A frontend fails to build after a kcommons change | You probably imported something Node-only. See section 9. |
479
+ | `npm publish` says the version already exists | Someone published that number already. Pull, then `npm version patch` again. |
480
+ | The report schedule runs at the wrong hour | `send_time` is IST and `calculateNextRunAt` returns UTC. Check you're not converting twice. |
481
+
482
+ ---
483
+
484
+ ## 16. Things that don't follow the rules yet
485
+
486
+ You will see some older code that doesn't match this document. Follow this document for new code, and fix old code only in a separate `REFACTOR:` commit.
487
+
488
+ | What | Where | How it should look |
489
+ | -------------------------------------- | -------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
490
+ | `prepare` cleans the wrong folder | `"prepare": "rm -rf ./dist && npx tsc"`, but the output folder is `build/` | `rm -rf ./build && npx tsc`, so deleted files don't linger in `build/` |
491
+ | `build/` is committed | `.gitignore` only ignores `node_modules` | Ignore `build/` and let `prepare` build it on publish |
492
+ | Tests end up in the package | `tsconfig.json` has no `exclude`, so `*.spec.ts` compile into `build/` | Exclude `**/*.spec.ts` |
493
+ | Old publish notes | This file used to be four lines of publish steps | This document |
494
+ | Sample type in the barrel | `ITesting` at the end of `index.ts` | Delete it |
495
+ | Same file exported twice | `reports/hsfpl/hsfpl_haltingVehicles.typings` under `// Plugins` and `// For Reports` | Only under `// For Reports` |
496
+ | Missing company prefix | `IHaltingVehiclesNeedsAction` in the HSFPL report typings | `IHSFPL_HaltingVehiclesNeedsAction` |
497
+ | File name typos | `companySepcificVendorItems`, `companyDocumentUplodPath`, `getDefaultVAlues`, `comparativeItemQUantitySplit`, `convertDurationToreadableFormat`, `removeQueryParamsFormReqStr.util.spec.ts` | Correct spelling (rename and update `index.ts` in one commit) |
498
+ | Mixed folder layout | Many entities at the top of `typings/`, newer ones under `typings/company/...` | New company entities go under `typings/company/` |
499
+ | Whole of date-fns re-exported | `export * from "date-fns"` in `index.ts` | Import date-fns directly in each project |
500
+ | `.DS_Store` files | `typings/`, `utils/`, repo root | Delete them and add `.DS_Store` to `.gitignore` |
501
+ | Projects on different versions | Backend `^18.25.4`, company panel `^18.25.6`, vendor panel `^18.22.4`; the ERP server and engine have no `kcommons` entry in `package.json` at all | Every project lists `kcommons` and is updated together |
502
+ | Registry ahead of `master` | npm has `18.26.0`, `package.json` here says `18.25.6` | Publish only from `master`, so the repo and npm agree |
503
+ | Utils without tests | `calculateNextRunAt`, `generateId`, `calculateToleranceRange`, `getFileExtension`, `stripQueryParams`, the validators and the extra-form utils have no `.spec.ts` | A spec next to each one, starting with `calculateNextRunAt` (it decides when reports are sent) |
504
+ | No lint / format config | No ESLint or Prettier here | Add the same Prettier config as the other projects |
505
+
506
+ ---
507
+
508
+ ## 17. Cheat sheet
509
+
510
+ Build it: `npx tsc` ➜ `build/`. Test it: `npm test`.
511
+
512
+ The change path: edit ➜ export from `index.ts` ➜ `npx tsc` ➜ (local: linked projects see it) ➜ merge ➜ `npm version patch` ➜ `npm publish` ➜ `npm install kcommons@<version>` in each project.
513
+
514
+ Naming at a glance (table `report_schedule_recipient`):
515
+
516
+ | Thing | Name |
517
+ | ----------------- | --------------------------------------------- |
518
+ | File | `typings/system/reportScheduleRecipient.typings.ts` |
519
+ | Full row | `IReportScheduleRecipient` |
520
+ | Without relations | `INestedReportScheduleRecipient` |
521
+ | Include enum | `REPORT_SCHEDULE_RECIPIENT_INCLUDE` |
522
+ | Report data type | `IABC_HaltingVehiclesReport` in `typings/reports/abc/abc_haltingVehicles.typings.ts` |
523
+ | Util | `utils/taxes.util.ts` + `utils/taxes.util.spec.ts` |
524
+ | Commit | `FEAT: Added report schedule recipient typings` |
525
+
526
+ Golden rules:
527
+
528
+ 1. Five projects depend on this. Add freely, but search before you rename or remove.
529
+ 2. Types follow the backend's Prisma schema, with the same field names and enum values.
530
+ 3. Every table gets `I<Name>`, `INested<Name>` and `<NAME>_INCLUDE`.
531
+ 4. Everything is exported from `index.ts`, and nothing is imported by deep path.
532
+ 5. Utils are pure, browser-safe and tested.
533
+ 6. Build after every change; publish only from `master`.
534
+ 7. When in doubt, copy what the files next to yours do.