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, +    }, +  });  }; | 
