1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
import { Application } from '@feathersjs/express';
import { HookContext } from '@feathersjs/feathers';
import blobService from 'feathers-blob';
import fs from 'fs-blob-store';
import moment from 'moment';
import Bluebird from 'bluebird';
import { PdfReader } from 'pdfreader'
import _ from 'lodash';
const dir = './documents';
const blobStorage = fs(dir);
const uploads = blobService({ Model: blobStorage });
// Async wrapper for pdfreader
const parsePdfItems = async (fileName: string): Promise<any[]> => {
return new Promise((resolve, reject) => {
const reader = new PdfReader();
const items: any[] = [];
reader.parseFileItems(fileName, (err: Error, item: any) => {
if (err) reject(err);
else if (item) items.push(item);
else resolve(items);
});
});
};
const parseTransfersBill = async (context: HookContext): Promise<HookContext> => {
const { id } = context.result;
const fileName = `${dir}/${id}`;
const items = await parsePdfItems(fileName);
const hash = _.groupBy(items, 'y')
const rows = _.map(hash, (elements: any[]) => _.map(elements, 'text'));
const transfers = rows.reduce((acc: any, cols: string[]) => {
if (cols[0]?.startsWith('УНП')) {
acc[acc.length - 1].vatId = cols[2];
acc[acc.length - 1].name = cols[3];
} else if (cols.length === 7) {
const [dateString, doc, op, code, account, debet, credit] = cols;
try {
const date = moment.utc(dateString, 'DD.MM.YYYY').toISOString();
acc.push({ date, doc, op, code, account, debet, credit });
} catch (e) {
console.log(`Skipping row because not a date: ${dateString}`);
}
}
return acc;
}, []);
// At this point we can remove the file
context.service.remove(id);
context.result = await Bluebird.mapSeries(transfers, async (transfer: any) => {
const { date, vatId, name } = transfer;
const debet = parseFloat(transfer.debet.replace(/ /g, ''));
const credit = parseFloat(transfer.credit.replace(/ /g, ''));
const operation = debet ? 'out' : 'in';
const amount = debet || credit;
const contractorId = await context.app
.service('contractors')
.find({ query: { vatId } })
.then((results: any[]) => {
if (results.length) return results[0];
return context.app
.service('contractors')
.create({ vatId, name });
})
.then((contractor: any) => contractor._id);
return context.app.service('transfers').create({
date,
operation,
amount,
contractorId,
});
});
return context;
};
export default (app: Application): void => {
app.use('/uploads', uploads);
app.service('uploads').hooks({
after: {
create: parseTransfersBill,
},
});
};
|