summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreug-vs <eug-vs@keemail.me>2021-03-20 17:01:41 +0300
committereug-vs <eug-vs@keemail.me>2021-03-20 17:01:41 +0300
commitf0fe802df9fd7e98c0333a80922f6008cab7abab (patch)
tree9d4ec9e822621c4693e015edf17811c340e8a1be
parent2434c687bbc8f5b42b380a75e48cf1879a508674 (diff)
downloadcommercel-api-f0fe802df9fd7e98c0333a80922f6008cab7abab.tar.gz
feat: parse pdf bills into transfers
-rw-r--r--package.json1
-rw-r--r--src/models/contractor/contractor.schema.ts5
-rw-r--r--src/services/uploads.service.ts79
-rw-r--r--src/types.ts1
-rw-r--r--yarn.lock42
5 files changed, 123 insertions, 5 deletions
diff --git a/package.json b/package.json
index 5701420..5baa782 100644
--- a/package.json
+++ b/package.json
@@ -26,6 +26,7 @@
"fs-blob-store": "^6.0.0",
"moment": "^2.29.1",
"mongoose": "^5.12.0",
+ "pdfreader": "^1.2.8",
"ts-node": "^9.1.1",
"typescript": "^4.2.3"
}
diff --git a/src/models/contractor/contractor.schema.ts b/src/models/contractor/contractor.schema.ts
index e3f7de6..d5ac115 100644
--- a/src/models/contractor/contractor.schema.ts
+++ b/src/models/contractor/contractor.schema.ts
@@ -13,6 +13,9 @@ export const contractorSchema = new Schema({
fullName: String,
vatId: String,
type: String,
- debt: Number
+ debt: {
+ type: Number,
+ default: 0
+ }
}, { timestamps: true });
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,
+ },
+ });
};
diff --git a/src/types.ts b/src/types.ts
index 745d7f2..fd1e7a2 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -1,3 +1,4 @@
declare module 'fs-blob-store';
declare module 'feathers-blob';
+declare module 'pdfreader';
diff --git a/yarn.lock b/yarn.lock
index cfc9423..2cb00e5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1099,7 +1099,7 @@ lodash.uniq@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
-lodash@^4.17.20:
+lodash@^4.17.13, lodash@^4.17.20:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@@ -1165,6 +1165,11 @@ minimist@^1.2.5:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
+minimist@~0.0.1:
+ version "0.0.10"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
+ integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=
+
mkdirp-classic@^0.5.3:
version "0.5.3"
resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113"
@@ -1283,6 +1288,14 @@ once@^1.3.0, once@^1.4.0:
dependencies:
wrappy "1"
+optimist@^0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
+ integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY=
+ dependencies:
+ minimist "~0.0.1"
+ wordwrap "~0.0.2"
+
pako@~1.0.2:
version "1.0.11"
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
@@ -1313,6 +1326,23 @@ path-to-regexp@0.1.7:
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
+pdf2json@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/pdf2json/-/pdf2json-1.2.0.tgz#fdb395fad1d18248756cfbc758066a2f15b903bf"
+ integrity sha512-Z/m+OFOe13Nn2SHQNSINZ6Mh2b8t2bK3whL3L6b5Av1wqDvotYvpMg1Zi8aEPV37jF0jG0yQ83c8XuuNbIsn6Q==
+ dependencies:
+ async "^3.2.0"
+ lodash "^4.17.13"
+ optimist "^0.6.1"
+ xmldom "^0.3.0"
+
+pdfreader@^1.2.8:
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/pdfreader/-/pdfreader-1.2.8.tgz#9f82ef695ca0bc4524f79fd5ca55f014205706b7"
+ integrity sha512-LD9NdIaY1vc8kUcuFpJPHJF4nbyc1HHL3TehyiEw9KC7nN175pOfmdRUkjUGW28xr2f+ADLLGLl7ZyDXL7EBRw==
+ dependencies:
+ pdf2json "1.2.0"
+
printj@~1.1.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222"
@@ -1732,6 +1762,11 @@ vary@^1, vary@~1.1.2:
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
+wordwrap@~0.0.2:
+ version "0.0.3"
+ resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
+ integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc=
+
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
@@ -1747,6 +1782,11 @@ xmlchars@^2.2.0:
resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb"
integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==
+xmldom@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.3.0.tgz#e625457f4300b5df9c2e1ecb776147ece47f3e5a"
+ integrity sha512-z9s6k3wxE+aZHgXYxSTpGDo7BYOUfJsIRyoZiX6HTjwpwfS2wpQBQKa2fD+ShLyPkqDYo5ud7KitmLZ2Cd6r0g==
+
xmlhttprequest-ssl@~1.5.4:
version "1.5.5"
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"