summaryrefslogtreecommitdiff
path: root/src/services/uploads.service.ts
blob: 3479d0fac476e02cd48be6ca7578ce6f34c54c66 (plain)
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(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,
    },
  });
};