Merge pull request 'Make UI improvements' (#1) from mtsz/mt940-mbank-ts:ui-improvements into master
Reviewed-on: #1
This commit is contained in:
		
						commit
						5f86deeb0a
					
				| @ -1,12 +1,7 @@ | ||||
| { | ||||
| 	"phabricator.uri": "https://hub.sealcode.org/", | ||||
| 	"arc.land.onto.default": "hotwire", | ||||
|   "load": [ | ||||
|     "arcanist-linters", | ||||
|     "arc-unit-mocha/src" | ||||
|   ], | ||||
| 	"load": ["arcanist-linters", "arc-unit-mocha/src"], | ||||
| 	"unit.engine": "MochaEngine", | ||||
|   "unit.mocha.include": [ | ||||
|     ".test/**/*.ts" | ||||
|   ] | ||||
| 	"unit.mocha.include": [".test/**/*.ts"] | ||||
| } | ||||
							
								
								
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -6,5 +6,8 @@ lib | ||||
| coverage | ||||
| @types | ||||
| 
 | ||||
| public/*.js | ||||
| /public/bundle.js.map | ||||
| public/bundle.* | ||||
| public/*.woff | ||||
| public/*.woff2 | ||||
| 
 | ||||
| .DS_Store | ||||
|  | ||||
							
								
								
									
										17
									
								
								.prettierrc
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								.prettierrc
									
									
									
									
									
								
							| @ -1,14 +1,7 @@ | ||||
| { | ||||
|   useTabs: true, | ||||
|   tabWidth: 4, | ||||
|   trailingComma: "es5", | ||||
|   "overrides": [ | ||||
|     { | ||||
|       "files": "*.yml", | ||||
|       "options": { | ||||
|         "tabWidth": 2, | ||||
|         "useTabs": false | ||||
|       } | ||||
|     } | ||||
|   ] | ||||
| 	"useTabs": true, | ||||
| 	"tabWidth": 4, | ||||
| 	"trailingComma": "es5", | ||||
| 	"printWidth": 120, | ||||
| 	"htmlWhitespaceSensitivity": "ignore" | ||||
| } | ||||
| @ -1,4 +1,4 @@ | ||||
| # Mbank mt940 converter | ||||
| # mBank MT940 converter | ||||
| 
 | ||||
| ## Uruchamianie | ||||
| 
 | ||||
| @ -9,7 +9,7 @@ npm start | ||||
| 
 | ||||
| ## Testowanie | ||||
| 
 | ||||
| Wygeneruj raz plik mt940 oraz csv za ten sam okres, i wykonaj: | ||||
| Wygeneruj raz plik MT940 oraz csv za ten sam okres, i wykonaj: | ||||
| 
 | ||||
| ``` | ||||
| node . convert < tests/real_csv.csv > tests/new.txt && diff --side-by-side --color tests/real_mt940.txt tests/new.txt | ||||
|  | ||||
							
								
								
									
										943
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										943
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										11
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								package.json
									
									
									
									
									
								
							| @ -7,13 +7,18 @@ | ||||
| 		"test": "mocha", | ||||
| 		"build": "npm run build-node && npm run build-browser", | ||||
| 		"build-node": "tsc", | ||||
| 		"build-browser": "esbuild src/browser.ts --bundle --minify --sourcemap --target=firefox120 --outfile=public/bundle.js", | ||||
| 		"build-browser": "esbuild src/browser.ts --bundle --minify --sourcemap --target=firefox120 --outfile=public/bundle.js --loader:.woff=file --loader:.woff2=file", | ||||
| 		"watch-node": "tsc --watch", | ||||
| 		"watch-browser": "esbuild src/browser.ts --bundle --outfile=public/bundle.js --watch --loader:.woff=file --loader:.woff2=file", | ||||
| 		"postinstall": "npm run build", | ||||
| 		"clean-coverage": "rm -rf coverage .nyc_output .xunit", | ||||
| 		"coverage": "npm run clean-coverage && nyc mocha", | ||||
| 		"test-reports": "npm run clean-coverage && nyc --reporter clover mocha --reporter xunit --reporter-option output=.xunit", | ||||
| 		"coverage-html": "npm run test-reports && nyc report --reporter lcov && xdg-open coverage/lcov-report/index.html", | ||||
| 		"start": "http-server public -p 8080" | ||||
| 		"start": "http-server public -p 8080", | ||||
| 		"dev": "concurrently --names \"NODE,BROWSER,SERVER\" --prefix-colors \"blue,magenta,green\" \"npm run watch-node\" \"npm run watch-browser\" \"npm run start\"", | ||||
| 		"format": "prettier --write .", | ||||
| 		"format:check": "prettier --check ." | ||||
| 	}, | ||||
| 	"author": "", | ||||
| 	"license": "ISC", | ||||
| @ -22,6 +27,7 @@ | ||||
| 		"@types/diff": "^5.2.1", | ||||
| 		"@typescript-eslint/eslint-plugin": "^5.58.0", | ||||
| 		"@typescript-eslint/parser": "^5.58.0", | ||||
| 		"concurrently": "^9.2.0", | ||||
| 		"diff": "^5.2.0", | ||||
| 		"eslint": "^8.38.0", | ||||
| 		"eslint-config-prettier": "^8.8.0", | ||||
| @ -36,6 +42,7 @@ | ||||
| 	}, | ||||
| 	"types": "./@types/index.d.ts", | ||||
| 	"dependencies": { | ||||
| 		"@fontsource/atkinson-hyperlegible": "^5.2.6", | ||||
| 		"@types/mocha": "^10.0.1", | ||||
| 		"@types/node": "^20.10.4", | ||||
| 		"@types/yargs": "^17.0.32", | ||||
|  | ||||
| @ -1,68 +1,77 @@ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
| <html lang="pl"> | ||||
| 	<head> | ||||
| 		<title>mBank mt940 konwerter</title> | ||||
| 		<title>mBank MT940 konwerter</title> | ||||
| 		<meta charset="utf-8" /> | ||||
| 		<meta name="viewport" content="width=device-width, initial-scale=1" /> | ||||
| 		<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.classless.min.css" /> | ||||
| 		<link rel="stylesheet" href="styles.css" /> | ||||
| 	</head> | ||||
| 	<style> | ||||
| 		p { | ||||
| 			max-width: 600px; | ||||
| 		} | ||||
| 
 | ||||
| 		input, | ||||
| 		button { | ||||
| 			height: 40px; | ||||
| 			font-size: 20px; | ||||
| 		} | ||||
| 
 | ||||
| 		.hidden { | ||||
| 			display: none; | ||||
| 		} | ||||
| 
 | ||||
| 		.success { | ||||
| 			background-color: hsl(120, 100%, 85.1%); | ||||
| 			padding: 2rem; | ||||
| 			margin: 1rem; | ||||
| 			font-size: 1.2rem; | ||||
| 			color: hsl(120, 100%, 7.1%); | ||||
| 		} | ||||
| 	</style> | ||||
| 	<body> | ||||
| 		<h1>mBank mt940 konwerter</h1> | ||||
| 
 | ||||
| 		<header> | ||||
| 			<section> | ||||
| 				<h1>mBank MT940 konwerter</h1> | ||||
| 			</section> | ||||
| 		</header> | ||||
| 		<main> | ||||
| 			<section> | ||||
| 				<p> | ||||
| 			Za pomocą tego narzędzia za darmo przekonwertujesz plik CSV | ||||
| 			wygenerowany przez mbank do formatu mt940. Konwersja odbywa sie w | ||||
| 			przeglądarce, Twoje dane nie są nigdzie wysyłane. Dla pewności | ||||
| 			możesz na czas konwersji wyłączyć dostęp do Internetu na Twoim | ||||
| 			komputerze, zamknąć tę stronę, i włączyć dostęp do Internetu | ||||
| 			ponownie. | ||||
| 					Za pomocą tego narzędzia za darmo przekonwertujesz plik CSV wygenerowany przez mBank do formatu | ||||
| 					MT940. Konwersja odbywa się w przeglądarce, Twoje dane nie są nigdzie wysyłane. Dla pewności | ||||
| 					możesz na czas konwersji wyłączyć dostęp do Internetu na Twoim komputerze, zamknąć | ||||
| 					tę stronę, i włączyć dostęp do Internetu ponownie. | ||||
| 				</p> | ||||
| 		<div><input type="file" name="csv" id="csv" /></div> | ||||
| 		<button id="submit">Konwertuj</button> | ||||
| 		<div class="success hidden"> | ||||
| 
 | ||||
| 				<form> | ||||
| 					<fieldset> | ||||
| 						<label for="csv">Wybierz plik CSV z mBanku:</label> | ||||
| 						<input type="file" name="csv" id="csv" accept=".csv" /> | ||||
| 					</fieldset> | ||||
| 					<button type="button" id="submit">Konwertuj</button> | ||||
| 				</form> | ||||
| 
 | ||||
| 				<div class="success hidden" role="alert"> | ||||
| 					<p> | ||||
| 				Rozpoczęto pobieranie wygenerowanego raportu mt940. Cieszymy | ||||
| 				się, że mogliśmy Ci oszczędzić trochę wydatków. Jeżeli chcesz | ||||
| 				się nam odwdzięczyć, zachęcamy do | ||||
| 				<a | ||||
| 					href="https://www.internet-czas-dzialac.pl/contact/#wesprzyj-nas" | ||||
| 					>wspierania naszej fundacji</a | ||||
| 				> | ||||
| 						<strong>Sukces!</strong> | ||||
| 						Rozpoczęto pobieranie wygenerowanego raportu MT940. Cieszymy się, że mogliśmy Ci oszczędzić | ||||
| 						trochę wydatków. Jeżeli chcesz się nam odwdzięczyć, zachęcamy do | ||||
| 						<a target="_blank" href="https://www.internet-czas-dzialac.pl/contact/#wesprzyj-nas"> | ||||
| 							wspierania naszej fundacji | ||||
| 						</a> | ||||
| 					</p> | ||||
| 				</div> | ||||
| 			</section> | ||||
| 		</main> | ||||
| 
 | ||||
| 		<footer> | ||||
| 			<section> | ||||
| 				<a target="_blank" href="https://www.internet-czas-dzialac.pl/"> | ||||
| 					<figure id="icd-logo-container"> | ||||
| 						<div id="icd-logo"></div> | ||||
| 					</figure> | ||||
| 				</a> | ||||
| 
 | ||||
| 				<p> | ||||
| 					Aplikacja została wykonana przez | ||||
| 			<a href="https://www.internet-czas-dzialac.pl/"> | ||||
| 					<a target="_blank" href="https://www.internet-czas-dzialac.pl/"> | ||||
| 						Fundację „Internet. Czas działać!” | ||||
| 					</a> | ||||
| 					<br /> | ||||
| 					i jest utrzymywana przez | ||||
| 			<a href="https://www.sealcode.it/">Sealcode</a> | ||||
| 					<a target="_blank" href="https://www.sealcode.it/">Sealcode</a> | ||||
| 					• | ||||
| 					<a target="_blank" href="https://git.internet-czas-dzialac.pl/icd/mt940-mbank-ts">Kod źródłowy</a> | ||||
| 				</p> | ||||
| 
 | ||||
| 				<p> | ||||
| 			<a href="https://git.internet-czas-dzialac.pl/icd/mt940-mbank-ts"> | ||||
| 				Kod źródłowy | ||||
| 			</a> | ||||
| 			<script src="bundle.js"></script> | ||||
| 					<small> | ||||
| 						Wykorzystuje czcionkę | ||||
| 						<a target="_blank" href="https://brailleinstitute.org/freefont">Atkinson Hyperlegible</a> | ||||
| 						na licencji SIL Open Font License | ||||
| 					</small> | ||||
| 				</p> | ||||
| 			</section> | ||||
| 		</footer> | ||||
| 		<script src="bundle.js"></script> | ||||
| 	</body> | ||||
| </html> | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								public/logo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/logo.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 30 KiB | 
							
								
								
									
										96
									
								
								public/styles.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								public/styles.css
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,96 @@ | ||||
| :root { | ||||
| 	--pico-font-family: "Atkinson Hyperlegible", sans-serif; | ||||
| 	--icd-rentgen-color: #99ffdd; | ||||
| 	--success-background-color: hsl(120, 100%, 85.1%); | ||||
| 	--success-color: hsl(120, 100%, 7.1%); | ||||
| } | ||||
| 
 | ||||
| section { | ||||
| 	max-width: 800px; | ||||
| 	margin: 0 auto; | ||||
| } | ||||
| 
 | ||||
| button { | ||||
| 	width: 100%; | ||||
| 	font-weight: bold !important; | ||||
| 	border: none; | ||||
| 	box-shadow: none; | ||||
| } | ||||
| 
 | ||||
| #submit { | ||||
| 	background-color: black; | ||||
| 	color: var(--icd-rentgen-color); | ||||
| } | ||||
| 
 | ||||
| #submit:hover { | ||||
| 	background-color: var(--icd-rentgen-color); | ||||
| 	color: black; | ||||
| } | ||||
| 
 | ||||
| #submit, | ||||
| #submit:hover { | ||||
| 	border: 0; | ||||
| } | ||||
| 
 | ||||
| .hidden { | ||||
| 	display: none; | ||||
| } | ||||
| 
 | ||||
| .success { | ||||
| 	background-color: var(--success-background-color); | ||||
| 	color: var(--success-color); | ||||
| 	padding: 2rem; | ||||
| 	margin: 1rem; | ||||
| 	font-size: 1.2rem; | ||||
| } | ||||
| 
 | ||||
| header, | ||||
| footer { | ||||
| 	max-width: unset !important; | ||||
| 	background-color: black; | ||||
| 	text-align: center; | ||||
| } | ||||
| 
 | ||||
| header section h1, | ||||
| footer section p { | ||||
| 	color: white; | ||||
| } | ||||
| 
 | ||||
| header section h1 { | ||||
| 	margin: 1rem 0; | ||||
| } | ||||
| 
 | ||||
| footer section p a { | ||||
| 	color: var(--icd-rentgen-color); | ||||
| } | ||||
| 
 | ||||
| body { | ||||
| 	min-height: 100vh; | ||||
| 	display: flex; | ||||
| 	flex-direction: column; | ||||
| } | ||||
| 
 | ||||
| main { | ||||
| 	flex: 1; | ||||
| } | ||||
| 
 | ||||
| #icd-logo { | ||||
| 	height: 48px; | ||||
| 	aspect-ratio: 1200/319; | ||||
| 	background-color: white; | ||||
| 	mask-image: url("logo.png"); | ||||
| 	mask-repeat: no-repeat; | ||||
| 	mask-size: contain; | ||||
| 	mask-position: center; | ||||
| 	-webkit-mask-image: url("logo.png"); | ||||
| 	-webkit-mask-repeat: no-repeat; | ||||
| 	-webkit-mask-size: contain; | ||||
| 	-webkit-mask-position: center; | ||||
| } | ||||
| 
 | ||||
| figure#icd-logo-container { | ||||
| 	background-color: black; | ||||
| 	padding: 1rem; | ||||
| 	width: fit-content; | ||||
| 	margin: 0 auto 1em auto; | ||||
| } | ||||
| @ -1,4 +1,5 @@ | ||||
| import { convert } from "."; | ||||
| import "@fontsource/atkinson-hyperlegible"; | ||||
| 
 | ||||
| function download(data: string, filename: string, type: string) { | ||||
| 	var file = new Blob([data], { type: type }); | ||||
| @ -30,9 +31,7 @@ async function handle() { | ||||
| 		const result = convert(string); | ||||
| 		download( | ||||
| 			result.output, | ||||
| 			`raport-${result.range.date_start.getFullYear()}-${( | ||||
| 				result.range.date_start.getMonth() + 1 | ||||
| 			) | ||||
| 			`raport-${result.range.date_start.getFullYear()}-${(result.range.date_start.getMonth() + 1) | ||||
| 				.toString() | ||||
| 				.padStart(2, "0")}.mt940`,
 | ||||
| 			"text" | ||||
|  | ||||
| @ -7,47 +7,31 @@ import * as Diff from "diff"; | ||||
| 
 | ||||
| describe("mt940 converter", () => { | ||||
| 	it("converts properly", async () => { | ||||
| 		const content = await fs.readFile( | ||||
| 			path.resolve(__dirname, "../tests/real_csv.csv"), | ||||
| 			{ | ||||
| 		const content = await fs.readFile(path.resolve(__dirname, "../tests/real_csv.csv"), { | ||||
| 			encoding: null, | ||||
| 			} | ||||
| 		); | ||||
| 		}); | ||||
| 		const result = convert(iconv.decode(content, "cp1250")); | ||||
| 		const expected_result = await fs.readFile( | ||||
| 			path.resolve(__dirname, "../tests/real_mt940.txt"), | ||||
| 			"utf-8" | ||||
| 		); | ||||
| 		const expected_result = await fs.readFile(path.resolve(__dirname, "../tests/real_mt940.txt"), "utf-8"); | ||||
| 		try { | ||||
| 			assert.strictEqual(result.output, expected_result); | ||||
| 		} catch (e) { | ||||
| 			console.error("There was a difference. Fixes to apply:"); | ||||
| 			console.log( | ||||
| 				Diff.createPatch("mt940", result.output, expected_result) | ||||
| 			); | ||||
| 			console.log(Diff.createPatch("mt940", result.output, expected_result)); | ||||
| 			throw new Error("Texts differ"); | ||||
| 		} | ||||
| 	}); | ||||
| 
 | ||||
| 	it.only("converts properly", async () => { | ||||
| 		const content = await fs.readFile( | ||||
| 			path.resolve(__dirname, "../tests/real_csv_2.csv"), | ||||
| 			{ | ||||
| 		const content = await fs.readFile(path.resolve(__dirname, "../tests/real_csv_2.csv"), { | ||||
| 			encoding: null, | ||||
| 			} | ||||
| 		); | ||||
| 		}); | ||||
| 		const result = convert(iconv.decode(content, "cp1250")); | ||||
| 		const expected_result = await fs.readFile( | ||||
| 			path.resolve(__dirname, "../tests/real_mt940_2.txt"), | ||||
| 			"utf-8" | ||||
| 		); | ||||
| 		const expected_result = await fs.readFile(path.resolve(__dirname, "../tests/real_mt940_2.txt"), "utf-8"); | ||||
| 		try { | ||||
| 			assert.strictEqual(result.output, expected_result); | ||||
| 		} catch (e) { | ||||
| 			console.error("There was a difference. Fixes to apply:"); | ||||
| 			console.log( | ||||
| 				Diff.createPatch("mt940", result.output, expected_result) | ||||
| 			); | ||||
| 			console.log(Diff.createPatch("mt940", result.output, expected_result)); | ||||
| 			throw new Error("Texts differ"); | ||||
| 		} | ||||
| 	}); | ||||
|  | ||||
							
								
								
									
										96
									
								
								src/index.ts
									
									
									
									
									
								
							
							
						
						
									
										96
									
								
								src/index.ts
									
									
									
									
									
								
							| @ -1,9 +1,4 @@ | ||||
| import { | ||||
| 	addLineNumbers, | ||||
| 	chunks, | ||||
| 	fillWithEmpty, | ||||
| 	removeRepeatingSpace, | ||||
| } from "./utils"; | ||||
| import { addLineNumbers, chunks, fillWithEmpty, removeRepeatingSpace } from "./utils"; | ||||
| 
 | ||||
| class Account { | ||||
| 	constructor( | ||||
| @ -35,18 +30,12 @@ class Transaction { | ||||
| 	})(); | ||||
| 
 | ||||
| 	formatTitle() { | ||||
| 		return addLineNumbers( | ||||
| 			fillWithEmpty(chunks(this.title.trim(), 27), 9), | ||||
| 			20 | ||||
| 		).join("\n"); | ||||
| 		return addLineNumbers(fillWithEmpty(chunks(this.title.trim(), 27), 9), 20).join("\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	formatPerson() { | ||||
| 		const ret = addLineNumbers( | ||||
| 			fillWithEmpty( | ||||
| 				chunks(removeRepeatingSpace(this.person).trim(), 27), | ||||
| 				2 | ||||
| 			).slice(0, 2), | ||||
| 			fillWithEmpty(chunks(removeRepeatingSpace(this.person).trim(), 27), 2).slice(0, 2), | ||||
| 			32 | ||||
| 		).join("\n"); | ||||
| 		return ret; | ||||
| @ -55,26 +44,11 @@ class Transaction { | ||||
| 	toMT940() { | ||||
| 		// just a bunch of heuristics
 | ||||
| 		const prefix_fns = [ | ||||
| 			() => | ||||
| 				this.description.includes("OPŁATA-PRZELEW WEWN.") | ||||
| 					? "169" | ||||
| 					: false, | ||||
| 			() => | ||||
| 				this.description.includes("PRZELEW WEWNĘTRZNY PRZY") | ||||
| 					? "160" | ||||
| 					: false, | ||||
| 			() => | ||||
| 				this.description.includes("OPŁATA-PRZELEW WEWN. DO") | ||||
| 					? "755" | ||||
| 					: false, | ||||
| 			() => | ||||
| 				this.description.includes("PRZELEW ZEWNĘTRZNY WYCH") | ||||
| 					? "152" | ||||
| 					: false, | ||||
| 			() => | ||||
| 				this.description.includes("OPŁATA PRZELEW ZEW.DOWO") | ||||
| 					? "771" | ||||
| 					: false, | ||||
| 			() => (this.description.includes("OPŁATA-PRZELEW WEWN.") ? "169" : false), | ||||
| 			() => (this.description.includes("PRZELEW WEWNĘTRZNY PRZY") ? "160" : false), | ||||
| 			() => (this.description.includes("OPŁATA-PRZELEW WEWN. DO") ? "755" : false), | ||||
| 			() => (this.description.includes("PRZELEW ZEWNĘTRZNY WYCH") ? "152" : false), | ||||
| 			() => (this.description.includes("OPŁATA PRZELEW ZEW.DOWO") ? "771" : false), | ||||
| 			() => (this.amount > 0 ? "150" : false), | ||||
| 			() => "169", | ||||
| 		]; | ||||
| @ -86,11 +60,9 @@ class Transaction { | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		const result = `:61:${mtDate(this.acc_date)}${mtDate( | ||||
| 			this.op_date | ||||
| 		).slice(2)}${this.amount > 0 ? "C" : "D"}${mtAmount( | ||||
| 			this.amount | ||||
| 		)}S${prefix}${Transaction.counter.next().value} | ||||
| 		const result = `:61:${mtDate(this.acc_date)}${mtDate(this.op_date).slice(2)}${ | ||||
| 			this.amount > 0 ? "C" : "D" | ||||
| 		}${mtAmount(this.amount)}S${prefix}${Transaction.counter.next().value} | ||||
| :86:${prefix} | ||||
| :86:${prefix}~00B${prefix}${this.description.slice(0, 23)} | ||||
| ${this.formatTitle()} | ||||
| @ -107,10 +79,7 @@ ${this.formatPerson()} | ||||
| } | ||||
| 
 | ||||
| class Range { | ||||
| 	constructor( | ||||
| 		public date_start: Date, | ||||
| 		public date_end: Date | ||||
| 	) {} | ||||
| 	constructor(public date_start: Date, public date_end: Date) {} | ||||
| } | ||||
| 
 | ||||
| abstract class CSVParser { | ||||
| @ -138,10 +107,7 @@ class mBankParser extends CSVParser { | ||||
| 			this.parseAmount(lines[last - 2][7]), | ||||
| 			lines[18][0] | ||||
| 		); | ||||
| 		const range = new Range( | ||||
| 			this.parseDate(lines[14][0]), | ||||
| 			this.parseDate(lines[14][1]) | ||||
| 		); | ||||
| 		const range = new Range(this.parseDate(lines[14][0]), this.parseDate(lines[14][1])); | ||||
| 		const transactions = []; | ||||
| 		for (let i = 38; i <= last - 5; i++) { | ||||
| 			const line = lines[i]; | ||||
| @ -151,29 +117,14 @@ class mBankParser extends CSVParser { | ||||
| 			} | ||||
| 			if (line.length != 9) { | ||||
| 				console.log({ line }); | ||||
| 				throw new Error( | ||||
| 					"Wrong amount of columns! maybe a semicolon got stuck in a transaction description?" | ||||
| 				); | ||||
| 				throw new Error("Wrong amount of columns! maybe a semicolon got stuck in a transaction description?"); | ||||
| 			} | ||||
| 			const date_acc = new Date(line[0]); | ||||
| 			const date_op = new Date(line[1]); | ||||
| 			const [description, title, person, account_number] = line | ||||
| 				.slice(2) | ||||
| 				.map(this.trimString); | ||||
| 			const [amount, balance_after] = line | ||||
| 				.slice(6) | ||||
| 				.map((s) => this.parseAmount(s)); | ||||
| 			const [description, title, person, account_number] = line.slice(2).map(this.trimString); | ||||
| 			const [amount, balance_after] = line.slice(6).map((s) => this.parseAmount(s)); | ||||
| 			transactions.push( | ||||
| 				new Transaction( | ||||
| 					date_acc, | ||||
| 					date_op, | ||||
| 					description, | ||||
| 					title, | ||||
| 					person, | ||||
| 					account_number, | ||||
| 					amount, | ||||
| 					balance_after | ||||
| 				) | ||||
| 				new Transaction(date_acc, date_op, description, title, person, account_number, amount, balance_after) | ||||
| 			); | ||||
| 		} | ||||
| 		return { account, range, transactions }; | ||||
| @ -203,9 +154,10 @@ class mBankParser extends CSVParser { | ||||
| } | ||||
| 
 | ||||
| function mtDate(d: Date) { | ||||
| 	return `${d.getFullYear() - 2000}${(d.getMonth() + 1) | ||||
| 	return `${d.getFullYear() - 2000}${(d.getMonth() + 1).toString().padStart(2, "0")}${d | ||||
| 		.getDate() | ||||
| 		.toString() | ||||
| 		.padStart(2, "0")}${d.getDate().toString().padStart(2, "0")}`;
 | ||||
| 		.padStart(2, "0")}`;
 | ||||
| } | ||||
| 
 | ||||
| function mtAmount(n: number) { | ||||
| @ -218,12 +170,8 @@ export function convert(csv_utf8: string): { output: string; range: Range } { | ||||
| 	const string = `:20:MT940
 | ||||
| :25:/PL${account.number.replaceAll(/[^0-9]/g, "")} | ||||
| :28C:${mtDate(range.date_start)} | ||||
| :60F:D${mtDate(range.date_start)}${account.currency}${mtAmount( | ||||
| 		account.initial_balance | ||||
| 	)} | ||||
| :60F:D${mtDate(range.date_start)}${account.currency}${mtAmount(account.initial_balance)} | ||||
| ${transactions.map((t) => t.toMT940()).join("\n")} | ||||
| :62F:D${mtDate(range.date_end)}${account.currency}${mtAmount( | ||||
| 		account.closing_balance | ||||
| 	)}`;
 | ||||
| :62F:D${mtDate(range.date_end)}${account.currency}${mtAmount(account.closing_balance)}`;
 | ||||
| 	return { output: string, range }; | ||||
| } | ||||
|  | ||||
| @ -15,11 +15,7 @@ export function fillWithEmpty(array: string[], target_length: number) { | ||||
| 	return a; | ||||
| } | ||||
| 
 | ||||
| export function addLineNumbers( | ||||
| 	s: string[], | ||||
| 	start_num: number, | ||||
| 	prefix = "~" | ||||
| ): string[] { | ||||
| export function addLineNumbers(s: string[], start_num: number, prefix = "~"): string[] { | ||||
| 	return s.map((l, i) => `${prefix}${start_num + i}${l}`); | ||||
| } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user