@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,328 @@
1
+ "use strict";
2
+ /**
3
+ * Main API for generating SHAAM uniform format reports
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateUniformFormatReport = generateUniformFormatReport;
7
+ const encoder_js_1 = require("../generator/format/encoder.js");
8
+ const index_js_1 = require("../generator/records/index.js");
9
+ const errors_js_1 = require("../validation/errors.js");
10
+ const validate_input_js_1 = require("../validation/validate-input.js");
11
+ /**
12
+ * Generates SHAAM uniform format report files (INI.TXT and BKMVDATA.TXT)
13
+ * from a high-level JSON input object.
14
+ *
15
+ * @param input - The report input data
16
+ * @param options - Generation options
17
+ * @returns Report output with generated file content
18
+ */
19
+ function generateUniformFormatReport(input, options = {}) {
20
+ // Validate input data first
21
+ const validationMode = options.validationMode || 'fail-fast';
22
+ const validationErrors = (0, validate_input_js_1.validateInput)(input, validationMode);
23
+ if (validationErrors.length > 0) {
24
+ if (validationMode === 'fail-fast') {
25
+ // This should have already thrown, but just in case
26
+ throw new errors_js_1.ShaamFormatError('Validation failed', validationErrors);
27
+ }
28
+ // For collect-all mode, we still throw if there are errors
29
+ // The user can catch and inspect the errors if needed
30
+ throw new errors_js_1.ShaamFormatError('Input validation failed', validationErrors);
31
+ }
32
+ const records = [];
33
+ const iniRecords = [];
34
+ const recordCounts = {};
35
+ let recordNumber = 1;
36
+ // Helper function to count and add data record
37
+ const addRecord = (recordType, recordContent) => {
38
+ records.push(recordContent);
39
+ recordCounts[recordType] = (recordCounts[recordType] || 0) + 1;
40
+ recordNumber++;
41
+ };
42
+ // Helper function to add INI record
43
+ const addIniRecord = (recordType, recordContent) => {
44
+ iniRecords.push(recordContent);
45
+ recordCounts[recordType] = (recordCounts[recordType] || 0) + 1;
46
+ };
47
+ // Generate A000 record for INI.TXT
48
+ const fileHeaderRecord = {
49
+ reservedFuture: '',
50
+ totalRecords: '0', // Will be updated later with actual count
51
+ vatId: input.business.taxId,
52
+ softwareRegNumber: '12345678', // TODO: Use actual software registration number
53
+ softwareName: 'SHAAM Generator',
54
+ softwareVersion: '1.0.0',
55
+ vendorVatId: '123456789', // TODO: Use actual vendor VAT ID
56
+ vendorName: 'Accounter',
57
+ softwareType: '2', // Multi-year software
58
+ fileOutputPath: options.fileNameBase || 'report',
59
+ accountingType: '2', // Double-entry accounting
60
+ balanceRequired: '1',
61
+ companyRegId: '',
62
+ withholdingFileNum: '',
63
+ reserved1017: '',
64
+ businessName: input.business.name,
65
+ businessStreet: '',
66
+ businessHouseNum: '',
67
+ businessCity: '',
68
+ businessZip: '',
69
+ taxYear: '',
70
+ startDate: input.business.reportingPeriod.startDate.replace(/-/g, ''),
71
+ endDate: input.business.reportingPeriod.endDate.replace(/-/g, ''),
72
+ processStartDate: new Date().toISOString().slice(0, 10).replace(/-/g, ''),
73
+ processStartTime: new Date().toTimeString().slice(0, 5).replace(':', ''),
74
+ languageCode: '0', // Hebrew
75
+ characterEncoding: '1', // ISO-8859-8-i
76
+ compressionSoftware: '',
77
+ reserved1031: '',
78
+ baseCurrency: 'ILS',
79
+ reserved1033: '',
80
+ branchInfoFlag: '0', // No branches for now
81
+ reserved1035: '',
82
+ };
83
+ addIniRecord('A000', (0, index_js_1.encodeA000)(fileHeaderRecord));
84
+ // Add A000Sum records for each record type to INI.TXT
85
+ // Calculate expected counts based on input data
86
+ const expectedCounts = {
87
+ A100: 1,
88
+ C100: input.documents.length,
89
+ D110: input.documents.length,
90
+ D120: input.documents.length,
91
+ B100: input.journalEntries.length,
92
+ B110: input.accounts.length,
93
+ M100: input.inventory.length,
94
+ Z900: 1,
95
+ };
96
+ // Add summary records for each record type
97
+ for (const [recordType, count] of Object.entries(expectedCounts)) {
98
+ if (count > 0) {
99
+ const summaryRecord = {
100
+ code: recordType,
101
+ recordCount: count.toString(),
102
+ };
103
+ addIniRecord('A000Sum', (0, index_js_1.encodeA000Sum)(summaryRecord));
104
+ }
105
+ }
106
+ // 1. Business metadata - A100 record
107
+ const businessMetadata = {
108
+ recordNumber: recordNumber.toString(),
109
+ vatId: input.business.taxId,
110
+ reserved: '',
111
+ };
112
+ addRecord('A100', (0, index_js_1.encodeA100)(businessMetadata));
113
+ // TODO: 2. Summaries... (not implemented yet)
114
+ // 3. For each document in input.documents
115
+ for (const document of input.documents) {
116
+ // Document header - C100 record
117
+ const documentRecord = {
118
+ code: 'C100',
119
+ recordNumber: recordNumber.toString(),
120
+ vatId: input.business.taxId,
121
+ documentType: document.type,
122
+ documentId: document.id,
123
+ documentIssueDate: document.date.replace(/-/g, ''), // Convert YYYY-MM-DD to YYYYMMDD
124
+ documentIssueTime: '',
125
+ customerName: '',
126
+ customerStreet: '',
127
+ customerHouseNumber: '',
128
+ customerCity: '',
129
+ customerPostCode: '',
130
+ customerCountry: '',
131
+ customerCountryCode: '',
132
+ customerPhone: '',
133
+ customerVatId: '',
134
+ documentValueDate: '',
135
+ foreignCurrencyAmount: '',
136
+ currencyCode: '',
137
+ amountBeforeDiscount: '',
138
+ documentDiscount: '',
139
+ amountAfterDiscountExcludingVat: '',
140
+ vatAmount: '',
141
+ amountIncludingVat: document.amount.toFixed(2), // Format as decimal with 2 places
142
+ withholdingTaxAmount: '',
143
+ customerKey: '',
144
+ matchingField: '',
145
+ cancelledAttribute1: '',
146
+ cancelledDocument: '',
147
+ cancelledAttribute2: '',
148
+ documentDate: '',
149
+ branchKey: '',
150
+ cancelledAttribute3: '',
151
+ actionExecutor: '',
152
+ lineConnectingField: '',
153
+ reserved: '',
154
+ };
155
+ addRecord('C100', (0, index_js_1.encodeC100)(documentRecord));
156
+ // Document line - D110 record
157
+ const documentLineRecord = {
158
+ code: 'D110',
159
+ recordNumber: recordNumber.toString(),
160
+ vatId: input.business.taxId,
161
+ documentType: document.type,
162
+ documentNumber: document.id,
163
+ lineNumber: '1',
164
+ baseDocumentType: '',
165
+ baseDocumentNumber: '',
166
+ transactionType: '',
167
+ internalCatalogCode: '',
168
+ goodsServiceDescription: document.description || 'Item',
169
+ manufacturerName: '',
170
+ serialNumber: '',
171
+ unitOfMeasureDescription: '',
172
+ quantity: '1',
173
+ unitPriceExcludingVat: '',
174
+ lineDiscount: '',
175
+ lineTotal: '',
176
+ vatRatePercent: '',
177
+ reserved1: '',
178
+ branchId: '1',
179
+ reserved2: '',
180
+ documentDate: document.date.replace(/-/g, ''),
181
+ headerLinkField: '',
182
+ baseDocumentBranchId: '',
183
+ reserved3: '',
184
+ };
185
+ addRecord('D110', (0, index_js_1.encodeD110)(documentLineRecord));
186
+ // Payment record - D120 record (if applicable)
187
+ const paymentRecord = {
188
+ code: 'D120',
189
+ recordNumber: recordNumber.toString(),
190
+ vatId: input.business.taxId,
191
+ documentType: document.type,
192
+ documentNumber: document.id,
193
+ lineNumber: '1',
194
+ paymentMethod: '1', // Default payment method
195
+ bankNumber: '',
196
+ branchNumber: '',
197
+ accountNumber: '',
198
+ checkNumber: '',
199
+ paymentDueDate: '',
200
+ lineAmount: document.amount.toFixed(2), // Format as decimal with 2 places
201
+ acquirerCode: '',
202
+ cardBrand: '',
203
+ creditTransactionType: '',
204
+ firstPaymentAmount: '',
205
+ installmentsCount: '',
206
+ additionalPaymentAmount: '',
207
+ reserved1: '',
208
+ branchId: '1',
209
+ reserved2: '',
210
+ documentDate: document.date.replace(/-/g, ''),
211
+ headerLinkField: '',
212
+ reserved: '',
213
+ };
214
+ addRecord('D120', (0, index_js_1.encodeD120)(paymentRecord));
215
+ }
216
+ // 4. Journal lines: for each entry and its lines
217
+ for (const entry of input.journalEntries) {
218
+ const journalRecord = {
219
+ code: 'B100',
220
+ recordNumber: recordNumber.toString(),
221
+ vatId: input.business.taxId,
222
+ transactionNumber: entry.id.replace(/\D/g, '') || '1', // Extract only digits, default to '1'
223
+ transactionLineNumber: '1',
224
+ batchNumber: '',
225
+ transactionType: '',
226
+ referenceDocument: '',
227
+ referenceDocumentType: '',
228
+ referenceDocument2: '',
229
+ referenceDocumentType2: '',
230
+ details: entry.description || '',
231
+ date: entry.date.replace(/-/g, ''),
232
+ valueDate: entry.date.replace(/-/g, ''), // Same as date for simplicity
233
+ accountKey: entry.accountId,
234
+ counterAccountKey: '',
235
+ debitCreditIndicator: (entry.amount >= 0 ? '1' : '2'),
236
+ currencyCode: '',
237
+ transactionAmount: Math.abs(entry.amount).toFixed(2), // Format as decimal with 2 places
238
+ foreignCurrencyAmount: '',
239
+ quantityField: '',
240
+ matchingField1: '',
241
+ matchingField2: '',
242
+ branchId: '',
243
+ entryDate: entry.date.replace(/-/g, ''),
244
+ operatorUsername: '',
245
+ reserved: '',
246
+ };
247
+ addRecord('B100', (0, index_js_1.encodeB100)(journalRecord));
248
+ }
249
+ // 5. Accounts: B110 records
250
+ for (const account of input.accounts) {
251
+ const accountRecord = {
252
+ code: 'B110',
253
+ recordNumber: recordNumber.toString(),
254
+ vatId: input.business.taxId,
255
+ accountKey: account.id,
256
+ accountName: account.name,
257
+ trialBalanceCode: account.type,
258
+ trialBalanceCodeDescription: account.type,
259
+ customerSupplierAddressStreet: '',
260
+ customerSupplierAddressHouseNumber: '',
261
+ customerSupplierAddressCity: '',
262
+ customerSupplierAddressZip: '',
263
+ customerSupplierAddressCountry: '',
264
+ countryCode: '',
265
+ parentAccountKey: '',
266
+ accountOpeningBalance: '0',
267
+ totalDebits: '0',
268
+ totalCredits: '0',
269
+ accountingClassificationCode: '',
270
+ supplierCustomerTaxId: '',
271
+ branchId: '',
272
+ openingBalanceForeignCurrency: '',
273
+ foreignCurrencyCode: '',
274
+ reserved: '',
275
+ };
276
+ addRecord('B110', (0, index_js_1.encodeB110)(accountRecord));
277
+ }
278
+ // 6. Inventory: M100 records
279
+ for (const item of input.inventory) {
280
+ const inventoryRecord = {
281
+ code: 'M100',
282
+ recordNumber: recordNumber.toString(),
283
+ vatId: input.business.taxId,
284
+ universalItemCode: '',
285
+ supplierItemCode: '',
286
+ internalItemCode: item.id,
287
+ itemName: item.name,
288
+ classificationCode: '',
289
+ classificationDescription: '',
290
+ unitOfMeasure: '',
291
+ openingStock: '0',
292
+ totalStockIn: '0',
293
+ totalStockOut: item.quantity.toString(),
294
+ endPeriodCostNonBonded: '',
295
+ endPeriodCostBonded: '',
296
+ reserved: '',
297
+ };
298
+ addRecord('M100', (0, index_js_1.encodeM100)(inventoryRecord));
299
+ }
300
+ // 7. Closing record: Z900
301
+ const closingRecord = {
302
+ recordNumber: recordNumber.toString(),
303
+ vatId: input.business.taxId,
304
+ totalRecords: records.length.toString(), // Count of records before Z900 is added
305
+ reserved: '',
306
+ };
307
+ addRecord('Z900', (0, index_js_1.encodeZ900)(closingRecord));
308
+ // Build iniText and dataText using the assembler
309
+ const iniText = (0, encoder_js_1.assembleFile)(iniRecords);
310
+ const dataText = (0, encoder_js_1.assembleFile)(records);
311
+ // Create virtual File objects
312
+ const iniFile = new File([iniText], `${options.fileNameBase || 'report'}.INI.TXT`, {
313
+ type: 'text/plain',
314
+ });
315
+ const dataFile = new File([dataText], `${options.fileNameBase || 'report'}.BKMVDATA.TXT`, {
316
+ type: 'text/plain',
317
+ });
318
+ return {
319
+ iniText,
320
+ dataText,
321
+ iniFile,
322
+ dataFile,
323
+ summary: {
324
+ totalRecords: records.length + iniRecords.length,
325
+ perType: recordCounts,
326
+ },
327
+ };
328
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ /**
3
+ * SHAAM format constants
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SHAAM_VERSION = void 0;
7
+ /**
8
+ * SHAAM specification version identifier
9
+ * Used in fields 1104 (A100) and 1154 (Z900)
10
+ */
11
+ exports.SHAAM_VERSION = '&OF1.31&';
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ /**
3
+ * Fixed-width formatting utilities
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.formatField = formatField;
7
+ exports.encodeFixedWidth = encodeFixedWidth;
8
+ exports.formatNumericField = formatNumericField;
9
+ exports.joinFields = joinFields;
10
+ exports.joinRecords = joinRecords;
11
+ exports.joinLinesWithCRLF = joinLinesWithCRLF;
12
+ exports.assembleFile = assembleFile;
13
+ const newline_js_1 = require("../../format/newline.js");
14
+ const padding_js_1 = require("../../format/padding.js");
15
+ /**
16
+ * Formats a field value with specified width and alignment
17
+ *
18
+ * @param value - The value to format
19
+ * @param width - Target field width
20
+ * @param align - Alignment ('left' or 'right')
21
+ * @param padChar - Character to use for padding (default: space)
22
+ * @returns Formatted fixed-width string
23
+ */
24
+ function formatField(value, width, align, padChar = ' ') {
25
+ if (align === 'left') {
26
+ return (0, padding_js_1.padRight)(value, width, padChar);
27
+ }
28
+ return (0, padding_js_1.padLeft)(value, width, padChar);
29
+ }
30
+ /**
31
+ * Encodes a value to fixed-width format with padding
32
+ *
33
+ * @param value - The value to encode
34
+ * @param width - Target width
35
+ * @param padChar - Padding character (default: space)
36
+ * @param align - Alignment ('left' or 'right')
37
+ * @returns Fixed-width encoded string
38
+ */
39
+ function encodeFixedWidth(value, width, padChar = ' ', align = 'left') {
40
+ const str = String(value);
41
+ return formatField(str, width, align, padChar);
42
+ }
43
+ /**
44
+ * Helper function to format numeric fields with zero padding
45
+ */
46
+ function formatNumericField(value, width) {
47
+ return (0, padding_js_1.padLeft)(value, width, '0');
48
+ }
49
+ /**
50
+ * Joins an array of field values into a single record line with CRLF ending
51
+ * This is used by individual record encoders to create their output
52
+ *
53
+ * @param fields - Array of formatted field values
54
+ * @returns Single record line ending with CRLF
55
+ */
56
+ function joinFields(fields) {
57
+ return fields.join('') + newline_js_1.CRLF;
58
+ }
59
+ /**
60
+ * Joins an array of record lines that already have CRLF endings
61
+ *
62
+ * @param lines - Array of record lines to join (each line should already end with CRLF)
63
+ * @returns Joined string
64
+ */
65
+ function joinRecords(lines) {
66
+ return lines.join('');
67
+ }
68
+ /**
69
+ * Joins an array of record lines and adds CRLF to each line
70
+ *
71
+ * @param lines - Array of record lines to join (without CRLF endings)
72
+ * @returns Joined string with CRLF line endings
73
+ */
74
+ function joinLinesWithCRLF(lines) {
75
+ return lines.map(line => line + newline_js_1.CRLF).join('');
76
+ }
77
+ /**
78
+ * Creates a complete SHAAM format file by joining records
79
+ * This is the main function for assembling final file content
80
+ *
81
+ * @param records - Array of encoded record strings (each already ending with CRLF)
82
+ * @returns Complete file content ready for output
83
+ */
84
+ function assembleFile(records) {
85
+ return joinRecords(records);
86
+ }
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.A000SumInputSchema = exports.A000SumSchema = void 0;
4
+ exports.encodeA000Sum = encodeA000Sum;
5
+ exports.parseA000Sum = parseA000Sum;
6
+ const zod_1 = require("zod");
7
+ const encoder_js_1 = require("../format/encoder.js");
8
+ /**
9
+ * A000Sum Record Schema - Record count summary for INI.TXT
10
+ * Fields 1050-1051 based on SHAAM uniform format specification
11
+ */
12
+ exports.A000SumSchema = zod_1.z.object({
13
+ // Field 1050: Record Code (4) - Required - Alphanumeric
14
+ code: zod_1.z.string().min(1).max(4).describe('Record type code being summarized'),
15
+ // Field 1051: Record Count (15) - Required - Numeric
16
+ recordCount: zod_1.z
17
+ .string()
18
+ .min(1)
19
+ .max(15)
20
+ .regex(/^\d+$/)
21
+ .describe('Total number of records of this type'),
22
+ });
23
+ /**
24
+ * A000Sum Input Schema - for user input (no auto-generated fields)
25
+ */
26
+ exports.A000SumInputSchema = exports.A000SumSchema;
27
+ /**
28
+ * Encodes an A000Sum record to fixed-width string format
29
+ * Total line width: 19 characters + CRLF
30
+ */
31
+ function encodeA000Sum(input) {
32
+ const fullRecord = {
33
+ ...input,
34
+ };
35
+ const fields = [
36
+ (0, encoder_js_1.formatField)(fullRecord.code, 4, 'left'), // Field 1050: Record code (4)
37
+ (0, encoder_js_1.formatNumericField)(fullRecord.recordCount, 15), // Field 1051: Record count (15)
38
+ ];
39
+ return (0, encoder_js_1.joinFields)(fields);
40
+ }
41
+ /**
42
+ * Parses a fixed-width A000Sum record line back to object
43
+ * Expected line length: 19 characters (excluding CRLF)
44
+ */
45
+ function parseA000Sum(line) {
46
+ // Remove CRLF if present
47
+ const cleanLine = line.replace(/\r?\n$/, '');
48
+ if (cleanLine.length !== 19) {
49
+ throw new Error(`Invalid A000Sum record length: expected 19 characters, got ${cleanLine.length}`);
50
+ }
51
+ let offset = 0;
52
+ // Extract fields at their fixed positions
53
+ const code = cleanLine.slice(offset, offset + 4).trim();
54
+ offset += 4; // Field 1050 (4)
55
+ const recordCount = cleanLine
56
+ .slice(offset, offset + 15)
57
+ .trim()
58
+ .replace(/^0+/, '') || '0';
59
+ offset += 15; // Field 1051 (15)
60
+ const parsed = {
61
+ code,
62
+ recordCount,
63
+ };
64
+ // Validate against schema
65
+ return exports.A000SumSchema.parse(parsed);
66
+ }