@accounter/shaam-uniform-format-generator 0.1.0 → 0.1.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.
Files changed (269) hide show
  1. package/README.md +366 -13
  2. package/dist/README.md +476 -0
  3. package/dist/cjs/api/generate-report-legacy.js +6 -0
  4. package/dist/cjs/api/generate-report.js +328 -0
  5. package/dist/cjs/constants.js +11 -0
  6. package/dist/cjs/generator/format/encoder.js +86 -0
  7. package/dist/cjs/generator/records/a000-sum.js +66 -0
  8. package/dist/cjs/generator/records/a000.js +349 -0
  9. package/dist/cjs/generator/records/a100.js +107 -0
  10. package/dist/cjs/generator/records/b100.js +305 -0
  11. package/dist/cjs/generator/records/b110.js +255 -0
  12. package/dist/cjs/generator/records/c100.js +338 -0
  13. package/dist/cjs/generator/records/d110.js +272 -0
  14. package/dist/cjs/generator/records/d120.js +278 -0
  15. package/{cjs → dist/cjs}/generator/records/index.js +1 -0
  16. package/dist/cjs/generator/records/m100.js +177 -0
  17. package/dist/cjs/generator/records/z900.js +93 -0
  18. package/{cjs → dist/cjs}/index.js +3 -0
  19. package/dist/cjs/records/a100.js +78 -0
  20. package/dist/cjs/records/index.js +20 -0
  21. package/dist/cjs/records/z900.js +82 -0
  22. package/dist/cjs/types/enums.js +457 -0
  23. package/{cjs → dist/cjs}/types/index.js +6 -1
  24. package/dist/cjs/utils/file-helpers.js +198 -0
  25. package/dist/cjs/utils/index.js +8 -0
  26. package/dist/cjs/utils/key-generator.js +71 -0
  27. package/dist/esm/api/generate-report-legacy.js +2 -0
  28. package/dist/esm/api/generate-report.js +325 -0
  29. package/dist/esm/constants.js +8 -0
  30. package/dist/esm/generator/format/encoder.js +77 -0
  31. package/dist/esm/generator/records/a000-sum.js +61 -0
  32. package/dist/esm/generator/records/a000.js +344 -0
  33. package/dist/esm/generator/records/a100.js +102 -0
  34. package/dist/esm/generator/records/b100.js +300 -0
  35. package/dist/esm/generator/records/b110.js +250 -0
  36. package/dist/esm/generator/records/c100.js +333 -0
  37. package/dist/esm/generator/records/d110.js +267 -0
  38. package/dist/esm/generator/records/d120.js +273 -0
  39. package/{esm → dist/esm}/generator/records/index.js +1 -0
  40. package/dist/esm/generator/records/m100.js +172 -0
  41. package/dist/esm/generator/records/z900.js +88 -0
  42. package/{esm → dist/esm}/index.js +3 -0
  43. package/dist/esm/records/a100.js +73 -0
  44. package/dist/esm/records/index.js +11 -0
  45. package/dist/esm/records/z900.js +77 -0
  46. package/dist/esm/types/enums.js +454 -0
  47. package/{esm → dist/esm}/types/index.js +5 -1
  48. package/dist/esm/utils/file-helpers.js +188 -0
  49. package/dist/esm/utils/index.js +5 -0
  50. package/dist/esm/utils/key-generator.js +65 -0
  51. package/dist/package.json +54 -0
  52. package/dist/typings/api/generate-report-legacy.d.cts +1 -0
  53. package/dist/typings/api/generate-report-legacy.d.ts +1 -0
  54. package/dist/typings/constants.d.cts +8 -0
  55. package/dist/typings/constants.d.ts +8 -0
  56. package/dist/typings/generator/format/encoder.d.cts +57 -0
  57. package/dist/typings/generator/format/encoder.d.ts +57 -0
  58. package/dist/typings/generator/records/a000-sum.d.cts +40 -0
  59. package/dist/typings/generator/records/a000-sum.d.ts +40 -0
  60. package/dist/typings/generator/records/a000.d.cts +238 -0
  61. package/dist/typings/generator/records/a000.d.ts +238 -0
  62. package/dist/typings/generator/records/a100.d.cts +59 -0
  63. package/dist/typings/generator/records/a100.d.ts +59 -0
  64. package/dist/typings/generator/records/b100.d.cts +101 -0
  65. package/dist/typings/generator/records/b100.d.ts +101 -0
  66. package/dist/typings/generator/records/b110.d.cts +89 -0
  67. package/dist/typings/generator/records/b110.d.ts +89 -0
  68. package/dist/typings/generator/records/c100.d.cts +133 -0
  69. package/dist/typings/generator/records/c100.d.ts +133 -0
  70. package/dist/typings/generator/records/d110.d.cts +98 -0
  71. package/dist/typings/generator/records/d110.d.ts +98 -0
  72. package/dist/typings/generator/records/d120.d.cts +95 -0
  73. package/dist/typings/generator/records/d120.d.ts +95 -0
  74. package/{typings → dist/typings}/generator/records/index.d.cts +1 -0
  75. package/{typings → dist/typings}/generator/records/index.d.ts +1 -0
  76. package/dist/typings/generator/records/m100.d.cts +69 -0
  77. package/dist/typings/generator/records/m100.d.ts +69 -0
  78. package/dist/typings/generator/records/z900.d.cts +61 -0
  79. package/dist/typings/generator/records/z900.d.ts +61 -0
  80. package/{typings → dist/typings}/index.d.cts +3 -0
  81. package/{typings → dist/typings}/index.d.ts +3 -0
  82. package/dist/typings/records/a100.d.cts +35 -0
  83. package/dist/typings/records/a100.d.ts +35 -0
  84. package/dist/typings/records/index.d.cts +2 -0
  85. package/dist/typings/records/index.d.ts +2 -0
  86. package/dist/typings/records/z900.d.cts +38 -0
  87. package/dist/typings/records/z900.d.ts +38 -0
  88. package/dist/typings/types/enums.d.cts +162 -0
  89. package/dist/typings/types/enums.d.ts +162 -0
  90. package/{typings → dist/typings}/types/index.d.cts +17 -14
  91. package/{typings → dist/typings}/types/index.d.ts +17 -14
  92. package/dist/typings/utils/file-helpers.d.cts +131 -0
  93. package/dist/typings/utils/file-helpers.d.ts +131 -0
  94. package/dist/typings/utils/index.d.cts +5 -0
  95. package/dist/typings/utils/index.d.ts +5 -0
  96. package/dist/typings/utils/key-generator.d.cts +41 -0
  97. package/dist/typings/utils/key-generator.d.ts +41 -0
  98. package/documentation/IncomeTax_IncomeTaxSoftwareHousesInfo_horaot1.31_2_05.pdf +0 -0
  99. package/documentation/_4D6963726F736F667420576F7264202D20F8E5E0E9ED20F8E7E5F720F8E5E0E9ED20F9F7E5F32E646F63_.pdf +0 -0
  100. package/documentation/a000-sum.csv +3 -0
  101. package/documentation/a000.csv +37 -0
  102. package/documentation/a100.csv +7 -0
  103. package/documentation/b100.csv +29 -0
  104. package/documentation/b110.csv +26 -0
  105. package/documentation/c100.csv +37 -0
  106. package/documentation/d110.csv +27 -0
  107. package/documentation/d120.csv +26 -0
  108. package/documentation/m100.csv +17 -0
  109. package/documentation/z900.csv +8 -0
  110. package/package.json +50 -29
  111. package/prompt_plan.md +259 -0
  112. package/spec.md +206 -0
  113. package/src/api/generate-report.ts +366 -0
  114. package/src/api/parse-files.ts +33 -0
  115. package/src/constants.ts +9 -0
  116. package/src/format/index.ts +6 -0
  117. package/src/format/newline.ts +8 -0
  118. package/src/format/padding.ts +39 -0
  119. package/src/generator/format/decoder.ts +15 -0
  120. package/src/generator/format/encoder.ts +95 -0
  121. package/src/generator/format/index.ts +6 -0
  122. package/src/generator/index.ts +6 -0
  123. package/src/generator/records/a000-sum.ts +78 -0
  124. package/src/generator/records/a000.ts +373 -0
  125. package/src/generator/records/a100.ts +118 -0
  126. package/src/generator/records/b100.ts +317 -0
  127. package/src/generator/records/b110.ts +267 -0
  128. package/src/generator/records/c100.ts +347 -0
  129. package/src/generator/records/d110.ts +286 -0
  130. package/src/generator/records/d120.ts +293 -0
  131. package/src/generator/records/index.ts +14 -0
  132. package/src/generator/records/m100.ts +185 -0
  133. package/src/generator/records/z900.ts +104 -0
  134. package/src/index.ts +18 -0
  135. package/src/parser/data-parser.ts +14 -0
  136. package/src/parser/index.ts +6 -0
  137. package/src/parser/ini-parser.ts +14 -0
  138. package/src/types/enums.ts +531 -0
  139. package/src/types/index.ts +110 -0
  140. package/src/utils/file-helpers.ts +221 -0
  141. package/src/utils/index.ts +6 -0
  142. package/src/utils/key-generator.ts +75 -0
  143. package/src/validation/errors.ts +35 -0
  144. package/src/validation/index.ts +6 -0
  145. package/src/validation/validate-input.ts +67 -0
  146. package/tests/debug-output.test.ts +81 -0
  147. package/tests/format/crlf-join.test.ts +124 -0
  148. package/tests/format/encoder.test.ts +80 -0
  149. package/tests/format/newline.test.ts +19 -0
  150. package/tests/format/padding.test.ts +74 -0
  151. package/tests/index.test.ts +29 -0
  152. package/tests/ini-text.test.ts +122 -0
  153. package/tests/integration/comprehensive.integration.test.ts +350 -0
  154. package/tests/integration/roundtrip.integration.test.ts +377 -0
  155. package/tests/records/a000-sum.test.ts +278 -0
  156. package/tests/records/a000.test.ts +318 -0
  157. package/tests/records/a100.test.ts +239 -0
  158. package/tests/records/b100.test.ts +419 -0
  159. package/tests/records/b110.test.ts +445 -0
  160. package/tests/records/c100.test.ts +333 -0
  161. package/tests/records/d110.test.ts +93 -0
  162. package/tests/records/d120.test.ts +275 -0
  163. package/tests/records/m100.test.ts +437 -0
  164. package/tests/records/z900.test.ts +254 -0
  165. package/tests/types/enums.test.ts +290 -0
  166. package/tests/utils/file-helpers.test.ts +276 -0
  167. package/tests/utils/key-generator.test.ts +121 -0
  168. package/tests/validation/document-type-validation.test.ts +521 -0
  169. package/tests/validation/validate-input.test.ts +219 -0
  170. package/todo.md +203 -0
  171. package/tsconfig.json +10 -0
  172. package/vitest.config.ts +11 -0
  173. package/cjs/api/generate-report.js +0 -53
  174. package/cjs/generator/format/encoder.js +0 -46
  175. package/cjs/generator/records/a000.js +0 -8
  176. package/cjs/generator/records/a100.js +0 -8
  177. package/cjs/generator/records/b100.js +0 -8
  178. package/cjs/generator/records/b110.js +0 -8
  179. package/cjs/generator/records/c100.js +0 -8
  180. package/cjs/generator/records/d110.js +0 -8
  181. package/cjs/generator/records/d120.js +0 -8
  182. package/cjs/generator/records/m100.js +0 -8
  183. package/cjs/generator/records/z900.js +0 -8
  184. package/esm/api/generate-report.js +0 -50
  185. package/esm/generator/format/encoder.js +0 -42
  186. package/esm/generator/records/a000.js +0 -5
  187. package/esm/generator/records/a100.js +0 -5
  188. package/esm/generator/records/b100.js +0 -5
  189. package/esm/generator/records/b110.js +0 -5
  190. package/esm/generator/records/c100.js +0 -5
  191. package/esm/generator/records/d110.js +0 -5
  192. package/esm/generator/records/d120.js +0 -5
  193. package/esm/generator/records/m100.js +0 -5
  194. package/esm/generator/records/z900.js +0 -5
  195. package/typings/generator/format/encoder.d.cts +0 -33
  196. package/typings/generator/format/encoder.d.ts +0 -33
  197. package/typings/generator/records/a000.d.cts +0 -4
  198. package/typings/generator/records/a000.d.ts +0 -4
  199. package/typings/generator/records/a100.d.cts +0 -4
  200. package/typings/generator/records/a100.d.ts +0 -4
  201. package/typings/generator/records/b100.d.cts +0 -4
  202. package/typings/generator/records/b100.d.ts +0 -4
  203. package/typings/generator/records/b110.d.cts +0 -4
  204. package/typings/generator/records/b110.d.ts +0 -4
  205. package/typings/generator/records/c100.d.cts +0 -4
  206. package/typings/generator/records/c100.d.ts +0 -4
  207. package/typings/generator/records/d110.d.cts +0 -4
  208. package/typings/generator/records/d110.d.ts +0 -4
  209. package/typings/generator/records/d120.d.cts +0 -4
  210. package/typings/generator/records/d120.d.ts +0 -4
  211. package/typings/generator/records/m100.d.cts +0 -4
  212. package/typings/generator/records/m100.d.ts +0 -4
  213. package/typings/generator/records/z900.d.cts +0 -4
  214. package/typings/generator/records/z900.d.ts +0 -4
  215. /package/{cjs → dist/cjs}/api/parse-files.js +0 -0
  216. /package/{cjs → dist/cjs}/format/index.js +0 -0
  217. /package/{cjs → dist/cjs}/format/newline.js +0 -0
  218. /package/{cjs → dist/cjs}/format/padding.js +0 -0
  219. /package/{cjs → dist/cjs}/generator/format/decoder.js +0 -0
  220. /package/{cjs → dist/cjs}/generator/format/index.js +0 -0
  221. /package/{cjs → dist/cjs}/generator/index.js +0 -0
  222. /package/{cjs → dist/cjs}/package.json +0 -0
  223. /package/{cjs → dist/cjs}/parser/data-parser.js +0 -0
  224. /package/{cjs → dist/cjs}/parser/index.js +0 -0
  225. /package/{cjs → dist/cjs}/parser/ini-parser.js +0 -0
  226. /package/{cjs → dist/cjs}/validation/errors.js +0 -0
  227. /package/{cjs → dist/cjs}/validation/index.js +0 -0
  228. /package/{cjs → dist/cjs}/validation/validate-input.js +0 -0
  229. /package/{esm → dist/esm}/api/parse-files.js +0 -0
  230. /package/{esm → dist/esm}/format/index.js +0 -0
  231. /package/{esm → dist/esm}/format/newline.js +0 -0
  232. /package/{esm → dist/esm}/format/padding.js +0 -0
  233. /package/{esm → dist/esm}/generator/format/decoder.js +0 -0
  234. /package/{esm → dist/esm}/generator/format/index.js +0 -0
  235. /package/{esm → dist/esm}/generator/index.js +0 -0
  236. /package/{esm → dist/esm}/parser/data-parser.js +0 -0
  237. /package/{esm → dist/esm}/parser/index.js +0 -0
  238. /package/{esm → dist/esm}/parser/ini-parser.js +0 -0
  239. /package/{esm → dist/esm}/validation/errors.js +0 -0
  240. /package/{esm → dist/esm}/validation/index.js +0 -0
  241. /package/{esm → dist/esm}/validation/validate-input.js +0 -0
  242. /package/{typings → dist/typings}/api/generate-report.d.cts +0 -0
  243. /package/{typings → dist/typings}/api/generate-report.d.ts +0 -0
  244. /package/{typings → dist/typings}/api/parse-files.d.cts +0 -0
  245. /package/{typings → dist/typings}/api/parse-files.d.ts +0 -0
  246. /package/{typings → dist/typings}/format/index.d.cts +0 -0
  247. /package/{typings → dist/typings}/format/index.d.ts +0 -0
  248. /package/{typings → dist/typings}/format/newline.d.cts +0 -0
  249. /package/{typings → dist/typings}/format/newline.d.ts +0 -0
  250. /package/{typings → dist/typings}/format/padding.d.cts +0 -0
  251. /package/{typings → dist/typings}/format/padding.d.ts +0 -0
  252. /package/{typings → dist/typings}/generator/format/decoder.d.cts +0 -0
  253. /package/{typings → dist/typings}/generator/format/decoder.d.ts +0 -0
  254. /package/{typings → dist/typings}/generator/format/index.d.cts +0 -0
  255. /package/{typings → dist/typings}/generator/format/index.d.ts +0 -0
  256. /package/{typings → dist/typings}/generator/index.d.cts +0 -0
  257. /package/{typings → dist/typings}/generator/index.d.ts +0 -0
  258. /package/{typings → dist/typings}/parser/data-parser.d.cts +0 -0
  259. /package/{typings → dist/typings}/parser/data-parser.d.ts +0 -0
  260. /package/{typings → dist/typings}/parser/index.d.cts +0 -0
  261. /package/{typings → dist/typings}/parser/index.d.ts +0 -0
  262. /package/{typings → dist/typings}/parser/ini-parser.d.cts +0 -0
  263. /package/{typings → dist/typings}/parser/ini-parser.d.ts +0 -0
  264. /package/{typings → dist/typings}/validation/errors.d.cts +0 -0
  265. /package/{typings → dist/typings}/validation/errors.d.ts +0 -0
  266. /package/{typings → dist/typings}/validation/index.d.cts +0 -0
  267. /package/{typings → dist/typings}/validation/index.d.ts +0 -0
  268. /package/{typings → dist/typings}/validation/validate-input.d.cts +0 -0
  269. /package/{typings → dist/typings}/validation/validate-input.d.ts +0 -0
@@ -0,0 +1,198 @@
1
+ "use strict";
2
+ /**
3
+ * File Helper Utilities for SHAAM Uniform Format Generator
4
+ * Provides utilities for creating and managing File objects
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.FileNaming = void 0;
8
+ exports.createFile = createFile;
9
+ exports.createIniFile = createIniFile;
10
+ exports.createDataFile = createDataFile;
11
+ exports.createShaamFiles = createShaamFiles;
12
+ exports.validateShaamFile = validateShaamFile;
13
+ exports.readFileAsText = readFileAsText;
14
+ exports.getFileInfo = getFileInfo;
15
+ /**
16
+ * Creates a File object with the given text content and filename
17
+ * This is a utility function to standardize File creation across the package
18
+ *
19
+ * @param text - The text content for the file
20
+ * @param name - The filename (should include extension)
21
+ * @param options - Optional File constructor options
22
+ * @returns A File object containing the text content
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const iniFile = createFile(iniText, 'report.INI.TXT');
27
+ * const dataFile = createFile(dataText, 'report.BKMVDATA.TXT');
28
+ * ```
29
+ */
30
+ function createFile(text, name, options = { type: 'text/plain' }) {
31
+ if (!text || typeof text !== 'string') {
32
+ throw new Error('Text content must be a non-empty string');
33
+ }
34
+ if (!name || typeof name !== 'string') {
35
+ throw new Error('Filename must be a non-empty string');
36
+ }
37
+ // Ensure we have proper line endings for SHAAM format
38
+ const normalizedText = text.replace(/\r?\n/g, '\r\n');
39
+ return new File([normalizedText], name, {
40
+ type: 'text/plain',
41
+ ...options,
42
+ });
43
+ }
44
+ /**
45
+ * Creates an INI.TXT File object with standardized naming
46
+ *
47
+ * @param iniText - The INI text content
48
+ * @param baseFileName - Base filename (without extension)
49
+ * @returns A File object for the INI file
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * const iniFile = createIniFile(iniText, 'my-report');
54
+ * // Creates file named: my-report.INI.TXT
55
+ * ```
56
+ */
57
+ function createIniFile(iniText, baseFileName = 'report') {
58
+ const fileName = `${baseFileName}.INI.TXT`;
59
+ return createFile(iniText, fileName);
60
+ }
61
+ /**
62
+ * Creates a BKMVDATA.TXT File object with standardized naming
63
+ *
64
+ * @param dataText - The data text content
65
+ * @param baseFileName - Base filename (without extension)
66
+ * @returns A File object for the data file
67
+ *
68
+ * @example
69
+ * ```typescript
70
+ * const dataFile = createDataFile(dataText, 'my-report');
71
+ * // Creates file named: my-report.BKMVDATA.TXT
72
+ * ```
73
+ */
74
+ function createDataFile(dataText, baseFileName = 'report') {
75
+ const fileName = `${baseFileName}.BKMVDATA.TXT`;
76
+ return createFile(dataText, fileName);
77
+ }
78
+ /**
79
+ * Creates both INI and Data File objects from the report output
80
+ *
81
+ * @param iniText - The INI text content
82
+ * @param dataText - The data text content
83
+ * @param baseFileName - Base filename (without extension)
84
+ * @returns An object containing both File objects
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * const { iniFile, dataFile } = createShaamFiles(iniText, dataText, 'my-report');
89
+ * ```
90
+ */
91
+ function createShaamFiles(iniText, dataText, baseFileName = 'report') {
92
+ return {
93
+ iniFile: createIniFile(iniText, baseFileName),
94
+ dataFile: createDataFile(dataText, baseFileName),
95
+ };
96
+ }
97
+ /**
98
+ * Validates that a File object appears to be a valid SHAAM format file
99
+ *
100
+ * @param file - The File object to validate
101
+ * @param expectedType - Expected file type ('ini' | 'data')
102
+ * @returns True if the file appears valid
103
+ *
104
+ * @example
105
+ * ```typescript
106
+ * const isValidIni = validateShaamFile(iniFile, 'ini');
107
+ * const isValidData = validateShaamFile(dataFile, 'data');
108
+ * ```
109
+ */
110
+ function validateShaamFile(file, expectedType) {
111
+ if (!file || !(file instanceof File)) {
112
+ return false;
113
+ }
114
+ // Check filename convention
115
+ const expectedExtension = expectedType === 'ini' ? '.INI.TXT' : '.BKMVDATA.TXT';
116
+ if (!file.name.toUpperCase().endsWith(expectedExtension)) {
117
+ return false;
118
+ }
119
+ // Check MIME type
120
+ if (file.type !== 'text/plain') {
121
+ return false;
122
+ }
123
+ // Check that file has content
124
+ if (file.size === 0) {
125
+ return false;
126
+ }
127
+ return true;
128
+ }
129
+ /**
130
+ * Reads text content from a File object
131
+ * This is an async utility for reading File objects back to text
132
+ *
133
+ * @param file - The File object to read
134
+ * @returns Promise that resolves to the text content
135
+ *
136
+ * @example
137
+ * ```typescript
138
+ * const text = await readFileAsText(file);
139
+ * ```
140
+ */
141
+ async function readFileAsText(file) {
142
+ if (!file || !(file instanceof File)) {
143
+ throw new Error('Input must be a valid File object');
144
+ }
145
+ return file.text();
146
+ }
147
+ /**
148
+ * Gets file information from a File object
149
+ *
150
+ * @param file - The File object to inspect
151
+ * @returns File information object
152
+ *
153
+ * @example
154
+ * ```typescript
155
+ * const info = getFileInfo(iniFile);
156
+ * console.log(`File: ${info.name}, Size: ${info.size} bytes`);
157
+ * ```
158
+ */
159
+ function getFileInfo(file) {
160
+ if (!file || !(file instanceof File)) {
161
+ throw new Error('Input must be a valid File object');
162
+ }
163
+ return {
164
+ name: file.name,
165
+ size: file.size,
166
+ type: file.type,
167
+ lastModified: file.lastModified,
168
+ };
169
+ }
170
+ /**
171
+ * File naming utilities for SHAAM format files
172
+ */
173
+ exports.FileNaming = {
174
+ /**
175
+ * Generates a standardized INI filename
176
+ */
177
+ iniFileName: (base = 'report') => `${base}.INI.TXT`,
178
+ /**
179
+ * Generates a standardized data filename
180
+ */
181
+ dataFileName: (base = 'report') => `${base}.BKMVDATA.TXT`,
182
+ /**
183
+ * Extracts base filename from a SHAAM file
184
+ */
185
+ extractBaseName: (fileName) => {
186
+ if (!fileName || !exports.FileNaming.isValidShaamFileName(fileName)) {
187
+ return 'report';
188
+ }
189
+ const name = fileName.replace(/\.(INI|BKMVDATA)\.TXT$/i, '');
190
+ return name || 'report';
191
+ },
192
+ /**
193
+ * Validates filename follows SHAAM conventions
194
+ */
195
+ isValidShaamFileName: (fileName) => {
196
+ return /\.(INI|BKMVDATA)\.TXT$/i.test(fileName);
197
+ },
198
+ };
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ /**
3
+ * Utility functions for SHAAM uniform format generator
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const tslib_1 = require("tslib");
7
+ tslib_1.__exportStar(require("./file-helpers.js"), exports);
8
+ tslib_1.__exportStar(require("./key-generator.js"), exports);
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ /**
3
+ * Key generator utility for generating unique identifiers
4
+ * Used for fields 1004, 1103, and 1153 which require randomly generated unique IDs
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.defaultKeyGenerator = exports.KeyGeneratorContext = void 0;
8
+ exports.generateRandomKey = generateRandomKey;
9
+ exports.generatePrimaryIdentifier = generatePrimaryIdentifier;
10
+ /**
11
+ * Generates a random numeric string of specified length
12
+ * @param length - The length of the numeric string to generate (max 15 digits)
13
+ * @returns A random numeric string padded with leading zeros if necessary
14
+ */
15
+ function generateRandomKey(length = 15) {
16
+ if (length <= 0 || length > 15) {
17
+ throw new Error('Key length must be between 1 and 15 digits');
18
+ }
19
+ // Generate a random number with the specified number of digits
20
+ // For length 15, max value is 999,999,999,999,999 (15 nines)
21
+ const maxValue = Math.pow(10, length) - 1;
22
+ const minValue = Math.pow(10, length - 1); // Ensures we always get the full length
23
+ // Generate random number between minValue and maxValue
24
+ const randomNum = Math.floor(Math.random() * (maxValue - minValue + 1)) + minValue;
25
+ // Convert to string and pad with zeros if needed
26
+ return randomNum.toString().padStart(length, '0');
27
+ }
28
+ /**
29
+ * Generates a primary identifier for fields 1004, 1103, and 1153
30
+ * These fields must have the same value across all records in a single file
31
+ * @returns A 15-digit numeric string
32
+ */
33
+ function generatePrimaryIdentifier() {
34
+ return generateRandomKey(15);
35
+ }
36
+ /**
37
+ * Key generator context to maintain consistent IDs across records
38
+ * This ensures that fields 1004, 1103, and 1153 use the same value within a single file
39
+ */
40
+ class KeyGeneratorContext {
41
+ _primaryIdentifier = null;
42
+ /**
43
+ * Gets or generates the primary identifier for this context
44
+ * Ensures the same ID is used across all records that require it
45
+ */
46
+ getPrimaryIdentifier() {
47
+ this._primaryIdentifier ||= generatePrimaryIdentifier();
48
+ return this._primaryIdentifier;
49
+ }
50
+ /**
51
+ * Resets the context, generating new IDs for the next file
52
+ */
53
+ reset() {
54
+ this._primaryIdentifier = null;
55
+ }
56
+ /**
57
+ * Sets a specific primary identifier (useful for testing or when you have a specific ID requirement)
58
+ */
59
+ setPrimaryIdentifier(id) {
60
+ if (!/^\d{1,15}$/.test(id)) {
61
+ throw new Error('Primary identifier must be a numeric string with 1-15 digits');
62
+ }
63
+ this._primaryIdentifier = id.padStart(15, '0');
64
+ }
65
+ }
66
+ exports.KeyGeneratorContext = KeyGeneratorContext;
67
+ /**
68
+ * Default key generator context instance
69
+ * Use this for most cases to ensure consistency across records
70
+ */
71
+ exports.defaultKeyGenerator = new KeyGeneratorContext();
@@ -0,0 +1,2 @@
1
+ // Placeholder for generateReport implementation
2
+ export { generateUniformFormatReport } from './generate-report.js';
@@ -0,0 +1,325 @@
1
+ /**
2
+ * Main API for generating SHAAM uniform format reports
3
+ */
4
+ import { assembleFile } from '../generator/format/encoder.js';
5
+ import { encodeA000, encodeA000Sum, encodeA100, encodeB100, encodeB110, encodeC100, encodeD110, encodeD120, encodeM100, encodeZ900, } from '../generator/records/index.js';
6
+ import { ShaamFormatError } from '../validation/errors.js';
7
+ import { validateInput } from '../validation/validate-input.js';
8
+ /**
9
+ * Generates SHAAM uniform format report files (INI.TXT and BKMVDATA.TXT)
10
+ * from a high-level JSON input object.
11
+ *
12
+ * @param input - The report input data
13
+ * @param options - Generation options
14
+ * @returns Report output with generated file content
15
+ */
16
+ export function generateUniformFormatReport(input, options = {}) {
17
+ // Validate input data first
18
+ const validationMode = options.validationMode || 'fail-fast';
19
+ const validationErrors = validateInput(input, validationMode);
20
+ if (validationErrors.length > 0) {
21
+ if (validationMode === 'fail-fast') {
22
+ // This should have already thrown, but just in case
23
+ throw new ShaamFormatError('Validation failed', validationErrors);
24
+ }
25
+ // For collect-all mode, we still throw if there are errors
26
+ // The user can catch and inspect the errors if needed
27
+ throw new ShaamFormatError('Input validation failed', validationErrors);
28
+ }
29
+ const records = [];
30
+ const iniRecords = [];
31
+ const recordCounts = {};
32
+ let recordNumber = 1;
33
+ // Helper function to count and add data record
34
+ const addRecord = (recordType, recordContent) => {
35
+ records.push(recordContent);
36
+ recordCounts[recordType] = (recordCounts[recordType] || 0) + 1;
37
+ recordNumber++;
38
+ };
39
+ // Helper function to add INI record
40
+ const addIniRecord = (recordType, recordContent) => {
41
+ iniRecords.push(recordContent);
42
+ recordCounts[recordType] = (recordCounts[recordType] || 0) + 1;
43
+ };
44
+ // Generate A000 record for INI.TXT
45
+ const fileHeaderRecord = {
46
+ reservedFuture: '',
47
+ totalRecords: '0', // Will be updated later with actual count
48
+ vatId: input.business.taxId,
49
+ softwareRegNumber: '12345678', // TODO: Use actual software registration number
50
+ softwareName: 'SHAAM Generator',
51
+ softwareVersion: '1.0.0',
52
+ vendorVatId: '123456789', // TODO: Use actual vendor VAT ID
53
+ vendorName: 'Accounter',
54
+ softwareType: '2', // Multi-year software
55
+ fileOutputPath: options.fileNameBase || 'report',
56
+ accountingType: '2', // Double-entry accounting
57
+ balanceRequired: '1',
58
+ companyRegId: '',
59
+ withholdingFileNum: '',
60
+ reserved1017: '',
61
+ businessName: input.business.name,
62
+ businessStreet: '',
63
+ businessHouseNum: '',
64
+ businessCity: '',
65
+ businessZip: '',
66
+ taxYear: '',
67
+ startDate: input.business.reportingPeriod.startDate.replace(/-/g, ''),
68
+ endDate: input.business.reportingPeriod.endDate.replace(/-/g, ''),
69
+ processStartDate: new Date().toISOString().slice(0, 10).replace(/-/g, ''),
70
+ processStartTime: new Date().toTimeString().slice(0, 5).replace(':', ''),
71
+ languageCode: '0', // Hebrew
72
+ characterEncoding: '1', // ISO-8859-8-i
73
+ compressionSoftware: '',
74
+ reserved1031: '',
75
+ baseCurrency: 'ILS',
76
+ reserved1033: '',
77
+ branchInfoFlag: '0', // No branches for now
78
+ reserved1035: '',
79
+ };
80
+ addIniRecord('A000', encodeA000(fileHeaderRecord));
81
+ // Add A000Sum records for each record type to INI.TXT
82
+ // Calculate expected counts based on input data
83
+ const expectedCounts = {
84
+ A100: 1,
85
+ C100: input.documents.length,
86
+ D110: input.documents.length,
87
+ D120: input.documents.length,
88
+ B100: input.journalEntries.length,
89
+ B110: input.accounts.length,
90
+ M100: input.inventory.length,
91
+ Z900: 1,
92
+ };
93
+ // Add summary records for each record type
94
+ for (const [recordType, count] of Object.entries(expectedCounts)) {
95
+ if (count > 0) {
96
+ const summaryRecord = {
97
+ code: recordType,
98
+ recordCount: count.toString(),
99
+ };
100
+ addIniRecord('A000Sum', encodeA000Sum(summaryRecord));
101
+ }
102
+ }
103
+ // 1. Business metadata - A100 record
104
+ const businessMetadata = {
105
+ recordNumber: recordNumber.toString(),
106
+ vatId: input.business.taxId,
107
+ reserved: '',
108
+ };
109
+ addRecord('A100', encodeA100(businessMetadata));
110
+ // TODO: 2. Summaries... (not implemented yet)
111
+ // 3. For each document in input.documents
112
+ for (const document of input.documents) {
113
+ // Document header - C100 record
114
+ const documentRecord = {
115
+ code: 'C100',
116
+ recordNumber: recordNumber.toString(),
117
+ vatId: input.business.taxId,
118
+ documentType: document.type,
119
+ documentId: document.id,
120
+ documentIssueDate: document.date.replace(/-/g, ''), // Convert YYYY-MM-DD to YYYYMMDD
121
+ documentIssueTime: '',
122
+ customerName: '',
123
+ customerStreet: '',
124
+ customerHouseNumber: '',
125
+ customerCity: '',
126
+ customerPostCode: '',
127
+ customerCountry: '',
128
+ customerCountryCode: '',
129
+ customerPhone: '',
130
+ customerVatId: '',
131
+ documentValueDate: '',
132
+ foreignCurrencyAmount: '',
133
+ currencyCode: '',
134
+ amountBeforeDiscount: '',
135
+ documentDiscount: '',
136
+ amountAfterDiscountExcludingVat: '',
137
+ vatAmount: '',
138
+ amountIncludingVat: document.amount.toFixed(2), // Format as decimal with 2 places
139
+ withholdingTaxAmount: '',
140
+ customerKey: '',
141
+ matchingField: '',
142
+ cancelledAttribute1: '',
143
+ cancelledDocument: '',
144
+ cancelledAttribute2: '',
145
+ documentDate: '',
146
+ branchKey: '',
147
+ cancelledAttribute3: '',
148
+ actionExecutor: '',
149
+ lineConnectingField: '',
150
+ reserved: '',
151
+ };
152
+ addRecord('C100', encodeC100(documentRecord));
153
+ // Document line - D110 record
154
+ const documentLineRecord = {
155
+ code: 'D110',
156
+ recordNumber: recordNumber.toString(),
157
+ vatId: input.business.taxId,
158
+ documentType: document.type,
159
+ documentNumber: document.id,
160
+ lineNumber: '1',
161
+ baseDocumentType: '',
162
+ baseDocumentNumber: '',
163
+ transactionType: '',
164
+ internalCatalogCode: '',
165
+ goodsServiceDescription: document.description || 'Item',
166
+ manufacturerName: '',
167
+ serialNumber: '',
168
+ unitOfMeasureDescription: '',
169
+ quantity: '1',
170
+ unitPriceExcludingVat: '',
171
+ lineDiscount: '',
172
+ lineTotal: '',
173
+ vatRatePercent: '',
174
+ reserved1: '',
175
+ branchId: '1',
176
+ reserved2: '',
177
+ documentDate: document.date.replace(/-/g, ''),
178
+ headerLinkField: '',
179
+ baseDocumentBranchId: '',
180
+ reserved3: '',
181
+ };
182
+ addRecord('D110', encodeD110(documentLineRecord));
183
+ // Payment record - D120 record (if applicable)
184
+ const paymentRecord = {
185
+ code: 'D120',
186
+ recordNumber: recordNumber.toString(),
187
+ vatId: input.business.taxId,
188
+ documentType: document.type,
189
+ documentNumber: document.id,
190
+ lineNumber: '1',
191
+ paymentMethod: '1', // Default payment method
192
+ bankNumber: '',
193
+ branchNumber: '',
194
+ accountNumber: '',
195
+ checkNumber: '',
196
+ paymentDueDate: '',
197
+ lineAmount: document.amount.toFixed(2), // Format as decimal with 2 places
198
+ acquirerCode: '',
199
+ cardBrand: '',
200
+ creditTransactionType: '',
201
+ firstPaymentAmount: '',
202
+ installmentsCount: '',
203
+ additionalPaymentAmount: '',
204
+ reserved1: '',
205
+ branchId: '1',
206
+ reserved2: '',
207
+ documentDate: document.date.replace(/-/g, ''),
208
+ headerLinkField: '',
209
+ reserved: '',
210
+ };
211
+ addRecord('D120', encodeD120(paymentRecord));
212
+ }
213
+ // 4. Journal lines: for each entry and its lines
214
+ for (const entry of input.journalEntries) {
215
+ const journalRecord = {
216
+ code: 'B100',
217
+ recordNumber: recordNumber.toString(),
218
+ vatId: input.business.taxId,
219
+ transactionNumber: entry.id.replace(/\D/g, '') || '1', // Extract only digits, default to '1'
220
+ transactionLineNumber: '1',
221
+ batchNumber: '',
222
+ transactionType: '',
223
+ referenceDocument: '',
224
+ referenceDocumentType: '',
225
+ referenceDocument2: '',
226
+ referenceDocumentType2: '',
227
+ details: entry.description || '',
228
+ date: entry.date.replace(/-/g, ''),
229
+ valueDate: entry.date.replace(/-/g, ''), // Same as date for simplicity
230
+ accountKey: entry.accountId,
231
+ counterAccountKey: '',
232
+ debitCreditIndicator: (entry.amount >= 0 ? '1' : '2'),
233
+ currencyCode: '',
234
+ transactionAmount: Math.abs(entry.amount).toFixed(2), // Format as decimal with 2 places
235
+ foreignCurrencyAmount: '',
236
+ quantityField: '',
237
+ matchingField1: '',
238
+ matchingField2: '',
239
+ branchId: '',
240
+ entryDate: entry.date.replace(/-/g, ''),
241
+ operatorUsername: '',
242
+ reserved: '',
243
+ };
244
+ addRecord('B100', encodeB100(journalRecord));
245
+ }
246
+ // 5. Accounts: B110 records
247
+ for (const account of input.accounts) {
248
+ const accountRecord = {
249
+ code: 'B110',
250
+ recordNumber: recordNumber.toString(),
251
+ vatId: input.business.taxId,
252
+ accountKey: account.id,
253
+ accountName: account.name,
254
+ trialBalanceCode: account.type,
255
+ trialBalanceCodeDescription: account.type,
256
+ customerSupplierAddressStreet: '',
257
+ customerSupplierAddressHouseNumber: '',
258
+ customerSupplierAddressCity: '',
259
+ customerSupplierAddressZip: '',
260
+ customerSupplierAddressCountry: '',
261
+ countryCode: '',
262
+ parentAccountKey: '',
263
+ accountOpeningBalance: '0',
264
+ totalDebits: '0',
265
+ totalCredits: '0',
266
+ accountingClassificationCode: '',
267
+ supplierCustomerTaxId: '',
268
+ branchId: '',
269
+ openingBalanceForeignCurrency: '',
270
+ foreignCurrencyCode: '',
271
+ reserved: '',
272
+ };
273
+ addRecord('B110', encodeB110(accountRecord));
274
+ }
275
+ // 6. Inventory: M100 records
276
+ for (const item of input.inventory) {
277
+ const inventoryRecord = {
278
+ code: 'M100',
279
+ recordNumber: recordNumber.toString(),
280
+ vatId: input.business.taxId,
281
+ universalItemCode: '',
282
+ supplierItemCode: '',
283
+ internalItemCode: item.id,
284
+ itemName: item.name,
285
+ classificationCode: '',
286
+ classificationDescription: '',
287
+ unitOfMeasure: '',
288
+ openingStock: '0',
289
+ totalStockIn: '0',
290
+ totalStockOut: item.quantity.toString(),
291
+ endPeriodCostNonBonded: '',
292
+ endPeriodCostBonded: '',
293
+ reserved: '',
294
+ };
295
+ addRecord('M100', encodeM100(inventoryRecord));
296
+ }
297
+ // 7. Closing record: Z900
298
+ const closingRecord = {
299
+ recordNumber: recordNumber.toString(),
300
+ vatId: input.business.taxId,
301
+ totalRecords: records.length.toString(), // Count of records before Z900 is added
302
+ reserved: '',
303
+ };
304
+ addRecord('Z900', encodeZ900(closingRecord));
305
+ // Build iniText and dataText using the assembler
306
+ const iniText = assembleFile(iniRecords);
307
+ const dataText = assembleFile(records);
308
+ // Create virtual File objects
309
+ const iniFile = new File([iniText], `${options.fileNameBase || 'report'}.INI.TXT`, {
310
+ type: 'text/plain',
311
+ });
312
+ const dataFile = new File([dataText], `${options.fileNameBase || 'report'}.BKMVDATA.TXT`, {
313
+ type: 'text/plain',
314
+ });
315
+ return {
316
+ iniText,
317
+ dataText,
318
+ iniFile,
319
+ dataFile,
320
+ summary: {
321
+ totalRecords: records.length + iniRecords.length,
322
+ perType: recordCounts,
323
+ },
324
+ };
325
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * SHAAM format constants
3
+ */
4
+ /**
5
+ * SHAAM specification version identifier
6
+ * Used in fields 1104 (A100) and 1154 (Z900)
7
+ */
8
+ export const SHAAM_VERSION = '&OF1.31&';
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Fixed-width formatting utilities
3
+ */
4
+ import { CRLF } from '../../format/newline.js';
5
+ import { padLeft, padRight } from '../../format/padding.js';
6
+ /**
7
+ * Formats a field value with specified width and alignment
8
+ *
9
+ * @param value - The value to format
10
+ * @param width - Target field width
11
+ * @param align - Alignment ('left' or 'right')
12
+ * @param padChar - Character to use for padding (default: space)
13
+ * @returns Formatted fixed-width string
14
+ */
15
+ export function formatField(value, width, align, padChar = ' ') {
16
+ if (align === 'left') {
17
+ return padRight(value, width, padChar);
18
+ }
19
+ return padLeft(value, width, padChar);
20
+ }
21
+ /**
22
+ * Encodes a value to fixed-width format with padding
23
+ *
24
+ * @param value - The value to encode
25
+ * @param width - Target width
26
+ * @param padChar - Padding character (default: space)
27
+ * @param align - Alignment ('left' or 'right')
28
+ * @returns Fixed-width encoded string
29
+ */
30
+ export function encodeFixedWidth(value, width, padChar = ' ', align = 'left') {
31
+ const str = String(value);
32
+ return formatField(str, width, align, padChar);
33
+ }
34
+ /**
35
+ * Helper function to format numeric fields with zero padding
36
+ */
37
+ export function formatNumericField(value, width) {
38
+ return padLeft(value, width, '0');
39
+ }
40
+ /**
41
+ * Joins an array of field values into a single record line with CRLF ending
42
+ * This is used by individual record encoders to create their output
43
+ *
44
+ * @param fields - Array of formatted field values
45
+ * @returns Single record line ending with CRLF
46
+ */
47
+ export function joinFields(fields) {
48
+ return fields.join('') + CRLF;
49
+ }
50
+ /**
51
+ * Joins an array of record lines that already have CRLF endings
52
+ *
53
+ * @param lines - Array of record lines to join (each line should already end with CRLF)
54
+ * @returns Joined string
55
+ */
56
+ export function joinRecords(lines) {
57
+ return lines.join('');
58
+ }
59
+ /**
60
+ * Joins an array of record lines and adds CRLF to each line
61
+ *
62
+ * @param lines - Array of record lines to join (without CRLF endings)
63
+ * @returns Joined string with CRLF line endings
64
+ */
65
+ export function joinLinesWithCRLF(lines) {
66
+ return lines.map(line => line + CRLF).join('');
67
+ }
68
+ /**
69
+ * Creates a complete SHAAM format file by joining records
70
+ * This is the main function for assembling final file content
71
+ *
72
+ * @param records - Array of encoded record strings (each already ending with CRLF)
73
+ * @returns Complete file content ready for output
74
+ */
75
+ export function assembleFile(records) {
76
+ return joinRecords(records);
77
+ }