@financica/pcmn 0.1.0

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/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0
4
+
5
+ Initial release. Belgian PCMN class taxonomy:
6
+
7
+ - Income-statement classes (60-66, 70-76) to economic categories via
8
+ `plCategoryForCode`, including the statutory director-remuneration rule
9
+ (618 to "Services et biens divers").
10
+ - Liquidity classes (54/55/57) via `isCashClass`.
11
+ - Fixed-asset classes (20-28) via `fixedAssetGroupForCode`.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Financica
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # @financica/pcmn
2
+
3
+ Zero-dependency Belgian **PCMN** (Plan Comptable Minimum Normalisé) class
4
+ taxonomy. It maps income-statement and fixed-asset account classes to a small
5
+ set of economic categories, so any app in the suite classifies revenue, costs
6
+ and assets the same way. It is deliberately class-level (not a full chart of
7
+ accounts): the shared thing is the *meaning* of each PCMN class.
8
+
9
+ ```ts
10
+ import { plCategoryForCode, isCashClass, fixedAssetGroupForCode } from "@financica/pcmn";
11
+
12
+ plCategoryForCode("700000"); // "revenue"
13
+ plCategoryForCode("610000"); // "services"
14
+ plCategoryForCode("620200"); // "personnel"
15
+ plCategoryForCode("618000"); // "services" <- the director-remuneration rule
16
+ isCashClass("550000"); // true
17
+ fixedAssetGroupForCode("23"); // "tangible"
18
+ ```
19
+
20
+ ## The director-remuneration rule (618)
21
+
22
+ In the PCMN, the remuneration of a company director/manager who is **not**
23
+ employed under a contract of employment (a self-employed *dirigeant
24
+ d'entreprise*, the usual case for an SRL/SA founder paying themselves) is booked
25
+ in account **618**, which belongs to class **61 "Services et biens divers"** —
26
+ not class 62 "Rémunérations". `plCategoryForCode` encodes this so owner pay is
27
+ never miscounted as personnel, which is what lets a financial plan reconcile
28
+ against real bookkeeping.
29
+
30
+ ## Exports
31
+
32
+ - `PlCategory`, `PCMN_PL_CLASSES`, `plCategoryForCode(code)` — income-statement
33
+ classes (60-66 charges, 70-76 income) and the categories they map to.
34
+ - `DIRECTOR_REMUNERATION_ACCOUNT` (`"618"`).
35
+ - `CASH_CLASSES`, `isCashClass(code)` — liquidity classes 54/55/57.
36
+ - `FixedAssetGroup`, `PCMN_FIXED_ASSET_CLASSES`, `fixedAssetGroupForCode(code)`
37
+ — balance-sheet fixed-asset classes 20-28.
38
+
39
+ Account codes may be passed at any length (2-digit class up to a full leaf
40
+ code); classification uses the leading digits.
41
+
42
+ ## License
43
+
44
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,152 @@
1
+ 'use strict';
2
+
3
+ // src/pl.ts
4
+ var PCMN_PL_CLASSES = {
5
+ "60": {
6
+ code: "60",
7
+ category: "goods",
8
+ side: "debit",
9
+ label: "Approvisionnements et marchandises"
10
+ },
11
+ "61": {
12
+ code: "61",
13
+ category: "services",
14
+ side: "debit",
15
+ label: "Services et biens divers"
16
+ },
17
+ "62": {
18
+ code: "62",
19
+ category: "personnel",
20
+ side: "debit",
21
+ label: "R\xE9mun\xE9rations, charges sociales et pensions"
22
+ },
23
+ "63": {
24
+ code: "63",
25
+ category: "depreciation",
26
+ side: "debit",
27
+ label: "Amortissements, r\xE9ductions de valeur et provisions"
28
+ },
29
+ "64": {
30
+ code: "64",
31
+ category: "otherOperatingCharges",
32
+ side: "debit",
33
+ label: "Autres charges d'exploitation"
34
+ },
35
+ "65": {
36
+ code: "65",
37
+ category: "financialCharges",
38
+ side: "debit",
39
+ label: "Charges financi\xE8res"
40
+ },
41
+ "66": {
42
+ code: "66",
43
+ category: "exceptionalCharges",
44
+ side: "debit",
45
+ label: "Charges exceptionnelles"
46
+ },
47
+ "70": {
48
+ code: "70",
49
+ category: "revenue",
50
+ side: "credit",
51
+ label: "Chiffre d'affaires"
52
+ },
53
+ "74": {
54
+ code: "74",
55
+ category: "otherOperatingIncome",
56
+ side: "credit",
57
+ label: "Autres produits d'exploitation"
58
+ },
59
+ "75": {
60
+ code: "75",
61
+ category: "financialIncome",
62
+ side: "credit",
63
+ label: "Produits financiers"
64
+ },
65
+ "76": {
66
+ code: "76",
67
+ category: "exceptionalIncome",
68
+ side: "credit",
69
+ label: "Produits exceptionnels"
70
+ }
71
+ };
72
+ var DIRECTOR_REMUNERATION_ACCOUNT = "618";
73
+ function plCategoryForCode(code) {
74
+ const trimmed = code.trim();
75
+ if (trimmed.startsWith(DIRECTOR_REMUNERATION_ACCOUNT)) return "services";
76
+ return PCMN_PL_CLASSES[trimmed.slice(0, 2)]?.category ?? null;
77
+ }
78
+ var CASH_CLASSES = ["54", "55", "57"];
79
+ function isCashClass(code) {
80
+ return CASH_CLASSES.includes(code.trim().slice(0, 2));
81
+ }
82
+
83
+ // src/assets.ts
84
+ var PCMN_FIXED_ASSET_CLASSES = {
85
+ "20": {
86
+ code: "20",
87
+ group: "formationExpenses",
88
+ label: "Frais d'\xE9tablissement",
89
+ depreciable: true
90
+ },
91
+ "21": {
92
+ code: "21",
93
+ group: "intangible",
94
+ label: "Immobilisations incorporelles",
95
+ depreciable: true
96
+ },
97
+ "22": {
98
+ code: "22",
99
+ group: "tangible",
100
+ label: "Terrains et constructions",
101
+ depreciable: true
102
+ },
103
+ "23": {
104
+ code: "23",
105
+ group: "tangible",
106
+ label: "Installations, machines et outillage",
107
+ depreciable: true
108
+ },
109
+ "24": {
110
+ code: "24",
111
+ group: "tangible",
112
+ label: "Mobilier et mat\xE9riel roulant",
113
+ depreciable: true
114
+ },
115
+ "25": {
116
+ code: "25",
117
+ group: "tangible",
118
+ label: "Immobilisations d\xE9tenues en location-financement et droits similaires",
119
+ depreciable: true
120
+ },
121
+ "26": {
122
+ code: "26",
123
+ group: "tangible",
124
+ label: "Autres immobilisations corporelles",
125
+ depreciable: true
126
+ },
127
+ "27": {
128
+ code: "27",
129
+ group: "tangible",
130
+ label: "Immobilisations corporelles en cours et acomptes vers\xE9s",
131
+ depreciable: false
132
+ },
133
+ "28": {
134
+ code: "28",
135
+ group: "financial",
136
+ label: "Immobilisations financi\xE8res",
137
+ depreciable: false
138
+ }
139
+ };
140
+ function fixedAssetGroupForCode(code) {
141
+ return PCMN_FIXED_ASSET_CLASSES[code.trim().slice(0, 2)]?.group ?? null;
142
+ }
143
+
144
+ exports.CASH_CLASSES = CASH_CLASSES;
145
+ exports.DIRECTOR_REMUNERATION_ACCOUNT = DIRECTOR_REMUNERATION_ACCOUNT;
146
+ exports.PCMN_FIXED_ASSET_CLASSES = PCMN_FIXED_ASSET_CLASSES;
147
+ exports.PCMN_PL_CLASSES = PCMN_PL_CLASSES;
148
+ exports.fixedAssetGroupForCode = fixedAssetGroupForCode;
149
+ exports.isCashClass = isCashClass;
150
+ exports.plCategoryForCode = plCategoryForCode;
151
+ //# sourceMappingURL=index.cjs.map
152
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/pl.ts","../src/assets.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Belgian PCMN (Plan Comptable Minimum Normalisé) profit-and-loss taxonomy: the\n * 2-digit account classes of the statutory income statement and the economic\n * categories the Financica suite groups them into. This is the single shared\n * definition: financica aggregates its real ledger through it, and\n * financica-plan projects the same categories, so a plan and its actuals\n * reconcile line for line.\n */\n\n/** Economic P&L buckets, aligned to the Belgian statutory income statement. */\nexport type PlCategory =\n\t| \"revenue\"\n\t| \"goods\"\n\t| \"services\"\n\t| \"personnel\"\n\t| \"depreciation\"\n\t| \"otherOperatingCharges\"\n\t| \"otherOperatingIncome\"\n\t| \"financialCharges\"\n\t| \"financialIncome\"\n\t| \"exceptionalCharges\"\n\t| \"exceptionalIncome\";\n\n/** Natural balance side: charges (6x) are debit, income (7x) is credit. */\nexport type PlSide = \"debit\" | \"credit\";\n\nexport interface PcmnPlClass {\n\t/** 2-digit PCMN class, e.g. \"60\". */\n\treadonly code: string;\n\treadonly category: PlCategory;\n\treadonly side: PlSide;\n\t/** French rubric of the Belgian income statement. */\n\treadonly label: string;\n}\n\n/**\n * The compared P&L classes (charges 60-66, income 70-76). Classes outside this\n * set (71 stock variation, 72 own work capitalised, 73 subsidies, ...) are not\n * mapped: both apps leave them out of the compared categories.\n */\nexport const PCMN_PL_CLASSES: Readonly<Record<string, PcmnPlClass>> = {\n\t\"60\": {\n\t\tcode: \"60\",\n\t\tcategory: \"goods\",\n\t\tside: \"debit\",\n\t\tlabel: \"Approvisionnements et marchandises\",\n\t},\n\t\"61\": {\n\t\tcode: \"61\",\n\t\tcategory: \"services\",\n\t\tside: \"debit\",\n\t\tlabel: \"Services et biens divers\",\n\t},\n\t\"62\": {\n\t\tcode: \"62\",\n\t\tcategory: \"personnel\",\n\t\tside: \"debit\",\n\t\tlabel: \"Rémunérations, charges sociales et pensions\",\n\t},\n\t\"63\": {\n\t\tcode: \"63\",\n\t\tcategory: \"depreciation\",\n\t\tside: \"debit\",\n\t\tlabel: \"Amortissements, réductions de valeur et provisions\",\n\t},\n\t\"64\": {\n\t\tcode: \"64\",\n\t\tcategory: \"otherOperatingCharges\",\n\t\tside: \"debit\",\n\t\tlabel: \"Autres charges d'exploitation\",\n\t},\n\t\"65\": {\n\t\tcode: \"65\",\n\t\tcategory: \"financialCharges\",\n\t\tside: \"debit\",\n\t\tlabel: \"Charges financières\",\n\t},\n\t\"66\": {\n\t\tcode: \"66\",\n\t\tcategory: \"exceptionalCharges\",\n\t\tside: \"debit\",\n\t\tlabel: \"Charges exceptionnelles\",\n\t},\n\t\"70\": {\n\t\tcode: \"70\",\n\t\tcategory: \"revenue\",\n\t\tside: \"credit\",\n\t\tlabel: \"Chiffre d'affaires\",\n\t},\n\t\"74\": {\n\t\tcode: \"74\",\n\t\tcategory: \"otherOperatingIncome\",\n\t\tside: \"credit\",\n\t\tlabel: \"Autres produits d'exploitation\",\n\t},\n\t\"75\": {\n\t\tcode: \"75\",\n\t\tcategory: \"financialIncome\",\n\t\tside: \"credit\",\n\t\tlabel: \"Produits financiers\",\n\t},\n\t\"76\": {\n\t\tcode: \"76\",\n\t\tcategory: \"exceptionalIncome\",\n\t\tside: \"credit\",\n\t\tlabel: \"Produits exceptionnels\",\n\t},\n};\n\n/**\n * PCMN 618 — remuneration and benefits of company directors/managers who are\n * NOT employed under a contract of employment (dirigeants d'entreprise\n * indépendants). It belongs to class 61 \"Services et biens divers\", NOT class\n * 62 \"Rémunérations\". This is the one PCMN subtlety that both apps must get\n * right so an owner's own pay reconciles between a plan and its actuals.\n */\nexport const DIRECTOR_REMUNERATION_ACCOUNT = \"618\";\n\n/**\n * The P&L category for a PCMN account code of any length (2-digit class up to a\n * full leaf code), or null when the code is not one of the compared P&L\n * classes. Applies the 618 rule explicitly before falling back to the class, so\n * self-employed director remuneration is never miscounted as personnel.\n */\nexport function plCategoryForCode(code: string): PlCategory | null {\n\tconst trimmed = code.trim();\n\tif (trimmed.startsWith(DIRECTOR_REMUNERATION_ACCOUNT)) return \"services\";\n\treturn PCMN_PL_CLASSES[trimmed.slice(0, 2)]?.category ?? null;\n}\n\n/**\n * PCMN liquidity classes (valeurs disponibles): 54 term deposits, 55 banks, 57\n * cash on hand. Their net movement is the treasury / cash position. (50-53\n * current investments and 56 are excluded, matching the suite's cash view.)\n */\nexport const CASH_CLASSES = [\"54\", \"55\", \"57\"] as const;\nexport type CashClass = (typeof CASH_CLASSES)[number];\n\n/** Whether an account code belongs to a liquidity (cash) class. */\nexport function isCashClass(code: string): boolean {\n\treturn (CASH_CLASSES as readonly string[]).includes(code.trim().slice(0, 2));\n}\n","/**\n * Belgian PCMN fixed-asset taxonomy (balance-sheet classes 20-28). Used by\n * financica-plan to model investments and their depreciation against the\n * statutory asset rubrics.\n */\n\n/** Statutory fixed-asset groups of the Belgian balance sheet. */\nexport type FixedAssetGroup =\n\t| \"formationExpenses\" // 20 frais d'établissement\n\t| \"intangible\" // 21 immobilisations incorporelles\n\t| \"tangible\" // 22-27 immobilisations corporelles\n\t| \"financial\"; // 28 immobilisations financières\n\nexport interface PcmnFixedAssetClass {\n\t/** 2-digit PCMN class, e.g. \"22\". */\n\treadonly code: string;\n\treadonly group: FixedAssetGroup;\n\t/** French rubric of the Belgian balance sheet. */\n\treadonly label: string;\n\t/**\n\t * Whether the class is depreciated at all. Financial assets (28) and\n\t * assets under construction (27) are not; land within 22 is not either,\n\t * but that split is finer than the class and left to the caller.\n\t */\n\treadonly depreciable: boolean;\n}\n\nexport const PCMN_FIXED_ASSET_CLASSES: Readonly<\n\tRecord<string, PcmnFixedAssetClass>\n> = {\n\t\"20\": {\n\t\tcode: \"20\",\n\t\tgroup: \"formationExpenses\",\n\t\tlabel: \"Frais d'établissement\",\n\t\tdepreciable: true,\n\t},\n\t\"21\": {\n\t\tcode: \"21\",\n\t\tgroup: \"intangible\",\n\t\tlabel: \"Immobilisations incorporelles\",\n\t\tdepreciable: true,\n\t},\n\t\"22\": {\n\t\tcode: \"22\",\n\t\tgroup: \"tangible\",\n\t\tlabel: \"Terrains et constructions\",\n\t\tdepreciable: true,\n\t},\n\t\"23\": {\n\t\tcode: \"23\",\n\t\tgroup: \"tangible\",\n\t\tlabel: \"Installations, machines et outillage\",\n\t\tdepreciable: true,\n\t},\n\t\"24\": {\n\t\tcode: \"24\",\n\t\tgroup: \"tangible\",\n\t\tlabel: \"Mobilier et matériel roulant\",\n\t\tdepreciable: true,\n\t},\n\t\"25\": {\n\t\tcode: \"25\",\n\t\tgroup: \"tangible\",\n\t\tlabel: \"Immobilisations détenues en location-financement et droits similaires\",\n\t\tdepreciable: true,\n\t},\n\t\"26\": {\n\t\tcode: \"26\",\n\t\tgroup: \"tangible\",\n\t\tlabel: \"Autres immobilisations corporelles\",\n\t\tdepreciable: true,\n\t},\n\t\"27\": {\n\t\tcode: \"27\",\n\t\tgroup: \"tangible\",\n\t\tlabel: \"Immobilisations corporelles en cours et acomptes versés\",\n\t\tdepreciable: false,\n\t},\n\t\"28\": {\n\t\tcode: \"28\",\n\t\tgroup: \"financial\",\n\t\tlabel: \"Immobilisations financières\",\n\t\tdepreciable: false,\n\t},\n};\n\n/** The fixed-asset group for a PCMN account code, or null if not classes 20-28. */\nexport function fixedAssetGroupForCode(code: string): FixedAssetGroup | null {\n\treturn PCMN_FIXED_ASSET_CLASSES[code.trim().slice(0, 2)]?.group ?? null;\n}\n"]}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Belgian PCMN (Plan Comptable Minimum Normalisé) profit-and-loss taxonomy: the
3
+ * 2-digit account classes of the statutory income statement and the economic
4
+ * categories the Financica suite groups them into. This is the single shared
5
+ * definition: financica aggregates its real ledger through it, and
6
+ * financica-plan projects the same categories, so a plan and its actuals
7
+ * reconcile line for line.
8
+ */
9
+ /** Economic P&L buckets, aligned to the Belgian statutory income statement. */
10
+ type PlCategory = "revenue" | "goods" | "services" | "personnel" | "depreciation" | "otherOperatingCharges" | "otherOperatingIncome" | "financialCharges" | "financialIncome" | "exceptionalCharges" | "exceptionalIncome";
11
+ /** Natural balance side: charges (6x) are debit, income (7x) is credit. */
12
+ type PlSide = "debit" | "credit";
13
+ interface PcmnPlClass {
14
+ /** 2-digit PCMN class, e.g. "60". */
15
+ readonly code: string;
16
+ readonly category: PlCategory;
17
+ readonly side: PlSide;
18
+ /** French rubric of the Belgian income statement. */
19
+ readonly label: string;
20
+ }
21
+ /**
22
+ * The compared P&L classes (charges 60-66, income 70-76). Classes outside this
23
+ * set (71 stock variation, 72 own work capitalised, 73 subsidies, ...) are not
24
+ * mapped: both apps leave them out of the compared categories.
25
+ */
26
+ declare const PCMN_PL_CLASSES: Readonly<Record<string, PcmnPlClass>>;
27
+ /**
28
+ * PCMN 618 — remuneration and benefits of company directors/managers who are
29
+ * NOT employed under a contract of employment (dirigeants d'entreprise
30
+ * indépendants). It belongs to class 61 "Services et biens divers", NOT class
31
+ * 62 "Rémunérations". This is the one PCMN subtlety that both apps must get
32
+ * right so an owner's own pay reconciles between a plan and its actuals.
33
+ */
34
+ declare const DIRECTOR_REMUNERATION_ACCOUNT = "618";
35
+ /**
36
+ * The P&L category for a PCMN account code of any length (2-digit class up to a
37
+ * full leaf code), or null when the code is not one of the compared P&L
38
+ * classes. Applies the 618 rule explicitly before falling back to the class, so
39
+ * self-employed director remuneration is never miscounted as personnel.
40
+ */
41
+ declare function plCategoryForCode(code: string): PlCategory | null;
42
+ /**
43
+ * PCMN liquidity classes (valeurs disponibles): 54 term deposits, 55 banks, 57
44
+ * cash on hand. Their net movement is the treasury / cash position. (50-53
45
+ * current investments and 56 are excluded, matching the suite's cash view.)
46
+ */
47
+ declare const CASH_CLASSES: readonly ["54", "55", "57"];
48
+ type CashClass = (typeof CASH_CLASSES)[number];
49
+ /** Whether an account code belongs to a liquidity (cash) class. */
50
+ declare function isCashClass(code: string): boolean;
51
+
52
+ /**
53
+ * Belgian PCMN fixed-asset taxonomy (balance-sheet classes 20-28). Used by
54
+ * financica-plan to model investments and their depreciation against the
55
+ * statutory asset rubrics.
56
+ */
57
+ /** Statutory fixed-asset groups of the Belgian balance sheet. */
58
+ type FixedAssetGroup = "formationExpenses" | "intangible" | "tangible" | "financial";
59
+ interface PcmnFixedAssetClass {
60
+ /** 2-digit PCMN class, e.g. "22". */
61
+ readonly code: string;
62
+ readonly group: FixedAssetGroup;
63
+ /** French rubric of the Belgian balance sheet. */
64
+ readonly label: string;
65
+ /**
66
+ * Whether the class is depreciated at all. Financial assets (28) and
67
+ * assets under construction (27) are not; land within 22 is not either,
68
+ * but that split is finer than the class and left to the caller.
69
+ */
70
+ readonly depreciable: boolean;
71
+ }
72
+ declare const PCMN_FIXED_ASSET_CLASSES: Readonly<Record<string, PcmnFixedAssetClass>>;
73
+ /** The fixed-asset group for a PCMN account code, or null if not classes 20-28. */
74
+ declare function fixedAssetGroupForCode(code: string): FixedAssetGroup | null;
75
+
76
+ export { CASH_CLASSES, type CashClass, DIRECTOR_REMUNERATION_ACCOUNT, type FixedAssetGroup, PCMN_FIXED_ASSET_CLASSES, PCMN_PL_CLASSES, type PcmnFixedAssetClass, type PcmnPlClass, type PlCategory, type PlSide, fixedAssetGroupForCode, isCashClass, plCategoryForCode };
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Belgian PCMN (Plan Comptable Minimum Normalisé) profit-and-loss taxonomy: the
3
+ * 2-digit account classes of the statutory income statement and the economic
4
+ * categories the Financica suite groups them into. This is the single shared
5
+ * definition: financica aggregates its real ledger through it, and
6
+ * financica-plan projects the same categories, so a plan and its actuals
7
+ * reconcile line for line.
8
+ */
9
+ /** Economic P&L buckets, aligned to the Belgian statutory income statement. */
10
+ type PlCategory = "revenue" | "goods" | "services" | "personnel" | "depreciation" | "otherOperatingCharges" | "otherOperatingIncome" | "financialCharges" | "financialIncome" | "exceptionalCharges" | "exceptionalIncome";
11
+ /** Natural balance side: charges (6x) are debit, income (7x) is credit. */
12
+ type PlSide = "debit" | "credit";
13
+ interface PcmnPlClass {
14
+ /** 2-digit PCMN class, e.g. "60". */
15
+ readonly code: string;
16
+ readonly category: PlCategory;
17
+ readonly side: PlSide;
18
+ /** French rubric of the Belgian income statement. */
19
+ readonly label: string;
20
+ }
21
+ /**
22
+ * The compared P&L classes (charges 60-66, income 70-76). Classes outside this
23
+ * set (71 stock variation, 72 own work capitalised, 73 subsidies, ...) are not
24
+ * mapped: both apps leave them out of the compared categories.
25
+ */
26
+ declare const PCMN_PL_CLASSES: Readonly<Record<string, PcmnPlClass>>;
27
+ /**
28
+ * PCMN 618 — remuneration and benefits of company directors/managers who are
29
+ * NOT employed under a contract of employment (dirigeants d'entreprise
30
+ * indépendants). It belongs to class 61 "Services et biens divers", NOT class
31
+ * 62 "Rémunérations". This is the one PCMN subtlety that both apps must get
32
+ * right so an owner's own pay reconciles between a plan and its actuals.
33
+ */
34
+ declare const DIRECTOR_REMUNERATION_ACCOUNT = "618";
35
+ /**
36
+ * The P&L category for a PCMN account code of any length (2-digit class up to a
37
+ * full leaf code), or null when the code is not one of the compared P&L
38
+ * classes. Applies the 618 rule explicitly before falling back to the class, so
39
+ * self-employed director remuneration is never miscounted as personnel.
40
+ */
41
+ declare function plCategoryForCode(code: string): PlCategory | null;
42
+ /**
43
+ * PCMN liquidity classes (valeurs disponibles): 54 term deposits, 55 banks, 57
44
+ * cash on hand. Their net movement is the treasury / cash position. (50-53
45
+ * current investments and 56 are excluded, matching the suite's cash view.)
46
+ */
47
+ declare const CASH_CLASSES: readonly ["54", "55", "57"];
48
+ type CashClass = (typeof CASH_CLASSES)[number];
49
+ /** Whether an account code belongs to a liquidity (cash) class. */
50
+ declare function isCashClass(code: string): boolean;
51
+
52
+ /**
53
+ * Belgian PCMN fixed-asset taxonomy (balance-sheet classes 20-28). Used by
54
+ * financica-plan to model investments and their depreciation against the
55
+ * statutory asset rubrics.
56
+ */
57
+ /** Statutory fixed-asset groups of the Belgian balance sheet. */
58
+ type FixedAssetGroup = "formationExpenses" | "intangible" | "tangible" | "financial";
59
+ interface PcmnFixedAssetClass {
60
+ /** 2-digit PCMN class, e.g. "22". */
61
+ readonly code: string;
62
+ readonly group: FixedAssetGroup;
63
+ /** French rubric of the Belgian balance sheet. */
64
+ readonly label: string;
65
+ /**
66
+ * Whether the class is depreciated at all. Financial assets (28) and
67
+ * assets under construction (27) are not; land within 22 is not either,
68
+ * but that split is finer than the class and left to the caller.
69
+ */
70
+ readonly depreciable: boolean;
71
+ }
72
+ declare const PCMN_FIXED_ASSET_CLASSES: Readonly<Record<string, PcmnFixedAssetClass>>;
73
+ /** The fixed-asset group for a PCMN account code, or null if not classes 20-28. */
74
+ declare function fixedAssetGroupForCode(code: string): FixedAssetGroup | null;
75
+
76
+ export { CASH_CLASSES, type CashClass, DIRECTOR_REMUNERATION_ACCOUNT, type FixedAssetGroup, PCMN_FIXED_ASSET_CLASSES, PCMN_PL_CLASSES, type PcmnFixedAssetClass, type PcmnPlClass, type PlCategory, type PlSide, fixedAssetGroupForCode, isCashClass, plCategoryForCode };
package/dist/index.js ADDED
@@ -0,0 +1,144 @@
1
+ // src/pl.ts
2
+ var PCMN_PL_CLASSES = {
3
+ "60": {
4
+ code: "60",
5
+ category: "goods",
6
+ side: "debit",
7
+ label: "Approvisionnements et marchandises"
8
+ },
9
+ "61": {
10
+ code: "61",
11
+ category: "services",
12
+ side: "debit",
13
+ label: "Services et biens divers"
14
+ },
15
+ "62": {
16
+ code: "62",
17
+ category: "personnel",
18
+ side: "debit",
19
+ label: "R\xE9mun\xE9rations, charges sociales et pensions"
20
+ },
21
+ "63": {
22
+ code: "63",
23
+ category: "depreciation",
24
+ side: "debit",
25
+ label: "Amortissements, r\xE9ductions de valeur et provisions"
26
+ },
27
+ "64": {
28
+ code: "64",
29
+ category: "otherOperatingCharges",
30
+ side: "debit",
31
+ label: "Autres charges d'exploitation"
32
+ },
33
+ "65": {
34
+ code: "65",
35
+ category: "financialCharges",
36
+ side: "debit",
37
+ label: "Charges financi\xE8res"
38
+ },
39
+ "66": {
40
+ code: "66",
41
+ category: "exceptionalCharges",
42
+ side: "debit",
43
+ label: "Charges exceptionnelles"
44
+ },
45
+ "70": {
46
+ code: "70",
47
+ category: "revenue",
48
+ side: "credit",
49
+ label: "Chiffre d'affaires"
50
+ },
51
+ "74": {
52
+ code: "74",
53
+ category: "otherOperatingIncome",
54
+ side: "credit",
55
+ label: "Autres produits d'exploitation"
56
+ },
57
+ "75": {
58
+ code: "75",
59
+ category: "financialIncome",
60
+ side: "credit",
61
+ label: "Produits financiers"
62
+ },
63
+ "76": {
64
+ code: "76",
65
+ category: "exceptionalIncome",
66
+ side: "credit",
67
+ label: "Produits exceptionnels"
68
+ }
69
+ };
70
+ var DIRECTOR_REMUNERATION_ACCOUNT = "618";
71
+ function plCategoryForCode(code) {
72
+ const trimmed = code.trim();
73
+ if (trimmed.startsWith(DIRECTOR_REMUNERATION_ACCOUNT)) return "services";
74
+ return PCMN_PL_CLASSES[trimmed.slice(0, 2)]?.category ?? null;
75
+ }
76
+ var CASH_CLASSES = ["54", "55", "57"];
77
+ function isCashClass(code) {
78
+ return CASH_CLASSES.includes(code.trim().slice(0, 2));
79
+ }
80
+
81
+ // src/assets.ts
82
+ var PCMN_FIXED_ASSET_CLASSES = {
83
+ "20": {
84
+ code: "20",
85
+ group: "formationExpenses",
86
+ label: "Frais d'\xE9tablissement",
87
+ depreciable: true
88
+ },
89
+ "21": {
90
+ code: "21",
91
+ group: "intangible",
92
+ label: "Immobilisations incorporelles",
93
+ depreciable: true
94
+ },
95
+ "22": {
96
+ code: "22",
97
+ group: "tangible",
98
+ label: "Terrains et constructions",
99
+ depreciable: true
100
+ },
101
+ "23": {
102
+ code: "23",
103
+ group: "tangible",
104
+ label: "Installations, machines et outillage",
105
+ depreciable: true
106
+ },
107
+ "24": {
108
+ code: "24",
109
+ group: "tangible",
110
+ label: "Mobilier et mat\xE9riel roulant",
111
+ depreciable: true
112
+ },
113
+ "25": {
114
+ code: "25",
115
+ group: "tangible",
116
+ label: "Immobilisations d\xE9tenues en location-financement et droits similaires",
117
+ depreciable: true
118
+ },
119
+ "26": {
120
+ code: "26",
121
+ group: "tangible",
122
+ label: "Autres immobilisations corporelles",
123
+ depreciable: true
124
+ },
125
+ "27": {
126
+ code: "27",
127
+ group: "tangible",
128
+ label: "Immobilisations corporelles en cours et acomptes vers\xE9s",
129
+ depreciable: false
130
+ },
131
+ "28": {
132
+ code: "28",
133
+ group: "financial",
134
+ label: "Immobilisations financi\xE8res",
135
+ depreciable: false
136
+ }
137
+ };
138
+ function fixedAssetGroupForCode(code) {
139
+ return PCMN_FIXED_ASSET_CLASSES[code.trim().slice(0, 2)]?.group ?? null;
140
+ }
141
+
142
+ export { CASH_CLASSES, DIRECTOR_REMUNERATION_ACCOUNT, PCMN_FIXED_ASSET_CLASSES, PCMN_PL_CLASSES, fixedAssetGroupForCode, isCashClass, plCategoryForCode };
143
+ //# sourceMappingURL=index.js.map
144
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/pl.ts","../src/assets.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Belgian PCMN (Plan Comptable Minimum Normalisé) profit-and-loss taxonomy: the\n * 2-digit account classes of the statutory income statement and the economic\n * categories the Financica suite groups them into. This is the single shared\n * definition: financica aggregates its real ledger through it, and\n * financica-plan projects the same categories, so a plan and its actuals\n * reconcile line for line.\n */\n\n/** Economic P&L buckets, aligned to the Belgian statutory income statement. */\nexport type PlCategory =\n\t| \"revenue\"\n\t| \"goods\"\n\t| \"services\"\n\t| \"personnel\"\n\t| \"depreciation\"\n\t| \"otherOperatingCharges\"\n\t| \"otherOperatingIncome\"\n\t| \"financialCharges\"\n\t| \"financialIncome\"\n\t| \"exceptionalCharges\"\n\t| \"exceptionalIncome\";\n\n/** Natural balance side: charges (6x) are debit, income (7x) is credit. */\nexport type PlSide = \"debit\" | \"credit\";\n\nexport interface PcmnPlClass {\n\t/** 2-digit PCMN class, e.g. \"60\". */\n\treadonly code: string;\n\treadonly category: PlCategory;\n\treadonly side: PlSide;\n\t/** French rubric of the Belgian income statement. */\n\treadonly label: string;\n}\n\n/**\n * The compared P&L classes (charges 60-66, income 70-76). Classes outside this\n * set (71 stock variation, 72 own work capitalised, 73 subsidies, ...) are not\n * mapped: both apps leave them out of the compared categories.\n */\nexport const PCMN_PL_CLASSES: Readonly<Record<string, PcmnPlClass>> = {\n\t\"60\": {\n\t\tcode: \"60\",\n\t\tcategory: \"goods\",\n\t\tside: \"debit\",\n\t\tlabel: \"Approvisionnements et marchandises\",\n\t},\n\t\"61\": {\n\t\tcode: \"61\",\n\t\tcategory: \"services\",\n\t\tside: \"debit\",\n\t\tlabel: \"Services et biens divers\",\n\t},\n\t\"62\": {\n\t\tcode: \"62\",\n\t\tcategory: \"personnel\",\n\t\tside: \"debit\",\n\t\tlabel: \"Rémunérations, charges sociales et pensions\",\n\t},\n\t\"63\": {\n\t\tcode: \"63\",\n\t\tcategory: \"depreciation\",\n\t\tside: \"debit\",\n\t\tlabel: \"Amortissements, réductions de valeur et provisions\",\n\t},\n\t\"64\": {\n\t\tcode: \"64\",\n\t\tcategory: \"otherOperatingCharges\",\n\t\tside: \"debit\",\n\t\tlabel: \"Autres charges d'exploitation\",\n\t},\n\t\"65\": {\n\t\tcode: \"65\",\n\t\tcategory: \"financialCharges\",\n\t\tside: \"debit\",\n\t\tlabel: \"Charges financières\",\n\t},\n\t\"66\": {\n\t\tcode: \"66\",\n\t\tcategory: \"exceptionalCharges\",\n\t\tside: \"debit\",\n\t\tlabel: \"Charges exceptionnelles\",\n\t},\n\t\"70\": {\n\t\tcode: \"70\",\n\t\tcategory: \"revenue\",\n\t\tside: \"credit\",\n\t\tlabel: \"Chiffre d'affaires\",\n\t},\n\t\"74\": {\n\t\tcode: \"74\",\n\t\tcategory: \"otherOperatingIncome\",\n\t\tside: \"credit\",\n\t\tlabel: \"Autres produits d'exploitation\",\n\t},\n\t\"75\": {\n\t\tcode: \"75\",\n\t\tcategory: \"financialIncome\",\n\t\tside: \"credit\",\n\t\tlabel: \"Produits financiers\",\n\t},\n\t\"76\": {\n\t\tcode: \"76\",\n\t\tcategory: \"exceptionalIncome\",\n\t\tside: \"credit\",\n\t\tlabel: \"Produits exceptionnels\",\n\t},\n};\n\n/**\n * PCMN 618 — remuneration and benefits of company directors/managers who are\n * NOT employed under a contract of employment (dirigeants d'entreprise\n * indépendants). It belongs to class 61 \"Services et biens divers\", NOT class\n * 62 \"Rémunérations\". This is the one PCMN subtlety that both apps must get\n * right so an owner's own pay reconciles between a plan and its actuals.\n */\nexport const DIRECTOR_REMUNERATION_ACCOUNT = \"618\";\n\n/**\n * The P&L category for a PCMN account code of any length (2-digit class up to a\n * full leaf code), or null when the code is not one of the compared P&L\n * classes. Applies the 618 rule explicitly before falling back to the class, so\n * self-employed director remuneration is never miscounted as personnel.\n */\nexport function plCategoryForCode(code: string): PlCategory | null {\n\tconst trimmed = code.trim();\n\tif (trimmed.startsWith(DIRECTOR_REMUNERATION_ACCOUNT)) return \"services\";\n\treturn PCMN_PL_CLASSES[trimmed.slice(0, 2)]?.category ?? null;\n}\n\n/**\n * PCMN liquidity classes (valeurs disponibles): 54 term deposits, 55 banks, 57\n * cash on hand. Their net movement is the treasury / cash position. (50-53\n * current investments and 56 are excluded, matching the suite's cash view.)\n */\nexport const CASH_CLASSES = [\"54\", \"55\", \"57\"] as const;\nexport type CashClass = (typeof CASH_CLASSES)[number];\n\n/** Whether an account code belongs to a liquidity (cash) class. */\nexport function isCashClass(code: string): boolean {\n\treturn (CASH_CLASSES as readonly string[]).includes(code.trim().slice(0, 2));\n}\n","/**\n * Belgian PCMN fixed-asset taxonomy (balance-sheet classes 20-28). Used by\n * financica-plan to model investments and their depreciation against the\n * statutory asset rubrics.\n */\n\n/** Statutory fixed-asset groups of the Belgian balance sheet. */\nexport type FixedAssetGroup =\n\t| \"formationExpenses\" // 20 frais d'établissement\n\t| \"intangible\" // 21 immobilisations incorporelles\n\t| \"tangible\" // 22-27 immobilisations corporelles\n\t| \"financial\"; // 28 immobilisations financières\n\nexport interface PcmnFixedAssetClass {\n\t/** 2-digit PCMN class, e.g. \"22\". */\n\treadonly code: string;\n\treadonly group: FixedAssetGroup;\n\t/** French rubric of the Belgian balance sheet. */\n\treadonly label: string;\n\t/**\n\t * Whether the class is depreciated at all. Financial assets (28) and\n\t * assets under construction (27) are not; land within 22 is not either,\n\t * but that split is finer than the class and left to the caller.\n\t */\n\treadonly depreciable: boolean;\n}\n\nexport const PCMN_FIXED_ASSET_CLASSES: Readonly<\n\tRecord<string, PcmnFixedAssetClass>\n> = {\n\t\"20\": {\n\t\tcode: \"20\",\n\t\tgroup: \"formationExpenses\",\n\t\tlabel: \"Frais d'établissement\",\n\t\tdepreciable: true,\n\t},\n\t\"21\": {\n\t\tcode: \"21\",\n\t\tgroup: \"intangible\",\n\t\tlabel: \"Immobilisations incorporelles\",\n\t\tdepreciable: true,\n\t},\n\t\"22\": {\n\t\tcode: \"22\",\n\t\tgroup: \"tangible\",\n\t\tlabel: \"Terrains et constructions\",\n\t\tdepreciable: true,\n\t},\n\t\"23\": {\n\t\tcode: \"23\",\n\t\tgroup: \"tangible\",\n\t\tlabel: \"Installations, machines et outillage\",\n\t\tdepreciable: true,\n\t},\n\t\"24\": {\n\t\tcode: \"24\",\n\t\tgroup: \"tangible\",\n\t\tlabel: \"Mobilier et matériel roulant\",\n\t\tdepreciable: true,\n\t},\n\t\"25\": {\n\t\tcode: \"25\",\n\t\tgroup: \"tangible\",\n\t\tlabel: \"Immobilisations détenues en location-financement et droits similaires\",\n\t\tdepreciable: true,\n\t},\n\t\"26\": {\n\t\tcode: \"26\",\n\t\tgroup: \"tangible\",\n\t\tlabel: \"Autres immobilisations corporelles\",\n\t\tdepreciable: true,\n\t},\n\t\"27\": {\n\t\tcode: \"27\",\n\t\tgroup: \"tangible\",\n\t\tlabel: \"Immobilisations corporelles en cours et acomptes versés\",\n\t\tdepreciable: false,\n\t},\n\t\"28\": {\n\t\tcode: \"28\",\n\t\tgroup: \"financial\",\n\t\tlabel: \"Immobilisations financières\",\n\t\tdepreciable: false,\n\t},\n};\n\n/** The fixed-asset group for a PCMN account code, or null if not classes 20-28. */\nexport function fixedAssetGroupForCode(code: string): FixedAssetGroup | null {\n\treturn PCMN_FIXED_ASSET_CLASSES[code.trim().slice(0, 2)]?.group ?? null;\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@financica/pcmn",
3
+ "version": "0.1.0",
4
+ "description": "Zero-dependency Belgian PCMN (Plan Comptable Minimum Normalisé) class taxonomy: maps income-statement and fixed-asset account classes to economic categories, with the statutory director-remuneration (618) rule.",
5
+ "keywords": [
6
+ "pcmn",
7
+ "belgium",
8
+ "belgian",
9
+ "chart-of-accounts",
10
+ "accounting",
11
+ "bookkeeping",
12
+ "income-statement",
13
+ "minimum-normalise",
14
+ "typescript"
15
+ ],
16
+ "license": "MIT",
17
+ "author": "Financica",
18
+ "homepage": "https://github.com/financica/pcmn#readme",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/financica/pcmn.git"
22
+ },
23
+ "bugs": {
24
+ "url": "https://github.com/financica/pcmn/issues"
25
+ },
26
+ "type": "module",
27
+ "sideEffects": false,
28
+ "main": "./dist/index.cjs",
29
+ "module": "./dist/index.js",
30
+ "types": "./dist/index.d.ts",
31
+ "exports": {
32
+ ".": {
33
+ "types": "./dist/index.d.ts",
34
+ "import": "./dist/index.js",
35
+ "require": "./dist/index.cjs"
36
+ },
37
+ "./package.json": "./package.json"
38
+ },
39
+ "files": [
40
+ "dist",
41
+ "src",
42
+ "!src/**/*.test.ts",
43
+ "CHANGELOG.md",
44
+ "LICENSE",
45
+ "README.md"
46
+ ],
47
+ "engines": {
48
+ "node": ">=18"
49
+ },
50
+ "scripts": {
51
+ "build": "tsup",
52
+ "clean": "rm -rf dist",
53
+ "lint": "tsc --noEmit",
54
+ "type-check": "tsc --noEmit",
55
+ "test": "vitest run",
56
+ "test:watch": "vitest",
57
+ "ci": "npm run lint && npm run test && npm run build",
58
+ "prepublishOnly": "npm run clean && npm run build && npm test"
59
+ },
60
+ "devDependencies": {
61
+ "@types/node": "^26.1.1",
62
+ "tsup": "^8.5.1",
63
+ "typescript": "^5.9.3",
64
+ "vitest": "^4.1.10"
65
+ },
66
+ "publishConfig": {
67
+ "access": "public"
68
+ }
69
+ }
package/src/assets.ts ADDED
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Belgian PCMN fixed-asset taxonomy (balance-sheet classes 20-28). Used by
3
+ * financica-plan to model investments and their depreciation against the
4
+ * statutory asset rubrics.
5
+ */
6
+
7
+ /** Statutory fixed-asset groups of the Belgian balance sheet. */
8
+ export type FixedAssetGroup =
9
+ | "formationExpenses" // 20 frais d'établissement
10
+ | "intangible" // 21 immobilisations incorporelles
11
+ | "tangible" // 22-27 immobilisations corporelles
12
+ | "financial"; // 28 immobilisations financières
13
+
14
+ export interface PcmnFixedAssetClass {
15
+ /** 2-digit PCMN class, e.g. "22". */
16
+ readonly code: string;
17
+ readonly group: FixedAssetGroup;
18
+ /** French rubric of the Belgian balance sheet. */
19
+ readonly label: string;
20
+ /**
21
+ * Whether the class is depreciated at all. Financial assets (28) and
22
+ * assets under construction (27) are not; land within 22 is not either,
23
+ * but that split is finer than the class and left to the caller.
24
+ */
25
+ readonly depreciable: boolean;
26
+ }
27
+
28
+ export const PCMN_FIXED_ASSET_CLASSES: Readonly<
29
+ Record<string, PcmnFixedAssetClass>
30
+ > = {
31
+ "20": {
32
+ code: "20",
33
+ group: "formationExpenses",
34
+ label: "Frais d'établissement",
35
+ depreciable: true,
36
+ },
37
+ "21": {
38
+ code: "21",
39
+ group: "intangible",
40
+ label: "Immobilisations incorporelles",
41
+ depreciable: true,
42
+ },
43
+ "22": {
44
+ code: "22",
45
+ group: "tangible",
46
+ label: "Terrains et constructions",
47
+ depreciable: true,
48
+ },
49
+ "23": {
50
+ code: "23",
51
+ group: "tangible",
52
+ label: "Installations, machines et outillage",
53
+ depreciable: true,
54
+ },
55
+ "24": {
56
+ code: "24",
57
+ group: "tangible",
58
+ label: "Mobilier et matériel roulant",
59
+ depreciable: true,
60
+ },
61
+ "25": {
62
+ code: "25",
63
+ group: "tangible",
64
+ label: "Immobilisations détenues en location-financement et droits similaires",
65
+ depreciable: true,
66
+ },
67
+ "26": {
68
+ code: "26",
69
+ group: "tangible",
70
+ label: "Autres immobilisations corporelles",
71
+ depreciable: true,
72
+ },
73
+ "27": {
74
+ code: "27",
75
+ group: "tangible",
76
+ label: "Immobilisations corporelles en cours et acomptes versés",
77
+ depreciable: false,
78
+ },
79
+ "28": {
80
+ code: "28",
81
+ group: "financial",
82
+ label: "Immobilisations financières",
83
+ depreciable: false,
84
+ },
85
+ };
86
+
87
+ /** The fixed-asset group for a PCMN account code, or null if not classes 20-28. */
88
+ export function fixedAssetGroupForCode(code: string): FixedAssetGroup | null {
89
+ return PCMN_FIXED_ASSET_CLASSES[code.trim().slice(0, 2)]?.group ?? null;
90
+ }
package/src/index.ts ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @financica/pcmn — the Belgian PCMN (Plan Comptable Minimum Normalisé) class
3
+ * taxonomy shared across the Financica suite. A single, dependency-free
4
+ * definition of which account classes map to which economic categories, so
5
+ * financica (aggregating a real ledger) and financica-plan (projecting one)
6
+ * classify income, costs and assets identically.
7
+ */
8
+
9
+ export {
10
+ CASH_CLASSES,
11
+ type CashClass,
12
+ DIRECTOR_REMUNERATION_ACCOUNT,
13
+ isCashClass,
14
+ PCMN_PL_CLASSES,
15
+ type PcmnPlClass,
16
+ type PlCategory,
17
+ plCategoryForCode,
18
+ type PlSide,
19
+ } from "./pl.js";
20
+ export {
21
+ type FixedAssetGroup,
22
+ fixedAssetGroupForCode,
23
+ PCMN_FIXED_ASSET_CLASSES,
24
+ type PcmnFixedAssetClass,
25
+ } from "./assets.js";
package/src/pl.ts ADDED
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Belgian PCMN (Plan Comptable Minimum Normalisé) profit-and-loss taxonomy: the
3
+ * 2-digit account classes of the statutory income statement and the economic
4
+ * categories the Financica suite groups them into. This is the single shared
5
+ * definition: financica aggregates its real ledger through it, and
6
+ * financica-plan projects the same categories, so a plan and its actuals
7
+ * reconcile line for line.
8
+ */
9
+
10
+ /** Economic P&L buckets, aligned to the Belgian statutory income statement. */
11
+ export type PlCategory =
12
+ | "revenue"
13
+ | "goods"
14
+ | "services"
15
+ | "personnel"
16
+ | "depreciation"
17
+ | "otherOperatingCharges"
18
+ | "otherOperatingIncome"
19
+ | "financialCharges"
20
+ | "financialIncome"
21
+ | "exceptionalCharges"
22
+ | "exceptionalIncome";
23
+
24
+ /** Natural balance side: charges (6x) are debit, income (7x) is credit. */
25
+ export type PlSide = "debit" | "credit";
26
+
27
+ export interface PcmnPlClass {
28
+ /** 2-digit PCMN class, e.g. "60". */
29
+ readonly code: string;
30
+ readonly category: PlCategory;
31
+ readonly side: PlSide;
32
+ /** French rubric of the Belgian income statement. */
33
+ readonly label: string;
34
+ }
35
+
36
+ /**
37
+ * The compared P&L classes (charges 60-66, income 70-76). Classes outside this
38
+ * set (71 stock variation, 72 own work capitalised, 73 subsidies, ...) are not
39
+ * mapped: both apps leave them out of the compared categories.
40
+ */
41
+ export const PCMN_PL_CLASSES: Readonly<Record<string, PcmnPlClass>> = {
42
+ "60": {
43
+ code: "60",
44
+ category: "goods",
45
+ side: "debit",
46
+ label: "Approvisionnements et marchandises",
47
+ },
48
+ "61": {
49
+ code: "61",
50
+ category: "services",
51
+ side: "debit",
52
+ label: "Services et biens divers",
53
+ },
54
+ "62": {
55
+ code: "62",
56
+ category: "personnel",
57
+ side: "debit",
58
+ label: "Rémunérations, charges sociales et pensions",
59
+ },
60
+ "63": {
61
+ code: "63",
62
+ category: "depreciation",
63
+ side: "debit",
64
+ label: "Amortissements, réductions de valeur et provisions",
65
+ },
66
+ "64": {
67
+ code: "64",
68
+ category: "otherOperatingCharges",
69
+ side: "debit",
70
+ label: "Autres charges d'exploitation",
71
+ },
72
+ "65": {
73
+ code: "65",
74
+ category: "financialCharges",
75
+ side: "debit",
76
+ label: "Charges financières",
77
+ },
78
+ "66": {
79
+ code: "66",
80
+ category: "exceptionalCharges",
81
+ side: "debit",
82
+ label: "Charges exceptionnelles",
83
+ },
84
+ "70": {
85
+ code: "70",
86
+ category: "revenue",
87
+ side: "credit",
88
+ label: "Chiffre d'affaires",
89
+ },
90
+ "74": {
91
+ code: "74",
92
+ category: "otherOperatingIncome",
93
+ side: "credit",
94
+ label: "Autres produits d'exploitation",
95
+ },
96
+ "75": {
97
+ code: "75",
98
+ category: "financialIncome",
99
+ side: "credit",
100
+ label: "Produits financiers",
101
+ },
102
+ "76": {
103
+ code: "76",
104
+ category: "exceptionalIncome",
105
+ side: "credit",
106
+ label: "Produits exceptionnels",
107
+ },
108
+ };
109
+
110
+ /**
111
+ * PCMN 618 — remuneration and benefits of company directors/managers who are
112
+ * NOT employed under a contract of employment (dirigeants d'entreprise
113
+ * indépendants). It belongs to class 61 "Services et biens divers", NOT class
114
+ * 62 "Rémunérations". This is the one PCMN subtlety that both apps must get
115
+ * right so an owner's own pay reconciles between a plan and its actuals.
116
+ */
117
+ export const DIRECTOR_REMUNERATION_ACCOUNT = "618";
118
+
119
+ /**
120
+ * The P&L category for a PCMN account code of any length (2-digit class up to a
121
+ * full leaf code), or null when the code is not one of the compared P&L
122
+ * classes. Applies the 618 rule explicitly before falling back to the class, so
123
+ * self-employed director remuneration is never miscounted as personnel.
124
+ */
125
+ export function plCategoryForCode(code: string): PlCategory | null {
126
+ const trimmed = code.trim();
127
+ if (trimmed.startsWith(DIRECTOR_REMUNERATION_ACCOUNT)) return "services";
128
+ return PCMN_PL_CLASSES[trimmed.slice(0, 2)]?.category ?? null;
129
+ }
130
+
131
+ /**
132
+ * PCMN liquidity classes (valeurs disponibles): 54 term deposits, 55 banks, 57
133
+ * cash on hand. Their net movement is the treasury / cash position. (50-53
134
+ * current investments and 56 are excluded, matching the suite's cash view.)
135
+ */
136
+ export const CASH_CLASSES = ["54", "55", "57"] as const;
137
+ export type CashClass = (typeof CASH_CLASSES)[number];
138
+
139
+ /** Whether an account code belongs to a liquidity (cash) class. */
140
+ export function isCashClass(code: string): boolean {
141
+ return (CASH_CLASSES as readonly string[]).includes(code.trim().slice(0, 2));
142
+ }