diff options
author | eug-vs <eug-vs@keemail.me> | 2021-03-20 17:01:41 +0300 |
---|---|---|
committer | eug-vs <eug-vs@keemail.me> | 2021-03-20 17:01:41 +0300 |
commit | f0fe802df9fd7e98c0333a80922f6008cab7abab (patch) | |
tree | 9d4ec9e822621c4693e015edf17811c340e8a1be /src/services | |
parent | 2434c687bbc8f5b42b380a75e48cf1879a508674 (diff) | |
download | commercel-api-f0fe802df9fd7e98c0333a80922f6008cab7abab.tar.gz |
feat: parse pdf bills into transfers
Diffstat (limited to 'src/services')
-rw-r--r-- | src/services/uploads.service.ts | 79 |
1 files changed, 76 insertions, 3 deletions
diff --git a/src/services/uploads.service.ts b/src/services/uploads.service.ts index 520079f..1d39a66 100644 --- a/src/services/uploads.service.ts +++ b/src/services/uploads.service.ts @@ -1,13 +1,86 @@ 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 blobStorage = fs('./uploads'); - +const dir = './documents'; +const blobStorage = fs(dir); const uploads = blobService({ Model: blobStorage }); + +const parseTransfersBill = async (context: HookContext): Promise<HookContext> => { + const { id } = context.result; + const fileName = `${dir}/${id}`; + + const reader = new PdfReader(); + const items: any[] = []; + + reader.parseFileItems(fileName, (err: Error, item: any) => { + if (item) items.push(item); + else { // Finished parsing. TODO: wrap into async + 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; + }, []); + + return 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, + }); + }).then(() => context.service.remove(id)); + } + }); + + return context; +}; + + export default (app: Application): void => { - app.use('/uploads', uploads) + app.use('/uploads', uploads); + + app.service('uploads').hooks({ + after: { + create: parseTransfersBill, + }, + }); }; |