diff --git a/.gitignore b/.gitignore index 7509db0..cacfcd7 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,6 @@ build/ # javascript *.js + +# data +data/ diff --git a/package.json b/package.json index f479203..df71c4c 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,9 @@ "version": "0.0.1", "description": "BIJ1 Compliance Facilitator App", "transform": {}, - "main": "src/app.js", + "main": "build/src/app.js", "scripts": { - "start": "tsc; node src/app.js", + "start": "tsc; node build/src/app.js", "dev": "chokidar src -c 'npm run test'", "test": "jshint --config .jshintrc ./src && jest" }, @@ -21,9 +21,13 @@ "homepage": "https://gitlab.com/bij1/bij1-compliance#readme", "dependencies": { "@mollie/api-client": "^3.5.1", + "@types/papaparse": "^5.2.6", + "@types/ramda": "^0.27.45", "airtable": "^0.11.1", "chokidar-cli": "^3.0.0", "mollie": "^2.0.2", + "papaparse": "^5.3.1", + "ramda": "^0.27.1", "typescript": "^4.4.3" }, "devDependencies": { diff --git a/src/app.ts b/src/app.ts index da39e1a..5deafc2 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,16 +1,29 @@ "use strict"; -import { createMollieClient } from '@mollie/api-client'; -import { log } from './utils'; +import { writeFileSync } from 'fs'; +import { unparse } from 'papaparse'; +import { createMollieClient, MollieClient } from '@mollie/api-client'; +import { log, mapKeys, prepend } from './utils'; import { mollieKeys, listAll } from './mollie'; async function main() { const mollie = createMollieClient({ apiKey: mollieKeys.leden }); - const page$ = mollie.customers.list(); - const list = await listAll(page$, 500); - // const list = Array.from(await page$); - // log(list); - const list_ = list.map(({ id, name, email, createdAt }) => ({ id, name, email, createdAt })); - log(list_); - log(list_.length); + exportMollieCustomers(mollie); + exportMolliePayments(mollie); } + +async function exportMollieCustomers(mollie: MollieClient) { + const page$ = mollie.customers.list(); + const list = (await listAll(page$, 500)) + .map(({ id, name, email, createdAt }) => ({ id, name, email, createdAt })); + writeFileSync('./data/customers.csv', unparse(list)); +} + +async function exportMolliePayments(mollie: MollieClient) { + const page$ = mollie.payments.list(); + const list = (await listAll(page$, 500)) + // const list = Array.from(await page$) + .map(({ id, createdAt, paidAt, description, method, status, isCancelable, sequenceType, profileId, customerId, mandateId, details, amount, settlementAmount, amountRefunded, amountRemaining }) => ({ id, createdAt, paidAt, description, method, status, isCancelable, sequenceType, profileId, customerId, mandateId, ...mapKeys(prepend('details.'))(details), ...mapKeys(prepend('amount.'))(amount), ...mapKeys(prepend('settlementAmount.'))(settlementAmount), ...mapKeys(prepend('amountRefunded.'))(amountRefunded), ...mapKeys(prepend('amountRemaining.'))(amountRemaining) })); + writeFileSync('./data/payments.csv', unparse(list)); +} + main(); diff --git a/src/mollie.ts b/src/mollie.ts index 434281e..01b82c3 100644 --- a/src/mollie.ts +++ b/src/mollie.ts @@ -8,6 +8,7 @@ export const mollieKeys = { export async function listAll(list$: Promise>, ms: number = 1000): Promise { const list = await list$; const { count, nextPage, links } = list; + console.log('.'); await new Promise(resolve => setTimeout(resolve, ms)); const rest = await (nextPage ? listAll(nextPage()) : Promise.resolve([])); return [...list, ...rest]; diff --git a/src/utils.ts b/src/utils.ts index d77f372..f923888 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1 +1,8 @@ +import * as R from 'ramda'; + export const log = console.log.bind(console); + +export const mapKeys: (fn: (k: string) => string) => (o?: {[k: string]: any}) => {[k: string]: any} = (fn: (k: string) => string) => + R.pipe(R.defaultTo({}), Object.entries, R.map(R.adjust(0, fn)), Object.fromEntries); + +export const prepend: (k: string) => (k: string) => string = R.curry((a,b) => a+b); diff --git a/tsconfig.json b/tsconfig.json index 278e70a..1be0687 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -48,7 +48,7 @@ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ - // "outDir": "./", /* Specify an output folder for all emitted files. */ + "outDir": "./build", /* Specify an output folder for all emitted files. */ // "removeComments": true, /* Disable emitting comments. */ // "noEmit": true, /* Disable emitting files from a compilation. */ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ diff --git a/uml/data.txt b/uml/data.txt index 89b0c19..df307a1 100644 --- a/uml/data.txt +++ b/uml/data.txt @@ -16,22 +16,82 @@ map Details { signatureDate: ISO 8601 datum } +map MollieCustomer { + resource => 'customer' + id => unieke code beginnend met 'cst_' + mode => 'test'/'live' + name => Naam lid + email => email + locale => taal in iso formaat bv nl_NL. soms null. + metadata => null + createdAt => ISO 8601 datum+tijd+tijdzone + _links => *-> MollieCustomerLinks +} + +map MollieLink { + href => url + type => ISO type e.g. 'text/html' +} + +' map MollieCustomerLinks { +' self *-> MollieCustomer +' dashboard *-> MollieDashboard +' mandates *-> MollieMandate +' payments *-> MolliePayment +' } + +map MollieCustomerLinks { + self *-> MollieLink + dashboard *-> MollieLink + mandates *-> MollieLink + payments *-> MollieLink +} + map MolliePayment { - resource => payment + resource => 'payment' amount *-> Amount settlementAmount *-> Amount - id => unieke code - mode => test + id => unieke code beginnend met 'tr_' + mode => 'test'/'live' createdAt => ISO 8601 datum+tijd+tijdzone - description => Maandelijkse Contributie BIJ1 | 1001 - method => directdebit - status => pending + description => 'Maandelijkse Contributie BIJ1 | ' + identifier #### + method => 'directdebit' + status => 'paid'/'pending' isCancelable => true/false - profileId => xxxxx - customerId => xxxxx - mandateId => xxxxx - sequenceType => recurring + profileId => xxxxx, begint met 'pfl_' + customerId => xxxxx, begint met 'cst_' + mandateId => xxxxx, begint met 'mdt_' + sequenceType => 'recurring' details *-> Details + paidAt => ISO 8601 datum+tijd+tijdzone + amountRefunded *-> Amount + amountRemaining *-> Amount + locale => taal in iso formaat bv nl_NL. soms null. + metadata => null + webhookUrl => url + redirectUrl => null + _links => *-> MolliePaymentLinks + _embedded => undefined +} + +' map MolliePaymentLinks { +' self *-> MolliePayment +' dashboard *-> MollieDashboard +' customer *-> MollieCustomer +' mandate *-> MollieMandate +' } + +map MolliePaymentLinks { + self *-> MollieLink + dashboard *-> MollieLink + customer *-> MollieLink + mandate *-> MollieLink +} + +map MollieDashboard { +} + +map MollieMandate { } map Airtable { diff --git a/yarn.lock b/yarn.lock index 4faf9c7..2f57370 100644 --- a/yarn.lock +++ b/yarn.lock @@ -597,11 +597,25 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.17.20.tgz#74cc80438fd0467dc4377ee5bbad89a886df3c10" integrity sha512-gI5Sl30tmhXsqkNvopFydP7ASc4c2cLfGNQrVKN3X90ADFWFsPEsotm/8JHSUJQKTHbwowAHtcJPeyVhtKv0TQ== +"@types/papaparse@^5.2.6": + version "5.2.6" + resolved "https://registry.yarnpkg.com/@types/papaparse/-/papaparse-5.2.6.tgz#0bba18de4d15eff65883bc7c0794e0134de9e7c7" + integrity sha512-xGKSd0UTn58N1h0+zf8mW863Rv8BvXcGibEgKFtBIXZlcDXAmX/T4RdDO2mwmrmOypUDt5vRgo2v32a78JdqUA== + dependencies: + "@types/node" "*" + "@types/prettier@^2.1.5": version "2.4.1" resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.4.1.tgz#e1303048d5389563e130f5bdd89d37a99acb75eb" integrity sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw== +"@types/ramda@^0.27.45": + version "0.27.45" + resolved "https://registry.yarnpkg.com/@types/ramda/-/ramda-0.27.45.tgz#1d692736da8f8c199e10c751d4799cab03cd9acd" + integrity sha512-WDH7bIuy+JQHzYx6jgo+ytSHco/J+DWaUfxXQ2eBjilxIj4rG0aqQNU56AtO5Tem9hmx8na2ouSAtn5Tz8RePQ== + dependencies: + ts-toolbelt "^6.15.1" + "@types/stack-utils@^2.0.0": version "2.0.1" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" @@ -2402,6 +2416,11 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +papaparse@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/papaparse/-/papaparse-5.3.1.tgz#770b7a9124d821d4b2132132b7bd7dce7194b5b1" + integrity sha512-Dbt2yjLJrCwH2sRqKFFJaN5XgIASO9YOFeFP8rIBRG2Ain8mqk5r1M6DkfvqEVozVcz3r3HaUGw253hA1nLIcA== + parse5@6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" @@ -2484,6 +2503,11 @@ punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +ramda@^0.27.1: + version "0.27.1" + resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.27.1.tgz#66fc2df3ef873874ffc2da6aa8984658abacf5c9" + integrity sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw== + react-is@^17.0.1: version "17.0.2" resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" @@ -2829,6 +2853,11 @@ ts-jest@^27.0.5: semver "7.x" yargs-parser "20.x" +ts-toolbelt@^6.15.1: + version "6.15.5" + resolved "https://registry.yarnpkg.com/ts-toolbelt/-/ts-toolbelt-6.15.5.tgz#cb3b43ed725cb63644782c64fbcad7d8f28c0a83" + integrity sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A== + type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"