sie-parser
Version:
SIE file parser for JavaScript (WIP)
429 lines (408 loc) • 11.7 kB
text/typescript
import { readFileSync } from 'fs';
import {
TypeSIE,
TypeSIE_VER_EXPORT,
TypeSIE_KONTO,
TypeSIE_KONTO_EXPORT,
} from './typings/sie';
class sieParser {
private sie: string[];
public sieObject: TypeSIE;
constructor(path: string) {
const buffer = readFileSync(`${path}`);
const parsed = this.string(buffer);
this.sie = this.sieLines(parsed);
this.sieObject = this.parse();
}
private string(buffer: Buffer) {
// Thanks @piksel for this function ;)
const mapUTF8 =
'ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ';
return Array.from(buffer)
.map((b) =>
b < 128 ? String.fromCharCode(b) : mapUTF8.substr(b - 128, 1)
)
.join('');
}
private sieLineParser(str: string): string[] {
const result = [];
let current = '';
let inQuotes = false;
let inBrackets = false;
for (let i = 0; i < str.length; i++) {
if (str[i] === '"') {
inQuotes = !inQuotes;
continue;
}
if (str[i] === ' ' && !inQuotes && !inBrackets) {
result.push(current);
current = '';
} else {
current += str[i];
}
}
result.push(current);
return result;
}
private sieLines(str: string): string[] {
return str.split('\n');
}
private parse(): TypeSIE {
const sie: TypeSIE = { VER: {} };
let inBrackets = false;
let currentBracketName = '';
for (let i = 0; i < this.sie.length; i++) {
const e = this.sie[i];
const values = this.sieLineParser(e.trim());
const indexProp = values[0].replace('#', '');
if (e[0] === '{') {
inBrackets = true;
continue;
}
if (e[0] === '}') {
inBrackets = false;
continue;
}
if (indexProp === 'VER') {
const objectName = values[1] + values[2];
currentBracketName = objectName;
sie.VER[objectName] = {
serie: values[1],
vernr: values[2],
verdatum: values[3],
vertext: values[4],
regdatum: values[5],
sign: values[6],
TRANS: [],
RTRANS: [],
BTRANS: [],
};
continue;
}
if (inBrackets && indexProp === 'TRANS') {
sie.VER[currentBracketName].TRANS.push({
kontonr: values[1],
object: values[2],
belop: values[3],
transdat: values[4],
kvantitet: values[5],
sign: values[6],
});
continue;
}
if (inBrackets && indexProp === 'RTRANS') {
sie.VER[currentBracketName].RTRANS.push({
kontonr: values[1],
object: values[2],
belop: values[3],
transdat: values[4],
kvantitet: values[5],
sign: values[6],
});
continue;
}
switch (indexProp) {
case 'ADRESS':
sie.ADRESS = {
kontakt: values[1],
postadr: values[2],
tel: values[3],
utdelningsadr: values[4],
};
break;
case 'BKOD':
sie.BKOD = values[1];
break;
case 'DIM':
if (!sie.DIM) sie.DIM = [];
sie.DIM?.push({
dimensionsnr: values[1],
namn: values[2],
});
break;
case 'ENHET':
sie.ENHET = {
kontonr: values[1],
enhet: values[2],
};
break;
case 'FLAGGA':
sie.FLAGGA = values[1];
break;
case 'FNAMN':
sie.FNAM = values[1];
break;
case 'FNR':
sie.FNR = values[1];
break;
case 'FORMAT':
sie.FORMAT = values[1];
break;
case 'FTYP':
sie.FTYP = values[1];
break;
case 'GEN':
sie.GEN = {
datum: values[1],
sign: values[2],
};
break;
case 'IB':
if (!sie.IB) sie.IB = [];
sie.IB?.push({
årsnr: values[1],
konto: values[2],
saldo: values[3],
kvantitet: values[4],
});
break;
case 'KONTO':
if (!sie.KONTO) sie.KONTO = [];
sie.KONTO?.push({
kontonr: values[1],
kontonamn: values[2],
});
break;
case 'KPTYP':
sie.KPTYP = values[1];
break;
case 'KTYP':
sie.KTYP = {
kontonr: values[1],
kontotyp: values[2],
};
break;
case 'OBJECT':
sie.OBJECT?.push({
dimensionsnr: values[1],
objektnr: values[2],
objektnamn: values[3],
});
break;
case 'OIB':
{
// TODO: Test this function with real SIE files
const [dimensionsnr, objektnr] = values[3]
.replace('"', ' ')
.trim()
.split(' ');
sie.OIB = {
årsnr: values[1],
konto: values[2],
objectspecifikation: { dimensionsnr, objektnr },
saldo: values[4],
kvantitet: values[5],
};
}
break;
case 'OMFATTN':
sie.OMFATTN = values[1];
break;
case 'ORGNR':
sie.ORGNR = {
orgnr: values[1],
förvnr: values[2],
verknr: values[3],
};
break;
case 'OUB':
{
// TODO: Test this function with real SIE files
const [dimensionsnr, objektnr] = values[3]
.replace('"', ' ')
.trim()
.split(' ');
sie.OUB = {
årsnr: values[1],
konto: values[2],
objectspecifikation: { dimensionsnr, objektnr },
saldo: values[4],
kvantitet: values[5],
};
}
break;
case 'PBUDGET':
{
// TODO: Test this function wsith real SIE files
if (!sie.PBUDGET) sie.PBUDGET = [];
const [dimensionsnr, objektnr] = values[4]
.replace('"', ' ')
.trim()
.split(' ');
sie.PBUDGET.push({
årsnr: values[1],
period: values[2],
konto: values[3],
objectspecifikation: { dimensionsnr, objektnr },
saldo: values[5],
kvantitet: values[6],
});
}
break;
case 'PROGRAM':
sie.PROGRAM = {
programnamn: values[1],
verision: values[2],
};
break;
case 'PROSA':
sie.PROSA = values[1];
break;
case 'PSALDO':
{
if (!sie.PSALDO) sie.PSALDO = [];
const [dimensionsnr, objektnr] = values[4]
.replace('"', ' ')
.trim()
.split(' ');
sie.PSALDO.push({
årsnr: values[1],
period: values[2],
konto: values[3],
objectspecifikation: {
dimensionsnr: dimensionsnr !== '{}' ? dimensionsnr : undefined,
objektnr,
},
saldo: values[5],
kvantitet: values[6],
});
}
break;
case 'RAR':
if (!sie.RAR) sie.RAR = [];
sie.RAR?.push({
årsnr: values[1],
start: values[2],
slut: values[3],
});
break;
case 'RES':
if (!sie.RES) sie.RES = [];
sie.RES?.push({
års: values[1],
konto: values[2],
saldo: values[3],
kvantitet: values[4],
});
break;
case 'SIETYP':
sie.SIETYP = values[1];
break;
case 'SRU':
if (!sie.SRU) sie.SRU = [];
sie.SRU?.push({
konto: values[1],
'SRU-kod': values[2],
});
break;
case 'TAXAR':
sie.TAXAR = values[1];
break;
case 'UB':
if (!sie.UB) sie.UB = [];
sie.UB.push({
årsnr: values[1],
konto: values[2],
saldo: values[3],
kvantitet: values[4],
});
break;
case 'UNDERDIM':
if (!sie.UNDERDIM) sie.UNDERDIM = [];
sie.UNDERDIM.push({
dimensionsnr: values[1],
namn: values[2],
superdimension: values[3],
});
break;
case 'VALUTA':
sie.VALUTA = values[1];
break;
default:
break;
}
}
return sie;
}
public getVerifications(): string[] {
const element = this.sieObject.VER;
return Object.keys(element);
}
public getVerificationData(verification: string): TypeSIE_VER_EXPORT {
const element = this.sieObject.VER[verification];
return element;
}
public getSeries(series: string) {
const element = Object.keys(this.sieObject.VER).map((key) => {
const e = this.sieObject.VER[key];
if (e.serie === series.toUpperCase()) return e;
});
const filteredElement = element.filter((e) => e !== undefined);
if (filteredElement.length === 0) return undefined;
return filteredElement;
}
public getSerieDateRange(
dateStart: number,
dateEnd: number,
opt?: {
timeType?: 'verdatum' | 'regdatum';
serie?: string;
}
) {
if (dateStart.toString().length !== 8)
throw Error('Invalid dateStart length');
if (dateEnd.toString().length !== 8)
throw Error('Invalid dateStart length');
const element = Object.keys(this.sieObject.VER).map((key) => {
const e = this.sieObject.VER[key];
const time =
!opt?.timeType || opt.timeType !== 'regdatum'
? Number(e.verdatum)
: Number(e.regdatum);
if (!time) return undefined;
if (time <= dateEnd && time >= dateStart) {
if (opt?.serie) {
if (e.serie === opt.serie.toUpperCase()) {
return e;
}
return undefined;
}
return e;
}
});
const filteredElement = element.filter((e) => e !== undefined);
if (filteredElement.length === 0) return undefined;
return filteredElement;
}
public getAccount(
kontonr?: string | number,
opts?: { ib?: boolean; ub?: boolean; psaldo?: boolean; konto?: boolean }
): TypeSIE_KONTO_EXPORT | TypeSIE_KONTO[] | undefined {
if (!kontonr) {
const element = this.sieObject.KONTO;
return element;
}
let returnObj: TypeSIE_KONTO_EXPORT = {};
kontonr = kontonr.toString();
const kontoDesc: TypeSIE_KONTO | undefined = this.sieObject.KONTO?.find(
(e) => e.kontonr === kontonr
);
if (!kontoDesc) return undefined;
if (opts?.konto !== false) {
returnObj = { ...kontoDesc };
}
if (opts?.ib !== false) {
returnObj.IB = this.sieObject.IB?.filter((e) => e.konto === kontonr);
}
if (opts?.ub !== false) {
returnObj.UB = this.sieObject.UB?.filter((e) => e.konto === kontonr);
}
if (opts?.psaldo !== false) {
returnObj.PSALDO = this.sieObject.PSALDO?.filter(
(e) => e.konto === kontonr
);
}
return returnObj;
}
}
export = sieParser;