@mostajs/crm 0.0.1

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.
package/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ @mostajs/crm
2
+ Copyright (C) 2026 Dr Hamid MADANI <drmdh@msn.com>
3
+
4
+ This program is free software: you can redistribute it and/or modify it under
5
+ the terms of the GNU Affero General Public License as published by the Free
6
+ Software Foundation, either version 3 of the License, or (at your option) any
7
+ later version.
8
+
9
+ This program is distributed in the hope that it will be useful, but WITHOUT
10
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
+ FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
12
+ details.
13
+
14
+ You should have received a copy of the GNU Affero General Public License
15
+ along with this program. If not, see <https://www.gnu.org/licenses/agpl-3.0.html>.
package/README.md ADDED
@@ -0,0 +1,55 @@
1
+ # @mostajs/crm
2
+
3
+ > Domaine **CRM trading** (clients, employés, fournisseurs, commandes, commentaires, proformats). Module **mince** qui **compose** `@mostajs/workflow` (automate de commande à 9 états + historique immuable + **couleurs** + `party`), `@mostajs/numbering` (n° commande / réf proforma) et `@mostajs/i18n` (libellés d'état FR/EN/AR). N'implémente que ses **entités + règles métier**.
4
+
5
+ **Auteur** : Dr Hamid MADANI <drmdh@msn.com> · **Licence** : AGPL-3.0-or-later
6
+ **Consommateur** : application TRADING — déployée sur **https://crm.amia.fr** (amia).
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm i @mostajs/crm @mostajs/workflow @mostajs/statemachine @mostajs/trigger @mostajs/numbering @mostajs/i18n
12
+ ```
13
+
14
+ ## Exemple
15
+
16
+ ```ts
17
+ import { createCrm, createMemoryRepositories } from "@mostajs/crm";
18
+
19
+ const crm = createCrm({ repositories: createMemoryRepositories(), locale: "fr" });
20
+
21
+ const client = await crm.repositories.clients.save({ nom: "Doe", societe: "ACME" });
22
+ const order = await crm.createOrder({ clientId: client.id, text: "100x widgets" });
23
+ // order.number ≈ "2026-05-31-001" ; order.state = "init"
24
+
25
+ await crm.transitionOrder(order.id, "notification_attente", { actorId: "u1" }, { comment: "envoyé" });
26
+ await crm.orderHistory(order.id); // historique immuable (qui / quand / from→to)
27
+
28
+ crm.orderStateLabel("notification_attente"); // i18n : "Notification — en attente" (fr)
29
+ crm.orderStateColors()["client_informe"]; // "#10B981"
30
+ ```
31
+
32
+ ## Automate de commande (preset `orderWorkflow`)
33
+
34
+ `init` (admin/manager/employé) → `notification_attente` (émetteur) → `relance_emetteur_attente` (émetteur) → `reponse_attente` (destinataire) → `relance_destinataire_attente` (destinataire) → `validation_attente` (émetteur) → `finalisation_attente` (destinataire) → `client_informe` (émetteur). `annulee` depuis tout état non terminal.
35
+
36
+ Chaque état porte une **couleur** (`#RRGGBB`), une **`party`** (`sender`/`receiver`) et un **libellé = clé i18n** (`order:state.<id>`, traduit FR/EN/AR via `@mostajs/i18n`).
37
+
38
+ ## Entités (CDC §3)
39
+
40
+ `Client`, `Employee` (statut `Libre`/`Occupé`, `userId`), `Supplier`, `Order` (number, clientId, assigneeId, text, attachments, state), `Comment`, `Proforma` (ref, orderId, supplierId, pdfFileId).
41
+
42
+ ## Composition
43
+
44
+ | Capacité | Module |
45
+ |---|---|
46
+ | états + historique immuable + couleurs/party | `@mostajs/workflow` (→ statemachine + audit) |
47
+ | n° commande / réf proforma | `@mostajs/numbering` |
48
+ | libellés d'état | `@mostajs/i18n` |
49
+ | persistance (v0.1) | `@mostajs/repository`/`orm` |
50
+ | fichiers PDF/images (v0.1) | `@mostajs/storage` |
51
+ | droits Admin/Employé (v0.1) | `@mostajs/auth` + `@mostajs/rbac` |
52
+
53
+ ## Statut
54
+
55
+ **v0.0.1** — cœur **implémenté et testé** (entités, dépôts mémoire, `createOrder`/`assignFreeEmployee`/`transitionOrder`/`addProforma`/`listProformas`, couleurs + i18n). Feuille de route : `docs/03-PLAN-DEV-CRM.md` (0.1 repos ORM + storage + rbac ; 0.2 pages/handlers UI ; 1.0 = 14 livrables). Étude : `docs/01-ETUDE-ETAT-ART-CRM-07062026.md`.
package/dist/crm.d.ts ADDED
@@ -0,0 +1,99 @@
1
+ /**
2
+ * @mostajs/crm — service de domaine (compose workflow + numbering).
3
+ *
4
+ * N'implémente que les entités CRM et leurs règles métier (numérotation,
5
+ * assignation, suivi d'état, proformats). Le suivi d'état + l'historique
6
+ * immuable viennent de @mostajs/workflow ; les références de @mostajs/numbering.
7
+ *
8
+ * @author Dr Hamid MADANI <drmdh@msn.com>
9
+ * @license AGPL-3.0-or-later
10
+ */
11
+ import { type Workflow } from "@mostajs/workflow";
12
+ import { type Numbering } from "@mostajs/numbering";
13
+ import type { ExecutedTransition } from "@mostajs/statemachine";
14
+ import { type I18nInstance, type TranslateVars } from "@mostajs/i18n";
15
+ import { type CrmRepositories, type Employee, type Order, type Comment, type Proforma, type ProformaFilter } from "./types.js";
16
+ export interface CrmOptions {
17
+ repositories: CrmRepositories;
18
+ /** Service de numérotation (défaut : un service mémoire ; séquences `order`/`proforma` déclarées). */
19
+ numbering?: Numbering;
20
+ /** Workflow de commande (défaut : preset `orderWorkflow`, sans enforcement de permission). */
21
+ workflow?: Workflow;
22
+ /** Instance i18n (défaut : créée avec les bundles `order` FR/EN/AR). */
23
+ i18n?: I18nInstance;
24
+ /** Locale par défaut si `i18n` non fourni (défaut : `"fr"`). */
25
+ locale?: string;
26
+ /** Horloge injectée (testabilité). */
27
+ now?: () => Date;
28
+ }
29
+ /** Vue d'un état pour l'UI : id + libellé traduit + couleur + party. */
30
+ export interface OrderStateView {
31
+ id: string;
32
+ label: string;
33
+ color?: string;
34
+ party?: string;
35
+ terminal: boolean;
36
+ }
37
+ export interface CreateOrderInput {
38
+ clientId: string;
39
+ text: string;
40
+ assigneeId?: string;
41
+ attachments?: string[];
42
+ }
43
+ export declare class Crm {
44
+ private readonly repos;
45
+ private readonly numbering;
46
+ private readonly workflow;
47
+ private readonly i18n;
48
+ private readonly now;
49
+ constructor(opts: CrmOptions);
50
+ /** Accès à l'instance i18n (locale, setLocale, t…). */
51
+ get translator(): I18nInstance;
52
+ /** Traduit une clé i18n (passe-plat vers @mostajs/i18n). */
53
+ t(key: string, vars?: TranslateVars): string;
54
+ /** Accès direct aux dépôts (CRUD clients/employés/fournisseurs — droits gérés à l'app). */
55
+ get repositories(): CrmRepositories;
56
+ /** Crée une commande : numéro auto, état initial du workflow. (Création Admin — CDC §3.4.) */
57
+ createOrder(input: CreateOrderInput): Promise<Order & {
58
+ id: string;
59
+ }>;
60
+ /** Assigne le premier employé au statut `Libre` (CDC §3.4). */
61
+ assignFreeEmployee(orderId: string): Promise<Employee & {
62
+ id: string;
63
+ }>;
64
+ /** Change l'état d'une commande via le workflow (garde + historique immuable). */
65
+ transitionOrder(orderId: string, to: string, actor?: {
66
+ actorId?: string;
67
+ }, opts?: {
68
+ comment?: string;
69
+ }): Promise<ExecutedTransition>;
70
+ /** Historique chronologique immuable des états d'une commande (CDC §3.6). */
71
+ orderHistory(orderId: string): Promise<ExecutedTransition[]>;
72
+ addComment(orderId: string, authorId: string, text: string): Promise<Comment & {
73
+ id: string;
74
+ }>;
75
+ listComments(orderId: string): Promise<(Comment & {
76
+ id: string;
77
+ })[]>;
78
+ /** Ajoute un proformat (réf auto) à une commande. */
79
+ addProforma(orderId: string, input: {
80
+ supplierId: string;
81
+ pdfFileId?: string;
82
+ }): Promise<Proforma & {
83
+ id: string;
84
+ }>;
85
+ /** Liste des proformats avec filtres fournisseur / client / date (CDC §3.9). */
86
+ listProformas(filter?: ProformaFilter): Promise<(Proforma & {
87
+ id: string;
88
+ })[]>;
89
+ /** Map id d'état → code couleur (pour badges/kanban). */
90
+ orderStateColors(): Record<string, string | undefined>;
91
+ /** Libellé **traduit** d'un état (via @mostajs/i18n ; clé `order:state.<id>`). */
92
+ orderStateLabel(stateId: string): string;
93
+ /** Vue UI de tous les états : id + libellé traduit + couleur + party (triés par poids). */
94
+ orderStates(): OrderStateView[];
95
+ private requireOrder;
96
+ }
97
+ /** Crée le service CRM. Sans options de composition, utilise des dépôts/numbering/workflow par défaut. */
98
+ export declare function createCrm(opts: CrmOptions): Crm;
99
+ //# sourceMappingURL=crm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crm.d.ts","sourceRoot":"","sources":["../src/crm.ts"],"names":[],"mappings":"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"}
package/dist/crm.js ADDED
@@ -0,0 +1,160 @@
1
+ /**
2
+ * @mostajs/crm — service de domaine (compose workflow + numbering).
3
+ *
4
+ * N'implémente que les entités CRM et leurs règles métier (numérotation,
5
+ * assignation, suivi d'état, proformats). Le suivi d'état + l'historique
6
+ * immuable viennent de @mostajs/workflow ; les références de @mostajs/numbering.
7
+ *
8
+ * @author Dr Hamid MADANI <drmdh@msn.com>
9
+ * @license AGPL-3.0-or-later
10
+ */
11
+ import { defineWorkflow, orderWorkflowDef, orderWorkflowBundles } from "@mostajs/workflow";
12
+ import { createNumbering } from "@mostajs/numbering";
13
+ import { createI18n } from "@mostajs/i18n";
14
+ import { NotFoundError, NoFreeEmployeeError, } from "./types.js";
15
+ /** Date civile locale `YYYY-MM-DD` d'un instant (cohérent avec la numérotation locale). */
16
+ function localDate(d) {
17
+ const p2 = (n) => String(n).padStart(2, "0");
18
+ return `${d.getFullYear()}-${p2(d.getMonth() + 1)}-${p2(d.getDate())}`;
19
+ }
20
+ export class Crm {
21
+ repos;
22
+ numbering;
23
+ workflow;
24
+ i18n;
25
+ now;
26
+ constructor(opts) {
27
+ this.repos = opts.repositories;
28
+ this.now = opts.now ?? (() => new Date());
29
+ this.numbering = opts.numbering ?? createNumbering({ now: this.now });
30
+ this.numbering.define({ name: "order", format: "YYYY-MM-DD-NNN", resetEvery: "day" });
31
+ this.numbering.define({ name: "proforma", format: "PF-YYYY-MM-DD-XXX", resetEvery: "day" });
32
+ this.workflow = opts.workflow ?? defineWorkflow(orderWorkflowDef(), { now: this.now });
33
+ this.i18n =
34
+ opts.i18n ?? createI18n({ locale: opts.locale ?? "fr", fallback: "en", bundles: orderWorkflowBundles() });
35
+ }
36
+ /** Accès à l'instance i18n (locale, setLocale, t…). */
37
+ get translator() {
38
+ return this.i18n;
39
+ }
40
+ /** Traduit une clé i18n (passe-plat vers @mostajs/i18n). */
41
+ t(key, vars) {
42
+ return this.i18n.t(key, vars);
43
+ }
44
+ /** Accès direct aux dépôts (CRUD clients/employés/fournisseurs — droits gérés à l'app). */
45
+ get repositories() {
46
+ return this.repos;
47
+ }
48
+ // ── Commandes ──────────────────────────────────────────────────────────────
49
+ /** Crée une commande : numéro auto, état initial du workflow. (Création Admin — CDC §3.4.) */
50
+ async createOrder(input) {
51
+ const date = this.now();
52
+ const number = await this.numbering.next("order", { date });
53
+ return this.repos.orders.save({
54
+ number,
55
+ clientId: input.clientId,
56
+ text: input.text,
57
+ assigneeId: input.assigneeId,
58
+ attachments: input.attachments ?? [],
59
+ createdAt: date.toISOString(),
60
+ state: this.workflow.initial,
61
+ });
62
+ }
63
+ /** Assigne le premier employé au statut `Libre` (CDC §3.4). */
64
+ async assignFreeEmployee(orderId) {
65
+ const order = await this.requireOrder(orderId);
66
+ const free = (await this.repos.employees.find((e) => e.statut === "Libre"))[0];
67
+ if (!free)
68
+ throw new NoFreeEmployeeError("Aucun employé au statut Libre.");
69
+ order.assigneeId = free.id;
70
+ await this.repos.orders.save(order);
71
+ return free;
72
+ }
73
+ /** Change l'état d'une commande via le workflow (garde + historique immuable). */
74
+ async transitionOrder(orderId, to, actor = {}, opts = {}) {
75
+ const order = await this.requireOrder(orderId);
76
+ const executed = await this.workflow.transition({ entityType: "order", entityId: order.id }, order.state ?? this.workflow.initial, to,
77
+ // `orderId` dans `data` → permet aux gardes de transition (Phase 2) de charger la commande.
78
+ { actorId: actor.actorId, comment: opts.comment, data: { assigneeId: order.assigneeId, orderId: order.id } });
79
+ order.state = to;
80
+ await this.repos.orders.save(order);
81
+ return executed;
82
+ }
83
+ /** Historique chronologique immuable des états d'une commande (CDC §3.6). */
84
+ orderHistory(orderId) {
85
+ return this.workflow.history({ entityType: "order", entityId: orderId });
86
+ }
87
+ // ── Commentaires (CDC §3.7) ──────────────────────────────────────────────────
88
+ async addComment(orderId, authorId, text) {
89
+ await this.requireOrder(orderId);
90
+ return this.repos.comments.save({ orderId, authorId, text, createdAt: this.now().toISOString() });
91
+ }
92
+ listComments(orderId) {
93
+ return this.repos.comments.find((c) => c.orderId === orderId);
94
+ }
95
+ // ── Proformats (CDC §3.8/§3.9) ───────────────────────────────────────────────
96
+ /** Ajoute un proformat (réf auto) à une commande. */
97
+ async addProforma(orderId, input) {
98
+ await this.requireOrder(orderId);
99
+ const date = this.now();
100
+ const ref = await this.numbering.next("proforma", { date });
101
+ return this.repos.proformas.save({
102
+ ref,
103
+ orderId,
104
+ supplierId: input.supplierId,
105
+ pdfFileId: input.pdfFileId,
106
+ createdAt: date.toISOString(),
107
+ });
108
+ }
109
+ /** Liste des proformats avec filtres fournisseur / client / date (CDC §3.9). */
110
+ async listProformas(filter = {}) {
111
+ let list = await this.repos.proformas.all();
112
+ if (filter.supplierId)
113
+ list = list.filter((p) => p.supplierId === filter.supplierId);
114
+ if (filter.clientId) {
115
+ const orderIds = new Set((await this.repos.orders.find((o) => o.clientId === filter.clientId)).map((o) => o.id));
116
+ list = list.filter((p) => orderIds.has(p.orderId));
117
+ }
118
+ if (filter.date) {
119
+ list = list.filter((p) => p.createdAt !== undefined && localDate(new Date(p.createdAt)) === filter.date);
120
+ }
121
+ return list;
122
+ }
123
+ // ── États & couleurs (UI) ────────────────────────────────────────────────────
124
+ /** Map id d'état → code couleur (pour badges/kanban). */
125
+ orderStateColors() {
126
+ const out = {};
127
+ for (const [id, state] of this.workflow.states)
128
+ out[id] = state.color;
129
+ return out;
130
+ }
131
+ /** Libellé **traduit** d'un état (via @mostajs/i18n ; clé `order:state.<id>`). */
132
+ orderStateLabel(stateId) {
133
+ const state = this.workflow.states.get(stateId);
134
+ return this.i18n.t(state?.label ?? `order:state.${stateId}`);
135
+ }
136
+ /** Vue UI de tous les états : id + libellé traduit + couleur + party (triés par poids). */
137
+ orderStates() {
138
+ return [...this.workflow.states.values()]
139
+ .slice()
140
+ .sort((a, b) => (a.weight ?? 0) - (b.weight ?? 0))
141
+ .map((s) => ({
142
+ id: s.id,
143
+ label: this.i18n.t(s.label ?? `order:state.${s.id}`),
144
+ color: s.color,
145
+ party: s.meta?.party,
146
+ terminal: s.terminal === true,
147
+ }));
148
+ }
149
+ async requireOrder(id) {
150
+ const order = await this.repos.orders.get(id);
151
+ if (!order)
152
+ throw new NotFoundError(`Commande introuvable : ${id}`);
153
+ return order;
154
+ }
155
+ }
156
+ /** Crée le service CRM. Sans options de composition, utilise des dépôts/numbering/workflow par défaut. */
157
+ export function createCrm(opts) {
158
+ return new Crm(opts);
159
+ }
160
+ //# sourceMappingURL=crm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crm.js","sourceRoot":"","sources":["../src/crm.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @mostajs/crm — point d'entrée public (domaine CRM trading).
3
+ *
4
+ * Compose @mostajs/workflow (automate de commande + historique + couleurs),
5
+ * @mostajs/numbering (n° commande / réf proforma) et @mostajs/i18n (libellés d'état).
6
+ * N'implémente que ses 6 entités et ses règles métier.
7
+ *
8
+ * @author Dr Hamid MADANI <drmdh@msn.com>
9
+ * @license AGPL-3.0-or-later
10
+ */
11
+ export { type EmployeeStatus, type Client, type Employee, type Supplier, type Order, type Comment, type Proforma, type Collection, type CrmRepositories, type ProformaFilter, CrmError, NotFoundError, NoFreeEmployeeError, } from "./types.js";
12
+ export { MemoryCollection, createMemoryRepositories } from "./store.js";
13
+ export { Crm, createCrm, type CrmOptions, type CreateOrderInput, type OrderStateView, } from "./crm.js";
14
+ export { orderWorkflowDef, orderWorkflowBundles, ORDER_STATE_IDS } from "@mostajs/workflow";
15
+ export { makeOrderCopilotTools } from "./tools.js";
16
+ export type { CrmCopilotTool, OrderToolDeps } from "./tools.js";
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,MAAM,EACX,KAAK,QAAQ,EACb,KAAK,QAAQ,EACb,KAAK,KAAK,EACV,KAAK,OAAO,EACZ,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,QAAQ,EACR,aAAa,EACb,mBAAmB,GACpB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,EACL,GAAG,EACH,SAAS,EACT,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,cAAc,GACpB,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAG5F,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @mostajs/crm — point d'entrée public (domaine CRM trading).
3
+ *
4
+ * Compose @mostajs/workflow (automate de commande + historique + couleurs),
5
+ * @mostajs/numbering (n° commande / réf proforma) et @mostajs/i18n (libellés d'état).
6
+ * N'implémente que ses 6 entités et ses règles métier.
7
+ *
8
+ * @author Dr Hamid MADANI <drmdh@msn.com>
9
+ * @license AGPL-3.0-or-later
10
+ */
11
+ export { CrmError, NotFoundError, NoFreeEmployeeError, } from "./types.js";
12
+ export { MemoryCollection, createMemoryRepositories } from "./store.js";
13
+ export { Crm, createCrm, } from "./crm.js";
14
+ // Ré-exports pratiques du preset d'automate de commande.
15
+ export { orderWorkflowDef, orderWorkflowBundles, ORDER_STATE_IDS } from "@mostajs/workflow";
16
+ // Outils copilote du domaine « commande » (forme ChatTool structurelle, DI app).
17
+ export { makeOrderCopilotTools } from "./tools.js";
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAWL,QAAQ,EACR,aAAa,EACb,mBAAmB,GACpB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,EACL,GAAG,EACH,SAAS,GAIV,MAAM,UAAU,CAAC;AAElB,yDAAyD;AACzD,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAE5F,iFAAiF;AACjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * @mostajs/crm — dépôts en mémoire (défaut / tests).
3
+ *
4
+ * Mono-process. En production : adaptateurs @mostajs/repository/orm (v0.1).
5
+ *
6
+ * @author Dr Hamid MADANI <drmdh@msn.com>
7
+ * @license AGPL-3.0-or-later
8
+ */
9
+ import { type Collection, type CrmRepositories } from "./types.js";
10
+ export declare class MemoryCollection<T extends {
11
+ id?: string;
12
+ }> implements Collection<T> {
13
+ private readonly prefix;
14
+ private readonly items;
15
+ private seq;
16
+ constructor(prefix: string);
17
+ save(entity: T): Promise<T & {
18
+ id: string;
19
+ }>;
20
+ get(id: string): Promise<(T & {
21
+ id: string;
22
+ }) | undefined>;
23
+ all(): Promise<(T & {
24
+ id: string;
25
+ })[]>;
26
+ find(predicate: (entity: T & {
27
+ id: string;
28
+ }) => boolean): Promise<(T & {
29
+ id: string;
30
+ })[]>;
31
+ remove(id: string): Promise<boolean>;
32
+ }
33
+ /** Crée un jeu de dépôts en mémoire pour les six entités du domaine. */
34
+ export declare function createMemoryRepositories(): CrmRepositories;
35
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,KAAK,UAAU,EACf,KAAK,eAAe,EACrB,MAAM,YAAY,CAAC;AAEpB,qBAAa,gBAAgB,CAAC,CAAC,SAAS;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,CAAE,YAAW,UAAU,CAAC,CAAC,CAAC;IAInE,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAyC;IAC/D,OAAO,CAAC,GAAG,CAAK;gBAEa,MAAM,EAAE,MAAM;IAErC,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IAO5C,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,SAAS,CAAC;IAI1D,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;IAItC,IAAI,CACR,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,GACjD,OAAO,CAAC,CAAC,CAAC,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;IAI5B,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAG3C;AAED,wEAAwE;AACxE,wBAAgB,wBAAwB,IAAI,eAAe,CAS1D"}
package/dist/store.js ADDED
@@ -0,0 +1,46 @@
1
+ /**
2
+ * @mostajs/crm — dépôts en mémoire (défaut / tests).
3
+ *
4
+ * Mono-process. En production : adaptateurs @mostajs/repository/orm (v0.1).
5
+ *
6
+ * @author Dr Hamid MADANI <drmdh@msn.com>
7
+ * @license AGPL-3.0-or-later
8
+ */
9
+ export class MemoryCollection {
10
+ prefix;
11
+ items = new Map();
12
+ seq = 0;
13
+ constructor(prefix) {
14
+ this.prefix = prefix;
15
+ }
16
+ async save(entity) {
17
+ const id = entity.id ?? `${this.prefix}-${++this.seq}`;
18
+ const stored = { ...entity, id };
19
+ this.items.set(id, stored);
20
+ return stored;
21
+ }
22
+ async get(id) {
23
+ return this.items.get(id);
24
+ }
25
+ async all() {
26
+ return [...this.items.values()];
27
+ }
28
+ async find(predicate) {
29
+ return [...this.items.values()].filter(predicate);
30
+ }
31
+ async remove(id) {
32
+ return this.items.delete(id);
33
+ }
34
+ }
35
+ /** Crée un jeu de dépôts en mémoire pour les six entités du domaine. */
36
+ export function createMemoryRepositories() {
37
+ return {
38
+ clients: new MemoryCollection("client"),
39
+ employees: new MemoryCollection("emp"),
40
+ suppliers: new MemoryCollection("sup"),
41
+ orders: new MemoryCollection("order"),
42
+ comments: new MemoryCollection("cmt"),
43
+ proformas: new MemoryCollection("pf"),
44
+ };
45
+ }
46
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,MAAM,OAAO,gBAAgB;IAIE;IAHZ,KAAK,GAAG,IAAI,GAAG,EAA8B,CAAC;IACvD,GAAG,GAAG,CAAC,CAAC;IAEhB,YAA6B,MAAc;QAAd,WAAM,GAAN,MAAM,CAAQ;IAAG,CAAC;IAE/C,KAAK,CAAC,IAAI,CAAC,MAAS;QAClB,MAAM,EAAE,GAAG,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC;QACvD,MAAM,MAAM,GAAG,EAAE,GAAG,MAAM,EAAE,EAAE,EAAwB,CAAC;QACvD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QAC3B,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,EAAU;QAClB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,GAAG;QACP,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,IAAI,CACR,SAAkD;QAElD,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EAAU;QACrB,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC;CACF;AAED,wEAAwE;AACxE,MAAM,UAAU,wBAAwB;IACtC,OAAO;QACL,OAAO,EAAE,IAAI,gBAAgB,CAAC,QAAQ,CAAC;QACvC,SAAS,EAAE,IAAI,gBAAgB,CAAC,KAAK,CAAC;QACtC,SAAS,EAAE,IAAI,gBAAgB,CAAC,KAAK,CAAC;QACtC,MAAM,EAAE,IAAI,gBAAgB,CAAC,OAAO,CAAC;QACrC,QAAQ,EAAE,IAAI,gBAAgB,CAAC,KAAK,CAAC;QACrC,SAAS,EAAE,IAAI,gBAAgB,CAAC,IAAI,CAAC;KACtC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * @mostajs/crm — outils COPILOTE du domaine « commande » (forme `ChatTool` structurelle, sans
3
+ * dépendre de @mostajs/chatbot). Les opérations métier (createOrder…) vivent ici, dans leur module ;
4
+ * l'app injecte ses préoccupations transverses (acteur courant, permissions, audit) par **DI**.
5
+ *
6
+ * Usage (app) :
7
+ * makeOrderCopilotTools({ getCrm, getActor, can, audit })
8
+ *
9
+ * @author Dr Hamid MADANI <drmdh@msn.com>
10
+ * @license AGPL-3.0-or-later
11
+ */
12
+ import type { Crm } from "./crm.js";
13
+ /** Outil compatible `ChatTool` de @mostajs/chatbot (forme structurelle). */
14
+ export interface CrmCopilotTool {
15
+ name: string;
16
+ description: string;
17
+ schema: Record<string, unknown>;
18
+ run(input: unknown): Promise<unknown>;
19
+ }
20
+ /** Préoccupations transverses injectées par l'app (le module ne connaît ni l'auth ni l'audit). */
21
+ export interface OrderToolDeps {
22
+ getCrm: () => Promise<Crm>;
23
+ /** Résout l'acteur réel (jamais celui passé par le LLM). Type laissé à l'app (transmis tel quel). */
24
+ getActor: () => Promise<any>;
25
+ /** Contrôle de permission wildcard-aware. */
26
+ can: (actor: any, action: string) => boolean;
27
+ /**
28
+ * HITL gouverné par les permissions (optionnel). Renvoie true si l'acteur peut exécuter SANS
29
+ * confirmation manuelle (ex. droit « <action>.auto »). Absent → confirmation toujours requise.
30
+ */
31
+ autoConfirm?: (actor: any, action: string) => boolean;
32
+ /** Journalisation optionnelle. */
33
+ audit?: (actor: any, action: string, scope: string, meta: any) => void | Promise<void>;
34
+ }
35
+ /** Outils copilote « commande » (création, …). Écritures gardées + confirmées (human-in-the-loop). */
36
+ export declare function makeOrderCopilotTools(deps: OrderToolDeps): CrmCopilotTool[];
37
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAEpC,4EAA4E;AAC5E,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,GAAG,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACvC;AAED,kGAAkG;AAClG,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3B,qGAAqG;IAErG,QAAQ,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7B,6CAA6C;IAE7C,GAAG,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IAC7C;;;OAGG;IAEH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IACtD,kCAAkC;IAElC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxF;AAQD,sGAAsG;AACtG,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,aAAa,GAAG,cAAc,EAAE,CAkC3E"}
package/dist/tools.js ADDED
@@ -0,0 +1,56 @@
1
+ const obj = (i) => (i ?? {});
2
+ const str = (v) => (v == null ? "" : String(v)).trim();
3
+ const label = (p) => [p.prenom, p.nom].filter(Boolean).join(" ") || p.societe || p.nom || p.id || "?";
4
+ const match = (p, q) => p.id === q || `${p.nom ?? ""} ${p.prenom ?? ""} ${p.societe ?? ""} ${p.email ?? ""}`.toLowerCase().includes(q.toLowerCase());
5
+ /** Outils copilote « commande » (création, …). Écritures gardées + confirmées (human-in-the-loop). */
6
+ export function makeOrderCopilotTools(deps) {
7
+ return [
8
+ {
9
+ name: "create_order",
10
+ description: "CRÉE une nouvelle commande. ÉCRITURE : nécessite confirm=true. Réservé à l'admin/habilité (order.create). Préciser le CLIENT (nom/société/email ou id, doit déjà exister) et l'OBJET (ce qui est à traiter/sourcer) ; assigné optionnel. Sans confirmation, renvoie un aperçu.",
11
+ schema: {
12
+ type: "object",
13
+ properties: {
14
+ client: { type: "string", description: "Client : nom, société, email ou id (doit déjà exister)" },
15
+ object: { type: "string", description: "Objet / description de la commande" },
16
+ assignee: { type: "string", description: "Employé assigné (nom ou id) — optionnel" },
17
+ confirm: { type: "boolean", description: "true pour créer réellement" },
18
+ },
19
+ required: ["client", "object"],
20
+ },
21
+ async run(input) {
22
+ const i = obj(input);
23
+ const clientQ = str(i.client);
24
+ const text = str(i.object);
25
+ if (!clientQ || !text)
26
+ return { error: "préciser le client et l'objet de la commande" };
27
+ const crm = await deps.getCrm();
28
+ const actor = await deps.getActor();
29
+ if (!deps.can(actor, "order.create"))
30
+ return { error: "permission refusée (order.create)" };
31
+ const clients = (await crm.repositories.clients.all());
32
+ const client = clients.find((c) => c.id === clientQ) || clients.find((c) => match(c, clientQ));
33
+ if (!client?.id)
34
+ return { error: `client « ${clientQ} » introuvable — créer le client d'abord` };
35
+ let assigneeId;
36
+ let assigneeName;
37
+ const aq = str(i.assignee);
38
+ if (aq) {
39
+ const emps = (await crm.repositories.employees.all());
40
+ const emp = emps.find((e) => e.id === aq) || emps.find((e) => match(e, aq));
41
+ if (emp?.id) {
42
+ assigneeId = emp.id;
43
+ assigneeName = label(emp);
44
+ }
45
+ }
46
+ const auto = deps.autoConfirm?.(actor, "order.create") === true;
47
+ if (!auto && i.confirm !== true)
48
+ return { needsConfirmation: true, action: "create_order", client: label(client), objet: text.slice(0, 200), assigne: assigneeName ?? "(aucun)", note: "Aperçu — aucune commande créée. Rappelle avec confirm=true après validation (ou accorde « order.create.auto » au rôle)." };
49
+ const order = await crm.createOrder({ clientId: client.id, text, assigneeId });
50
+ await deps.audit?.(actor, "order.create", "copilot", { resource: order.number, resourceId: order.id, details: { via: "copilot", clientId: client.id, assigneeId } });
51
+ return { ok: true, commande: order.number, id: order.id, client: label(client), assigne: assigneeName, message: "commande créée — sourcing possible (market_sourcing / agora_sourcing), puis export/RFQ" };
52
+ },
53
+ },
54
+ ];
55
+ }
56
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * @mostajs/crm — entités du domaine (CDC §3) et contrats de persistance.
3
+ *
4
+ * @author Dr Hamid MADANI <drmdh@msn.com>
5
+ * @license AGPL-3.0-or-later
6
+ */
7
+ /** Statut de disponibilité d'un employé (CDC §3.2). */
8
+ export type EmployeeStatus = "Libre" | "Occupé";
9
+ export interface Client {
10
+ id?: string;
11
+ nom: string;
12
+ prenom?: string;
13
+ societe?: string;
14
+ telephone?: string;
15
+ email?: string;
16
+ adresse?: string;
17
+ notes?: string;
18
+ }
19
+ export interface Employee {
20
+ id?: string;
21
+ nom: string;
22
+ prenom?: string;
23
+ email?: string;
24
+ telephone?: string;
25
+ statut: EmployeeStatus;
26
+ /** Lien vers le compte d'authentification (@mostajs/auth/rbac). L'employé métier ≠ le compte. */
27
+ userId?: string;
28
+ }
29
+ export interface Supplier {
30
+ id?: string;
31
+ nom: string;
32
+ telephone?: string;
33
+ email?: string;
34
+ adresse?: string;
35
+ notesInternes?: string;
36
+ }
37
+ export interface Order {
38
+ id?: string;
39
+ /** Numéro métier auto `AAAA-MM-JJ-NNN` (via @mostajs/numbering). */
40
+ number?: string;
41
+ clientId: string;
42
+ assigneeId?: string;
43
+ createdAt?: string;
44
+ /** Texte de la commande (en anglais — CDC §3.4). */
45
+ text: string;
46
+ /** Identifiants de fichiers joints (@mostajs/storage) : images/PDF. */
47
+ attachments?: string[];
48
+ /** État courant (id d'état du workflow `order`). */
49
+ state?: string;
50
+ }
51
+ export interface Comment {
52
+ id?: string;
53
+ orderId: string;
54
+ authorId: string;
55
+ createdAt?: string;
56
+ text: string;
57
+ }
58
+ export interface Proforma {
59
+ id?: string;
60
+ /** Référence auto `PF-AAAA-MM-JJ-XXX` (via @mostajs/numbering). */
61
+ ref?: string;
62
+ orderId: string;
63
+ supplierId: string;
64
+ /** Identifiant du PDF (@mostajs/storage). */
65
+ pdfFileId?: string;
66
+ createdAt?: string;
67
+ }
68
+ /** Collection persistée minimale (DB-agnostique). En prod : adaptateur @mostajs/repository. */
69
+ export interface Collection<T extends {
70
+ id?: string;
71
+ }> {
72
+ save(entity: T): Promise<T & {
73
+ id: string;
74
+ }>;
75
+ get(id: string): Promise<(T & {
76
+ id: string;
77
+ }) | undefined>;
78
+ all(): Promise<(T & {
79
+ id: string;
80
+ })[]>;
81
+ find(predicate: (entity: T & {
82
+ id: string;
83
+ }) => boolean): Promise<(T & {
84
+ id: string;
85
+ })[]>;
86
+ remove(id: string): Promise<boolean>;
87
+ }
88
+ /** Les six dépôts d'entités du domaine. */
89
+ export interface CrmRepositories {
90
+ clients: Collection<Client>;
91
+ employees: Collection<Employee>;
92
+ suppliers: Collection<Supplier>;
93
+ orders: Collection<Order>;
94
+ comments: Collection<Comment>;
95
+ proformas: Collection<Proforma>;
96
+ }
97
+ /** Filtres de la page proformats (CDC §3.9). */
98
+ export interface ProformaFilter {
99
+ supplierId?: string;
100
+ clientId?: string;
101
+ /** Date `YYYY-MM-DD`. */
102
+ date?: string;
103
+ }
104
+ export declare class CrmError extends Error {
105
+ constructor(message: string);
106
+ }
107
+ /** Entité introuvable. */
108
+ export declare class NotFoundError extends CrmError {
109
+ }
110
+ /** Aucun employé au statut `Libre` pour l'assignation automatique. */
111
+ export declare class NoFreeEmployeeError extends CrmError {
112
+ }
113
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,uDAAuD;AACvD,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEhD,MAAM,WAAW,MAAM;IACrB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,cAAc,CAAC;IACvB,iGAAiG;IACjG,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,KAAK;IACpB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,OAAO;IACtB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,mEAAmE;IACnE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,+FAA+F;AAC/F,MAAM,WAAW,UAAU,CAAC,CAAC,SAAS;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE;IACnD,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7C,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,SAAS,CAAC,CAAC;IAC3D,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC,CAAC;IACvC,IAAI,CAAC,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC,CAAC;IAC1F,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACtC;AAED,2CAA2C;AAC3C,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAC5B,SAAS,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;IAChC,SAAS,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;IAChC,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;IAC1B,QAAQ,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;IAC9B,SAAS,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;CACjC;AAED,gDAAgD;AAChD,MAAM,WAAW,cAAc;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yBAAyB;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,QAAS,SAAQ,KAAK;gBACrB,OAAO,EAAE,MAAM;CAI5B;AACD,0BAA0B;AAC1B,qBAAa,aAAc,SAAQ,QAAQ;CAAG;AAC9C,sEAAsE;AACtE,qBAAa,mBAAoB,SAAQ,QAAQ;CAAG"}
package/dist/types.js ADDED
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @mostajs/crm — entités du domaine (CDC §3) et contrats de persistance.
3
+ *
4
+ * @author Dr Hamid MADANI <drmdh@msn.com>
5
+ * @license AGPL-3.0-or-later
6
+ */
7
+ export class CrmError extends Error {
8
+ constructor(message) {
9
+ super(message);
10
+ this.name = new.target.name;
11
+ }
12
+ }
13
+ /** Entité introuvable. */
14
+ export class NotFoundError extends CrmError {
15
+ }
16
+ /** Aucun employé au statut `Libre` pour l'assignation automatique. */
17
+ export class NoFreeEmployeeError extends CrmError {
18
+ }
19
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAiGH,MAAM,OAAO,QAAS,SAAQ,KAAK;IACjC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;IAC9B,CAAC;CACF;AACD,0BAA0B;AAC1B,MAAM,OAAO,aAAc,SAAQ,QAAQ;CAAG;AAC9C,sEAAsE;AACtE,MAAM,OAAO,mBAAoB,SAAQ,QAAQ;CAAG"}
package/llms.txt ADDED
@@ -0,0 +1,69 @@
1
+ # @mostajs/crm — fiche LLM
2
+
3
+ RÔLE
4
+ Domaine CRM trading (CDC) : 6 entités — Client, Employee, Supplier, Order, Comment, Proforma —
5
+ et leurs règles métier. Module DOMAINE MINCE : compose @mostajs/workflow (automate de commande
6
+ 9 états + historique immuable + couleurs + party), @mostajs/numbering (n° commande AAAA-MM-JJ-NNN,
7
+ réf proforma PF-AAAA-MM-JJ-XXX) et @mostajs/i18n (libellés d'état FR/EN/AR). N'implémente QUE
8
+ ses entités + règles (assignation 1er employé Libre, suivi d'état, proformats, droits d'instance).
9
+ NE réimplémente PAS numérotation/états/journal (interdit §0). Persistance/fichiers/auth à l'assemblage.
10
+
11
+ INSTALL
12
+ npm i @mostajs/crm @mostajs/workflow @mostajs/statemachine @mostajs/trigger @mostajs/numbering @mostajs/i18n
13
+
14
+ EXPORTS
15
+ createCrm(opts) -> Crm # opts: { repositories, numbering?, workflow?, i18n?, locale?, now? }
16
+ createMemoryRepositories() -> CrmRepositories # défaut/tests (prod: adaptateurs @mostajs/repository)
17
+ MemoryCollection
18
+ orderWorkflowDef() / orderWorkflowBundles() / ORDER_STATE_IDS # ré-exports du preset (workflow)
19
+ Types : Client, Employee (statut "Libre"|"Occupé", userId), Supplier, Order, Comment, Proforma,
20
+ Collection<T>, CrmRepositories, ProformaFilter, CreateOrderInput, OrderStateView
21
+ Erreurs : CrmError, NotFoundError, NoFreeEmployeeError
22
+
23
+ API — Crm (asynchrone)
24
+ repositories # CRUD direct (droits gérés à l'app)
25
+ createOrder({ clientId, text, assigneeId?, attachments? }) -> Order # n° auto + état initial
26
+ assignFreeEmployee(orderId) -> Employee # 1er employé statut "Libre" (sinon NoFreeEmployeeError)
27
+ transitionOrder(orderId, to, { actorId? }, { comment? }) -> ExecutedTransition # via workflow
28
+ orderHistory(orderId) -> ExecutedTransition[] # historique immuable (CDC §3.6)
29
+ addComment(orderId, authorId, text) / listComments(orderId)
30
+ addProforma(orderId, { supplierId, pdfFileId? }) -> Proforma # réf auto
31
+ listProformas({ supplierId?, clientId?, date? }) -> Proforma[] # filtres (CDC §3.9)
32
+ orderStateColors() -> { [id]: "#RRGGBB" }
33
+ orderStateLabel(stateId) -> string # libellé TRADUIT via @mostajs/i18n
34
+ orderStates() -> OrderStateView[] # { id, label(traduit), color, party, terminal }
35
+ t(key, vars?) ; translator # passe-plat i18n
36
+
37
+ AUTOMATE DE COMMANDE (preset orderWorkflow — couleur + party par état)
38
+ init(#64748B, init: admin|manager|employe)
39
+ -> notification_attente(#3B82F6, sender) -> relance_emetteur_attente(#F59E0B, sender)
40
+ -> reponse_attente(#06B6D4, receiver) -> relance_destinataire_attente(#F97316, receiver)
41
+ -> validation_attente(#8B5CF6, sender) -> finalisation_attente(#14B8A6, receiver)
42
+ -> client_informe(#10B981, sender, terminal) ; annulee(#EF4444, terminal) depuis tout état non terminal
43
+ Libellés = clés i18n `order:state.<id>` traduites FR/EN/AR (orderWorkflowBundles()).
44
+
45
+ EXEMPLE
46
+ import { createCrm, createMemoryRepositories } from "@mostajs/crm";
47
+ const crm = createCrm({ repositories: createMemoryRepositories(), locale: "fr" });
48
+ await crm.repositories.clients.save({ nom: "Doe", societe: "ACME" });
49
+ const order = await crm.createOrder({ clientId: "client-1", text: "100x widgets" }); // number "AAAA-MM-JJ-001"
50
+ await crm.transitionOrder(order.id, "notification_attente", { actorId: "u1" });
51
+ crm.orderStateLabel("notification_attente"); // "Notification — en attente" (fr) / "Notification — waiting" (en)
52
+ crm.orderStateColors()["client_informe"]; // "#10B981"
53
+
54
+ DROITS (CDC §2 — à appliquer via @mostajs/rbac à l'assemblage)
55
+ Admin: tout. Employé: lecture seule globale ; +fournisseur ; modif état/proforma de SES commandes
56
+ (garde d'instance via rules/workflow : actor.id == order.assigneeId) ; +commentaire ; AUCUNE suppression.
57
+
58
+ PIÈGES
59
+ - Employee (profil métier + statut) ≠ compte auth/rbac : reliés par Employee.userId.
60
+ - createOrder pose l'état initial du workflow ; transitionOrder met à jour order.state après succès.
61
+ - MemoryCollection = mono-process (tests) ; en prod adaptateurs @mostajs/repository/orm.
62
+ - Libellés via @mostajs/i18n : ne pas coder les libellés en dur ; clé absente => clé renvoyée.
63
+ - Numéro de commande = référence MÉTIER (≠ clé technique).
64
+
65
+ STATUT
66
+ v0.0.1 — cœur IMPLÉMENTÉ (entités, repos mémoire, createOrder/assign/transition/proforma/listProformas,
67
+ couleurs + i18n), testé. v0.1 = repos ORM + storage PDF + checkPermission rbac. v0.2 = pages/handlers UI.
68
+ Voir docs/03-PLAN-DEV-CRM.md. Licence AGPL-3.0-or-later. Auteur Dr Hamid MADANI.
69
+ Consommateur : app TRADING déployée sur https://crm.amia.fr (amia).
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@mostajs/crm",
3
+ "version": "0.0.1",
4
+ "description": "CRM trading domain (clients, employees, suppliers, orders, comments, proformas). Thin domain module composing @mostajs/workflow (8-state order lifecycle + immutable history + state colors) and @mostajs/numbering (order/proforma references). Implements only its entities and business rules.",
5
+ "author": "Dr Hamid MADANI <drmdh@msn.com>",
6
+ "license": "AGPL-3.0-or-later",
7
+ "type": "module",
8
+ "main": "dist/index.js",
9
+ "types": "dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js",
14
+ "require": "./dist/index.js",
15
+ "default": "./dist/index.js"
16
+ }
17
+ },
18
+ "peerDependencies": {
19
+ "@mostajs/workflow": "^0.0.1",
20
+ "@mostajs/numbering": "^0.0.1",
21
+ "@mostajs/statemachine": "^0.0.1",
22
+ "@mostajs/trigger": "^0.0.1",
23
+ "@mostajs/i18n": "^0.1.0"
24
+ },
25
+ "files": [
26
+ "dist",
27
+ "LICENSE",
28
+ "README.md",
29
+ "llms.txt"
30
+ ],
31
+ "keywords": [
32
+ "crm",
33
+ "trading",
34
+ "orders",
35
+ "suppliers",
36
+ "proforma",
37
+ "workflow",
38
+ "domain",
39
+ "mosta",
40
+ "mostajs"
41
+ ],
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "https://github.com/apolocine/mosta-crm"
45
+ },
46
+ "homepage": "https://mostajs.dev/packages/crm",
47
+ "bugs": {
48
+ "url": "https://github.com/apolocine/mosta-crm/issues"
49
+ },
50
+ "engines": {
51
+ "node": ">=18.0.0"
52
+ },
53
+ "devDependencies": {
54
+ "@types/node": "^22.0.0",
55
+ "typescript": "^5.6.0",
56
+ "@mostajs/workflow": "^0.0.1",
57
+ "@mostajs/i18n": "^0.1.0",
58
+ "@mostajs/trigger": "^0.0.1",
59
+ "@mostajs/statemachine": "^0.0.1",
60
+ "@mostajs/numbering": "^0.0.1"
61
+ },
62
+ "scripts": {
63
+ "build": "tsc",
64
+ "dev": "tsc --watch",
65
+ "test": "node --test test-scripts/*.test.mjs"
66
+ }
67
+ }